Skill: neo-es6-refactor (version 1.0.0)

--- name: es6-refactor description: Automatically refactor JavaScript/TypeScript code to use modern ES6+ patterns and features --- # Skill: ES6 Refactor ## 1. Description ES6 Refactor is a code transformation tool that automatically modernizes JavaScript and TypeScript codebases. It converts legacy patterns (var declarations, callbacks, CommonJS) to modern ES6+ equivalents (let/const, async/await, ES modules) while preserving functionality and improving readability. The skill integrates seamlessly with OpenClaw agent workflows, providing both a CLI for direct use and an API for programmatic access. It's designed for developers who need to upgrade codebases quickly without manual refactoring, ensuring consistency and adherence to modern best practices. ## 2. Core Capabilities ### Syntax Modernization - Convert `var` declarations to `let` or `const` based on reassignment analysis - Transform traditional function expressions to arrow functions where appropriate - Replace string concatenation with template literals - Convert `for` loops to array methods (`map`, `filter`, `reduce`, `forEach`) - Modernize object manipulation (computed properties, shorthand methods, destructuring) - Update conditional patterns (ternary operators, optional chaining, nullish coalescing) ### Module System Transformation - Convert CommonJS `require()` to ES module `import` statements - Transform `module.exports` to `export`/`export default` syntax - Deduplicate and organize imports automatically - Handle dynamic imports for conditional loading - Preserve named exports and re-exports ### TypeScript Support - Preserve type annotations during refactoring - Improve interface definitions (convert to `type` aliases when appropriate, use generics) - Enhance type inference opportunities - Handle JSX syntax for React/TypeScript files - Maintain declaration file (`.d.ts`) compatibility ### Code Quality Guarantees - Output code passes syntax validation via AST parsing - Preserve original comments and formatting where possible - Generate properly indented, formatted output consistent with Prettier standards - Maintain 100% functional equivalence (no behavior changes) - Provide transformation logging for audit trails ### Integration Features - **CLI Interface**: Accept files via stdin or file paths, output to stdout or files - **Agent Mode**: Structured input/output for OpenClaw workflow integration - **Dry Run**: Preview changes without writing files - **Diff Output**: Show unified diffs of transformations - **Configuration**: Customizable transformation rules via JSON config ## 3. Out of Scope The following are explicitly NOT supported: - **Performance optimization**: Only syntax transformations; no algorithmic improvements - **Framework patterns**: No React hooks, Vue 3 composition API, Angular-specific patterns - **Non-JS/TS files**: CSS, HTML, JSON, configuration files are ignored - **Architectural changes**: No restructuring of project layout or module boundaries - **Testing**: No test generation, test migration, or validation execution - **Documentation**: No JSDoc generation or comment enhancement - **Minification**: Output remains human-readable - **Polyfills**: No runtime compatibility additions ## 4. Trigger Scenarios ### Natural Language Triggers - "Refactor this code to use modern JavaScript" - "Convert this to ES6+ syntax" - "Update this JavaScript to use arrow functions and destructuring" - "Modernize this TypeScript code" - "Automatically refactor legacy JavaScript patterns" - "Convert CommonJS to ES modules" - "Replace var with let/const throughout this code" - "Transform async callbacks to promises/async-await" - "Upgrade this codebase to ES2020" ### CLI Commands ```bash # Refactor a single file es6-refactor input.js --output output.js # Refactor with stdin/stdout cat legacy.js | es6-refactor > modern.js # Dry run with diff es6-refactor src/ --dry-run --diff # Agent mode (used by OpenClaw) es6-refactor --mode=agent --input=stdin --output=json # TypeScript-specific transformations es6-refactor component.tsx --typescript --strict # Batch processing with glob es6-refactor "src/**/*.js" --output "modernized/{filename}" ``` ### Agent API ```json { "action": "refactor", "code": "var x = 1; function foo() { return x; }", "language": "javascript", "target": "es2020", "options": { "preserveComments": true, "formatOutput": true } } ``` ## 5. Required Resources ### Script Dependencies - **@babel/core**: AST parsing and code generation - **@babel/parser**: JavaScript/TypeScript parser with JSX support - **@babel/traverse**: AST traversal for transformation passes - **@babel/generator**: Code generation from transformed AST - **@babel/preset-env**: Feature detection and polyfill guidance - **@babel/types**: AST node type definitions - **prettier**: Code formatting consistency - **commander**: CLI argument parsing - **glob**: File pattern matching for batch operations - **recast**: AST manipulation with source map preservation (optional) ### Reference Data - **references/patterns.json**: Legacy-to-modern transformation rules ```json { "var-to-const": { "pattern": "var {identifier} = {value}", "replace": "const {identifier} = {value}", "conditions": ["no-reassignment"] }, "callback-to-promise": { "pattern": "{func}(arg, function(result) { {body} })", "replace": "async function wrapper() { const result = await {func}(arg); {body} }" } } ``` - **references/es6-features.json**: Feature compatibility matrix by Node/Browser version ```json { "optional-chaining": { "introduced": "ES2020", "node": "14.0.0", "browsers": ["Chrome 80+", "Firefox 74+", "Safari 13.1+"] } } ``` ### Testing Assets - **assets/examples/**/*.js: Sample legacy code files for validation - **assets/**/*.d.ts: TypeScript definition files for type checking - **tests/**/*.test.js: Unit tests for each transformation rule ### Node.js Runtime - Minimum Node.js version: 14.x (for optional chaining support) - Recommended: 18.x or higher (full ES2022 support) ## 6. Technical Implementation Notes ### Transformation Pipeline 1. **Parse**: Use Babel parser to generate AST with accurate location data 2. **Analyze**: Determine code patterns and dependencies (imports, types, reassignments) 3. **Transform**: Apply rule-based modifications to AST nodes 4. **Type-check**: For TypeScript, validate type preservation 5. **Generate**: Output code with formatting and source maps 6. **Validate**: Syntax check output to ensure no errors ### Rule Engine - Rules stored in `references/patterns.json` match AST node types - Each rule includes: pattern selector, replacement template, conditional guards - Guards inspect scope, variable usage, and type information - Rules applied in priority order to avoid conflicts ### Error Handling - Syntax errors in input code reported with location and message - Unsupported patterns logged with suggestions - Partial transformations rolled back on unrecoverable errors - Exit codes: 0=success, 1=transformation errors, 2=usage error ## 7. Metadata - **Skill ID**: es6-refactor-001 - **Version**: 1.0.0 - **License**: MIT - **Maintainer**: OpenClaw Skill Factory - **Repository**: https://github.com/openclaw/skills/tree/main/es6-refactor - **Keywords**: javascript, typescript, refactor, es6, modernize, code-quality, ast, babel - **OpenClaw Compatibility**: 1.0+

path: README.md
content: # es6-refactor

![Audit](https://img.shields.io/badge/audit%3A%20PASS-brightgreen) ![License](https://img.shields.io/badge/license-MIT-blue) ![OpenClaw](https://img.shields.io/badge/OpenClaw-skill-orange)

> A skill that automatically refactors JavaScript/TypeScript code to use modern ES6+ features and patterns.

I don't see any previous context or what you were working on before. Could you tell me what task you'd like me to continue with? I can help with:

- Reading/writing files
- Running commands
- Managing sessions
- Web searches
- And more

Just let me know what you need and I'll get started.

## OpenClaw Marketplace

This skill is available on [ClawHub](https://clawhub.ai) — the OpenClaw skill marketplace.
Install it in any OpenClaw agent workspace with:

```bash
clawhub install es6-refactor
```

**Recommended price when commercial:** $39

## License

MIT © NeoSkillFactory


path: assets/examples/advanced-patterns.js
content: // Advanced ES5 to ES6+ Refactoring Patterns
// Complex transformations and edge cases

// ============================================
// COMPLEX PATTERN 1: Nested destructuring
// ============================================
// Before:
function processUserDataES5(data) {
  var address = data.address || {};
  var city = address.city || 'Unknown';
  var country = address.country || 'Unknown';
  var settings = data.settings || {};
  var theme = settings.theme || 'light';
  var notifications = settings.notifications || {};
  var email = notifications.email !== false;
  var push = notifications.push !== false;
  return {
    city: city,
    country: country,
    theme: theme,
    emailNotify: email,
    pushNotify: push
  };
}

// After:
const processUserDataES6 = (data = {}) => {
  const {
    address: {
      city = 'Unknown',
      country = 'Unknown'
    } = {},
    settings: {
      theme = 'light',
      notifications: {
        email = true,
        push = true
      } = {}
    } = {}
  } = data;

  return {
    city,
    country,
    theme,
    emailNotify: email,
    pushNotify: push
  };
};

// ============================================
// COMPLEX PATTERN 2: Class inheritance
// ============================================
// Before:
function AnimalES5(name) {
  this.name = name;
}

AnimalES5.prototype.speak = function() {
  console.log(this.name + ' makes a noise.');
};

function DogES5(name, breed) {
  AnimalES5.call(this, name);
  this.breed = breed;
}

DogES5.prototype = Object.create(AnimalES5.prototype);
DogES5.prototype.constructor = DogES5;
DogES5.prototype.speak = function() {
  console.log(this.name + ' barks.');
};

// After:
class AnimalES6 {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class DogES6 extends AnimalES6 {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }

  speak() {
    console.log(`${this.name} barks.`);
  }
}

// ============================================
// COMPLEX PATTERN 3: Nested callbacks to async/await
// ============================================
// Before:
function fetchComplexDataES5(userId, options, callback) {
  var timeout = options.timeout || 5000;
  var retries = options.retries || 3;

  getProfile(userId, function(err1, profile) {
    if (err1) return callback(err1);

    getPermissions(profile.role, function(err2, permissions) {
      if (err2) return callback(err2);

      getSettings(userId, function(err3, settings) {
        if (err3) return callback(err3);

        var result = {
          profile: profile,
          permissions: permissions,
          settings: settings,
          meta: {
            userId: userId,
            timestamp: new Date().toISOString()
          }
        };
        callback(null, result);
      });
    });
  });
}

// After:
async function fetchComplexDataES6(userId, options = {}) {
  const {timeout = 5000, retries = 3} = options;

  try {
    const [profile, permissions, settings] = await Promise.all([
      getProfilePromise(userId),
      getPermissionsPromise(profile.role),
      getSettingsPromise(userId)
    ]);

    return {
      profile,
      permissions,
      settings,
      meta: {
        userId,
        timestamp: new Date().toISOString()
      }
    };
  } catch (err) {
    throw err;
  }
}

// ============================================
// COMPLEX PATTERN 4: Object.defineProperty to computed properties
// ============================================
// Before:
var PersonES5 = function(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
};

Object.defineProperty(PersonES5.prototype, 'fullName', {
  get: function() {
    return this.firstName + ' ' + this.lastName;
  },
  set: function(name) {
    var parts = name.split(' ');
    this.firstName = parts[0] || '';
    this.lastName = parts.slice(1).join(' ') || '';
  },
  enumerable: true,
  configurable: true
});

Object.defineProperty(PersonES5.prototype, 'initials', {
  get: function() {
    return (this.firstName[0] + this.lastName[0]).toUpperCase();
  },
  enumerable: true,
  configurable: true
});

// After:
class PersonES6 {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }

  set fullName(name) {
    const parts = name.split(' ');
    this.firstName = parts[0] || '';
    this.lastName = parts.slice(1).join(' ') || '';
  }

  get initials() {
    return `${this.firstName[0]}${this.lastName[0]}`.toUpperCase();
  }
}

// ============================================
// COMPLEX PATTERN 5: Generator functions
// ============================================
// Before (ES5 iterator pattern):
function createRangeIteratorES5(start, end) {
  var current = start;
  return {
    next: function() {
      if (current < end) {
        return {value: current++, done: false};
      }
      return {value: undefined, done: true};
    }
  };
}

function iterateRangeES5(start, end) {
  var iterator = createRangeIteratorES5(start, end);
  var result = [];
  var step;
  while (!(step = iterator.next()).done) {
    result.push(step.value);
  }
  return result;
}

// After (ES6 generator):
function* createRangeGeneratorES6(start, end) {
  for (let i = start; i < end; i++) {
    yield i;
  }
}

const iterateRangeES6 = (start, end) => {
  return [...createRangeGeneratorES6(start, end)];
};

// ============================================
// COMPLEX PATTERN 6: Map/Set instead of objects/arrays
// ============================================
// Before:
var cacheES5 = {};
cacheES5['key1'] = 'value1';
cacheES5['key2'] = 'value2';

var hasKeyES5 = function(key) {
  return cacheES5.hasOwnProperty(key);
};

var getKeyES5 = function(key) {
  return cacheES5[key];
};

var allKeysES5 = function() {
  return Object.keys(cacheES5);
};

// After:
const cacheES6 = new Map();
cacheES6.set('key1', 'value1');
cacheES6.set('key2', 'value2');

const hasKeyES6 = (key) => cacheES6.has(key);
const getKeyES6 = (key) => cacheES6.get(key);
const allKeysES6 = () => Array.from(cacheES6.keys());

// ============================================
// COMPLEX PATTERN 7: Symbol-based properties
// ============================================
// Before (string key collisions possible):
var internalId = '_internalId_' + Math.random();

var objES5 = {};
objES5[internalId] = 123;

// After:
const internalIdSymbol = Symbol('internalId');
const objES6 = {
  [internalIdSymbol]: 123
};

// ============================================
// COMPLEX PATTERN 8: Iterators with for...of
// ============================================
// Before:
function iterateObjectKeysES5(obj) {
  var keys = Object.keys(obj);
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    console.log(key, obj[key]);
  }
}

