npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

lwc-convert

v1.8.0

Published

CLI tool to convert Salesforce Aura and Visualforce components to Lightning Web Components

Readme

🔄 lwc-convert

A precision TypeScript CLI tool for converting Salesforce Aura components and Visualforce pages to Lightning Web Components (LWC)


lwc-convert automates the migration of legacy Salesforce UI technologies to modern Lightning Web Components:

| Source Technology | Target | Confidence | |-------------------|--------|------------| | Aura Components | LWC | High | | Visualforce Pages | LWC | Medium-High |

What You Get

For each conversion, the tool generates a complete LWC bundle:

myComponent/
├── myComponent.html        # Converted template
├── myComponent.js          # ES6 class with decorators
├── myComponent.css         # Scoped styles
├── myComponent.js-meta.xml # Component configuration
└── CONVERSION_NOTES.md     # Action items & guidance

✨ Features

🎯 Single-Component Focus

Unlike batch tools that sacrifice accuracy, lwc-convert processes one component at a time for maximum precision and detailed error reporting.

📝 Two Output Modes

| Mode | Description | Best For | |------|-------------|----------| | Scaffolding (default) | Generates skeleton with // TODO: comments | Complex components requiring manual attention | | Full Conversion (--full) | Complete transformation with // REVIEW: markers | Simple, standard components |

🔍 Smart Analysis

  • Parses Aura markup, controllers, helpers, and styles
  • Analyzes Apex controllers for VF pages
  • Detects patterns and suggests modern equivalents
  • Identifies potential issues upfront
  • New! 📊 Complexity Grading: Analyze components before conversion to estimate effort and identify risks
  • New! 📈 CSV Export: Export grading reports for team tracking and stakeholder updates
  • New! 🔔 Update Notifications: Get notified when new versions are available

📋 Conversion Notes

Every conversion includes a detailed markdown file with:

  • ✅ Completed transformations
  • ⚠️ Items needing manual attention
  • 📖 Migration guidance and best practices

🚀 Quick Start

Interactive Mode

Just run lwc-convert without arguments to launch the interactive TUI:

npx lwc-convert

You'll be guided through:

  1. Select conversion type (Aura or Visualforce)
  2. Choose component from auto-discovered list or enter path
  3. Configure options (scaffolding/full, output dir, open folder)
  4. Confirm and convert!

Prerequisites

  • Node.js 18.0 or higher
  • npm 8.0 or higher

Installation

Via npm (recommended):

# Run directly with npx (no install needed)
npx lwc-convert aura AccountCard

# Or install globally
npm install -g lwc-convert
lwc-convert aura AccountCard

From source (for development):

git clone https://github.com/Lastonedown86/lwc-convert.git
cd lwc-convert
npm install
npm run build
npm link

Your First Conversion

Convert an Aura Component:

# Just use the component name — the CLI searches automatically!
lwc-convert aura AccountCard

# Or use a full path
lwc-convert aura ./force-app/main/default/aura/AccountCard

# Full conversion mode
lwc-convert aura AccountCard --full

Convert a Visualforce Page:

# Just use the page name (with or without .page extension)
lwc-convert vf ContactList

# With Apex controller (also supports just the class name)
lwc-convert vf ContactList --controller ContactListController

# Or use full paths
lwc-convert vf ./pages/ContactList.page --controller ./classes/ContactListController.cls

Preview Without Writing Files:

lwc-convert aura MyComponent --dry-run --verbose

Assess Conversion Complexity:

# Grade a single component
lwc-convert grade AccountCard --type aura

# Scan entire project and export report
lwc-convert grade --type both --format json -o report.json

# Export to CSV for team tracking (Excel/Sheets compatible)
lwc-convert grade --format csv -o migration-status.csv

# Filter to only problematic components
lwc-convert grade --filter "grade:D,F" --format csv -o needs-attention.csv

💡 Smart Path Resolution: The CLI automatically searches common Salesforce project locations:

  • force-app/main/default/aura/, src/aura/, aura/
  • force-app/main/default/pages/, src/pages/, pages/
  • force-app/main/default/classes/, src/classes/, classes/

