
Knitwork X
- 348 installs
- 3 repo stars
- Updated March 4, 2026
- hairyf/knitwork-x
knitwork-x is an agent skill for the knitwork-x npm library that helps developers programmatically generate safe JavaScript and TypeScript source strings for code generators, plugins, and AST-to-code pipelines.
About
knitwork-x is a Claude Code skill for the hairyf/knitwork-x package, a comprehensive fork of unjs/knitwork that emits JavaScript and TypeScript code as pure strings. Version 0.2.0 documents gen* helpers for ESM imports, classes, interfaces, enums, functions, type aliases, control flow, and object serialization, with 21 progressive-disclosure reference files loaded on demand. Every gen* function returns a string fragment suitable for splicing into larger modules without mutating inputs. Developers reach for knitwork-x when building codegen CLIs, bundler plugins, OpenAPI emitters, or dynamic module output where hand-written templates are error-prone. Install via npm install knitwork-x or npx nypm install knitwork-x, then compose outputs like genClass with nested genConstructor calls.
- Compose threaded posts and reply sequences for X
- Maintain cadence across hooks, CTAs, and follow-ups
- Apply character-limit and formatting guardrails
- Iterate voice and engagement patterns from drafts
- Knit standalone posts into cohesive distribution arcs
Knitwork X by the numbers
- 348 all-time installs (skills.sh)
- Ranked #832 of 1,879 Marketing & SEO skills by installs in the Skillselion catalog
- Data as of Jul 13, 2026 (Skillselion catalog sync)
npx skills add https://github.com/hairyf/knitwork-x --skill knitwork-xAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 348 |
|---|---|
| repo stars | ★ 3 |
| Last updated | March 4, 2026 |
| Repository | hairyf/knitwork-x ↗ |
How do you generate TypeScript source code programmatically?
Plan and draft multi-post X threads, reply chains, and campaign cadences in Claude while keeping narrative flow, tone, and platform formatting constraints intact.
Who is it for?
Tooling engineers building TypeScript or JavaScript code generators who need safe, composable string emitters instead of full AST printers.
Skip if: Application developers writing normal app components by hand who do not need programmatic source generation.
When should I use this skill?
A developer asks to generate TypeScript with knitwork-x, build a codegen plugin, or emit imports and classes as strings.
What you get
Composable gen* code strings for imports, classes, types, control flow, and serialized literals ready to write into .ts files.
- Generated import and export statements
- Composed class and interface source strings
- Serialized object and array literal fragments
By the numbers
- Skill metadata declares knitwork-x version 0.2.0
- SKILL.md indexes 21 reference topic files across core and features sections
- Package is forked from unjs/knitwork with extended TypeScript gen* APIs
Files
knitwork-x provides programmatic code generation for JavaScript and TypeScript. It is forked from knitwork and adds comprehensive TypeScript helpers: ESM (import/export), strings, variables, classes, interfaces, functions, types, control flow (if/try/loop/switch), and serialization (object/array/map/set). All gen* functions return strings suitable for splicing into source; they are pure and do not mutate inputs.
Use this skill when an agent needs to generate code strings (e.g. for codegen tools, plugins, or dynamic module output).
Core References
| Topic | Description | Reference |
|---|---|---|
| Overview | Purpose, install, when to use | core-overview |
| ESM | Import, export, default export, dynamic import | core-esm |
| String | genString, escapeString, genTemplateLiteral | core-string |
| Variable | genVariable, genVariableName | core-variable |
| Design Guidelines | Naming, params, options (for contributors) | core-design-guidelines |
Features
| Topic | Description | Reference |
|---|---|---|
| Class | genClass, genConstructor, genProperty, genMethod, getter/setter | features-class |
| Interface | genInterface, genIndexSignature | features-interface |
| Enum | genEnum, genConstEnum | features-enum |
| Function | genFunction, genArrowFunction, genBlock, genParam | features-function |
| Type | genTypeAlias, genUnion, genIntersection, genMappedType, etc. | features-type |
| Conditional | genConditionalType, genTernary | features-conditional |
| Decorator | genDecorator | features-decorator |
| Module & Namespace | genModule, genNamespace, genDeclareNamespace | features-module-namespace |
| Condition | genIf, genElse, genElseIf | features-condition |
| Try | genTry, genCatch, genFinally | features-try |
| Loop | genFor, genForOf, genWhile, genDoWhile | features-loop |
| Switch | genSwitch, genCase, genDefault | features-switch |
| Statement | genReturn, genThrow, genPrefixedBlock | features-statement |
| Object & Serialization | genObject, genArray, genMap, genSet, genTypeObject | features-object |
| Utils | genComment, genKey, genLiteral, genRegExp, wrapInDelimiters | features-utils |
Key Points
- Return type: Every
gen*function returns astring(code fragment). - Options: Most accept an optional
optionsobject (e.g.export,singleQuotes,indent); default to{}. - Indent: When supported, pass
indentas the last parameter; useindent + " "for nested blocks. - Strings: Use
genString(input, options)for quoted/escaped output sosingleQuotesis respected. - Composing: Combine
gen*outputs (e.g.genClass(..., [genConstructor(...)])) to build larger snippets.
Generation Info
- Source: docs/ (current project)
- Generated: 2026-02-02
Design Guidelines for knitwork-x APIs
Conventions for the gen* APIs—useful when extending or contributing to knitwork-x.
Naming
- Public API: Prefix with
gen+ verb/noun (e.g.genImport,genClass,genBlock). - Internal helpers: Use
_genprefix or non-gen names (e.g.escapeString,wrapInDelimiters).
Parameter Order
1. Required "subject" parameters (e.g. specifier, name, object). 2. Optional subject parameters (e.g. imports?, statements?). 3. Options object (e.g. options = {}). 4. Indent as the last parameter when supported (indent = "").
Options Object
- Type:
GenXxxOptionsorXxxCodeGenOptions; extendCodegenOptionswhen needed (e.g.singleQuotes?). - All option fields optional; callers default to
{}. - Boolean flags: e.g.
export,const,singleQuotes.
Return Value
- Always string (code fragment).
- Pure: no mutation of inputs; same input and options → stable output.
- Output is a fragment that can be spliced into source (may include newlines and indent).
Polymorphic Input
- Accept
T | T[]when "one vs many" is clear (e.g.statements?: string | string[]); normalize to array inside. - For object vs array shapes, use a union (e.g.
genTypeObject(object: TypeObject | TypeObjectField[])).
Strings and Keys
- Use genString(input, options) for any quoted/escaped string so
singleQuotesis respected. - Use genKey(key) for object literal keys (unquoted for valid identifiers, otherwise quoted).
Key Points
- When adding new
gen*helpers, follow the same parameter order and options pattern. - Pass CodegenOptions through to nested
genString,genEnum, etc., for consistent style.
<!-- Source references: docs/2.apis/index.md (Design Guidelines) -->
ESM Code Generation
Generate ESM module syntax: import, export, export default, and dynamic import().
genImport(specifier, imports?, options?)
Produces an import statement. imports can be:
- Omitted or default:
genImport('pkg')→import "pkg"; - String (default import):
genImport('pkg', 'foo')→import foo from "pkg"; - Array of names:
genImport('pkg', ['a', 'b'])→import { a, b } from "pkg"; - Array of `{ name, as }`:
genImport('pkg', [{ name: 'foo', as: 'bar' }])→import { foo as bar } from "pkg";
Options: type: true for type-only import; attributes: { type: 'json' } for import attributes.
genImport('vue', ['ref', 'computed'])
// => import { ref, computed } from "vue";
genImport('pkg', 'foo', { type: true })
// => import type foo from "pkg";genExport(specifier, exports?, options?)
Produces export ... from "specifier". exports can be a string, array of names, '*', or { name: '*', as: 'bar' }.
genExport('pkg', ['a', 'b'])
// => export { a, b } from "pkg";
genExport('pkg', { name: '*', as: 'bar' })
// => export * as bar from "pkg";genDefaultExport(value, _options?)
Produces export default value;. Use genString for quoted values; options (e.g. singleQuotes) apply to string output.
genDefaultExport('foo')
// => export default foo;genDynamicImport(specifier, options?)
Produces dynamic import() or typeof import(). Options:
- wrapper: true →
() => import("pkg") - interopDefault: true →
() => import("pkg").then(m => m.default || m) - type: true →
typeof import("pkg"); with name: 'foo' →typeof import("pkg").foo
genDynamicImport('pkg', { wrapper: true })
// => () => import("pkg")
genDynamicImport('pkg', { type: true, name: 'foo' })
// => typeof import("pkg").fooKey Points
- Module specifiers are passed as strings; the implementation uses
genStringfor the quoted output. - Use
type: truefor type-only imports/exports. - Use
attributesfor import attributes (e.g.with { type: "json" }).
<!-- Source references: docs/2.apis/3.esm.md, src/esm.ts, README ESM section -->
knitwork-x Overview
knitwork-x provides utilities to generate JavaScript and TypeScript code as strings. It is forked from knitwork and adds comprehensive TypeScript helpers: ESM, strings, variables, classes, interfaces, functions, types, control flow, and serialization.
When to Use
- Code generators: Build tools that emit JS/TS source (e.g. schema-to-types, API clients).
- Dynamic modules: Generate import/export and function/class bodies at runtime.
- AST-to-code: Turn structured data into code strings without a full AST library.
All exported helpers are pure: same inputs and options yield stable string output; no side effects or input mutation.
Installation
pnpm add knitwork-x
# or npm / yarn / bunUsage
Import the helpers you need and call them to get code strings:
import { genImport, genClass, genConstructor } from 'knitwork-x'
// ESM import
const imp = genImport('vue', ['ref', 'computed'])
// => import { ref, computed } from "vue";
// Class with constructor
const cls = genClass('Counter', [
genConstructor([], ['super();'])
], { export: true })
// => export class Counter { constructor() { super(); } }Key Points
- Every
gen*function returns a string (code fragment). - Use options (e.g.
export,singleQuotes) to control style; defaultoptions = {}. - Compose helpers: e.g. pass
genConstructor(...)as a member togenClass(...). - For quoted/escaped strings, use
genString(input, options)so quote style is consistent.
<!-- Source references: docs/1.guide/1.index.md, README.md -->
String and Literal Generation
Helpers for generating string literals, escaping, and template literals.
escapeString(id)
Escapes a string for use inside a JavaScript string literal (backslashes, quotes, newlines, etc.).
escapeString("foo'bar")
// => foo\'bar
escapeString("foo\nbar")
// => foo\nbargenString(input, options?)
Produces a quoted string literal with proper escaping. Options: singleQuotes: true for single quotes. Use this for any user-facing or config-driven string so quote style is consistent.
genString('foo')
// => "foo"
genString('foo', { singleQuotes: true })
// => 'foo'
genString('foo\nbar')
// => "foo\nbar"genTemplateLiteral(parts)
Produces a runtime template literal ` ...${expr}... . parts` is an array of alternating string chunks and expression names (as strings). Length must be odd: first and last are string parts, between them are expression names.
genTemplateLiteral(['hello ', 'x'])
// => `hello ${x}`
genTemplateLiteral(['prefix', 'expr', 'suffix'])
// => `prefix${expr}suffix`
genTemplateLiteral(['', 'value'])
// => `${value}`
genTemplateLiteral(['text only'])
// => `text only`Key Points
- Always use genString for values that need quoting/escaping so
singleQuotesand escaping are consistent across generated code. - genTemplateLiteral is for runtime template literals (values), not TypeScript template literal types (use
genTemplateLiteralTypefrom the type module).
<!-- Source references: docs/2.apis/1.string.md, src/string.ts -->
Variable Generation
Generate safe variable names and variable declarations (const / let).
genVariableName(name)
Produces a safe JavaScript identifier. Reserves (e.g. for, class) are prefixed with _; spaces and other invalid characters are replaced (e.g. with space → with_32space).
genVariableName('valid_import')
// => valid_import
genVariableName('for')
// => _for
genVariableName('with space')
// => with_32spacegenVariable(name, value, options?)
Produces a variable declaration. Options: kind: 'let' | 'var' | 'const' (default 'const'), export: true.
genVariable('a', '2')
// => const a = 2
genVariable('foo', "'bar'")
// => const foo = 'bar'
genVariable('x', '1', { kind: 'let' })
// => let x = 1
genVariable('y', '2', { export: true })
// => export const y = 2Key Points
- value is emitted as-is (no quoting). For string values use a quoted string like
"'bar'"or build withgenString(...)and pass the result. - Use genVariableName when generating identifiers from arbitrary names (e.g. import names, file names) to avoid invalid identifiers.
<!-- Source references: docs/2.apis/2.variable.md, src/variable.ts -->
Class Generation
Generate TypeScript/JavaScript classes, constructors, class properties, methods, and getters/setters.
genClass(name, members, options, indent?)
Produces class Name [extends Base] [implements I1, I2] { ... }. members is an array of strings (e.g. from genConstructor, genProperty, genMethod). Options: extends, implements (string or array), export.
genClass('Foo')
// => class Foo {}
genClass('Bar', [genConstructor([], ['super();'])])
// => class Bar { constructor() { super(); } }
genClass('Baz', [], { extends: 'Base', implements: ['I1', 'I2'] })
// => class Baz extends Base implements I1, I2 {}
genClass('Exported', [], { export: true })
// => export class Exported {}genConstructor(parameters, body, options, indent?)
Produces constructor(params) { [super(...);] ... }. parameters is an array of { name, type?, optional?, default? }. body is a string or array of statement strings. Options: super (arguments string).
genConstructor()
// => constructor() {}
genConstructor([{ name: 'x', type: 'string' }], ['super();', 'this.x = x;'])
// => constructor(x: string) { super(); this.x = x; }genProperty(field, indent?)
Produces a single property: [modifiers?] name [?:] type [ = value ]. field is TypeField: name, type?, optional?, value?, readonly?, static?, jsdoc?.
genProperty({ name: 'foo', type: 'string' })
// => foo: string
genProperty({ name: 'bar', type: 'number', optional: true })
// => bar?: number
genProperty({ name: 'x', value: '0' })
// => x = 0
genProperty({ name: 'id', type: 'string', readonly: true, static: true })
// => static readonly id: stringgenMethod(options, indent?)
Produces a method (or get/set) for class or object: name(params) { body }, get name() { }, set name(v) { }. Options: name, parameters, body, returnType, kind: 'get' | 'set', async, static, etc.
genGetter / genSetter
Shorthand for get/set: genGetter('value', ['return this._v;']), genSetter('value', 'v', ['this._v = v;']).
Key Points
- Compose members: pass
genConstructor(...),genProperty(...),genMethod(...)into the members array ofgenClass. - Use genProperty for both interface-like signatures and class fields with initializers (
value).
<!-- Source references: docs/2.apis/4.class.md, src/class.ts -->
Condition Generation (if / else)
Generate if, else if, and else blocks. genPrefixedBlock is a low-level helper for any prefix { body } form (e.g. while).
genIf(cond, statements, options, indent?)
Produces if (cond) { statements } or if (cond) statement. statements can be a string or array of strings. Options: bracket: false for single statement without braces.
genIf('x > 0', 'return x;')
// => if (x > 0) { return x; }
genIf('ok', ['doA();', 'doB();'])
// => if (ok) { doA(); doB(); }
genIf('x', 'console.log(x);', { bracket: false })
// => if (x) console.log(x);genElseIf(cond, statements, options, indent?)
Produces else if (cond) { statements } or single-statement form. Same options as genIf.
genElseIf('x < 0', 'return -x;')
// => else if (x < 0) { return -x; }genElse(statements, options, indent?)
Produces else { statements } or else statement. Options: bracket: false.
genElse(['return 0;'])
// => else { return 0; }
genElse('fallback();', { bracket: false })
// => else fallback();genPrefixedBlock(prefix, statements, options, indent?)
Low-level: produces prefix { statements } or prefix statement. Use for custom constructs or when building while/for-like blocks manually.
genPrefixedBlock('if (ok)', 'return true;')
// => if (ok) { return true; }
genPrefixedBlock('while (running)', ['step();', 'check();'])
// => while (running) { step(); check(); }Key Points
- Compose genIf + genElseIf + genElse to build full if/else chains; pass indent for nested formatting.
- bracket: false emits a single statement without
{ }(same as control-flow helpers in loop/switch).
<!-- Source references: docs/2.apis/13.condition.md, src/condition.ts -->
Conditional Type and Ternary
Generate TypeScript conditional types T extends U ? X : Y and JavaScript ternary expressions.
genConditionalType(checkType, extendsType, trueType, falseType)
Produces a conditional type: checkType extends extendsType ? trueType : falseType.
genConditionalType('T', 'U', 'X', 'Y')
// => T extends U ? X : Y
genConditionalType('T', 'null', 'never', 'T')
// => T extends null ? never : TUse for type-level conditionals (e.g. null/undefined stripping, distributive conditionals).
genTernary(cond, whenTrue, whenFalse)
Produces a runtime ternary: cond ? whenTrue : whenFalse.
genTernary('x > 0', 'x', '-x')
// => x > 0 ? x : -x
genTernary('ok', "'yes'", "'no'")
// => ok ? 'yes' : 'no'Key Points
- genConditionalType is for types only; genTernary is for value expressions.
- Arguments are emitted as-is; for string literals in ternary use quoted strings like
"'yes'".
<!-- Source references: docs/2.apis/9.conditional.md, src/conditional.ts -->
Decorator Generation
Generate decorator syntax @Decorator or @Decorator(args).
genDecorator(name, args?, indent?)
Produces @name or @name(args). args is optional; pass a string for the parenthesized argument list (e.g. "()", '("/api")', "(min: 0, max: 100)").
genDecorator('Component')
// => @Component
genDecorator('Injectable', '()')
// => @Injectable()
genDecorator('Route', '("/api")')
// => @Route("/api")
genDecorator('Validate', '(min: 0, max: 100)')
// => @Validate(min: 0, max: 100)Key Points
- args is emitted as-is (no quoting of the whole). Include parentheses in the string when you need
@Decorator(...). - Typically used together with genClass or genProperty / genMethod; prepend decorator lines with appropriate indent before the declaration.
<!-- Source references: docs/2.apis/10.decorator.md, src/decorator.ts -->
Enum Generation
Generate TypeScript enums and const enums. Members can be numeric, string, or auto-increment (undefined value).
genEnum(name, members, options, indent?)
Produces [const] enum Name { ... }. members is an object: key = member name, value = number, string, or undefined (auto-increment from 0). Options: export, const.
genEnum('Color', { Red: 0, Green: 1, Blue: 2 })
// => enum Color { Red = 0, Green = 1, Blue = 2 }
genEnum('Status', { Active: 'active', Inactive: 'inactive' })
// => enum Status { Active = "active", Inactive = "inactive" }
genEnum('Auto', { A: undefined, B: undefined, C: undefined })
// => enum Auto { A = 0, B = 1, C = 2 }
genEnum('MyEnum', { Foo: 1 }, { export: true, const: true })
// => export const enum MyEnum { Foo = 1 }genConstEnum(name, members, options, indent?)
Shorthand for genEnum(..., { const: true }).
genConstEnum('Direction', { Up: 1, Down: 2 })
// => const enum Direction { Up = 1, Down = 2 }Key Points
- Use undefined for auto-increment numeric members (0, 1, 2, ...).
- Pass CodegenOptions (e.g.
singleQuotes) so string enum values are quoted consistently.
<!-- Source references: docs/2.apis/6.enum.md, src/enum.ts -->
Function and Block Generation
Generate function declarations, arrow functions, statement blocks, and parameter lists. For class/object methods use genMethod (see features-object).
genFunction(options, indent?)
Produces [export] function name [<generics>](params) [: returnType] { body }. Options: name, parameters, body (string or array), returnType, generics, async, export.
genFunction({ name: 'foo' })
// => function foo() {}
genFunction({ name: 'foo', parameters: [{ name: 'x', type: 'string' }, { name: 'y', type: 'number', optional: true }] })
// => function foo(x: string, y?: number) {}
genFunction({ name: 'id', generics: [{ name: 'T' }], parameters: [{ name: 'x', type: 'T' }], returnType: 'T', body: ['return x;'] })
// => function id<T>(x: T): T { return x; }
genFunction({ name: 'foo', export: true })
// => export function foo() {}genArrowFunction(options)
Produces (params) => body or (params) => { statements }. body can be a single expression string (no braces) or an array of statements (block). Options: parameters, body, returnType, async.
genArrowFunction({ body: 'x + 1' })
// => () => x + 1
genArrowFunction({ parameters: [{ name: 'x', type: 'number' }], body: 'x * 2' })
// => (x: number) => x * 2
genArrowFunction({ parameters: [{ name: 'x' }], body: ['return x + 1;'] })
// => (x) => { return x + 1; }genBlock(statements?, indent?)
Produces { statements }. statements can be a single string or array of strings; normalized to array and joined with newlines and indent.
genBlock()
// => {}
genBlock('return x;')
// => { return x; }
genBlock(['const a = 1;', 'return a;'])
// => { const a = 1; return a; }genParam(p)
Produces a single parameter string from a TypeField: name [: type] [= default], name? for optional.
genParam({ name: 'x', type: 'string' })
// => x: string
genParam({ name: 'z', type: 'number', default: '0' })
// => z: number = 0Key Points
- Use genBlock wherever a block body is needed (functions, if/else, try/catch, etc.).
- body in genArrowFunction: one expression → no braces; array of statements → block with braces.
<!-- Source references: docs/2.apis/7.function.md, src/function.ts -->
Interface Generation
Generate TypeScript interfaces, index signatures, call signatures, and construct signatures.
genInterface(name, contents?, options, indent?)
Produces interface Name [extends Other] { ... }. contents can be an object (key → type string), an array of TypeField, or omitted for {}. Options: extends (string or array), export.
genInterface('FooInterface')
// => interface FooInterface {}
genInterface('FooInterface', { name: 'string', count: 'number' })
// => interface FooInterface { name: string, count: number }
genInterface('FooInterface', undefined, { extends: 'Other' })
// => interface FooInterface extends Other {}
genInterface('FooInterface', {}, { export: true })
// => export interface FooInterface {}genIndexSignature(keyType, valueType, keyName?)
Produces [keyName: keyType]: valueType. Default keyName is 'key'.
genIndexSignature('string', 'number')
// => [key: string]: number
genIndexSignature('number', 'string')
// => [key: number]: stringgenCallSignature(options)
Produces a call signature (params): returnType (and optional generics). Use inside interface body for callable types.
genCallSignature({ parameters: [{ name: 'x', type: 'string' }], returnType: 'number' })
// => (x: string): numbergenConstructSignature(options)
Produces a construct signature new (params): returnType. Use inside interface body for constructible types.
genConstructSignature({ parameters: [{ name: 'x', type: 'string' }], returnType: 'MyClass' })
// => new (x: string): MyClassKey Points
- contents can be a plain object
{ key: "type" }or an array of{ name, type, optional?, jsdoc? }. - Combine genIndexSignature with other members in contents for mixed interface shapes.
<!-- Source references: docs/2.apis/5.interface.md, src/interface.ts -->
Loop Generation
Generate for, for...of, for...in, while, and do...while loops.
genFor(init, test, update, statements, options, indent?)
Produces C-style for (init; test; update) { body }. init, test, update are strings (can be empty). statements can be a string or array. Options: bracket: false for single statement.
genFor('let i = 0', 'i < n', 'i++', 'console.log(i);')
// => for (let i = 0; i < n; i++) { console.log(i); }
genFor('', 'true', '', ['doWork();', 'if (done) break;'])
// => for (; true; ) { doWork(); if (done) break; }genForOf(left, iterable, statements, options, indent?)
Produces for (left of iterable) { body }. left is the loop variable (e.g. 'const x', 'let [k, v]').
genForOf('const x', 'items', 'console.log(x);')
// => for (const x of items) { console.log(x); }
genForOf('let [k, v]', 'Object.entries(obj)', ['process(k, v);'])
// => for (let [k, v] of Object.entries(obj)) { process(k, v); }genForIn(left, obj, statements, options, indent?)
Produces for (left in obj) { body }.
genForIn('const key', 'obj', 'console.log(key, obj[key]);')
// => for (const key in obj) { console.log(key, obj[key]); }genWhile(cond, statements, options, indent?)
Produces while (cond) { body }. Options: bracket: false.
genWhile('running', 'step();')
// => while (running) { step(); }genDoWhile(statements, cond, options, indent?)
Produces do { body } while (cond);. Options: bracket: false.
genDoWhile('step();', '!done')
// => do { step(); } while (!done);Key Points
- left in genForOf / genForIn is the full left-hand side (e.g.
'const x','let item'). - Use bracket: false when the body is a single statement and you want no braces.
<!-- Source references: docs/2.apis/15.loop.md, src/loop.ts -->
Module and Namespace Generation
Generate TypeScript declare module, module augmentation, namespace, and declare global blocks.
genModule(specifier, statements?) / genAugmentation(specifier, statements?)
Produces declare module "specifier" { ... }. genAugmentation is an alias for genModule. statements can be a string or array of strings (e.g. interface/type declarations).
genModule('@nuxt/utils')
// => declare module "@nuxt/utils" {}
genModule('@nuxt/utils', 'interface MyInterface {}')
// => declare module "@nuxt/utils" { interface MyInterface {} }
genModule('@nuxt/utils', [
'interface MyInterface { test?: string }',
'type MyType = string',
])
// => multi-line declare module with bothUse for ambient module augmentation (e.g. adding types to third-party packages).
genNamespace(name, statements?)
Produces namespace Name { ... }. statements can be a string or array of strings.
genNamespace('MyNamespace')
// => namespace MyNamespace {}
genNamespace('MyNamespace', ['interface MyInterface { test?: string }', 'const foo: string'])
// => namespace MyNamespace { ... }genDeclareNamespace(namespace, statements?)
Produces declare namespace (e.g. declare global { ... }). namespace is typically "global". statements can be a string or array of strings.
genDeclareNamespace('global')
// => declare global {}
genDeclareNamespace('global', 'interface Window {}')
// => declare global { interface Window {} }Key Points
- genModule / genAugmentation use the specifier as a string (quoted in output); use for package name or path.
- genDeclareNamespace('global') is the standard way to extend global scope in ambient declarations.
<!-- Source references: docs/2.apis/11.module.md, docs/2.apis/12.namespace.md, src/module.ts, src/namespace.ts -->
Object and Serialization Generation
Generate object literals, arrays, Map, Set (runtime serialization), TypeScript object types, and object/class methods (getter, setter, method).
Serialization (runtime values)
genObject(object, indent, options?)
Produces an object literal { key: value, ... }. object can be a plain object (key → value string) or array of { name, value, jsdoc? }. Values are not escaped or quoted (emit raw code).
genObject({ foo: 'bar', test: '() => import("pkg")' })
// => { foo: bar, test: () => import("pkg") }
genObject([{ name: 'count', value: '0', jsdoc: 'Counter value' }])
// => { /** Counter value */ count: 0 }genArray(array, indent, options?)
Produces an array literal [ ... ]. Values are not escaped or quoted.
genArray([1, 2, 3])
// => [1, 2, 3]genMap(entries, indent, options?) / genSet(values, indent, options?)
genMap produces new Map([...]) from array of [key, value]; genSet produces new Set([...]). String values are escaped and quoted via genString when options are passed.
genMap([['foo', 'bar'], ['baz', 1]])
// => new Map([["foo", "bar"], ["baz", 1]])
genSet(['foo', 'bar', 1])
// => new Set(["foo", "bar", 1])Type object (type-level)
genTypeObject (see features-type) produces { key: type } for type aliases and interfaces.
Method / getter / setter (class or object)
genMethod(options, indent?)
Produces a method or get/set: name(params) { body }, get name() { }, set name(v) { }. Options: name, parameters, body, returnType, kind: 'get' | 'set', async, static.
genMethod({ name: 'foo' })
// => foo() {}
genMethod({ name: 'bar', parameters: [{ name: 'x', type: 'string' }], body: ['return x;'], returnType: 'string' })
// => bar(x: string): string { return x; }
genMethod({ name: 'value', kind: 'get', body: ['return this._v;'], returnType: 'number' })
// => get value(): number { return this._v; }genGetter(name, body, options, indent?) / genSetter(name, paramName, body, options, indent?)
Shorthand for get/set. genSetter takes paramName and optional paramType in options.
Key Points
- genObject / genArray values are raw code strings; for string literals use genString and pass the result as the value.
- genMethod is shared between class members and object literal methods; use with genClass or inside object literal generation.
<!-- Source references: docs/2.apis/18.object.md, src/object.ts -->
Statement Generation
Generate return and throw statements. genPrefixedBlock is in the condition module; use it for any prefix { body } form.
genReturn(expr?, indent?)
Produces return expr; or return;. expr is optional.
genReturn('x')
// => return x;
genReturn()
// => return;
genReturn('a + b')
// => return a + b;genThrow(expr, indent?)
Produces throw expr;.
genThrow("new Error('failed')")
// => throw new Error('failed');
genThrow('e')
// => throw e;Key Points
- expr is emitted as-is (no quoting). For string literals use a quoted string like
"'error'"or build with genString. - Use genReturn / genThrow inside genBlock or as part of genIf / genSwitch body arrays.
<!-- Source references: docs/2.apis/17.statement.md, src/statement.ts -->
Switch Generation
Generate switch (expr) { cases } and case / default clauses. Compose by passing an array of case/default strings to genSwitch.
genSwitch(expr, cases, options, indent?)
Produces switch (expr) { cases }. cases is an array of strings (typically from genCase and genDefault).
genSwitch('x', [genCase('1', 'break;'), genDefault('return 0;')])
// => switch (x) { case 1: break; default: return 0; } (with newlines/indent)
genSwitch('key', [])
// => switch (key) {}genCase(value, statements?, indent?)
Produces case value: optionally followed by indented statements. Omit statements for fall-through.
genCase('1', 'break;')
// => case 1:\n break;
genCase("'a'", ['doA();', 'break;'])
// => case 'a':\n doA();\n break;
genCase('0')
// => case 0: (fall-through)genDefault(statements?, indent?)
Produces default: optionally followed by indented statements. Omit statements for fall-through.
genDefault('return 0;')
// => default:\n return 0;
genDefault()
// => default:Key Points
- value in genCase is emitted as-is (e.g.
'1',"'a'",'MyEnum.A'). - Build cases array by mixing genCase and genDefault in the desired order.
<!-- Source references: docs/2.apis/16.switch.md, src/switch.ts -->
Try / Catch / Finally Generation
Generate try, catch, and finally blocks. Compose them into a full try/catch/finally by concatenating the returned strings (with newlines/indent as needed).
genTry(statements, options, indent?)
Produces try { statements } or try statement. statements can be a string or array of strings. Options: bracket: false for single statement without braces.
genTry('mightThrow();')
// => try { mightThrow(); }
genTry(['const x = await f();', 'return x;'])
// => try { const x = await f(); return x; }
genTry('f();', { bracket: false })
// => try f();genCatch(statements, options, indent?)
Produces catch (binding) { statements } or catch { statements }. Options: binding (e.g. 'e') for catch variable; omit for optional catch binding. bracket: false for single statement.
genCatch(['throw e;'], { binding: 'e' })
// => catch (e) { throw e; }
genCatch(['logError();'])
// => catch { logError(); }genFinally(statements, options, indent?)
Produces finally { statements } or finally statement. Options: bracket: false.
genFinally('cleanup();')
// => finally { cleanup(); }
genFinally(['release();', "log('done');"])
// => finally { release(); log('done'); }Key Points
- Build full try/catch/finally by concatenating:
genTry(...) + ' ' + genCatch(...)and optionally+ ' ' + genFinally(...). - Use binding when you need the error variable in catch; omit for
catch { }(optional catch binding).
<!-- Source references: docs/2.apis/14.try.md, src/try.ts -->
Type Alias and Type Expression Generation
Generate type aliases, object types, union/intersection, mapped types, template literal types, and keyof/typeof/satisfies/assertion.
genTypeAlias(name, value, options, indent?)
Produces [export] type Name [<generics>] = value. value can be a string (raw type) or a type object (passed to genTypeObject). Options: export, generics.
genTypeAlias('Foo', 'string')
// => type Foo = string
genTypeAlias('FooType', { name: 'string', count: 'number' })
// => type FooType = { name: string, count: number }
genTypeAlias('Id', 'T', { generics: [{ name: 'T' }] })
// => type Id<T> = T
genTypeAlias('Baz', 'string', { export: true })
// => export type Baz = stringgenTypeObject(object, indent?)
Produces an object type { ... }. object can be a plain object (key → type), object with "key?": type for optional, or array of TypeObjectField. Supports nested objects and JSDoc.
genTypeObject({ name: 'string', count: 'number' })
// => { name: string, count: number }
genTypeObject([{ name: 'name', type: 'string' }, { name: 'count', type: 'number', required: true }])
// => { name?: string, count: number }genUnion(types) / genIntersection(types)
genUnion produces A | B | C; genIntersection produces A & B & C. types can be a string (single) or array of strings.
genUnion(['string', 'number'])
// => string | number
genIntersection(['A', 'B', 'C'])
// => A & B & CgenMappedType(keyName, keyType, valueType)
Produces { [K in keyof T]: U }.
genMappedType('K', 'keyof T', 'U')
// => { [K in keyof T]: U }genKeyOf(type) / genTypeof(expr)
genKeyOf → keyof Type; genTypeof → typeof expr.
genTemplateLiteralType(parts)
Produces a template literal type (type-level). parts is alternating string chunks and type names (same shape as genTemplateLiteral).
genTemplateLiteralType(['prefix', 'T', 'suffix'])
// => `prefix${T}suffix`genTypeAssertion(expr, type) / genSatisfies(expr, type)
genTypeAssertion → expr as Type; genSatisfies → expr satisfies Type.
genTypeExport(specifier, imports, options) / genInlineTypeImport(specifier, name?, options)
genTypeExport → export type { ... } from "specifier";. genInlineTypeImport → typeof import("specifier").name (default export when name omitted).
Key Points
- genTypeObject accepts both
{ key: "type" }and[{ name, type, required? }]; use the latter for optional keys and JSDoc. - Use genUnion/ genIntersection for complex types; pass options through for consistent quoting where applicable.
<!-- Source references: docs/2.apis/8.type.md, src/type.ts -->
Utils Generation
Utility helpers: comments, JSDoc, object keys, object literal shorthand, regex literals, and delimiter wrapping.
genComment(text, options?, indent?)
Produces a single-line // comment or block comment (non-JSDoc). Options: block: true for /* ... */.
genComment('Single line comment')
// => // Single line comment
genComment('Block comment', { block: true })
// => /* Block comment */genJSDocComment(jsdoc, indent?)
Produces a JSDoc block /** ... */. jsdoc can be a string, array of lines, or object (e.g. { description, param: { x: "number" }, returns: "void" }).
genJSDocComment('Single line')
// => /** Single line */
genJSDocComment({ description: 'Fn', param: { x: 'number' }, returns: 'void' })
// => /** Fn @param {number} x @returns {void} */ (formatted)genKey(key)
Produces a safe object key: unquoted for valid identifiers, otherwise quoted (e.g. genString). Use for object literal keys so reserved words and special characters are handled.
genKey('foo')
// => foo
genKey('foo-bar')
// => "foo-bar"
genKey('with space')
// => "with space"genLiteral(fields, indent, _options?)
Produces an object literal from field descriptors (shorthand and spread). fields is an array of ['key'] for shorthand or ['key', 'value'] or ['...', 'rest'] for spread.
genLiteral([['type'], ['type', 'A'], ['...', 'b']])
// => { type, type: A, ...b }genRegExp(pattern, flags?)
Produces a regex literal /pattern/flags.
genRegExp('foo')
// => /foo/
genRegExp('foo', 'gi')
// => /foo/gi
genRegExp('foo\\d+')
// => /foo\d+/wrapInDelimiters(lines, indent, delimiters, withComma?)
Low-level: wraps an array of strings in delimiters (e.g. {, }). delimiters is [open, close]. withComma controls trailing commas. Used internally by genObject, genBlock, genEnum, etc.
Key Points
- Use genKey for object literal keys so identifiers and reserved words are correct.
- Use genJSDocComment for JSDoc on functions, interfaces, or properties (pass indent for alignment).
<!-- Source references: docs/2.apis/19.utils.md, src/utils.ts -->
Related skills
How it compares
Choose knitwork-x over raw template literals when codegen must emit valid TypeScript with quoting, indentation, and ESM import rules handled by tested gen* helpers.
FAQ
What does knitwork-x generate?
knitwork-x provides pure gen* functions that return JavaScript or TypeScript source strings for imports, classes, types, control flow, and literals. The knitwork-x skill documents how to compose those fragments in codegen tools without mutating input objects.
How is knitwork-x different from unjs/knitwork?
knitwork-x is a fork of unjs/knitwork extended with comprehensive TypeScript helpers such as genInterface, genMappedType, genTry, and genSwitch. The skill tells agents to install the knitwork-x package rather than the original knitwork package.
When should an agent load knitwork-x reference files?
The knitwork-x skill keeps SKILL.md lean and points to 21 reference markdown files for ESM, classes, loops, and serialization topics. Agents load a specific reference only when generating that construct, following progressive disclosure.