// After:
const iterateObjectKeysES6 = (obj) => {
  for (const [key, value] of Object.entries(obj)) {
    console.log(key, value);
  }
};

// ============================================
// COMPLEX PATTERN 9: Promise chaining
// ============================================
// Before:
function fetchDataChainES5(userId) {
  fetchUser(userId)
    .then(function(user) {
      return fetchPosts(user.id);
    })
    .then(function(posts) {
      return fetchComments(posts[0].id);
    })
    .then(function(comments) {
      return processAll(user, posts, comments);
    })
    .catch(function(err) {
      console.error('Failed:', err);
    });
}

// After:
const fetchDataChainES6 = async (userId) => {
  try {
    const user = await fetchUser(userId);
    const posts = await fetchPosts(user.id);
    const comments = await fetchComments(posts[0].id);
    return processAll(user, posts, comments);
  } catch (err) {
    console.error('Failed:', err);
    throw err;
  }
};

// ============================================
// COMPLEX PATTERN 10: Enhanced object literals
// ============================================
// Before:
function createConfigES5(env, port, debug) {
  var config = {};
  config.env = env;
  config.port = port;
  config.debug = debug;
  config.server = {
    host: 'localhost',
    port: port,
    timeout: 30000
  };
  config.logging = {
    level: debug ? 'debug' : 'info',
    format: 'json'
  };
  return config;
}

// After:
const createConfigES6 = (env, port, debug) => ({
  env,
  port,
  debug,
  server: {
    host: 'localhost',
    port,
    timeout: 30000
  },
  logging: {
    level: debug ? 'debug' : 'info',
    format: 'json'
  }
});

export {
  processUserDataES5,
  processUserDataES6,
  AnimalES5,
  AnimalES6,
  DogES5,
  DogES6,
  fetchComplexDataES5,
  fetchComplexDataES6,
  PersonES5,
  PersonES6,
  createRangeIteratorES5,
  iterateRangeES5,
  createRangeGeneratorES6,
  iterateRangeES6,
  cacheES5,
  cacheES6,
  iterateObjectKeysES5,
  iterateObjectKeysES6,
  fetchDataChainES5,
  fetchDataChainES6,
  createConfigES5,
  createConfigES6
};


path: assets/examples/edge-cases.js
content: // Edge Cases and Special Scenarios in ES5→ES6+ Refactoring
// These demonstrate transformations that require careful handling

// ============================================
// EDGE CASE 1: this binding preservation
// ============================================
// DO NOT transform these to arrow functions!
var Counter = function() {
  this.count = 0;
};

Counter.prototype.increment = function() {
  this.count += 1;
  setTimeout(function() {
    // Need this to refer to Counter instance, not setTimeout
    console.log('Count:', this.count);
  }.bind(this), 1000);
};

// After refactoring (keep regular function with bind or use arrow carefully):
class CounterES6 {
  count = 0;

  increment() {
    this.count += 1;
    setTimeout(() => {
      // Arrow function preserves lexical this
      console.log('Count:', this.count);
    }, 1000);
  }
}

// But NOT this (arrow would lose instance binding):
var BadExample = {
  value: 42,
  getValue: () => this.value  // this is lexical (window/global), not BadExample!
};

// ============================================
// EDGE CASE 2: Arguments object in strict mode
// ============================================
'use strict';

var strictFunction = function() {
  // arguments exists but is not linked to parameters
  console.log(arguments.length);
  // This would throw in strict mode:
  // arguments[0] = 'new value'; // Silent fail or throw
};

// After (use rest):
const strictFunctionES6 = (...args) => {
  console.log(args.length);
  // args is a real array, not arguments object
  args[0] = 'new value'; // Works!
};

// ============================================
// EDGE CASE 3: Function hoisting differences
// ============================================
// ES5 function declarations are hoisted
var result1 =();
function result1() { return 'hoisted'; }  // OK - hoisted

// ES6: 'const' and 'let' are not hoisted (TDZ)
// const result2 = result2();  // ReferenceError!
// let result2 = () => 'not hoisted';

// Function expressions vs declarations:
var f = function fExpr() { return 'named function expression'; };
// fExpr is only available inside the function

// After ES6 class (no hoisting at all):
class MyClass {
  // Class declarations are not hoisted
  method() {}
}
// new MyClass() before declaration throws ReferenceError

// ============================================
// EDGE CASE 4: Hexadecimal/octal literal changes
// ============================================
var oldHex = 0xFF;      // ES5: valid
var oldOctal = 0755;    // ES5: valid (leading zero), but discouraged
var legacyOctal = 0o755; // ES6: valid, explicit octal

// Be careful with leading zeros in strict mode:
'use strict';
// var strictOctal = 0755; // SyntaxError in ES5 strict mode
var strictOctalES6 = 0o755; // OK

// ============================================
// EDGE CASE 5: Reserved words as property names
// ============================================
var objES5 = {
  'default': 1,
  'class': 2,
  'for': 3,
  'let': 4  // 'let' was future-reserved in ES5
};

// In ES6, these can be used unquoted in some contexts:
const objES6 = {
  default: 1,  // valid in object literals
  class: 2,
  'for': 3,    // 'for' is still a keyword, must quote
  let: 4       // 'let' is a keyword, must quote
};

// But 'default' and 'class' are now allowed as identifiers in many places:
const class = 'my-class';  // Valid in ES6!
const default = 'default value';  // Valid in ES6!

// ============================================
// EDGE CASE 6: Prototype chain manipulation
// ============================================
var Parent = function(name) {
  this.name = name;
};

Parent.prototype.sayHello = function() {
  return 'Hello from ' + this.name;
};

var Child = function(name, age) {
  Parent.call(this, name);  // Explicit constructor call
  this.age = age;
};

// Manual prototype chain setup (ES5):
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.sayAge = function() {
  return this.name + ' is ' + this.age;
};

// ES6 does this automatically with extends:
class ParentES6 {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    return `Hello from ${this.name}`;
  }
}

class ChildES6 extends ParentES6 {
  constructor(name, age) {
    super(name);  // Calls parent constructor
    this.age = age;
  }

  sayAge() {
    return `${this.name} is ${this.age}`;
  }
}

// ============================================
// EDGE CASE 7: getters/setters - descriptor vs syntax
// ============================================
var objES5 = {};
Object.defineProperty(objES5, 'value', {
  get: function() {
    return this._value;
  },
  set: function(newValue) {
    this._value = newValue * 2;  // Custom logic
  },
  enumerable: true,
  configurable: true
});

// ES6 class syntax:
class ES6Class {
  constructor(initialValue) {
    this._value = initialValue;
  }

  get value() {
    return this._value;
  }

  set value(newValue) {
    this._value = newValue * 2;  // Same custom logic
  }
}

// Object literal shorthand:
const objES6 = {
  _value: 0,
  get value() {
    return this._value;
  },
  set value(newValue) {
    this._value = newValue * 2;
  }
};

// ============================================
// EDGE CASE 8: Symbol properties
// ============================================
var sym = Symbol('secret');
var obj = {
  [sym]: 'hidden value',
  normalProp: 'visible'
};

// Symbols are guaranteed unique:
var sym2 = Symbol('secret');
console.log(sym === sym2);  // false

// Well-known symbols:
var arr = [1, 2, 3];
console.log(arr[Symbol.iterator]);  // Function

// ============================================
// EDGE CASE 9: Modifying built-in prototypes (discouraged)
// ============================================
Array.prototype.first = function() {
  return this[0];
};

// ES6 alternative (better):
if (!Array.prototype.first) {
  Object.defineProperty(Array.prototype, 'first', {
    value: function() {
      return this[0];
    },
    writable: true,
    configurable: true,
    enumerable: false  // Important: don't enumerate
  });
}

// Or use utility function:
const first = (arr) => arr[0];

// ============================================
// EDGE CASE 10: Implicit globals
// ============================================
function createGlobalLeakES5() {
  // Without var/let/const, creates global property
  accidentalGlobal = 'oops';
  var intentional = 'ok';
}

createGlobalLeakES5();
console.log(accidentalGlobal);  // 'oops' - pollutes global!

// ES6 with 'use strict' prevents this:
'use strict';
function noLeak() {
  // accidental = 'error';  // ReferenceError
  const proper = 'local';   // Block-scoped
  let alsoLocal = 'also local';
}

// ============================================
// EDGE CASE 11: Function constructor quirks
// ============================================
var F = function() {};
F.prototype = {constructor: F};

// In ES6, class constructors don't need manual prototype setup:
class ES6Class {
  constructor() {}
  // .prototype.constructor is automatically correct
}
console.log(ES6Class.prototype.constructor === ES6Class);  // true

// ============================================
// EDGE CASE 12: JSON parsing edge cases
// ============================================
var json = '{"value": NaN, "date": "2025-01-01"}';
var parsedES5 = JSON.parse(json);  // NaN becomes null in JSON!

var parsedES6 = JSON.parse(json, (key, value) => {
  // Reviver can handle special cases
  if (typeof value === 'number' && isNaN(value)) {
    return NaN;  // Restore NaN
  }
  return value;
});

// ============================================
// EDGE CASE 13: Exception handling differences
// ============================================
try {
  throw new Error('test');
} catch (e) {
  // ES5: e is any, no type checking
  console.log(e.message);
}

// ES6 with type guard:
try {
  throw new Error('test');
} catch (e) {
  if (e instanceof Error) {
    console.log(e.message);  // TypeScript knows e is Error here
  }
}

// ============================================
// EDGE CASE 14: Regular expression flags
// ============================================
var regexES5 = /pattern/gim;  // Global, case-insensitive, multiline

// ES6 adds 'u' (unicode) and 'y' (sticky)
const regexES6 = /pattern/guims;  // unicode, global, multiline, dotAll

// ============================================
// EDGE CASE 15: Math constants and methods
// ============================================
// ES5 had limited math constants
var es5Constants = {
  PI: Math.PI,
  E: Math.E,
  // Missing: Math.EULER_CONSTANT, Math.LN10, etc in ES5 but exist in ES6
};

// ES6 adds more constants:
const es6Constants = {
  PI: Math.PI,
  E: Math.E,
  LN10: Math.LN10,
  LOG2E: Math.LOG2E,
  LOG10E: Math.LOG10E,
  SQRT1_2: Math.SQRT1_2,
  SQRT2: Math.SQRT2,
  // New methods:
  // Math.cbrt(), Math.clz32(), Math.imul(), Math.sign(), Math.trunc()
};

// ============================================
// EDGE CASE 16: Tail call optimization (strict mode only)
// ============================================
'use strict';

// Proper tail call (TCO) - supported in ES6 but rarely implemented:
function factorial(n, acc = 1) {
  if (n <= 1) return acc;
  return factorial(n - 1, n * acc);  // Tail call
}

// Not a tail call (needs to multiply after recursive call):
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);  // Not tail-recursive
}

// TCO requires:
// 1. Strict mode
// 2. Tail position
// 3. No additional operations after recursive call
// 4. Same function in tail position
// 5. Engine support (Safari only as of 2025)

// ============================================
// EDGE CASE 17: Proxy traps
// ============================================
var target = {value: 42};

var handlerES5 = {
  // ES5 had Object.defineProperty, Object.observe (deprecated)
};

// ES6 Proxy - intercept operations:
const handler = {
  get(target, prop, receiver) {
    console.log(`Getting ${String(prop)}`);
    return Reflect.get(target, prop, receiver);
  },
  set(target, prop, value, receiver) {
    console.log(`Setting ${String(prop)} to ${value}`);
    return Reflect.set(target, prop, value, receiver);
  }
};

const proxy = new Proxy(target, handler);
console.log(proxy.value);  // Logs "Getting value"
proxy.value = 100;          // Logs "Setting value to 100"