📖 CLI Reference

Commands

lwc-convert                       # Launch interactive TUI
lwc-convert aura <name-or-path>   # Convert Aura component bundle
lwc-convert vf <name-or-path>     # Convert Visualforce page
lwc-convert grade [target]        # Assess conversion complexity
lwc-convert deps [target]         # Analyze component dependencies
lwc-convert session               # View session info and patterns

Global Options

| Option | Description | |--------|-------------| | -V, --version | Display version | | -h, --help | Show help |

Aura Command Options

lwc-convert aura <bundle-path> [options]

| Option | Description | Default | |--------|-------------|---------| | --full | Full conversion instead of scaffolding | false | | -o, --output <dir> | Output directory | ./lwc-output | | --open | Open output folder in file explorer | false | | --dry-run | Preview without writing files | false | | --verbose | Show detailed logs | false |

VF Command Options

lwc-convert vf <page-path> [options]

| Option | Description | Default | |--------|-------------|---------| | --full | Full conversion instead of scaffolding | false | | -o, --output <dir> | Output directory | ./lwc-output | | --controller <path> | Apex controller for enhanced analysis | — | | --open | Open output folder in file explorer | false | | --dry-run | Preview without writing files | false | | --verbose | Show detailed logs | false |

Grade Command Options

lwc-convert grade [target] [options]

| Option | Description | Default | |--------|-------------|---------| | -t, --type <type> | Component type (aura, vf, both) | both | | -o, --output <file> | Output file for report | — | | --format <format> | Output format (json, csv, console) | console | | --detailed | Show detailed breakdown | false | | --sort-by <field> | Sort by score, complexity, or name | score | | --filter <filter> | Filter results (e.g., grade:D,F) | — |

Deps Command Options

lwc-convert deps [target] [options]

| Option | Description | Default | |--------|-------------|---------| | -t, --type <type> | Component type (aura, vf, both) | both | | -o, --output <file> | Output file path | — | | --format <format> | Output format (console, json, mermaid) | console | | --conversion-order | Show recommended conversion order | false | | --focus <component> | Focus on specific component | — | | --depth <n> | Maximum depth to traverse (0 = unlimited) | 0 | | --circular-only | Only show circular dependencies | false |

Session Command Options

lwc-convert session [options]

| Option | Description | |--------|-------------| | --report | Generate full session report | | --patterns | Show learned patterns from session | | --cleanup | Clean up session data |


🔄 Output Modes

Scaffolding Mode (Default)

Generates an LWC skeleton optimized for manual completion:

import { LightningElement, api } from 'lwc';

// TODO: Import Apex method - verify class and method name
// import getRecords from '@salesforce/apex/MyController.getRecords';

export default class MyComponent extends LightningElement {
    // TODO: Verify if this should be @api (public) or private
    @api recordId;

    // Converted from aura:attribute "items"
    items = [];

    // TODO: Migrate logic from Aura init handler
    connectedCallback() {
        // Original init logic goes here
    }

    // TODO: Implement - converted from controller.handleSave
    handleSave(event) {
        // Original: component.get("v.record"), then server call
    }
}

Full Conversion Mode (--full)

Attempts complete code transformation:

import { LightningElement, api, wire } from 'lwc';
import getRecords from '@salesforce/apex/MyController.getRecords';

export default class MyComponent extends LightningElement {
    @api recordId;
    items = [];
    isLoading = false;

    connectedCallback() {
        this.loadRecords();
    }

    async loadRecords() {
        this.isLoading = true;
        try {
            // REVIEW: Verify Apex method parameters
            this.items = await getRecords({ recordId: this.recordId });
        } catch (error) {
            console.error('Error loading records:', error);
        } finally {
            this.isLoading = false;
        }
    }

    handleSave(event) {
        // REVIEW: Complex logic converted - verify behavior
        const record = { ...this.currentRecord };
        // ... conversion continues
    }
}

📊 Migration Tracking

CSV Export for Teams

Export grading results to CSV for tracking migration progress in spreadsheets:

