Comparing version 1.2.3 to 1.3.0
{ | ||
"name": "esrap", | ||
"version": "1.2.3", | ||
"version": "1.3.0", | ||
"description": "Parse in reverse", | ||
@@ -22,8 +22,9 @@ "repository": { | ||
"devDependencies": { | ||
"@vitest/ui": "^2.0.5", | ||
"acorn": "^8.10.0", | ||
"dts-buddy": "^0.2.4", | ||
"@vitest/ui": "^2.1.1", | ||
"acorn": "^8.11.3", | ||
"acorn-typescript": "^1.4.13", | ||
"dts-buddy": "^0.5.4", | ||
"prettier": "^3.0.3", | ||
"typescript": "^5.2.2", | ||
"vitest": "^2.0.5", | ||
"typescript": "^5.7.2", | ||
"vitest": "^2.1.1", | ||
"zimmerframe": "^1.0.0" | ||
@@ -33,5 +34,6 @@ }, | ||
"check": "tsc", | ||
"prepublishOnly": "pnpm test && dts-buddy", | ||
"prepublishOnly": "pnpm test && dts-buddy -m dts-buddy:./src/public.d.ts", | ||
"sandbox": "node test/sandbox/index.js", | ||
"test": "vitest --run" | ||
"test": "vitest --run", | ||
"test:ui": "vitest --ui" | ||
}, | ||
@@ -41,5 +43,5 @@ "license": "MIT", | ||
"@jridgewell/sourcemap-codec": "^1.4.15", | ||
"@types/estree": "^1.0.1" | ||
"@typescript-eslint/types": "^8.2.0" | ||
}, | ||
"packageManager": "pnpm@9.8.0" | ||
} |
@@ -47,2 +47,6 @@ # esrap | ||
## TypeScript | ||
`esrap` can also print TypeScript nodes, assuming they match the ESTree-like [`@typescript-eslint/types`](https://www.npmjs.com/package/@typescript-eslint/types). | ||
## Why not just use Prettier? | ||
@@ -49,0 +53,0 @@ |
@@ -1,13 +0,16 @@ | ||
/** @type {import('./types').Newline} */ | ||
/** @import { TSESTree } from '@typescript-eslint/types' */ | ||
/** @import { Chunk, Command, Dedent, Handlers, Indent, Newline, NodeWithComments, Sequence, State, TypeAnnotationNodes } from './types' */ | ||
/** @type {Newline} */ | ||
const newline = { type: 'Newline' }; | ||
/** @type {import('./types').Indent} */ | ||
/** @type {Indent} */ | ||
const indent = { type: 'Indent' }; | ||
/** @type {import('./types').Dedent} */ | ||
/** @type {Dedent} */ | ||
const dedent = { type: 'Dedent' }; | ||
/** | ||
* @param {import('./types').Command[]} children | ||
* @returns {import('./types').Sequence} | ||
* @param {Command[]} children | ||
* @returns {Sequence} | ||
*/ | ||
@@ -20,3 +23,3 @@ function create_sequence(...children) { | ||
* Rough estimate of the combined width of a group of commands | ||
* @param {import('./types').Command[]} commands | ||
* @param {Command[]} commands | ||
* @param {number} from | ||
@@ -43,6 +46,8 @@ * @param {number} to | ||
/** | ||
* @param {import('estree').Node} node | ||
* @param {import('./types').State} state | ||
* @param {TSESTree.Node} node | ||
* @param {State} state | ||
*/ | ||
export function handle(node, state) { | ||
const node_with_comments = /** @type {NodeWithComments} */ (node); | ||
const handler = handlers[node.type]; | ||
@@ -54,4 +59,4 @@ | ||
if (node.leadingComments) { | ||
prepend_comments(node.leadingComments, state, false); | ||
if (node_with_comments.leadingComments) { | ||
prepend_comments(node_with_comments.leadingComments, state, false); | ||
} | ||
@@ -62,4 +67,4 @@ | ||
if (node.trailingComments) { | ||
state.comments.push(node.trailingComments[0]); // there is only ever one | ||
if (node_with_comments.trailingComments) { | ||
state.comments.push(node_with_comments.trailingComments[0]); // there is only ever one | ||
} | ||
@@ -70,4 +75,4 @@ } | ||
* @param {string} content | ||
* @param {import('estree').Node} node | ||
* @returns {import('./types').Chunk} | ||
* @param {TSESTree.Node} node | ||
* @returns {Chunk} | ||
*/ | ||
@@ -83,4 +88,4 @@ function c(content, node) { | ||
/** | ||
* @param {import('estree').Comment[]} comments | ||
* @param {import('./types').State} state | ||
* @param {TSESTree.Comment[]} comments | ||
* @param {State} state | ||
* @param {boolean} newlines | ||
@@ -128,4 +133,8 @@ */ | ||
/** @type {Record<import('estree').Expression['type'] | 'Super' | 'RestElement', number>} */ | ||
/** @type {Record<TSESTree.Expression['type'] | 'Super' | 'RestElement', number>} */ | ||
const EXPRESSIONS_PRECEDENCE = { | ||
JSXFragment: 20, | ||
JSXElement: 20, | ||
ArrayPattern: 20, | ||
ObjectPattern: 20, | ||
ArrayExpression: 20, | ||
@@ -135,3 +144,2 @@ TaggedTemplateExpression: 20, | ||
Identifier: 20, | ||
Literal: 18, | ||
TemplateLiteral: 20, | ||
@@ -146,2 +154,7 @@ Super: 20, | ||
NewExpression: 19, | ||
Literal: 18, | ||
TSSatisfiesExpression: 18, | ||
TSInstantiationExpression: 18, | ||
TSNonNullExpression: 18, | ||
TSTypeAssertion: 18, | ||
AwaitExpression: 17, | ||
@@ -151,2 +164,3 @@ ClassExpression: 17, | ||
ObjectExpression: 17, | ||
TSAsExpression: 16, | ||
UpdateExpression: 16, | ||
@@ -165,4 +179,4 @@ UnaryExpression: 15, | ||
* | ||
* @param {import('estree').Expression} node | ||
* @param {import('estree').BinaryExpression | import('estree').LogicalExpression} parent | ||
* @param {TSESTree.Expression | TSESTree.PrivateIdentifier} node | ||
* @param {TSESTree.BinaryExpression | TSESTree.LogicalExpression} parent | ||
* @param {boolean} is_right | ||
@@ -172,2 +186,4 @@ * @returns | ||
function needs_parens(node, parent, is_right) { | ||
if (node.type === 'PrivateIdentifier') return false; | ||
// special case where logical expressions and coalesce expressions cannot be mixed, | ||
@@ -201,3 +217,3 @@ // either of them need to be wrapped with parentheses | ||
if ( | ||
/** @type {import('estree').BinaryExpression} */ (node).operator === '**' && | ||
/** @type {TSESTree.BinaryExpression} */ (node).operator === '**' && | ||
parent.operator === '**' | ||
@@ -212,3 +228,3 @@ ) { | ||
return ( | ||
OPERATOR_PRECEDENCE[/** @type {import('estree').BinaryExpression} */ (node).operator] <= | ||
OPERATOR_PRECEDENCE[/** @type {TSESTree.BinaryExpression} */ (node).operator] <= | ||
OPERATOR_PRECEDENCE[parent.operator] | ||
@@ -219,3 +235,3 @@ ); | ||
return ( | ||
OPERATOR_PRECEDENCE[/** @type {import('estree').BinaryExpression} */ (node).operator] < | ||
OPERATOR_PRECEDENCE[/** @type {TSESTree.BinaryExpression} */ (node).operator] < | ||
OPERATOR_PRECEDENCE[parent.operator] | ||
@@ -225,3 +241,3 @@ ); | ||
/** @param {import('estree').Node} node */ | ||
/** @param {TSESTree.Node} node */ | ||
function has_call_expression(node) { | ||
@@ -247,7 +263,9 @@ while (node) { | ||
/** | ||
* @param {import('estree').Node[]} nodes | ||
* @param {import('./types').State} state | ||
* @param {TSESTree.Node[]} nodes | ||
* @param {State} state | ||
*/ | ||
const handle_body = (nodes, state) => { | ||
let last_statement = /** @type {import('estree').Node} */ ({ type: 'EmptyStatement' }); | ||
let last_statement = /** @type {TSESTree.Node} */ ({ | ||
type: 'EmptyStatement' | ||
}); | ||
let first = true; | ||
@@ -264,7 +282,8 @@ let needs_margin = false; | ||
const leadingComments = statement.leadingComments; | ||
delete statement.leadingComments; | ||
const statement_with_comments = /** @type {NodeWithComments} */ (statement); | ||
const leading_comments = statement_with_comments.leadingComments; | ||
delete statement_with_comments.leadingComments; | ||
if (leadingComments && leadingComments.length > 0) { | ||
prepend_comments(leadingComments, state, true); | ||
if (leading_comments && leading_comments.length > 0) { | ||
prepend_comments(leading_comments, state, true); | ||
} | ||
@@ -288,3 +307,3 @@ | ||
while (state.comments.length) { | ||
const comment = /** @type {import('estree').Comment} */ (state.comments.shift()); | ||
const comment = /** @type {TSESTree.Comment} */ (state.comments.shift()); | ||
@@ -301,4 +320,4 @@ state.commands.push(add_newline ? newline : ' ', { type: 'Comment', comment }); | ||
/** | ||
* @param {import('estree').VariableDeclaration} node | ||
* @param {import('./types').State} state | ||
* @param {TSESTree.VariableDeclaration} node | ||
* @param {State} state | ||
*/ | ||
@@ -337,9 +356,9 @@ const handle_var_declaration = (node, state) => { | ||
/** | ||
* @template {import('estree').Node} T | ||
* @template {TSESTree.Node} T | ||
* @param {Array<T | null>} nodes | ||
* @param {import('./types').State} state | ||
* @param {State} state | ||
* @param {boolean} spaces | ||
* @param {(node: T, state: import('./types').State) => void} fn | ||
* @param {(node: T, state: State) => void} fn | ||
*/ | ||
function sequence(nodes, state, spaces, fn) { | ||
function sequence(nodes, state, spaces, fn, separator = ',') { | ||
if (nodes.length === 0) return; | ||
@@ -372,3 +391,3 @@ | ||
if (!is_last) { | ||
state.commands.push(','); | ||
state.commands.push(separator); | ||
} | ||
@@ -380,3 +399,3 @@ | ||
while (state.comments.length) { | ||
const comment = /** @type {import('estree').Comment} */ (state.comments.shift()); | ||
const comment = /** @type {TSESTree.Comment} */ (state.comments.shift()); | ||
state.commands.push({ type: 'Comment', comment }); | ||
@@ -394,3 +413,3 @@ if (!is_last) state.commands.push(join); | ||
// otherwise we'd duplicate a lot more stuff | ||
state.commands.push(','); | ||
state.commands.push(separator); | ||
} | ||
@@ -418,11 +437,162 @@ | ||
/** @satisfies {Record<string, (node: any, state: import('./types').State) => undefined>} */ | ||
/** | ||
* @param {TypeAnnotationNodes} node | ||
* @param {State} state | ||
*/ | ||
function handle_type_annotation(node, state) { | ||
switch (node.type) { | ||
case 'TSNumberKeyword': | ||
state.commands.push('number'); | ||
break; | ||
case 'TSStringKeyword': | ||
state.commands.push('string'); | ||
break; | ||
case 'TSBooleanKeyword': | ||
state.commands.push('boolean'); | ||
break; | ||
case 'TSAnyKeyword': | ||
state.commands.push('any'); | ||
break; | ||
case 'TSVoidKeyword': | ||
state.commands.push('void'); | ||
break; | ||
case 'TSUnknownKeyword': | ||
state.commands.push('unknown'); | ||
break; | ||
case 'TSNeverKeyword': | ||
state.commands.push('never'); | ||
break; | ||
case 'TSArrayType': | ||
handle_type_annotation(node.elementType, state); | ||
state.commands.push('[]'); | ||
break; | ||
case 'TSTypeAnnotation': | ||
state.commands.push(': '); | ||
handle_type_annotation(node.typeAnnotation, state); | ||
break; | ||
case 'TSTypeLiteral': | ||
state.commands.push('{ '); | ||
sequence(node.members, state, false, handle_type_annotation, ';'); | ||
state.commands.push(' }'); | ||
break; | ||
case 'TSPropertySignature': | ||
handle(node.key, state); | ||
if (node.optional) state.commands.push('?'); | ||
if (node.typeAnnotation) handle_type_annotation(node.typeAnnotation, state); | ||
break; | ||
case 'TSTypeReference': | ||
handle(node.typeName, state); | ||
// @ts-expect-error `acorn-typescript` and `@typescript-esling/types` have slightly different type definitions | ||
if (node.typeParameters) handle_type_annotation(node.typeParameters, state); | ||
break; | ||
case 'TSTypeParameterInstantiation': | ||
case 'TSTypeParameterDeclaration': | ||
state.commands.push('<'); | ||
for (let i = 0; i < node.params.length; i++) { | ||
handle_type_annotation(node.params[i], state); | ||
if (i != node.params.length - 1) state.commands.push(', '); | ||
} | ||
state.commands.push('>'); | ||
break; | ||
case 'TSTypeParameter': | ||
// @ts-expect-error `acorn-typescript` and `@typescript-esling/types` have slightly different type definitions | ||
state.commands.push(node.name); | ||
if (node.constraint) { | ||
state.commands.push(' extends '); | ||
handle_type_annotation(node.constraint, state); | ||
} | ||
break; | ||
case 'TSTypeQuery': | ||
state.commands.push('typeof '); | ||
handle(node.exprName, state); | ||
break; | ||
case 'TSEnumMember': | ||
handle(node.id, state); | ||
if (node.initializer) { | ||
state.commands.push(' = '); | ||
handle(node.initializer, state); | ||
} | ||
break; | ||
case 'TSFunctionType': | ||
if (node.typeParameters) handle_type_annotation(node.typeParameters, state); | ||
// @ts-expect-error `acorn-typescript` and `@typescript-esling/types` have slightly different type definitions | ||
const parameters = node.parameters; | ||
state.commands.push('('); | ||
sequence(parameters, state, false, handle); | ||
state.commands.push(') => '); | ||
// @ts-expect-error `acorn-typescript` and `@typescript-esling/types` have slightly different type definitions | ||
handle_type_annotation(node.typeAnnotation.typeAnnotation, state); | ||
break; | ||
case 'TSIndexSignature': | ||
const indexParameters = node.parameters; | ||
state.commands.push('['); | ||
sequence(indexParameters, state, false, handle); | ||
state.commands.push(']'); | ||
// @ts-expect-error `acorn-typescript` and `@typescript-esling/types` have slightly different type definitions | ||
handle_type_annotation(node.typeAnnotation, state); | ||
break; | ||
case 'TSMethodSignature': | ||
handle(node.key, state); | ||
// @ts-expect-error `acorn-typescript` and `@typescript-esling/types` have slightly different type definitions | ||
const parametersSignature = node.parameters; | ||
state.commands.push('('); | ||
sequence(parametersSignature, state, false, handle); | ||
state.commands.push(')'); | ||
// @ts-expect-error `acorn-typescript` and `@typescript-esling/types` have slightly different type definitions | ||
handle_type_annotation(node.typeAnnotation, state); | ||
break; | ||
case 'TSExpressionWithTypeArguments': | ||
handle(node.expression, state); | ||
break; | ||
case 'TSTupleType': | ||
state.commands.push('['); | ||
sequence(node.elementTypes, state, false, handle_type_annotation); | ||
state.commands.push(']'); | ||
break; | ||
case 'TSNamedTupleMember': | ||
handle(node.label, state); | ||
state.commands.push(': '); | ||
handle_type_annotation(node.elementType, state); | ||
break; | ||
case 'TSUnionType': | ||
sequence(node.types, state, false, handle_type_annotation, ' |'); | ||
break; | ||
case 'TSIntersectionType': | ||
sequence(node.types, state, false, handle_type_annotation, ' &'); | ||
break; | ||
case 'TSLiteralType': | ||
handle(node.literal, state); | ||
break; | ||
case 'TSConditionalType': | ||
handle_type_annotation(node.checkType, state); | ||
state.commands.push(' extends '); | ||
handle_type_annotation(node.extendsType, state); | ||
state.commands.push(' ? '); | ||
handle_type_annotation(node.trueType, state); | ||
state.commands.push(' : '); | ||
handle_type_annotation(node.falseType, state); | ||
break; | ||
default: | ||
throw new Error(`Not implemented type annotation ${node.type}`); | ||
} | ||
} | ||
/** @satisfies {Record<string, (node: any, state: State) => undefined>} */ | ||
const shared = { | ||
/** | ||
* @param {import('estree').ArrayExpression | import('estree').ArrayPattern} node | ||
* @param {import('./types').State} state | ||
* @param {TSESTree.ArrayExpression | TSESTree.ArrayPattern} node | ||
* @param {State} state | ||
*/ | ||
'ArrayExpression|ArrayPattern': (node, state) => { | ||
state.commands.push('['); | ||
sequence(/** @type {import('estree').Node[]} */ (node.elements), state, false, handle); | ||
sequence(/** @type {TSESTree.Node[]} */ (node.elements), state, false, handle); | ||
state.commands.push(']'); | ||
@@ -432,4 +602,4 @@ }, | ||
/** | ||
* @param {import('estree').BinaryExpression | import('estree').LogicalExpression} node | ||
* @param {import('./types').State} state | ||
* @param {TSESTree.BinaryExpression | TSESTree.LogicalExpression} node | ||
* @param {State} state | ||
*/ | ||
@@ -464,4 +634,4 @@ 'BinaryExpression|LogicalExpression': (node, state) => { | ||
/** | ||
* @param {import('estree').BlockStatement | import('estree').ClassBody} node | ||
* @param {import('./types').State} state | ||
* @param {TSESTree.BlockStatement | TSESTree.ClassBody} node | ||
* @param {State} state | ||
*/ | ||
@@ -482,8 +652,6 @@ 'BlockStatement|ClassBody': (node, state) => { | ||
/** | ||
* @param {import('estree').CallExpression | import('estree').NewExpression} node | ||
* @param {import('./types').State} state | ||
* @param {TSESTree.CallExpression | TSESTree.NewExpression} node | ||
* @param {State} state | ||
*/ | ||
'CallExpression|NewExpression': (node, state) => { | ||
const index = state.commands.length; | ||
if (node.type === 'NewExpression') { | ||
@@ -505,6 +673,9 @@ state.commands.push('new '); | ||
if (/** @type {import('estree').SimpleCallExpression} */ (node).optional) { | ||
if (/** @type {TSESTree.CallExpression} */ (node).optional) { | ||
state.commands.push('?.'); | ||
} | ||
// @ts-expect-error | ||
if (node.typeParameters) handle_type_annotation(node.typeParameters, state); | ||
const open = create_sequence(); | ||
@@ -527,3 +698,3 @@ const join = create_sequence(); | ||
while (state.comments.length) { | ||
const comment = /** @type {import('estree').Comment} */ (state.comments.shift()); | ||
const comment = /** @type {TSESTree.Comment} */ (state.comments.shift()); | ||
@@ -567,4 +738,4 @@ state.commands.push({ type: 'Comment', comment }); | ||
/** | ||
* @param {import('estree').ClassDeclaration | import('estree').ClassExpression} node | ||
* @param {import('./types').State} state | ||
* @param {TSESTree.ClassDeclaration | TSESTree.ClassExpression} node | ||
* @param {State} state | ||
*/ | ||
@@ -585,2 +756,7 @@ 'ClassDeclaration|ClassExpression': (node, state) => { | ||
if (node.implements) { | ||
state.commands.push('implements '); | ||
sequence(node.implements, state, false, handle_type_annotation); | ||
} | ||
handle(node.body, state); | ||
@@ -590,4 +766,4 @@ }, | ||
/** | ||
* @param {import('estree').ForInStatement | import('estree').ForOfStatement} node | ||
* @param {import('./types').State} state | ||
* @param {TSESTree.ForInStatement | TSESTree.ForOfStatement} node | ||
* @param {State} state | ||
*/ | ||
@@ -612,4 +788,4 @@ 'ForInStatement|ForOfStatement': (node, state) => { | ||
/** | ||
* @param {import('estree').FunctionDeclaration | import('estree').FunctionExpression} node | ||
* @param {import('./types').State} state | ||
* @param {TSESTree.FunctionDeclaration | TSESTree.FunctionExpression} node | ||
* @param {State} state | ||
*/ | ||
@@ -621,6 +797,14 @@ 'FunctionDeclaration|FunctionExpression': (node, state) => { | ||
if (node.typeParameters) { | ||
handle_type_annotation(node.typeParameters, state); | ||
} | ||
state.commands.push('('); | ||
sequence(node.params, state, false, handle); | ||
state.commands.push(') '); | ||
state.commands.push(')'); | ||
if (node.returnType) handle_type_annotation(node.returnType, state); | ||
state.commands.push(' '); | ||
handle(node.body, state); | ||
@@ -630,4 +814,4 @@ }, | ||
/** | ||
* @param {import('estree').RestElement | import('estree').SpreadElement} node | ||
* @param {import('./types').State} state | ||
* @param {TSESTree.RestElement | TSESTree.SpreadElement} node | ||
* @param {State} state | ||
*/ | ||
@@ -637,6 +821,9 @@ 'RestElement|SpreadElement': (node, state) => { | ||
handle(node.argument, state); | ||
// @ts-expect-error `acorn-typescript` and `@typescript-esling/types` have slightly different type definitions | ||
if (node.typeAnnotation) handle_type_annotation(node.typeAnnotation, state); | ||
} | ||
}; | ||
/** @type {import('./types').Handlers} */ | ||
/** @type {Handlers} */ | ||
const handlers = { | ||
@@ -768,2 +955,8 @@ ArrayExpression: shared['ArrayExpression|ArrayPattern'], | ||
Decorator(node, state) { | ||
state.commands.push('@'); | ||
handle(node.expression, state); | ||
state.commands.push(newline); | ||
}, | ||
DoWhileStatement(node, state) { | ||
@@ -872,2 +1065,4 @@ state.commands.push('do '); | ||
state.commands.push(c(name, node)); | ||
if (node.typeAnnotation) handle_type_annotation(node.typeAnnotation, state); | ||
}, | ||
@@ -895,9 +1090,9 @@ | ||
/** @type {import('estree').ImportNamespaceSpecifier | null} */ | ||
/** @type {TSESTree.ImportNamespaceSpecifier | null} */ | ||
let namespace_specifier = null; | ||
/** @type {import('estree').ImportDefaultSpecifier | null} */ | ||
/** @type {TSESTree.ImportDefaultSpecifier | null} */ | ||
let default_specifier = null; | ||
/** @type {import('estree').ImportSpecifier[]} */ | ||
/** @type {TSESTree.ImportSpecifier[]} */ | ||
const named_specifiers = []; | ||
@@ -916,2 +1111,3 @@ | ||
state.commands.push('import '); | ||
if (node.importKind == 'type') state.commands.push('type '); | ||
@@ -935,2 +1131,3 @@ if (default_specifier) { | ||
if (s.importKind == 'type') state.commands.push('type '); | ||
handle(s.local, state); | ||
@@ -961,6 +1158,7 @@ }); | ||
// str.replace(/\\u(\d{4})/g, (m, n) => String.fromCharCode(+n)) | ||
const value = | ||
node.raw ?? | ||
(typeof node.value === 'string' ? JSON.stringify(node.value) : String(node.value)); | ||
let value = node.raw; | ||
if (!value) | ||
value = typeof node.value === 'string' ? JSON.stringify(node.value) : String(node.value); | ||
state.commands.push(c(value, node)); | ||
@@ -1000,2 +1198,8 @@ }, | ||
MethodDefinition(node, state) { | ||
if (node.decorators) { | ||
for (const decorator of node.decorators) { | ||
handle(decorator, state); | ||
} | ||
} | ||
if (node.static) { | ||
@@ -1026,3 +1230,3 @@ state.commands.push('static '); | ||
handle(node.value.body, state); | ||
if (node.value.body) handle(node.value.body, state); | ||
}, | ||
@@ -1036,3 +1240,3 @@ | ||
if (p.type === 'Property' && p.value.type === 'FunctionExpression') { | ||
const fn = /** @type {import('estree').FunctionExpression} */ (p.value); | ||
const fn = /** @type {TSESTree.FunctionExpression} */ (p.value); | ||
@@ -1066,2 +1270,4 @@ if (p.kind === 'get' || p.kind === 'set') { | ||
state.commands.push('}'); | ||
if (node.typeAnnotation) handle_type_annotation(node.typeAnnotation, state); | ||
}, | ||
@@ -1104,2 +1310,6 @@ | ||
PropertyDefinition(node, state) { | ||
if (node.accessibility) { | ||
state.commands.push(node.accessibility, ' '); | ||
} | ||
if (node.static) { | ||
@@ -1117,2 +1327,7 @@ state.commands.push('static '); | ||
if (node.typeAnnotation) { | ||
state.commands.push(': '); | ||
handle_type_annotation(node.typeAnnotation.typeAnnotation, state); | ||
} | ||
if (node.value) { | ||
@@ -1131,5 +1346,6 @@ state.commands.push(' = '); | ||
if (node.argument) { | ||
const argumentWithComment = /** @type {NodeWithComments} */ (node.argument); | ||
const contains_comment = | ||
node.argument.leadingComments && | ||
node.argument.leadingComments.some((comment) => comment.type === 'Line'); | ||
argumentWithComment.leadingComments && | ||
argumentWithComment.leadingComments.some((comment) => comment.type === 'Line'); | ||
@@ -1228,3 +1444,3 @@ state.commands.push(contains_comment ? 'return (' : 'return '); | ||
state.commands.push('throw '); | ||
handle(node.argument, state); | ||
if (node.argument) handle(node.argument, state); | ||
state.commands.push(';'); | ||
@@ -1255,2 +1471,81 @@ }, | ||
TSAsExpression(node, state) { | ||
if (node.expression) { | ||
const needs_parens = | ||
EXPRESSIONS_PRECEDENCE[node.expression.type] < EXPRESSIONS_PRECEDENCE.TSAsExpression; | ||
if (needs_parens) { | ||
state.commands.push('('); | ||
handle(node.expression, state); | ||
state.commands.push(')'); | ||
} else { | ||
handle(node.expression, state); | ||
} | ||
} | ||
state.commands.push(' as '); | ||
handle_type_annotation(node.typeAnnotation, state); | ||
}, | ||
TSEnumDeclaration(node, state) { | ||
state.commands.push('enum '); | ||
handle(node.id, state); | ||
state.commands.push(' {', indent, newline); | ||
sequence(node.members, state, false, handle_type_annotation); | ||
state.commands.push(dedent, newline, '}', newline); | ||
}, | ||
TSNonNullExpression(node, state) { | ||
handle(node.expression, state); | ||
state.commands.push('!'); | ||
}, | ||
TSInterfaceBody(node, state) { | ||
sequence(node.body, state, false, handle_type_annotation, ';'); | ||
}, | ||
TSInterfaceDeclaration(node, state) { | ||
state.commands.push('interface '); | ||
handle(node.id, state); | ||
if (node.typeParameters) handle_type_annotation(node.typeParameters, state); | ||
if (node.extends) { | ||
state.commands.push(' extends '); | ||
sequence(node.extends, state, false, handle_type_annotation); | ||
} | ||
state.commands.push(' {'); | ||
handle(node.body, state); | ||
state.commands.push('}'); | ||
}, | ||
TSSatisfiesExpression(node, state) { | ||
if (node.expression) { | ||
const needs_parens = | ||
EXPRESSIONS_PRECEDENCE[node.expression.type] < EXPRESSIONS_PRECEDENCE.TSSatisfiesExpression; | ||
if (needs_parens) { | ||
state.commands.push('('); | ||
handle(node.expression, state); | ||
state.commands.push(')'); | ||
} else { | ||
handle(node.expression, state); | ||
} | ||
} | ||
state.commands.push(' satisfies '); | ||
handle_type_annotation(node.typeAnnotation, state); | ||
}, | ||
TSTypeAliasDeclaration(node, state) { | ||
state.commands.push('type '); | ||
handle(node.id, state); | ||
if (node.typeParameters) handle_type_annotation(node.typeParameters, state); | ||
state.commands.push(' = '); | ||
handle_type_annotation(node.typeAnnotation, state); | ||
state.commands.push(';'); | ||
}, | ||
TSQualifiedName(node, state) { | ||
handle(node.left, state); | ||
state.commands.push('.'); | ||
handle(node.right, state); | ||
}, | ||
UnaryExpression(node, state) { | ||
@@ -1257,0 +1552,0 @@ state.commands.push(node.operator); |
@@ -0,1 +1,3 @@ | ||
/** @import { TSESTree } from '@typescript-eslint/types' */ | ||
/** @import { Command, PrintOptions, State } from './types' */ | ||
import { handle } from './handlers.js'; | ||
@@ -18,11 +20,3 @@ import { encode } from '@jridgewell/sourcemap-codec'; | ||
/** | ||
* @typedef {{ | ||
* sourceMapSource?: string; | ||
* sourceMapContent?: string; | ||
* sourceMapEncodeMappings?: boolean; // default true | ||
* }} PrintOptions | ||
*/ | ||
/** | ||
* @param {import('estree').Node} node | ||
* @param {TSESTree.Node} node | ||
* @param {PrintOptions} opts | ||
@@ -35,2 +29,3 @@ * @returns {{ code: string, map: any }} // TODO | ||
{ | ||
//@ts-expect-error | ||
type: 'Program', | ||
@@ -44,3 +39,3 @@ body: node, | ||
/** @type {import('./types').State} */ | ||
/** @type {State} */ | ||
const state = { | ||
@@ -82,3 +77,3 @@ commands: [], | ||
/** @param {import('./types').Command} command */ | ||
/** @param {Command} command */ | ||
function run(command) { | ||
@@ -85,0 +80,0 @@ if (typeof command === 'string') { |
@@ -1,14 +0,37 @@ | ||
import { Comment, Node } from 'estree'; | ||
import { TSESTree } from '@typescript-eslint/types'; | ||
type NodeOf<T extends string, X> = X extends { type: T } ? X : never; | ||
type Handler<T> = (node: T, state: State) => undefined; | ||
export type Handlers = { | ||
[K in Node['type']]: Handler<NodeOf<K, Node>>; | ||
[T in TSESTree.Node['type']]: Handler<Extract<TSESTree.Node, { type: T }>>; | ||
}; | ||
export type TypeAnnotationNodes = | ||
| TSESTree.TypeNode | ||
| TSESTree.TypeElement | ||
| TSESTree.TSTypeAnnotation | ||
| TSESTree.TSPropertySignature | ||
| TSESTree.TSTypeParameter | ||
| TSESTree.TSTypeParameterDeclaration | ||
| TSESTree.TSTypeParameterInstantiation | ||
| TSESTree.TSEnumMember | ||
| TSESTree.TSInterfaceHeritage | ||
| TSESTree.TSClassImplements | ||
| TSExpressionWithTypeArguments; | ||
type TSExpressionWithTypeArguments = { | ||
type: 'TSExpressionWithTypeArguments'; | ||
expression: any; | ||
}; | ||
// `@typescript-eslint/types` differs from the official `estree` spec by handling | ||
// comments differently. This is a node which we can use to ensure type saftey. | ||
export type NodeWithComments = { | ||
leadingComments?: TSESTree.Comment[] | undefined; | ||
trailingComments?: TSESTree.Comment[] | undefined; | ||
} & TSESTree.Node; | ||
export interface State { | ||
commands: Command[]; | ||
comments: Comment[]; | ||
comments: TSESTree.Comment[]; | ||
multiline: boolean; | ||
@@ -50,5 +73,11 @@ } | ||
type: 'Comment'; | ||
comment: Comment; | ||
comment: TSESTree.Comment; | ||
} | ||
export type Command = string | Chunk | Newline | Indent | Dedent | Sequence | CommentChunk; | ||
export interface PrintOptions { | ||
sourceMapSource?: string; | ||
sourceMapContent?: string; | ||
sourceMapEncodeMappings?: boolean; // default true | ||
} |
@@ -1,16 +0,19 @@ | ||
declare module 'esrap' { | ||
declare module 'dts-buddy' { | ||
import type { TSESTree } from '@typescript-eslint/types'; | ||
export interface PrintOptions { | ||
sourceMapSource?: string; | ||
sourceMapContent?: string; | ||
sourceMapEncodeMappings?: boolean; // default true | ||
} | ||
/** | ||
* @returns // TODO | ||
*/ | ||
export function print(node: import('estree').Node, opts?: PrintOptions): { | ||
export function print(node: TSESTree.Node, opts?: PrintOptions): { | ||
code: string; | ||
map: any; | ||
}; | ||
export type PrintOptions = { | ||
sourceMapSource?: string; | ||
sourceMapContent?: string; | ||
sourceMapEncodeMappings?: boolean; | ||
}; | ||
export {}; | ||
} | ||
//# sourceMappingURL=index.d.ts.map |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
48741
9
1520
62
8
+ Added@typescript-eslint/types@8.19.0(transitive)
- Removed@types/estree@^1.0.1
- Removed@types/estree@1.0.6(transitive)