// ============================================
// EDGE CASE 18: Iterator protocol
// ============================================
var iterableES5 = {
  // ES5: custom iterator with next() method
  next: function() {
    if (this.index < this.data.length) {
      return {value: this.data[this.index++], done: false};
    }
    return {value: undefined, done: true};
  },
  index: 0,
  data: [1, 2, 3]
};

// ES6: Symbol.iterator
const iterableES6 = {
  data: [1, 2, 3],
  [Symbol.iterator]: function*() {
    for (const item of this.data) {
      yield item * 2;
    }
  }
};

for (const val of iterableES6) {
  console.log(val);  // 2, 4, 6
}

// ============================================
// EDGE CASE 19: String methods
// ============================================
var strES5 = 'hello';
// ES5 limited methods: charAt, indexOf, substr, substring, slice, etc.

// ES6 adds:
const strES6 = 'hello';
console.log(strES6.startsWith('he'));   // true
console.log(strES6.endsWith('lo'));     // true
console.log(strES6.includes('ell'));    // true
console.log(strES6.repeat(3));          // 'hellohellohello'
console.log(strES6.padStart(10, '*')); // '*****hello'
console.log(strES6.padEnd(10, '-'));   // 'hello-----'
// .trimStart(), .trimEnd() (ES2019)

// ============================================
// EDGE CASE 20: Object methods
// ============================================
var objKeys = {a: 1, b: 2, c: 3};

// ES5:
var keysES5 = Object.keys(objKeys);
var valuesES5 = Object.keys(objKeys).map(function(k) { return objKeys[k]; });
var hasOwnA = objKeys.hasOwnProperty('a');

// ES6:
const keysES6 = Object.keys(objKeys);
const valuesES6 = Object.values(objKeys);
const entriesES6 = Object.entries(objKeys);
const hasOwnAES6 = Object.hasOwn(objKeys, 'a');  // ES2022
// Object.values(), Object.entries() not available in ES5

// Destructuring from entries:
for (const [key, value] of Object.entries(objKeys)) {
  console.log(key, value);
}

// ============================================
// EDGE CASE 21: Number methods
// ============================================
var num = 42;

// ES6:
console.log(Number.isNaN(NaN));           // true (unlike global isNaN)
console.log(Number.isFinite(42));        // true
console.log(Number.isInteger(3.0));      // true
console.log(Number.parseInt('42', 10));  // Same as global parseInt
console.log(Number.parseFloat('3.14'));  // Same as global parseFloat

// Safe integer check:
console.log(Number.MAX_SAFE_INTEGER);  // 9007199254740991
console.log(Number.isSafeInteger(9007199254740991));  // true

// ============================================
// EDGE CASE 22: Global object property access differences
// ============================================
// ES5: global object properties can be shadowed
var undefined = 'hacked';  // Bad but possible in ES5 non-strict

// ES6: undefined is read-only
// undefined = 'hacked';  // TypeError in strict mode, ignored otherwise

// const, let not attached to global object:
var x = 1;   // window.x = 1 (in browser)
let y = 2;   // No window.y
const z = 3; // No window.z

// ============================================
// EDGE CASE 23: RegExp sticky flag
// ============================================
const text = 'a1b2c3';
const regexSticky = /[a-z]/y;  // Sticky: lastIndex matters

regexSticky.lastIndex = 0;
console.log(regexSticky.exec(text));  // ['a', index:0]
regexSticky.lastIndex = 1;
console.log(regexSticky.exec(text));  // null (index 1 is '1', not [a-z])

// ============================================
// EDGE CASE 24: Shared memory and Atomics (advanced)
// ============================================
// ES6 with Web Workers / SharedArrayBuffer
// const sharedBuffer = new SharedArrayBuffer(1024);
// const sharedArray = new Int32Array(sharedBuffer);
// Atomics.add(sharedArray, 0, 1);

// Not typically transformed - requires specific concurrency patterns

export {
  // Just for demonstration - not actually exporting as module
};


path: assets/examples/legacy-code.js
content: // Legacy JavaScript Code - ES5 Style
// This file demonstrates common ES5 patterns that should be refactored to ES6+

// ============================================
// PATTERN 1: var declarations
// ============================================
var globalConfig = {
  apiUrl: 'https://api.example.com/v1',
  timeout: 5000,
  retries: 3
};

var shouldRetry = true;
var retryCount = 0;

// ============================================
// PATTERN 2: Function expressions
// ============================================
var fetchData = function(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.onload = function() {
    if (xhr.status === 200) {
      callback(null, JSON.parse(xhr.responseText));
    } else {
      callback(new Error(xhr.statusText));
    }
  };
  xhr.onerror = function() {
    callback(new Error('Network error'));
  };
  xhr.send();
};

// ============================================
// PATTERN 3: String concatenation
// ============================================
var formatMessage = function(user, count) {
  var message = 'Hello ' + user.name + '! You have ' + count + ' unread messages.';
  if (count > 1) {
    message += ' Click here to view them.';
  }
  return message;
};

// ============================================
// PATTERN 4: Traditional for loops
// ============================================
var processItems = function(items) {
  var results = [];
  for (var i = 0; i < items.length; i++) {
    var item = items[i];
    if (item.active) {
      results.push(item.value * 2);
    }
  }
  return results;
};

var findIndex = function(arr, predicate) {
  for (var i = 0; i < arr.length; i++) {
    if (predicate(arr[i], i)) {
      return i;
    }
  }
  return -1;
};

// ============================================
// PATTERN 5: Object property repetition
// ============================================
var createUser = function(name, email, age) {
  return {
    name: name,
    email: email,
    age: age,
    role: 'user',
    active: true,
    createdAt: new Date().toISOString()
  };
};

// ============================================
// PATTERN 6: Manual object merging
// ============================================
var mergeOptions = function(defaults, options) {
  var result = {};
  for (var key in defaults) {
    if (defaults.hasOwnProperty(key)) {
      result[key] = defaults[key];
    }
  }
  for (var key in options) {
    if (options.hasOwnProperty(key)) {
      result[key] = options[key];
    }
  }
  return result;
};

// ============================================
// PATTERN 7: Callback-based async
// ============================================
var loadUser = function(userId, callback) {
  fetchData('/api/users/' + userId, function(err, user) {
    if (err) {
      return callback(err);
    }
    fetchData('/api/profile/' + user.profileId, function(err, profile) {
      if (err) {
        return callback(err);
      }
      callback(null, {
        user: user,
        profile: profile
      });
    });
  });
};