# Full project export
lwc-convert grade --format csv -o migration-status.csv

# Only components needing attention
lwc-convert grade --filter "grade:D,F" --format csv -o needs-attention.csv

CSV includes:

  • Component name, type, and file path
  • Score (0-100) and letter grade (A-F)
  • Complexity level and estimated manual hours
  • Automated conversion percentage
  • Warning count per component
  • Summary section with totals and grade distribution

Dependency Analysis

Visualize component relationships and plan conversion order:

# Show all dependencies
lwc-convert deps

# Get recommended conversion order (leaves first)
lwc-convert deps --conversion-order

# Focus on one component's dependency tree
lwc-convert deps --focus AccountCard

# Export as Mermaid diagram for documentation
lwc-convert deps --format mermaid -o deps.md

Session Learning

The tool learns patterns during your session to improve suggestions:

# View session summary
lwc-convert session

# See learned conversion patterns
lwc-convert session --patterns

# Full session report
lwc-convert session --report

🔔 Update Notifications

Starting with v1.5.0, lwc-convert automatically checks for updates and notifies you when a new version is available:

  ╭───────────────────────────────────────────────╮
  │  Update available: 1.5.0 → 1.6.0             │
  │  Run npm i -g lwc-convert to update          │
  ╰───────────────────────────────────────────────╯
  • Non-blocking: Check runs in background, doesn't slow commands
  • Cached: Only checks npm registry once per 24 hours
  • Graceful: Silently skips if offline or npm is unreachable

📋 Conversion Mappings

Aura to LWC

| Aura | LWC | |------|-----| | <aura:component> | <template> | | <aura:if isTrue="{!v.show}"> | <template if:true={show}> | | <aura:if isFalse="{!v.hide}"> | <template if:false={hide}> | | <aura:iteration items="{!v.list}" var="item"> | <template for:each={list} for:item="item"> | | <aura:set attribute="x"> | Named slots or JavaScript | | <aura:html tag="div"> | Direct HTML element |

| Aura | LWC | |------|-----| | {!v.propertyName} | {propertyName} | | {!v.object.field} | {object.field} | | {!c.handleClick} | {handleClick} | | {!globalId} | data-id attribute | | {!$Label.ns.name} | Import from @salesforce/label |

| Aura | LWC | |------|-----| | <aura:attribute name="x" type="String"/> | @api x; | | <aura:attribute access="private"/> | Property without @api | | <aura:attribute default="value"/> | x = 'value'; | | aura:id="elementId" | data-id="elementId" |

| Aura | LWC | |------|-----| | component.get("v.name") | this.name | | component.set("v.name", val) | this.name = val | | component.find("auraId") | this.template.querySelector('[data-id="auraId"]') | | helper.doSomething(cmp) | this.doSomething() | | $A.enqueueAction(action) | Imperative Apex call | | $A.getCallback(fn) | Direct function call |

| Aura Handler | LWC Lifecycle | |--------------|---------------| | init | connectedCallback() | | render | renderedCallback() | | afterRender | renderedCallback() | | unrender | disconnectedCallback() | | destroy | disconnectedCallback() |

| Aura | LWC | |------|-----| | $A.get("e.c:myEvent") | new CustomEvent('myevent', {...}) | | event.fire() | this.dispatchEvent(event) | | event.setParams({...}) | { detail: {...} } in CustomEvent | | event.getParam("x") | event.detail.x | | <aura:handler event="c:MyEvt" action="{!c.handle}"/> | onmyevent={handle} | | <aura:registerEvent name="x"/> | Document in JSDoc |

| Aura | LWC | |------|-----| | <lightning:button> | <lightning-button> | | <lightning:input> | <lightning-input> | | <lightning:card> | <lightning-card> | | <lightning:datatable> | <lightning-datatable> | | <lightning:recordEditForm> | <lightning-record-edit-form> | | iconName="standard:account" | icon-name="standard:account" |