// ============================================
// PATTERN 8: arguments object usage
// ============================================
var sum = function() {
  var total = 0;
  for (var i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
};

var Logger = function(prefix) {
  this.prefix = prefix || '';
};

Logger.prototype.log = function() {
  var args = Array.prototype.slice.call(arguments);
  args.unshift('[' + this.prefix + ']');
  console.log.apply(console, args);
};

// ============================================
// PATTERN 9: Array prototyping
// ============================================
Array.prototype.first = function() {
  return this[0];
};

Array.prototype.last = function() {
  return this[this.length - 1];
};

// ============================================
// PATTERN 10: Constructor functions
// ============================================
var Person = function(name, age) {
  this.name = name;
  this.age = age;
};

Person.prototype.greet = function() {
  return 'Hello, I\'m ' + this.name + ' and I\'m ' + this.age + ' years old.';
};

Person.prototype.haveBirthday = function() {
  this.age += 1;
  return this;
};

// ============================================
// PATTERN 11: Default parameter simulation
// ============================================
var connect = function(options) {
  options = options || {};
  var host = options.host || 'localhost';
  var port = options.port || 8080;
  var timeout = options.timeout || 30000;
  return {host: host, port: port, timeout: timeout};
};

// ============================================
// PATTERN 12: Module pattern (CommonJS)
// ============================================
var utils = {
  formatDate: function(date) {
    return date.getFullYear() + '-' +
           ('0' + (date.getMonth() + 1)).slice(-2) + '-' +
           ('0' + date.getDate()).slice(-2);
  },
  capitalize: function(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  },
  debounce: function(func, wait) {
    var timeout;
    return function() {
      var context = this;
      var args = arguments;
      clearTimeout(timeout);
      timeout = setTimeout(function() {
        func.apply(context, args);
      }, wait);
    };
  }
};

module.exports = utils;


path: assets/examples/refactored.js
content: // Refactored Modern JavaScript - ES6+
// This file demonstrates the same code after ES6+ refactoring

// ============================================
// PATTERN 1: const/let declarations
// ============================================
const globalConfig = {
  apiUrl: 'https://api.example.com/v1',
  timeout: 5000,
  retries: 3
};

let shouldRetry = true;
let retryCount = 0;

// ============================================
// PATTERN 2: Arrow functions
// ============================================
const fetchData = (url, callback) => {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.onload = () => {
    if (xhr.status === 200) {
      callback(null, JSON.parse(xhr.responseText));
    } else {
      callback(new Error(xhr.statusText));
    }
  };
  xhr.onerror = () => {
    callback(new Error('Network error'));
  };
  xhr.send();
};

// ============================================
// PATTERN 3: Template literals
// ============================================
const formatMessage = (user, count) => {
  let message = `Hello ${user.name}! You have ${count} unread messages.`;
  if (count > 1) {
    message += ' Click here to view them.';
  }
  return message;
};

// ============================================
// PATTERN 4: for...of loop
// ============================================
const processItems = (items) => {
  const results = [];
  for (const item of items) {
    if (item.active) {
      results.push(item.value * 2);
    }
  }
  return results;
};

const findIndex = (arr, predicate) => {
  for (let i = 0; i < arr.length; i++) {
    if (predicate(arr[i], i)) {
      return i;
    }
  }
  return -1;
};

// ============================================
// PATTERN 5: Object literal shorthand
// ============================================
const createUser = (name, email, age) => ({
  name,
  email,
  age,
  role: 'user',
  active: true,
  createdAt: new Date().toISOString()
});

// ============================================
// PATTERN 6: Object spread merging
// ============================================
const mergeOptions = (defaults, options) => ({
  ...defaults,
  ...options
});

// ============================================
// PATTERN 7: Promisified async (promises + async/await)
// ============================================
// First, let's promisify fetchData
const fetchDataPromise = (url) => {
  return new Promise((resolve, reject) => {
    fetchData(url, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  });
};

// Using async/await with proper error handling
const loadUser = async (userId) => {
  try {
    const user = await fetchDataPromise(`/api/users/${userId}`);
    const profile = await fetchDataPromise(`/api/profile/${user.profileId}`);
    return {user, profile};
  } catch (err) {
    throw err;
  }
};

// ============================================
// PATTERN 8: Rest parameters & spread
// ============================================
const sum = (...args) => {
  return args.reduce((acc, val) => acc + val, 0);
};

class Logger {
  constructor(prefix = '') {
    this.prefix = prefix;
  }

  log(...args) {
    console.log(`[${this.prefix}]`, ...args);
  }
}

// ============================================
// PATTERN 9: Array extensions (class syntax)
// ============================================
// Note: Modifying built-in prototypes is still discouraged
// But we can create utility classes instead
class ExtendedArray extends Array {
  first() {
    return this[0];
  }

  last() {
    return this[this.length - 1];
  }
}

// Or use utility functions:
const arrayUtils = {
  first: (arr) => arr[0],
  last: (arr) => arr[arr.length - 1]
};

// ============================================
// PATTERN 10: Class syntax
// ============================================
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  greet() {
    return `Hello, I'm ${this.name} and I'm ${this.age} years old.`;
  }

  haveBirthday() {
    this.age += 1;
    return this;
  }
}

// ============================================
// PATTERN 11: Default parameters
// ============================================
const connect = (options = {}) => {
  const {
    host = 'localhost',
    port = 8080,
    timeout = 30000
  } = options;

  return {host, port, timeout};
};

// ============================================
// PATTERN 12: Export as ES module
// ============================================
const utils = {
  formatDate: (date) => {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  },

  capitalize: (str) => {
    return str.charAt(0).toUpperCase() + str.slice(1);
  },

  debounce: (func, wait) => {
    let timeout;
    return function(...args) {
      const context = this;
      clearTimeout(timeout);
      timeout = setTimeout(() => {
        func.apply(context, args);
      }, wait);
    };
  }
};

// Destructuring examples
const {formatDate, capitalize, debounce} = utils;

// Export multiple named exports
export {
  utils,
  formatDate,
  capitalize,
  debounce,
  connect,
  Person,
  Logger,
  fetchDataPromise,
  loadUser,
  mergeOptions,
  createUser,
  processItems,
  findIndex,
  arrayUtils,
  ExtendedArray
};

// Default export (if this were the main module)
// export default utils;


path: assets/examples/test-suite.js
content: // Unit Test Suite for ES6 Refactor Skill
// Examples to test each transformation pattern

// ============================================
// TEST GROUP: Variable Declarations
// ============================================

// Test 1: Simple var to const
(function testVarToConst() {
  var simpleVar = 42;
  console.log(simpleVar);
});

// Test 2: var to let when reassigned
(function testVarToLet() {
  var counter = 0;
  for (var i = 0; i < 10; i++) {
    counter += i;
  }
});

// Test 3: Multiple var declarations
(function testMultipleVar() {
  var x = 1;
  var y = 2;
  var z = 3;
  console.log(x, y, z);
});

// ============================================
// TEST GROUP: Functions
// ============================================

// Test 4: Function expression to arrow
var add = function(a, b) {
  return a + b;
};

// Test 5: Multi-parameter arrow
const multiply = (a, b) => {
  return a * b;
};

// Test 6: Implicit return arrow
const double = (x) => x * 2;

// Test 7: Single parameter implicit return
const square = x => x * x;

// Test 8: Parentheses required for single param with destructuring
const duplicate = ([arr]) => [...arr, ...arr];

// Test 9: Arrow this context
var obj = {
  value: 10,
  increment: function() {
    setTimeout(() => {
      this.value += 1;  // Arrow preserves this
      console.log(this.value);
    }, 100);
  }
};

// ============================================
// TEST GROUP: Strings
// ============================================

// Test 10: Simple concatenation to template
var name = 'World';
var greeting = 'Hello, ' + name + '!';

// Test 11: Multiple interpolations
var firstName = 'John';
var lastName = 'Doe';
var age = 30;
var message = firstName + ' ' + lastName + ' is ' + age + ' years old.';

// Test 12: Empty template literal
var empty = '';

// ============================================
// TEST GROUP: Destructuring
// ============================================

// Test 13: Array destructuring
var pair = [1, 2];
var first = pair[0];
var second = pair[1];

// Test 14: Skip elements
var array = [1, 2, 3, 4, 5];
var firstEl = array[0];
var thirdEl = array[2];
var fifthEl = array[4];

// Test 15: Rest in destructuring
var [head, ...tail] = [1, 2, 3, 4];

// Test 16: Object destructuring
var person = {name: 'Alice', age: 25, city: 'NYC'};
var personName = person.name;
var personAge = person.age;

// Test 17: Rename in destructuring
var user = {username: 'jdoe', email: '[REDACTED_SECRET]'};
var userName = user.username;
var userEmail = user.email;

// Test 18: Nested object destructuring
var data = {
  user: {
    profile: {
      name: 'Bob',
      age: 30
    }
  }
};
var userNameNested = data.user.profile.name;
var userAgeNested = data.user.profile.age;

// Test 19: Default values in destructuring
var maybeName;
var nameDefault = maybeName || 'Guest';

// ============================================
// TEST GROUP: Loops
// ============================================

// Test 20: Traditional for to for...of
var numbers = [1, 2, 3, 4, 5];
var doubled = [];
for (var i = 0; i < numbers.length; i++) {
  doubled.push(numbers[i] * 2);
}

// Test 21: for...in with hasOwnProperty (to Object.keys)
var objLoop = {a: 1, b: 2, c: 3};
for (var key in objLoop) {
  if (objLoop.hasOwnProperty(key)) {
    console.log(key, objLoop[key]);
  }
}

// Test 22: Manual array iteration with index
var items = ['a', 'b', 'c'];
for (var idx = 0; idx < items.length; idx++) {
  console.log(idx, items[idx]);
}

// ============================================
// TEST GROUP: Objects
// ============================================

// Test 23: Property value shorthand
var a = 1;
var b = 2;
var c = 3;
var shorthandObj = {a: a, b: b, c: c};

// Test 24: Method shorthand
var methods = {
  getName: function() {
    return this.name;
  },
  getAge: function() {
    return this.age;
  }
};

// Test 25: Computed property names
var key = 'dynamic';
var computedObj = {};
computedObj['prop_' + key] = 'value';

// Test 26: Object.assign to spread
var defaults = {x: 10, y: 20};
var options = {y: 30, z: 40};
var merged = Object.assign({}, defaults, options);

// Test 27: Dynamic object creation
var dynamicObj = {};
dynamicObj['key' + 1] = 'value1';
dynamicObj['key' + 2] = 'value2';

// ============================================
// TEST GROUP: Arrays
// ============================================

// Test 28: Array.concat to spread
var arr1 = [1, 2];
var arr2 = [3, 4];
var concatenated = arr1.concat(arr2);

// Test 29: Array.prototype.push with apply
var newArr = [1, 2];
var more = [3, 4, 5];
Array.prototype.push.apply(newArr, more);

// ============================================
// TEST GROUP: Modules / CommonJS
// ============================================

// Test 30: CommonJS require
var fs = require('fs');
var path = require('path');

// Test 31: module.exports
var myModule = {
  func1: function() {},
  func2: function() {}
};
module.exports = myModule;

// Test 32: exports assignment
function helper() {}
exports.helper = helper;

// Test 33: module.exports = specific thing
function MyClass() {}
module.exports = MyClass;

// ============================================
// TEST GROUP: Classes
// ============================================

// Test 34: Constructor assignment to class properties
function Animal(name) {
  this.name = name;
  this.age = 0;
}

// Test 35: Prototype methods
Animal.prototype.speak = function() {
  return this.name + ' says hello';
};

// ============================================
// TEST GROUP: Async
// ============================================

// Test 36: Callback-style to Promise
function readFileCallbackES5(path, callback) {
  var fs = require('fs');
  fs.readFile(path, 'utf8', function(err, data) {
    if (err) return callback(err);
    callback(null, data);
  });
}

// Test 37: Promise.then chaining
var promise = new Promise(function(resolve, reject) {
  resolve(42);
});
promise.then(function(value) {
  return value * 2;
}).then(function(result) {
  console.log(result);
});

// ============================================
// TEST GROUP: Default Parameters
// ============================================

// Test 38: Manual default assignment
function connectES5(options) {
  options = options || {};
  var host = options.host || 'localhost';
  var port = options.port || 8080;
  return {host: host, port: port};
}

// ============================================
// TEST GROUP: Rest/Spread in function calls
// ============================================

// Test 39: Function.apply to spread
function sumES5() {
  var total = 0;
  for (var i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}

// Test 40: Function.prototype.call with array
var logES5 = Function.prototype.call.bind(console.log);
logES5.apply(console, [1, 2, 3]);

// ============================================
// TEST GROUP: Map/Filter/Reduce Arrow Conversion
// ============================================

// Test 41: map anonymous function
var nums = [1, 2, 3];
var doubledES5 = nums.map(function(x) {
  return x * 2;
});

// Test 42: filter with function
var filteredES5 = nums.filter(function(x) {
  return x % 2 === 0;
});

// Test 43: reduce with multi-line function
var sumES5Reduce = nums.reduce(function(acc, val) {
  return acc + val;
}, 0);

// ============================================
// TEST GROUP: Template Literal Edge Cases
// ============================================

// Test 44: Nested template literals
var nestedTemplate = 'Hello, ' + (true ? 'World' : 'Stranger') + '!';

// Test 45: Tagged template
var tag = function(strings, ...values) {
  return strings.reduce(function(acc, str, i) {
    return acc + str + (values[i] || '');
  }, '');
};
var tagged = tag`Hello ${name}!`;

// ============================================
// TEST GROUP: TypeScript-specific (if applicable)
// ============================================

// Test 46: Type assertion function (keep as-is)
function asString(value) {
  return String(value);
}

// Test 47: Class field declarations (JS class syntax)
class ModernClass {
  // Class fields (stage 3 proposal, may need handling)
  // field = value;
  // static staticField = value;
}

// ============================================
// TEST GROUP: Should NOT transform
// ============================================

// Test 48: var used as function-scoped intentionally (avoid converting to let)
(function IIFE() {
  var i;
  for (i = 0; i < 10; i++) {
    // i should be accessible outside loop in this closure
  }
});

// Test 49: this-dependent function (don't convert to arrow)
var objWithThis = {
  value: 100,
  getValue: function() {
    return this.value;
  }
};

// Test 50: Function constructor (arguments used intentionally)
var argsPrinter = function() {
  console.log(arguments);
};

// ============================================
// TEST GROUP: Edge Cases
// ============================================

// Test 51: Arguments with rest parameter shadow
function(...args) {
  // Should not have 'arguments' after transformation
}

// Test 52: Default parameter with undefined
function defaultTest(value) {
  value = value || 'default';
  return value;
}

// Test 53: Multiple default assignments in one function
function multiDefaults(a, b, c) {
  a = a || 1;
  b = b || 2;
  c = c || 3;
  return a + b + c;
}

// Export for testing
if (typeof module !== 'undefined' && module.exports) {
  module.exports = {
    testVarToConst: 1,
    testVarToLet: 2,
    testMultipleVar: 3,
    testArrow: 4,
    testImplicitReturn: 5,
    testTemplate: 6,
    testDestructuring: 7,
    testForOf: 8,
    testObjectShorthand: 9,
    testObjectAssign: 10,
    testCommonJS: 11,
    testCallback: 12,
    testDefaultParams: 13,
    testMapFilterReduce: 14,
    testNoTransform: 15
  };
}


path: assets/examples/typescript-example.ts
content: // TypeScript Examples - ES6+ with Type Annotations
// These examples demonstrate TypeScript-specific refactorings

// ============================================
// EXAMPLE 1: TypeScript Interfaces and Classes
// ============================================
interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user' | 'guest';
  profile?: Profile;  // Optional property
}

interface Profile {
  avatar?: string;
  bio?: string;
  location?: string;
}

interface ApiResponse<T> {
  data: T;
  success: boolean;
  error?: string;
  timestamp: Date;
}

class ApiClient {
  private baseUrl: string;
  private timeout: number;
  private defaultHeaders: Record<string, string>;

  constructor(config: {baseUrl: string; timeout?: number; headers?: Record<string, string>}) {
    this.baseUrl = config.baseUrl;
    this.timeout = config.timeout ?? 30000;
    this.defaultHeaders = config.headers ?? {};
  }

  async get<T>(endpoint: string, options: RequestInit = {}): Promise<ApiResponse<T>> {
    const url = `${this.baseUrl}${endpoint}`;
    const response = await fetch(url, {
      ...options,
      headers: {
        ...this.defaultHeaders,
        ...options.headers
      },
      signal: AbortSignal.timeout(this.timeout)
    });

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }

    const data = await response.json() as T;
    return {
      data,
      success: true,
      timestamp: new Date()
    };
  }

  post<T>(endpoint: string, body: unknown): Promise<ApiResponse<T>> {
    return this.get<T>(endpoint, {
      method: 'POST',
      body: JSON.stringify(body)
    });
  }
}

// ============================================
// EXAMPLE 2: Type Guards and Discriminated Unions
// ============================================
type Result<T, E> =
  | {type: 'success'; data: T}
  | {type: 'error'; error: E};

function isSuccess<T, E>(result: Result<T, E>): result is {type: 'success'; data: T} {
  return result.type === 'success';
}

type ApiError = {
  code: number;
  message: string;
  details?: unknown;
};

const fetchWithTypeSafety = async (url: string): Promise<Result<User, ApiError>> => {
  try {
    const client = new ApiClient({baseUrl: 'https://api.example.com'});
    const response = await client.get<User>(url);
    return {type: 'success', data: response.data};
  } catch (err) {
    return {
      type: 'error',
      error: {
        code: 500,
        message: err instanceof Error ? err.message : 'Unknown error'
      }
    };
  }
};

// ============================================
// EXAMPLE 3: Generic Functions and Constraints
// ============================================
function mergeAll<T>(...objects: Partial<T>[]): T {
  return objects.reduce((acc, obj) => ({...acc, ...obj}), {} as T);
}

interface Configuration {
  apiUrl: string;
  timeout: number;
  retries: number;
}

const config: Configuration = mergeAll(
  {apiUrl: 'https://default.example.com', timeout: 5000},
  {retries: 3, timeout: 10000}  // Override timeout
  // apiUrl is inherited from first object
);

// ============================================
// EXAMPLE 4: Utility Types and Mapped Types
// ============================================
type ReadonlyUser = Readonly<User>;

type PartialUser = Partial<User>;

type PickUser = Pick<User, 'id' | 'name'>;

type OmitUser = Omit<User, 'password'>;

// Mapped type for making all properties optional except required ones
type CreateDTO<T> = Omit<T, keyof T>;

// ============================================
// EXAMPLE 5: Type-Safe Event Emitters
// ============================================
type EventMap = {
  'user:created': {userId: number; timestamp: Date};
  'user:updated': {userId: number; changes: Partial<User>};
  'error': {message: string; code?: number};
};

class TypedEventEmitter {
  private listeners: Map<keyof EventMap, Array<(data: EventMap[keyof EventMap]) => void>> = new Map();

  on<K extends keyof EventMap>(event: K, callback: (data: EventMap[K]) => void): void {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, []);
    }
    this.listeners.get(event)!.push(callback);
  }

  emit<K extends keyof EventMap>(event: K, data: EventMap[K]): void {
    this.listeners.get(event)?.forEach(callback => callback(data));
  }
}

const emitter = new TypedEventEmitter();
emitter.on('user:created', (data) => {
  console.log(`User ${data.userId} created at ${data.timestamp}`);
});
emitter.emit('user:created', {userId: 123, timestamp: new Date()});

// ============================================
// EXAMPLE 6: Async Iterators and Generators
// ============================================
async function* fetchPaginated<T>(url: string, pageSize: number = 50): AsyncIterator<T[]> {
  let page = 1;
  let hasMore = true;

  while (hasMore) {
    const response = await fetch(`${url}?page=${page}&limit=${pageSize}`);
    const data = await response.json() as {items: T[]; total: number};
    yield data.items;
    hasMore = page * pageSize < data.total;
    page++;
  }
}

// Usage:
// for await (const items of fetchPaginated<User>('/api/users')) {
//   items.forEach(user => console.log(user.name));
// }

// ============================================
// EXAMPLE 7: Conditional Types and Inference
// ============================================
type ExtractId<T> = T extends {id: infer I} ? I : never;

type UserId = ExtractId<User>;  // number

function withId<T extends {id: unknown}>(item: T): T & {createdAt: Date} {
  return {...item, createdAt: new Date()};
}

const userWithTimestamp = withId({id: 1, name: 'Alice', email: '[REDACTED_SECRET]'});

// ============================================
// EXAMPLE 8: Template String Types (TS 4.1+)
// ============================================
type EventName<E extends string> = `on${E[0].toUpperCase()}${E.slice(1)}`;

type ClickHandler = EventName<'click'>;  // "onClick"
type MouseOverHandler = EventName<'mouseover'>;  // "onMouseOver"

// ============================================
// EXAMPLE 9: Discriminated Unions for State Machines
// ============================================
type State =
  | {status: 'idle'}
  | {status: 'loading'; startedAt: Date}
  | {status: 'success'; data: unknown}
  | {status: 'error'; error: Error; retryCount: number};

function handleState(state: State): string {
  switch (state.status) {
    case 'idle':
      return 'Ready to start';
    case 'loading':
      return `Loading... (started at ${state.startedAt.toISOString()})`;
    case 'success':
      return `Success! Data: ${JSON.stringify(state.data)}`;
    case 'error':
      return `Error: ${state.error.message} (retries: ${state.retryCount})`;
  }
}

// ============================================
// EXAMPLE 10: Module Augmentation
// ============================================
// Extending existing types
declare module 'http' {
  interface IncomingMessage {
    userId?: string;  // Custom header injection
  }
}

// Express-style request handler with typed request/response
interface Request {
  params: Record<string, string>;
  query: Record<string, string>;
  body: unknown;
  headers: Record<string, string>;
}

interface Response {
  status(code: number): this;
  json(data: unknown): this;
  send(data: string): this;
}

function createHandler(
  handler: (req: Request, res: Response) => Promise<void> | void
): (req: Request, res: Response) => void {
  return async (req, res) => {
    try {
      await handler(req, res);
    } catch (err) {
      res.status(500).json({error: err instanceof Error ? err.message : 'Unknown error'});
    }
  };
}

// ============================================
// EXAMPLE 11: Namespaces vs Modules
// ============================================
namespace Validation {
  export function isEmail(str: string): boolean {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str);
  }

  export function isUrl(str: string): boolean {
    try {
      new URL(str);
      return true;
    } catch {
      return false;
    }
  }

  export type Validator = (input: unknown) => boolean;
}

// ============================================
// EXAMPLE 12: Mixins with TypeScript
// ============================================
type Constructor<T = {}> = new (...args: unknown[]) => T;

function Timestamped<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    createdAt = new Date();
    updatedAt = new Date();

    touch() {
      this.updatedAt = new Date();
    }
  };
}

function WithId<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    id = crypto.randomUUID();
  };
}

class Entity {}
const TimestampedEntity = Timestamped(WithId(Entity));

const entity = new TimestampedEntity();
console.log(entity.id, entity.createdAt);

export {
  // Interfaces
  User,
  Profile,
  ApiResponse,
  Result,
  ApiError,
  EventMap,

  // Classes
  ApiClient,
  TypedEventEmitter,

  // Functions
  isSuccess,
  mergeAll,
  withId,
  createHandler,

  // Types
  ReadonlyUser,
  PartialUser,
  PickUser,
  OmitUser,
  ExtractId,
  EventName,
  State,
  Validation,

  // Example usage
  fetchWithTypeSafety,
  config,
  userWithTimestamp,
  emitter,
  entity
};


path: assets/refactor.d.ts
content: /**
 * ES6 Refactor Skill - TypeScript Definitions
 * Provides type definitions for the refactoring engine and CLI
 */

// ============================================
// Core Types
// ============================================

/**
 * Represents the source language version/target compatibility
 */
export type LanguageTarget =
  | 'es5'
  | 'es2015'
  | 'es2016'
  | 'es2017'
  | 'es2018'
  | 'es2019'
  | 'es2020'
  | 'es2021'
  | 'es2022'
  | 'esnext';

/**
 * Transformation confidence level (0-1)
 */
export type ConfidenceLevel = number;

/**
 * Refactoring pattern category
 */
export type PatternCategory =
  | 'variable-declarations'
  | 'functions'
  | 'strings'
  | 'loops'
  | 'destructuring'
  | 'objects'
  | 'arrays'
  | 'modules'
  | 'classes'
  | 'async'
  | 'literals';

/**
 * Conditions that must be met for a pattern to apply
 */
export interface PatternConditions {
  /** Whether variable is reassigned */
  reassigns?: boolean;
  /** Whether scope is block-level */
  scope?: 'block' | 'function' | 'global';
  /** Whether this binding needs to be preserved */
  preservesThis?: boolean;
  /** Whether it's a function expression */
  isExpression?: boolean;
  /** Whether function contains single return statement */
  singleReturn?: boolean;
  /** Whether function has side effects */
  noSideEffects?: boolean;
  /** Whether object properties match their values */
  keyMatchesValue?: boolean;
  /** Whether string contains concatenation */
  containsConcatenation?: boolean;
  /** Whether interpolation is needed */
  hasInterpolation?: boolean;
  /** Whether for loop only uses index for array access */
  usesIndexOnlyForAccess?: boolean;
  /** Whether loop modifies the array */
  noModifications?: boolean;
  /** Whether accessing sequential array indices */
  sequentialAccess?: boolean;
  /** Whether multiple extractions from same source */
  multipleExtractions?: boolean;
  /** Whether source object is same for all properties */
  sameSourceObject?: boolean;
  /** Number of properties to extract */
  propertyCount?: 'single' | 'multiple';
  /** Whether has default assignment */
  hasDefaultAssignment?: boolean;
  /** Whether uses arguments object */
  usesArguments?: boolean;
  /** Whether performing object merging */
  objectMerging?: boolean;
  /** Whether creates new object (vs mutation) */
  createsNewObject?: boolean;
  /** Whether it's a Node.js builtin */
  nodeBuiltin?: boolean;
  /** Whether it's a callback file */
  isModuleFile?: boolean;
  /** Whether it's a single export */
  singleExport?: boolean;
  /** Whether assignment is simple (no computation) */
  simpleAssignment?: boolean;
  /** Whether key is computed/dynamic */
  dynamicKey?: boolean;
  /** Whether it's a literal value */
  literalValue?: boolean;
  /** Whether using hasOwnProperty check */
  hasOwnCheck?: boolean;
  /** Whether iterating over object */
  objectIteration?: boolean;
}

/**
 * A single transformation pattern
 */
export interface Pattern {
  /** Unique pattern identifier */
  id: string;
  /** Human-readable description */
  description: string;
  /** Pattern category */
  category: PatternCategory;
  /** Legacy code pattern (may contain placeholders) */
  legacy: string;
  /** Modern replacement pattern */
  modern: string;
  /** Conditions for pattern matching */
  conditions: PatternConditions;
  /** Confidence score 0-1 */
  confidence: ConfidenceLevel;
  /** Lower numbers applied first */
  priority: number;
}

/**
 * Complete pattern library
 */
export interface PatternLibrary {
  patterns: Record<string, Pattern>;
}

// ============================================
// Feature Compatibility Types
// ============================================

/**
 * Browser compatibility info
 */
export interface BrowserCompatibility {
  chrome: string;
  firefox: string;
  safari: string;
  edge: string;
  ie: string | 'no';
}

/**
 * Mobile browser compatibility
 */
export interface MobileCompatibility {
  ios_safari: string;
  android_chrome: string;
}

/**
 * Complete feature compatibility data
 */
export interface FeatureCompatibility {
  browsers: BrowserCompatibility;
  node: string;
  mobile?: MobileCompatibility;
}

/**
 * ES6+ Feature definition
 */
export interface Feature {
  /** Feature name */
  name: string;
  /** ECMAScript version */
  ecmaVersion: 'ES2015' | 'ES2016' | 'ES2017' | 'ES2018' | 'ES2019' | 'ES2020' | 'ES2021' | 'ES2022' | 'ES2023';
  /** Brief description */
  description: string;
  /** Compatibility matrix */
  compatibility: FeatureCompatibility;
  /** Usage recommendations */
  usage: {
    recommended: boolean | 'modern_only' | 'with_bundler';
    notes: string[];
  };
  /** Related transformation patterns */
  patterns?: string[];
}

/**
 * Complete features database
 */
export interface FeatureDatabase {
  features: Record<string, Feature>;
  compatibility_guidelines: {
    [target: string]: {
      description: string;
      allowed_features: string[];
      needs_transpilation: boolean;
      tooling: string[] | null;
    };
  };
  deprecation_timeline: Record<
    string,
    {
      deprecated: boolean;
      recommended_replacement: string;
      reason: string;
      migration_difficulty: 'easy' | 'moderate' | 'hard';
    }
  >;
}

// ============================================
// AST and Transformation Types
// ============================================

/**
 * AST Node types we handle
 */
export type ASTNodeType =
  | 'VariableDeclaration'
  | 'FunctionExpression'
  | 'ArrowFunctionExpression'
  | 'CallExpression'
  | 'BinaryExpression'
  | 'MemberExpression'
  | 'ObjectExpression'
  | 'ArrayExpression'
  | 'ForStatement'
  | 'ForInStatement'
  | 'ForOfStatement'
  | 'TemplateLiteral'
  | 'ImportDeclaration'
  | 'ExportDefaultDeclaration'
  | 'ExportNamedDeclaration'
  | 'ClassDeclaration'
  | 'ClassExpression'
  | 'MethodDefinition'
  | 'Property';

/**
 * Position in source code
 */
export interface SourcePosition {
  line: number;
  column: number;
  offset: number;
}

/**
 * AST Node structure (simplified)
 */
export interface ASTNode {
  type: ASTNodeType;
  start: SourcePosition;
  end: SourcePosition;
  raw?: string;
  children?: ASTNode[];
  [key: string]: unknown;
}

/**
 * Transformation result for a single node
 */
export interface TransformationResult {
  original: ASTNode;
  transformed: ASTNode | ASTNode[];
  patternId: string;
  confidence: ConfidenceLevel;
  edits?: CodeEdit[];
}

/**
 * Code edit (for patch generation)
 */
export interface CodeEdit {
  start: SourcePosition;
  end: SourcePosition;
  replacement: string;
}

/**
 * Complete refactoring result
 */
export interface RefactoringResult {
  success: boolean;
  output: string;
  appliedPatterns: Array<{
    patternId: string;
    location: SourcePosition;
    confidence: ConfidenceLevel;
  }>;
  errors: string[];
  warnings: string[];
  stats: {
    patternsApplied: number;
    nodesTransformed: number;
    linesChanged: number;
  };
}

// ============================================
// CLI Types
// ============================================

/**
 * CLI configuration
 */
export interface CLIConfig {
  /** Source file path */
  from?: string;
  /** Output file path (defaults to stdout) */
  to?: string;
  /** Target language version */
  target?: LanguageTarget;
  /** Input format */
  type?: 'javascript' | 'typescript';
  /** Show diff output */
  diff?: boolean;
  /** Verbose logging */
  verbose?: boolean;
  /** Pattern filter */
  only?: string[];
  /** Exclude patterns */
  exclude?: string[];
  /** Confidence threshold */
  threshold?: number;
  /** Generate source maps */
  sourceMaps?: boolean;
  /** Lint after refactoring */
  lint?: boolean;
}

/**
 * CLI exit codes
 */
export type CLIExitCode = 0 | 1 | 2;

// ============================================
// Agent Integration Types
// ============================================