| Aura | LWC | |------|-----| | $A.util.isEmpty(x) | !x \|\| x.length === 0 | | $A.util.isUndefinedOrNull(x) | x === undefined \|\| x === null | | $A.util.addClass(el, 'cls') | el.classList.add('cls') | | $A.util.removeClass(el, 'cls') | el.classList.remove('cls') | | $A.util.toggleClass(el, 'cls') | el.classList.toggle('cls') |

Visualforce to LWC

| Visualforce | LWC | |-------------|-----| | <apex:page> | <template> | | <apex:form> | <lightning-record-edit-form> or <form> | | <apex:pageBlock> | <lightning-card> | | <apex:pageBlockSection> | <lightning-layout> | | <apex:pageBlockButtons> | SLDS button group |

| Visualforce | LWC | |-------------|-----| | <apex:inputText> | <lightning-input type="text"> | | <apex:inputTextarea> | <lightning-textarea> | | <apex:inputCheckbox> | <lightning-input type="checkbox"> | | <apex:inputField> | <lightning-input-field> | | <apex:selectList> | <lightning-combobox> | | <apex:selectRadio> | <lightning-radio-group> |

| Visualforce | LWC | |-------------|-----| | <apex:outputText> | {value} or <lightning-formatted-text> | | <apex:outputField> | <lightning-output-field> | | <apex:outputLabel> | <label> | | <apex:outputLink> | <a> or NavigationMixin |

| Visualforce | LWC | |-------------|-----| | <apex:pageBlockTable> | <lightning-datatable> | | <apex:dataTable> | <lightning-datatable> | | <apex:repeat> | <template for:each> | | <apex:dataList> | <template for:each> with <ul> | | <apex:detail> | <lightning-record-form> | | <apex:relatedList> | <lightning-related-list-view> |

| Visualforce | LWC | |-------------|-----| | <apex:commandButton> | <lightning-button onclick={handler}> | | <apex:commandLink> | <lightning-button variant="base"> | | <apex:actionFunction> | Imperative Apex call | | <apex:actionSupport> | Event handler (onclick, onchange) | | <apex:actionPoller> | setInterval in connectedCallback | | <apex:actionStatus> | <lightning-spinner> with loading state |

| Visualforce | LWC | |-------------|-----| | <apex:pageMessages> | ShowToastEvent | | <apex:messages> | ShowToastEvent | | <apex:message> | <lightning-helptext> or validation |

| Visualforce | LWC | |-------------|-----| | {!$CurrentPage.parameters.id} | @wire(CurrentPageReference) | | {!$User.Id} | import userId from '@salesforce/user/Id' | | {!$Label.ns.name} | import label from '@salesforce/label/ns.name' | | {!$Resource.name} | import res from '@salesforce/resourceUrl/name' |

| Visualforce | LWC | |-------------|-----| | Controller getter property | @wire decorator | | Controller action method | Imperative Apex with @AuraEnabled | | @RemoteAction | Imperative Apex with @AuraEnabled | | rerender="sectionId" | Reactive property update | | oncomplete="js()" | Promise .then() or async/await |


🏗️ Architecture

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│     Parsers     │────▶│  Transformers   │────▶│   Generators    │
└─────────────────┘     └─────────────────┘     └─────────────────┘
        │                       │                       │
        ▼                       ▼                       ▼
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│ • Aura Markup   │     │ • Markup Trans. │     │ • Scaffolding   │
│ • Aura JS       │     │ • JS Transform  │     │ • Full Convert  │
│ • Aura CSS      │     │ • Event Trans.  │     │ • Meta XML      │
│ • VF Page       │     │ • Data Binding  │     │ • Conv. Notes   │
│ • Apex Class    │     │                 │     │                 │
└─────────────────┘     └─────────────────┘     └─────────────────┘

Processing Pipeline

  1. Parse — Read and analyze source files (.cmp, Controller.js, Helper.js, .css, .page, .cls)
  2. Extract — Build intermediate representation (attributes, handlers, events, dependencies)
  3. Transform — Apply conversion rules (tag mappings, expressions, JavaScript patterns)
  4. Generate — Create complete LWC bundle (HTML, JS, CSS, meta XML)
  5. Document — Generate conversion notes with action items