/**
 * Agent request payload
 */
export interface AgentRequest {
  /** Source code to refactor */
  code: string;
  /** Language (javascript/typescript) */
  language: 'javascript' | 'typescript';
  /** Target compatibility */
  target: LanguageTarget;
  /** Specific patterns to apply (empty = all) */
  patterns?: string[];
  /** Patterns to skip */
  skipPatterns?: string[];
  /** Confidence threshold 0-1 */
  confidence?: number;
  /** Preserve original formatting */
  preserveFormatting?: boolean;
  /** Generate comments for each change */
  annotateChanges?: boolean;
}

/**
 * Agent response payload
 */
export interface AgentResponse {
  /** Refactored code */
  code: string;
  /** Applied transformations */
  transformations: Array<{
    pattern: string;
    location: {line: number; column: number};
    before: string;
    after: string;
  }>;
  /** Errors encountered */
  errors: string[];
  /** Warnings */
  warnings: string[];
  /** Stats */
  stats: {
    totalChanges: number;
    linesAdded: number;
    linesRemoved: number;
  };
  /** Execution time in ms */
  executionTime: number;
}

// ============================================
// Internal Engine Types
// ============================================

/**
 * Refactoring engine configuration
 */
export interface EngineConfig {
  /** Loaded pattern library */
  patterns: PatternLibrary;
  /** Loaded feature database */
  features: FeatureDatabase;
  /** Target language */
  target: LanguageTarget;
  /** Confidence threshold */
  confidenceThreshold: number;
  /** Enable TypeScript-specific transformations */
  typescriptMode: boolean;
  /** Preserve comments */
  preserveComments: boolean;
  /** Maximum edit distance for pattern matching */
  maxEditDistance: number;
}

/**
 * Context for a single refactoring operation
 */
export interface RefactorContext {
  /** Source code */
  source: string;
  /** AST root */
  ast: ASTNode;
  /** Language (javascript/typescript) */
  language: 'javascript' | 'typescript';
  /** Applied patterns (to avoid conflicts) */
  appliedPatterns: Set<string>;
  /** Accumulated code edits */
  edits: CodeEdit[];
  /** Configuration */
  config: EngineConfig;
}

// ============================================
// Utility Types
// ============================================

/**
 * Deep partial type
 */
export type DeepPartial<T> = T extends object
  ? {[P in keyof T]?: DeepPartial<T[P]>}
  : T;

/**
 * Pattern match result
 */
export interface PatternMatch {
  pattern: Pattern;
  /** Node(s) that match */
  nodes: ASTNode[];
  /** Match confidence */
  confidence: ConfidenceLevel;
  /** Location of match */
  location: SourcePosition;
}

// ============================================
// Module Exports
// ============================================

export default interface RefactorModule {
  /** Main refactoring function */
  refactor(context: RefactorContext): Promise<RefactoringResult>;

  /** Parse source to AST */
  parse(source: string, language: 'javascript' | 'typescript'): ASTNode;

  /** Generate code from AST */
  generate(ast: ASTNode, options?: {minify?: boolean}): string;

  /** Load pattern library */
  loadPatterns(path: string): Promise<PatternLibrary>;

  /** Load feature database */
  loadFeatures(path: string): Promise<FeatureDatabase>;

  /** Check if pattern applies */
  matches(node: ASTNode, pattern: Pattern): PatternMatch | null;

  /** Apply transformation */
  transform(node: ASTNode, pattern: Pattern): TransformationResult;

  /** Get available patterns */
  getPatterns(category?: PatternCategory): Pattern[];

  /** Validate target compatibility */
  validateFeature(feature: string, target: LanguageTarget): boolean;
}

export {};

path: package.json
content: {
  "name": "es6-refactor",
  "version": "1.0.0",
  "description": "Automatically refactor JavaScript/TypeScript code to use modern ES6+ patterns and features",
  "main": "scripts/index.js",
  "bin": {
    "es6-refactor": "./scripts/cli.js"
  },
  "scripts": {
    "test": "node tests/run.js",
    "lint": "eslint scripts/ --ext .js",
    "refactor": "node scripts/cli.js",
    "validate": "node scripts/validate.js"
  },
  "keywords": [
    "javascript",
    "typescript",
    "es6",
    "refactor",
    "modernize",
    "code-quality",
    "ast",
    "babel",
    "openclaw",
    "skill"
  ],
  "author": "OpenClaw Skill Factory",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/openclaw/skills",
    "directory": "es6-refactor"
  },
  "homepage": "https://docs.openclaw.ai/skills/es6-refactor",
  "bugs": {
    "url": "https://github.com/openclaw/skills/issues/new?template=skill-issue.yml"
  },
  "engines": {
    "node": ">=14.0.0",
    "openclaw": ">=1.0.0"
  },
  "files": [
    "scripts/",
    "references/",
    "assets/",
    "SKILL.md",
    "README.md"
  ],
  "dependencies": {
    "@babel/core": "^7.24.0",
    "@babel/generator": "^7.24.0",
    "@babel/parser": "^7.24.0",
    "@babel/preset-env": "^7.24.0",
    "@babel/traverse": "^7.24.0",
    "@babel/types": "^7.24.0",
    "chalk": "^4.1.2",
    "commander": "^11.1.0",
    "glob": "^10.3.10",
    "prettier": "^3.2.0",
    "recast": "^0.23.4"
  },
  "devDependencies": {
    "chai": "^4.3.8",
    "eslint": "^8.56.0",
    "mocha": "^10.2.0"
  },
  "openclaw": {
    "skill": {
      "id": "es6-refactor",
      "version": "1.0.0",
      "compatibility": ">=1.0.0",
      "permissions": [
        "file:read",
        "file:write"
      ],
      "capabilities": [
        "refactor:javascript",
        "refactor:typescript",
        "transform:es6",
        "transform:modules"
      ]
    }
  }
}


path: references/es6-features.json
content: {
  "metadata": {
    "version": "1.0.0",
    "description": "ES6+ feature compatibility matrix and usage guidelines",
    "generated": "2025-06-16",
    "sources": [
      "caniuse.com",
      "nodejs.org/en/docs/",
      "mdn.io"
    ]
  },
  "features": {
    "arrow_functions": {
      "name": "Arrow Functions",
      "stage": "stable",
      "ecmaVersion": "ES2015",
      "description": "Concise function syntax with lexical this binding",
      "compatibility": {
        "browsers": {
          "chrome": "45+",
          "firefox": "22+",
          "safari": "10+",
          "edge": "12+",
          "ie": "no"
        },
        "node": "4+",
        "mobile": {
          "ios_safari": "10+",
          "android_chrome": "45+"
        }
      },
      "usage": {
        "recommended": true,
        "notes": [
          "Use for callbacks, array methods, and concise functions",
          "Avoid when needing own this binding or as constructors",
          "Preserves lexical this context"
        ]
      },
      "patterns": ["function_to_arrow", "map_filter_reduce_arrow"]
    },
    "const_let": {
      "name": "Block-Scoped Declarations (const/let)",
      "stage": "stable",
      "ecmaVersion": "ES2015",
      "description": "Block-scoped variable declarations with const for immutable bindings",
      "compatibility": {
        "browsers": {
          "chrome": "41+",
          "firefox": "28+",
          "safari": "10+",
          "edge": "12+",
          "ie": "11 (partial)"
        },
        "node": "4+",
        "mobile": {
          "ios_safari": "10+",
          "android_chrome": "41+"
        }
      },
      "usage": {
        "recommended": true,
        "notes": [
          "Prefer const by default",
          "Use let only for reassigned variables",
          "Never use var in new code",
          "Temporal Dead Zone applies"
        ]
      },
      "patterns": ["var_to_const_let", "var_to_let"]
    },
    "template_literals": {
      "name": "Template Literals",
      "stage": "stable",
      "ecmaVersion": "ES2015",
      "description": "Multiline strings and string interpolation",
      "compatibility": {
        "browsers": {
          "chrome": "41+",
          "firefox": "31+",
          "safari": "10+",
          "edge": "12+",
          "ie": "no"
        },
        "node": "4+"
      },
      "usage": {
        "recommended": true,
        "notes": [
          "Safely use in all modern environments",
          "Consider tagged templates for advanced use",
          "Not supported in IE11 without transpilation"
        ]
      },
      "patterns": ["template_literal"]
    },
    "destructuring": {
      "name": "Destructuring Assignment",
      "stage": "stable",
      "ecmaVersion": "ES2015",
      "description": "Extract values from arrays/objects into distinct variables",
      "compatibility": {
        "browsers": {
          "chrome": "49+",
          "firefox": "41+",
          "safari": "10+",
          "edge": "12+",
          "ie": "no"
        },
        "node": "6+"
      },
      "usage": {
        "recommended": true,
        "notes": [
          "Great for function parameters",
          "Supports default values and renaming",
          "Can nest for deep destructuring",
          "May affect minification"
        ]
      },
      "patterns": ["destructuring_array", "destructuring_object"]
    },
    "default_params": {
      "name": "Default Parameters",
      "stage": "stable",
      "ecmaVersion": "ES2015",
      "description": "Initialize parameters with default values",
      "compatibility": {
        "browsers": {
          "chrome": "49+",
          "firefox": "15+",
          "safari": "10+",
          "edge": "12+",
          "ie": "no"
        },
        "node": "6+"
      },
      "usage": {
        "recommended": true,
        "notes": [
          "Clearer than manual assignment",
          "Evaluated at call time",
          "Can use expressions as defaults",
          "undefined triggers default"
        ]
      },
      "patterns": ["default_params"]
    },
    "rest_spread": {
      "name": "Rest Parameters & Spread Syntax",
      "stage": "stable",
      "ecmaVersion": "ES2015",
      "description": "Collect/expand iterables, replaces arguments object",
      "compatibility": {
        "browsers": {
          "chrome": "46+",
          "firefox": "16+",
          "safari": "10+",
          "edge": "12+",
          "ie": "no"
        },
        "node": "6+"
      },
      "usage": {
        "recommended": true,
        "notes": [
          "Use ...args instead of arguments",
          "Only last parameter can be rest",
          "Works with any iterable",
          "Spread in arrays/function calls requires ES2015+"
        ]
      },
      "patterns": ["rest_spread", "spread_merge", "array_spread_concat"]
    },
    "object_literal_enhancements": {
      "name": "Object Literal Enhancements",
      "stage": "stable",
      "ecmaVersion": "ES2015",
      "description": "Property shorthand, computed property names, method definitions",
      "compatibility": {
        "browsers": {
          "chrome": "47+",
          "firefox": "34+",
          "safari": "10+",
          "edge": "12+",
          "ie": "no"
        },
        "node": "6+"
      },
      "usage": {
        "recommended": true,
        "notes": [
          "Property value shorthand reduces repetition",
          "Method shorthand binds this automatically",
          "Computed property names for dynamic keys"
        ]
      },
      "patterns": ["object_literal_shorthand", "object_method_shorthand", "computed_property_names"]
    },
    "classes": {
      "name": "Classes",
      "stage": "stable",
      "ecmaVersion": "ES2015",
      "description": "Syntactic sugar over prototype-based inheritance",
      "compatibility": {
        "browsers": {
          "chrome": "51+",
          "firefox": "45+",
          "safari": "10+",
          "edge": "12+",
          "ie": "no"
        },
        "node": "6+"
      },
      "usage": {
        "recommended": true,
        "notes": [
          "Use for object constructors with inheritance",
          "Not to be confused with Java/C# classes",
          "Consider factory functions for simpler cases",
          "Subclass built-ins now works (Array, Error)"
        ]
      },
      "patterns": ["class_properties"]
    },
    "modules_esm": {
      "name": "ES Modules (ESM)",
      "stage": "stable",
      "ecmaVersion": "ES2015",
      "description": "Standardized module system with import/export",
      "compatibility": {
        "browsers": {
          "chrome": "61+",
          "firefox": "60+",
          "safari": "10.1+",
          "edge": "16+",
          "ie": "no"
        },
        "node": "12+ (with .mjs or \"type\":\"module\")"
      },
      "usage": {
        "recommended": "with_bundler",
        "notes": [
          "Use with bundlers (webpack, rollup) for broad compatibility",
          "Native support in modern browsers and Node 12+",
          "Static analysis enables tree-shaking",
          "Different from CommonJS in behavior (hoisting, circular deps)"
        ]
      },
      "patterns": ["commonjs_to_esm", "export_default"]
    },
    "async_await": {
      "name": "Async Functions",
      "stage": "stable",
      "ecmaVersion": "ES2017",
      "description": "Synchronous-style asynchronous code with promises",
      "compatibility": {
        "browsers": {
          "chrome": "55+",
          "firefox": "52+",
          "safari": "10.1+",
          "edge": "15+",
          "ie": "no"
        },
        "node": "7.6+"
      },
      "usage": {
        "recommended": true,
        "notes": [
          "Clean alternative to promise chains",
          "Top-level await available in modules (ES2022)",
          "Can use Babel for older environments",
          "Don't forget error handling"
        ]
      },
      "patterns": ["promisify_callback"]
    },
    "promises": {
      "name": "Promises",
      "stage": "stable",
      "ecmaVersion": "ES2015",
      "description": "Native promise implementation for async operations",
      "compatibility": {
        "browsers": {
          "chrome": "32+",
          "firefox": "29+",
          "safari": "8+",
          "edge": "12+",
          "ie": "no"
        },
        "node": "0.12+"
      },
      "usage": {
        "recommended": true,
        "notes": [
          "Native in all modern environments",
          "Polyfill required for IE11 if needed",
          "Avoid callback hell",
          "Consider async/await on top"
        ]
      }
    },
    "for_of": {
      "name": "for...of Loops",
      "stage": "stable",
      "ecmaVersion": "ES2015",
      "description": "Iterate over iterable objects (arrays, maps, sets, strings)",
      "compatibility": {
        "browsers": {
          "chrome": "38+",
          "firefox": "13+",
          "safari": "10+",
          "edge": "12+",
          "ie": "no"
        },
        "node": "4+"
      },
      "usage": {
        "recommended": true,
        "notes": [
          "Cleaner than traditional for loops",
          "Works with any iterable",
          "Cannot use with plain objects (use Object.keys/entries)",
          "Supports break/continue"
        ]
      },
      "patterns": ["for_to_for_of", "for_to_for_in"]
    },
    "numeric_separators": {
      "name": "Numeric Separators",
      "stage": "stable",
      "ecmaVersion": "ES2021",
      "description": "Underscore separators in numeric literals for readability",
      "compatibility": {
        "browsers": {
          "chrome": "74+",
          "firefox": "70+",
          "safari": "14+",
          "edge": "79+",
          "ie": "no"
        },
        "node": "14+"
      },
      "usage": {
        "recommended": "modern_only",
        "notes": [
          "1_000_000 is clearer than 1000000",
          "Works with binary, hex, octal, BigInt",
          "Cannot start or end with underscore",
          "Consider target runtime before using"
        ]
      }
    },
    "optional_chaining": {
      "name": "Optional Chaining (?.)",
      "stage": "stable",
      "ecmaVersion": "ES2020",
      "description": "Safe property access without null checks",
      "compatibility": {
        "browsers": {
          "chrome": "80+",
          "firefox": "74+",
          "safari": "13.1+",
          "edge": "80+",
          "ie": "no"
        },
        "node": "14+"
      },
      "usage": {
        "recommended": "modern_only",
        "notes": [
          "Short-circuits on null/undefined",
          "Works with function calls too",
          "Combine with nullish coalescing",
          "Not transpilable to ES5 without helper"
        ]
      }
    },
    "nullish_coalescing": {
      "name": "Nullish Coalescing (??)",
      "stage": "stable",
      "ecmaVersion": "ES2020",
      "description": "Default values with null/undefined check only",
      "compatibility": {
        "browsers": {
          "chrome": "80+",
          "firefox": "73+",
          "safari": "13.1+",
          "edge": "80+",
          "ie": "no"
        },
        "node": "14+"
      },
      "usage": {
        "recommended": "modern_only",
        "notes": [
          "Only coalesces on null/undefined",
          "Unlike || which checks falsy values",
          "Combine with optional chaining",
          "Perfect for configuration defaults"
        ]
      }
    }
  },
  "compatibility_guidelines": {
    "es5_target": {
      "description": "For maximum compatibility (IE11+)",
      "allowed_features": [
        "arrow_functions",
        "const_let",
        "template_literals",
        "destructuring",
        "default_params",
        "rest_spread",
        "object_literal_enhancements"
      ],
      "needs_transpilation": true,
      "tooling": ["@babel/preset-env", "typescript"]
    },
    "es2017_target": {
      "description": "Modern Node.js (8+) and evergreen browsers",
      "allowed_features": [
        "arrow_functions",
        "const_let",
        "template_literals",
        "destructuring",
        "default_params",
        "rest_spread",
        "object_literal_enhancements",
        "async_await",
        "classes"
      ],
      "needs_transpilation": false,
      "tooling": null
    },
    "es2020_target": {
      "description": "Latest modern environments",
      "allowed_features": [
        "all_previous",
        "optional_chaining",
        "nullish_coalescing",
        "numeric_separators"
      ],
      "needs_transpilation": false,
      "tooling": null
    }
  },
  "deprecation_timeline": {
    "var": {
      "deprecated": true,
      "recommended_replacement": "const/let",
      "reason": "Function-scoped, hoisting issues",
      "migration_difficulty": "easy"
    }
  }
}


path: references/patterns.json
content: {
  "metadata": {
    "version": "1.0.0",
    "description": "Legacy ES5/ES3 → Modern ES6+ transformation patterns",
    "author": "OpenClaw Skill Factory",
    "lastUpdated": "2025-06-16"
  },
  "patterns": {
    "var_to_const_let": {
      "description": "Convert var declarations to const/let based on reassignment detection",
      "category": "variable-declarations",
      "legacy": "var {name} = {value};",
      "modern": "const {name} = {value};",
      "conditions": {
        "reassigns": false,
        "scope": "block"
      },
      "confidence": 0.95,
      "priority": 1
    },
    "var_to_let": {
      "description": "Convert var to let when variable is reassigned",
      "category": "variable-declarations",
      "legacy": "var {name} = {value};",
      "modern": "let {name} = {value};",
      "conditions": {
        "reassigns": true
      },
      "confidence": 0.90,
      "priority": 2
    },
    "function_to_arrow": {
      "description": "Convert function expressions to arrow functions",
      "category": "functions",
      "legacy": "function ({params}) {\n  {body}\n}",
      "modern": "({params}) => {\n  {body}\n}",
      "conditions": {
        "preservesThis": false,
        "isExpression": true
      },
      "confidence": 0.85,
      "priority": 3
    },
    "function_to_arrow_implicit_return": {
      "description": "Convert single-expression arrow functions to implicit return",
      "category": "functions",
      "legacy": "({params}) => {\n  return {expression};\n}",
      "modern": "({params}) => {expression}",
      "conditions": {
        "singleReturn": true,
        "noSideEffects": true
      },
      "confidence": 0.80,
      "priority": 4
    },
    "object_literal_shorthand": {
      "description": "Convert object properties with same name to shorthand",
      "category": "objects",
      "legacy": "{name: name, age: age}",
      "modern": "{name, age}",
      "conditions": {
        "keyMatchesValue": true
      },
      "confidence": 0.98,
      "priority": 5
    },
    "object_method_shorthand": {
      "description": "Convert object method definitions to shorthand",
      "category": "objects",
      "legacy": "sayHello: function() {}",
      "modern": "sayHello() {}",
      "conditions": {},
      "confidence": 0.95,
      "priority": 6
    },
    "template_literal": {
      "description": "Convert string concatenation to template literals",
      "category": "strings",
      "legacy": "'Hello ' + name + '! You have ' + count + ' messages.'",
      "modern": "`Hello ${name}! You have ${count} messages.`",
      "conditions": {
        "containsConcatenation": true,
        "hasInterpolation": true
      },
      "confidence": 0.92,
      "priority": 7
    },
    "for_to_for_of": {
      "description": "Convert traditional for loops to for...of when index is not needed",
      "category": "loops",
      "legacy": "for (var i = 0; i < {array}.length; i++) {\n  var item = {array}[i];\n  {body}\n}",
      "modern": "for (const item of {array}) {\n  {body}\n}",
      "conditions": {
        "usesIndexOnlyForAccess": true,
        "noModifications": true
      },
      "confidence": 0.88,
      "priority": 8
    },
    "for_to_for_in": {
      "description": "Convert traditional for...in to Object.keys/entries iteration",
      "category": "loops",
      "legacy": "for (var key in obj) {\n  if (obj.hasOwnProperty(key)) {\n    {body}\n  }\n}",
      "modern": "for (const key of Object.keys(obj)) {\n  {body}\n}",
      "conditions": {
        "objectIteration": true,
        "hasOwnCheck": true
      },
      "confidence": 0.90,
      "priority": 9
    },
    "destructuring_array": {
      "description": "Convert array element access to array destructuring",
      "category": "destructuring",
      "legacy": "var first = arr[0];\nvar second = arr[1];",
      "modern": "const [first, second] = arr;",
      "conditions": {
        "sequentialAccess": true,
        "multipleExtractions": true
      },
      "confidence": 0.93,
      "priority": 10
    },
    "destructuring_object": {
      "description": "Convert repeated object property access to destructuring",
      "category": "destructuring",
      "legacy": "var name = user.name;\nvar email = user.email;",
      "modern": "const {name, email} = user;",
      "conditions": {
        "sameSourceObject": true,
        "propertyCount": "multiple"
      },
      "confidence": 0.94,
      "priority": 11
    },
    "default_params": {
      "description": "Add default parameters instead of manual checks",
      "category": "functions",
      "legacy": "function greet(name) {\n  name = name || 'World';\n  {body}\n}",
      "modern": "function greet(name = 'World') {\n  {body}\n}",
      "conditions": {
        "hasDefaultAssignment": true
      },
      "confidence": 0.96,
      "priority": 12
    },
    "rest_spread": {
      "description": "Convert arguments object to rest parameters",
      "category": "functions",
      "legacy": "function sum() {\n  var args = Array.prototype.slice.call(arguments);\n  {body}\n}",
      "modern": "function sum(...args) {\n  {body}\n}",
      "conditions": {
        "usesArguments": true
      },
      "confidence": 0.91,
      "priority": 13
    },
    "spread_merge": {
      "description": "Convert Object.assign to spread syntax",
      "category": "objects",
      "legacy": "Object.assign({}, defaults, options)",
      "modern": "{...defaults, ...options}",
      "conditions": {
        "objectMerging": true,
        "createsNewObject": true
      },
      "confidence": 0.90,
      "priority": 14
    },
    "array_spread_concat": {
      "description": "Convert concat calls to spread syntax",
      "category": "arrays",
      "legacy": "[].concat(arr1, arr2, arr3)",
      "modern": "[...arr1, ...arr2, ...arr3]",
      "conditions": {},
      "confidence": 0.89,
      "priority": 15
    },
    "map_filter_reduce_arrow": {
      "description": "Convert anonymous functions in array methods to arrow functions",
      "category": "arrays",
      "legacy": "arr.map(function(x) { return x * 2; })",
      "modern": "arr.map(x => x * 2)",
      "conditions": {
        "simpleReturn": true,
        "singleParam": true
      },
      "confidence": 0.92,
      "priority": 16
    },
    "promisify_callback": {
      "description": "Convert callback-based async to Promise-based",
      "category": "async",
      "legacy": "fs.readFile(path, function(err, data) {\n  {body}\n});",
      "modern": "fs.promises.readFile(path).then(data => {\n  {body}\n})",
      "conditions": {
        "nodeBuiltin": true,
        "errorFirstCallback": true
      },
      "confidence": 0.75,
      "priority": 17
    },
    "commonjs_to_esm": {
      "description": "Convert CommonJS require/module.exports to ES6 imports/exports",
      "category": "modules",
      "legacy": "var mod = require('module');\nmodule.exports = {foo: bar};",
      "modern": "import mod from 'module';\nexport const foo = bar;",
      "conditions": {
        "isModuleFile": true
      },
      "confidence": 0.85,
      "priority": 18
    },
    "export_default": {
      "description": "Convert module.exports = to export default",
      "category": "modules",
      "legacy": "module.exports = MyClass;",
      "modern": "export default MyClass;",
      "conditions": {
        "singleExport": true
      },
      "confidence": 0.95,
      "priority": 19
    },
    "class_properties": {
      "description": "Convert constructor assignments to class properties",
      "category": "classes",
      "legacy": "constructor() {\n  this.name = name;\n  this.age = age;\n}",
      "modern": "name;\nage;\nconstructor(){}",
      "conditions": {
        "simpleAssignment": true,
        "noComputation": true
      },
      "confidence": 0.88,
      "priority": 20
    },
    "computed_property_names": {
      "description": "Use computed property names in object literals",
      "category": "objects",
      "legacy": "var obj = {};\nobj['prop_' + key] = value;",
      "modern": "const obj = {\n  ['prop_' + key]: value\n};",
      "conditions": {
        "dynamicKey": true
      },
      "confidence": 0.87,
      "priority": 21
    },
    "binary_literals": {
      "description": "Convert parseInt to numeric literals when applicable",
      "category": "literals",
      "legacy": "parseInt('010', 8) // octal\nparseInt('0xFF', 16) // hex",
      "modern": "0o10 // octal\n0xFF // hex\n0b1010 // binary",
      "conditions": {
        "literalValue": true
      },
      "confidence": 0.95,
      "priority": 22
    }
  }
}