📁 Project Structure

lwc-convert/
├── src/
│   ├── index.ts                    # CLI entry point
│   ├── cli/
│   │   ├── commands/
│   │   │   ├── aura.ts             # Aura conversion command
│   │   │   └── vf.ts               # VF conversion command
│   │   └── options.ts              # CLI option definitions
│   ├── parsers/
│   │   ├── aura/                   # Aura file parsers
│   │   └── vf/                     # VF/Apex parsers
│   ├── transformers/
│   │   ├── aura-to-lwc/            # Aura transformation rules
│   │   └── vf-to-lwc/              # VF transformation rules
│   ├── generators/
│   │   ├── scaffolding.ts          # Skeleton generator
│   │   └── full-conversion.ts      # Complete converter
│   ├── mappings/                   # Conversion mapping configs
│   └── utils/                      # Shared utilities
├── tests/
│   ├── fixtures/                   # Sample components for testing
│   └── __tests__/                  # Test suites
├── package.json
├── tsconfig.json
└── README.md

🧪 Development

Setup

npm install        # Install dependencies
npm run build      # Compile TypeScript
npm run dev -- aura ./path/to/component  # Run with ts-node

Scripts

| Script | Description | |--------|-------------| | npm run build | Compile TypeScript → JavaScript | | npm run dev | Run CLI with ts-node | | npm test | Run Jest test suite | | npm run lint | Run ESLint | | npm run format | Format with Prettier |

Testing

npm test                              # Run all tests
npm test -- --testPathPattern=parsers # Run parser tests only
npm test -- --coverage                # Generate coverage report

Tech Stack

| Category | Technology | |----------|------------| | Language | TypeScript 5.x | | Runtime | Node.js 18+ | | CLI | Commander.js | | HTML/XML | htmlparser2 + domhandler | | JavaScript AST | Babel (parser, traverse, generator) | | CSS | PostCSS | | Testing | Jest + ts-jest | | Linting | ESLint | | Formatting | Prettier |


⚠️ Limitations

General

  • Single component only — No batch processing by design
  • Static analysis — Cannot detect runtime behavior
  • Manual testing required — Generated code should be tested

Aura-Specific

  • Complex/nested expressions may need manual adjustment
  • $A.createComponent patterns require manual migration
  • Application events need manual pub/sub or LMS setup
  • Custom renderers need manual conversion

Visualforce-Specific

  • apex:actionRegion needs architectural redesign
  • Page includes need component composition
  • renderAs="pdf" has no LWC equivalent
  • Inline JavaScript needs manual migration

🔧 Troubleshooting

Ensure you're pointing to the component folder containing the .cmp file, not a parent directory.

# ✅ Correct
lwc-convert aura ./aura/MyComponent

# ❌ Incorrect
lwc-convert aura ./aura

The VF command requires a .page file path, not a directory.

# ✅ Correct
lwc-convert vf ./pages/MyPage.page

# ❌ Incorrect
lwc-convert vf ./pages/
  1. Ensure Node.js 18+ is installed
  2. Delete node_modules and run npm install
  3. Check for TypeScript errors: npm run build

Getting Help

  1. Run with --verbose for detailed output
  2. Use --dry-run to preview without writing files
  3. Check the generated CONVERSION_NOTES.md file
  4. Review // TODO: and // REVIEW: comments in generated code

🤝 Contributing

Contributions are welcome! Here's how to help:

Reporting Issues

  1. Check existing issues first
  2. Include reproduction steps
  3. Attach sample component (sanitized) if possible
  4. Include CLI output with --verbose

Submitting Changes

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for new functionality
  4. Ensure all tests pass (npm test)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Development Guidelines

  • Follow existing code style
  • Add tests for new features
  • Update documentation for new mappings
  • Use Conventional Commits format:
    • feat: add new feature (triggers minor release)
    • fix: resolve bug (triggers patch release)
    • docs: update README (no release)
    • feat!: breaking change (triggers major release)

📄 License

MIT License — Copyright © 2025

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.


🙏 Acknowledgments