path: scripts/cli.js
content: #!/usr/bin/env node
/**
 * CLI for es6-refactor skill
 * Usage: es6-refactor [options] [file]
 *
 * Options:
 *   --from, -f        Source language version (ignored currently)
 *   --to, -t          Target ES version (ignored currently)
 *   --type, -l        Force language: 'js' or 'ts'
 *   --output, -o      Output file (default: stdout)
 *   --no-format       Skip Prettier formatting
 *   --rules, -r       Comma-separated list of rule names to apply
 *   --help, -h        Show help
 */

const { Command } = require('commander');
const fs = require('fs');
const path = require('path');
const { refactor } = require('./index');

async function run(argv = process.argv.slice(2)) {
  const program = new Command();

  program
    .name('es6-refactor')
    .description('Refactor JavaScript/TypeScript to modern ES6+ patterns')
    .version('1.0.0')
    .option('-f, --from <version>', 'Source version (ignored)')
    .option('-t, --to <version>', 'Target version (ignored)')
    .option('-l, --type <language>', 'Force language: js or ts')
    .option('-o, --output <file>', 'Output file path')
    .option('--no-format', 'Skip Prettier formatting')
    .option('-r, --rules <list>', 'Comma-separated list of rule names to apply')
    .argument('[file]', 'Input file (defaults to stdin)')
    .action(async (inputFile, options) => {
      // Determine language
      let language = options.type || 'javascript';
      if (language === 'ts') language = 'typescript';

      let code;
      if (inputFile) {
        const absPath = path.resolve(inputFile);
        code = fs.readFileSync(absPath, 'utf8');
        if (!options.type) {
          const ext = path.extname(absPath).toLowerCase();
          if (ext === '.ts' || ext === '.tsx') {
            language = 'typescript';
          } else if (ext === '.js' || ext === '.jsx') {
            language = 'javascript';
          }
        }
      } else {
        // Read from stdin asynchronously
        const chunks = [];
        for await (const chunk of process.stdin) {
          chunks.push(chunk);
        }
        code = Buffer.concat(chunks).toString('utf8');
      }

      const refactorOptions = {
        format: options.format !== false,
        rules: options.rules ? options.rules.split(',').map(s => s.trim()) : undefined
      };

      const result = refactor({ code, language, options: refactorOptions });

      if (options.output) {
        fs.writeFileSync(options.output, result, 'utf8');
      } else {
        process.stdout.write(result);
      }
    });

  await program.parseAsync(argv);
}

// If run directly (node scripts/cli.js), execute run()
if (require.main === module) {
  run().catch(err => {
    console.error('Error:', err.message);
    process.exit(1);
  });
}

// Export for programmatic use
module.exports = { run };

path: scripts/index.js
content: #!/usr/bin/env node
/**
 * es6-refactor skill entry point
 *
 * As a library:
 *   const { refactor } = require('es6-refactor');
 *   const result = refactor({ code, language, options });
 *
 * As a CLI (via bin):
 *   es6-refactor [options] [file]
 *
 * See CLI help: es6-refactor --help
 */

const path = require('path');

function refactor(context) {
  const { code, language = 'javascript', options = {} } = context;
  
  let transformer;
  if (language === 'typescript' || language === 'ts') {
    transformer = require('./types');
    if (typeof transformer.refactorTypeScript !== 'function') {
      throw new Error('types module does not export a refactorTypeScript function');
    }
    return transformer.refactorTypeScript(code, options);
  } else {
    transformer = require('./refactor');
    if (typeof transformer.refactorCode !== 'function') {
      throw new Error('refactor module does not export a refactorCode function');
    }
    return transformer.refactorCode(code, options);
  }
}

// Export for external use
module.exports = { refactor };

// If executed directly (e.g., `node scripts/index.js`), run as CLI
if (require.main === module) {
  const cli = require('./cli');
  cli.run(process.argv.slice(2)).catch(err => {
    console.error('Error:', err.message);
    process.exit(1);
  });
}

path: scripts/refactor.js
content: #!/usr/bin/env node
/**
 * Core refactoring engine for JavaScript
 * Usage (as library): const { refactorCode } = require('./refactor');
 */

const { parse } = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const t = require('@babel/types');
const path = require('path');
const fs = require('fs');

// Default built-in transformation rules
const BUILT_IN_RULES = {
  varToLet: {
    visitor: {
      VariableDeclaration(path) {
        if (path.node.kind === 'var') {
          path.node.kind = 'let';
        }
      }
    }
  },
  functionToArrow: {
    visitor: {
      FunctionExpression(path) {
        const parent = path.parent;
        if (!parent) return;
        // Skip if it's a method (inside object literal or class)
        if (parent.type === 'ObjectProperty' || parent.type === 'ObjectMethod' || parent.type === 'MethodDefinition' || parent.type === 'ClassMethod' || parent.type === 'ClassPrivateMethod') {
          return;
        }
        // Check for this, arguments, super, generator
        let hasThis = false;
        let hasArguments = false;
        let hasSuper = false;
        path.traverse({
          ThisExpression() { hasThis = true; },
          Identifier(id) {
            if (id.node.name === 'arguments') hasArguments = true;
            if (id.node.name === 'super') hasSuper = true;
          }
        });
        if (hasThis || hasArguments || hasSuper) return;
        if (path.node.generator) return;

        // Convert to arrow function
        const params = path.node.params.map(p => t.cloneNode(p));
        const body = path.node.body ? t.cloneNode(path.node.body) : t.blockStatement([]);
        const arrow = t.arrowFunctionExpression(params, body);
        arrow.async = !!path.node.async;
        if (path.node.rest) {
          arrow.rest = t.cloneNode(path.node.rest);
        }
        if (path.node.defaults) {
          arrow.defaults = path.node.defaults.map(d => t.cloneNode(d));
        }
        if (path.node.typeParameters) {
          arrow.typeParameters = t.cloneNode(path.node.typeParameters);
        }
        path.replaceWith(arrow);
      }
    }
  },
  objectShorthand: {
    visitor: {
      ObjectExpression(path) {
        for (const prop of path.node.properties) {
          if (prop.type === 'ObjectProperty' && !prop.shorthand && !prop.computed) {
            const key = prop.key;
            const value = prop.value;
            if (t.isIdentifier(key) && t.isIdentifier(value) && key.name === value.name) {
              prop.shorthand = true;
            }
          }
        }
      }
    }
  },
  templateLiteral: {
    visitor: {
      BinaryExpression(path) {
        if (path.node.operator !== '+') return;

        // Helper to flatten concatenation chain
        const flatten = (node) => {
          if (node.type === 'BinaryExpression' && node.operator === '+') {
            return [...flatten(node.left), ...flatten(node.right)];
          }
          if (t.isStringLiteral(node)) {
            return [{ type: 'string', value: node.value }];
          }
          return [{ type: 'expression', node }];
        };

        const parts = flatten(path.node);
        if (parts.length === 0) return;

        // Build template literal: alternating quasis and expressions
        let quasis = [];
        let expressions = [];
        let currentQuasi = '';

        for (const part of parts) {
          if (part.type === 'string') {
            currentQuasi += part.value;
          } else {
            quasis.push(t.templateElement({ raw: currentQuasi, cooked: currentQuasi }, false));
            expressions.push(t.cloneNode(part.node));
            currentQuasi = '';
          }
        }
        quasis.push(t.templateElement({ raw: currentQuasi, cooked: currentQuasi }, true));

        const template = t.templateLiteral(quasis, expressions);
        path.replaceWith(template);
      }
    }
  }
};

// Load ES6 features matrix (optional)
let ES6_FEATURES = {};
try {
  const featuresPath = path.resolve(__dirname, '../references/es6-features.json');
  ES6_FEATURES = JSON.parse(fs.readFileSync(featuresPath, 'utf8'));
} catch (e) {
  // Silently ignore if file missing
}

// Load enabled patterns from patterns.json (optional)
function loadPatternsFromFile() {
  try {
    const patternsPath = path.resolve(__dirname, '../references/patterns.json');
    const data = fs.readFileSync(patternsPath, 'utf8');
    const parsed = JSON.parse(data);
    if (Array.isArray(parsed)) {
      return parsed;
    } else if (parsed.enabledRules && Array.isArray(parsed.enabledRules)) {
      return parsed.enabledRules;
    } else {
      console.warn('patterns.json format not recognized; using defaults');
      return null;
    }
  } catch (e) {
    return null;
  }
}

function getEnabledRules(overrides) {
  if (overrides && Array.isArray(overrides)) {
    return overrides;
  }
  const fileRules = loadPatternsFromFile();
  if (fileRules) {
    return fileRules;
  }
  return Object.keys(BUILT_IN_RULES);
}

function refactorCode(code, options = {}) {
  const parserPlugins = options.parserPlugins || [];

  // Parse with Babel
  const ast = parse(code, {
    sourceType: 'module',
    plugins: parserPlugins
  });

  const enabledRuleNames = getEnabledRules(options.rules);
  const visitor = {};

  // Start with built-in rules
  enabledRuleNames.forEach(ruleName => {
    const rule = BUILT_IN_RULES[ruleName];
    if (rule && rule.visitor) {
      Object.assign(visitor, rule.visitor);
    } else {
      console.warn(`Rule '${ruleName}' not found or missing visitor.`);
    }
  });

  // Merge extra visitors if provided (for TypeScript-specific transforms)
  if (options.extraVisitors && typeof options.extraVisitors === 'object') {
    Object.assign(visitor, options.extraVisitors);
  }

  traverse(ast, visitor);

  const generateOptions = {
    retainLines: false,
    comments: true,
    compact: false,
    sourceMaps: false
  };
  let output = generate(ast, generateOptions).code;

  // Format with Prettier unless disabled
  if (options.format !== false) {
    try {
      const prettier = require('prettier');
      const parser = parserPlugins.includes('typescript') ? 'typescript' : 'babel';
      output = prettier.format(output, {
        parser,
        semi: true,
        singleQuote: true,
        trailingComma: 'es5',
        printWidth: 80
      });
    } catch (e) {
      // Prettier not available or formatting failed; continue with unformatted
    }
  }

  return output;
}

module.exports = { refactorCode, BUILT_IN_RULES };

path: scripts/types.js
content: #!/usr/bin/env node
/**
 * TypeScript-specific refactoring transformations
 * Usage (as library): const { refactorTypeScript } = require('./types');
 */

const { refactorCode } = require('./refactor');
const t = require('@babel/types');

// TypeScript-specific transformation: convert simple interfaces to type aliases
function tsInterfaceToType(path) {
  const node = path.node;
  if (node.type !== 'TSInterfaceDeclaration') return;
  // Skip if extends other interfaces
  if (node.extends && node.extends.length > 0) return;
  // Check for method signatures, call/construct signatures, index signatures
  if (node.body && node.body.body) {
    for (const element of node.body.body) {
      const type = element.type;
      if (type === 'TSMethodSignature' || type === 'TSCallSignature' || type === 'TSConstructSignature' || type === 'TSIndexSignature') {
        return;
      }
    }
  }

  // Collect TSPropertySignature elements
  const properties = [];
  for (const element of node.body.body) {
    if (element.type === 'TSPropertySignature') {
      properties.push(t.cloneNode(element));
    }
  }

  // Build TSObjectType from the property signatures
  const objectType = t.tsObjectType(properties);
  // Create a type alias: type <id> = <objectType>
  const typeAlias = t.tsTypeAlias(node.id, node.typeParameters, objectType);
  path.replaceWith(typeAlias);
}

function refactorTypeScript(code, options = {}) {
  // Ensure TypeScript parser plugin
  const parserPlugins = Array.isArray(options.parserPlugins) ? [...options.parserPlugins] : [];
  if (!parserPlugins.includes('typescript')) {
    parserPlugins.push('typescript');
  }
  // Also include common modern TypeScript/ES features if not already present
  const additionalPlugins = ['classProperties', 'decorators-legacy', 'optionalChaining', 'nullishCoalescingOperator'];
  for (const plugin of additionalPlugins) {
    if (!parserPlugins.includes(plugin)) {
      parserPlugins.push(plugin);
    }
  }

  // Add TypeScript-specific visitors
  const extraVisitors = {
    TSInterfaceDeclaration: tsInterfaceToType
  };

  // Use the common refactor engine with extra visitors
  return refactorCode(code, {
    ...options,
    parserPlugins,
    extraVisitors
  });
}

module.exports = { refactorTypeScript };

Security scan verdicts — ClawScan: suspicious | static analysis:  | VirusTotal: malicious | SkillSpector: suspicious (HIGH)