UNPKG

@vardario/astring-ts-generator

Version:

Custom TypeScript code generator implementation for astring, extending its capabilities to support TypeScript-specific syntax and features

973 lines (833 loc) 24.9 kB
import { GENERATOR, NEEDS_PARENTHESES } from 'astring'; function formatSequence(state, nodes) { const { generator } = state; state.write('('); if (nodes != null && nodes.length > 0) { generator[nodes[0].type](nodes[0], state); const { length } = nodes; for (let i = 1; i < length; i++) { const param = nodes[i]; state.write(', '); generator[param.type](param, state); } } state.write(')'); } function hasCallExpression(node) { let currentNode = node; while (currentNode != null) { const { type } = currentNode; if (type[0] === 'C' && type[1] === 'a') { return true; } else if (type[0] === 'M' && type[1] === 'e' && type[2] === 'm') { currentNode = currentNode.object; } else { return false; } } } const typescriptGenerator = { ...GENERATOR, AccessorProperty(node, state) { if (node.readonly) { state.write('readonly '); } if (node.static) { state.write('static '); } state.write('accessor '); if (node.key.type === 'Identifier') { this[node.key.type](node.key, state); } else { state.write('['); this[node.key.type](node.key, state); state.write(']'); } if (node.typeAnnotation) { state.write(': '); this[node.typeAnnotation.type](node.typeAnnotation, state); } state.write(';'); }, Identifier(node, state, definite) { if (node.decorators) { node.decorators.forEach(decorator => { typescriptGenerator[decorator.type](decorator, state); state.write(' '); }); } state.write(node.name, node); if (definite) { state.write('!'); } if (node.optional) { state.write('?'); } if (node.typeAnnotation) { state.write(': '); typescriptGenerator[node.typeAnnotation.type](node.typeAnnotation, state); } }, VariableDeclarator(node, state) { this[node.id.type](node.id, state, node.definite); if (node.init != null) { state.write(' = '); this[node.init.type](node.init, state); } }, FunctionDeclaration: function (node, state) { state.write( (node.async ? 'async ' : '') + (node.generator ? 'function* ' : 'function ') + (node.id ? node.id.name : ''), node ); if (node.typeParameters) { typescriptGenerator[node.typeParameters.type](node.typeParameters, state); } formatSequence(state, node.params); if (node.returnType) { state.write(': '); typescriptGenerator[node.returnType.type](node.returnType, state); } state.write(' '); typescriptGenerator[node.body.type](node.body, state); }, FunctionExpression: function (node, state) { typescriptGenerator.FunctionDeclaration(node, state); }, ArrowFunctionExpression(node, state) { if (node.typeParameters) { typescriptGenerator[node.typeParameters.type](node.typeParameters, state); } state.write(node.async ? 'async ' : '', node); const { params } = node; if (params != null) { formatSequence(state, node.params); } if (node.returnType) { state.write(': '); typescriptGenerator[node.returnType.type](node.returnType, state); } state.write(' => '); if (node.body.type[0] === 'O') { state.write('('); this.ObjectExpression(node.body, state); state.write(')'); } else { typescriptGenerator[node.body.type](node.body, state); } }, PropertyDefinition(node, state) { if (node.decorators) { node.decorators.forEach(decorator => { typescriptGenerator[decorator.type](decorator, state); state.write('\n'); }); } if (node.declare) { state.write('declare '); } if (node.static) { state.write('static '); } if (node.accessor) { state.write('accessor '); } if (node.accessibility) { state.write(node.accessibility); state.write(' '); } if (node.readonly) { state.write('readonly '); } if (node.computed) { state.write('['); } typescriptGenerator[node.key.type](node.key, state); if (node.definite) { state.write('!'); } if (node.optional) { state.write('?'); } if (node.typeAnnotation) { state.write(': '); typescriptGenerator[node.typeAnnotation.type](node.typeAnnotation, state); } if (node.computed) { state.write(']'); } if (node.value == null) { if (node.key.type[0] !== 'F') { state.write(';'); } return; } state.write(' = '); typescriptGenerator[node.value.type](node.value, state); state.write(';'); }, ObjectPattern(node, state) { state.write('{'); if (node.properties.length > 0) { const { properties } = node, { length } = properties; for (let i = 0; ; ) { typescriptGenerator[properties[i].type](properties[i], state); if (++i < length) { state.write(', '); } else { break; } } } state.write('}'); if (node.typeAnnotation) { state.write(': '); typescriptGenerator[node.typeAnnotation.type](node.typeAnnotation, state); } }, ImportExpression(node, state) { state.write('import('); typescriptGenerator[node.source.type](node.source, state); if (node.arguments) { state.write(', '); const [argument] = node.arguments; typescriptGenerator[argument.type](argument, state); } if (node.options) { state.write(', '); this[node.options.type](node.options, state); } state.write(')'); }, ImportDeclaration(node, state) { state.write('import '); if (node.importKind === 'type') { state.write('type '); } const { specifiers, attributes } = node; const { length } = specifiers; let i = 0; if (length > 0) { for (; i < length; ) { if (i > 0) { state.write(', '); } const specifier = specifiers[i]; const type = specifier.type[6]; if (type === 'D') { state.write(specifier.local.name, specifier); i++; } else if (type === 'N') { state.write('* as ' + specifier.local.name, specifier); i++; } else { break; } } if (i < length) { state.write('{'); for (;;) { const specifier = specifiers[i]; const { name } = specifier.imported; if (specifier.importKind === 'type') { state.write('type '); } state.write(name, specifier); if (name !== specifier.local.name) { state.write(' as ' + specifier.local.name); } if (++i < length) { state.write(', '); } else { break; } } state.write('}'); } state.write(' from '); } this.Literal(node.source, state); if (attributes && attributes.length > 0) { state.write(' with { '); for (let i = 0; i < attributes.length; i++) { this.ImportAttribute(attributes[i], state); if (i < attributes.length - 1) state.write(', '); } state.write(' }'); } state.write(';'); }, ExportNamedDeclaration(node, state) { state.write('export '); if (node.declaration) { this[node.declaration.type](node.declaration, state); } else { state.write('{'); const { specifiers } = node, { length } = specifiers; if (length > 0) { for (let i = 0; ; ) { const specifier = specifiers[i]; const { name } = specifier.local; if (specifier.exportKind !== 'value') { state.write(`${specifier.exportKind} `); } state.write(name, specifier); if (name !== specifier.exported.name) { state.write(' as ' + specifier.exported.name); } if (++i < length) { state.write(', '); } else { break; } } } state.write('}'); if (node.source) { state.write(' from '); this.Literal(node.source, state); } if (node.attributes && node.attributes.length > 0) { state.write(' with { '); for (let i = 0; i < node.attributes.length; i++) { this.ImportAttribute(node.attributes[i], state); if (i < node.attributes.length - 1) state.write(', '); } state.write(' }'); } state.write(';'); } }, MethodDefinition(node, state) { if (node.decorators) { node.decorators.forEach(decorator => { typescriptGenerator[decorator.type](decorator, state); state.write('\n'); }); } if (node.static) { state.write('static '); } if (node.abstract) { state.write('abstract '); } if (node.accessibility) { state.write(`${node.accessibility} `); } const kind = node.kind[0]; if (kind === 'g' || kind === 's') { state.write(node.kind + ' '); } if (node.value.async) { state.write('async '); } if (node.value.generator) { state.write('*'); } if (node.computed) { state.write('['); this[node.key.type](node.key, state); state.write(']'); } else { this[node.key.type](node.key, state); } if (node.typeParameters) { typescriptGenerator[node.typeParameters.type](node.typeParameters, state); } if (node?.value?.typeParameters) { typescriptGenerator[node.value.typeParameters.type](node.value.typeParameters, state); } formatSequence(state, node.value.params); if (node.value.returnType) { state.write(': '); typescriptGenerator[node.value.returnType.type](node.value.returnType, state); } if (node.value.body) { state.write(' '); this[node.value.body.type](node.value.body, state); } }, NewExpression(node, state) { state.write('new '); const precedence = state.expressionsPrecedence[node.callee.type]; if ( precedence === NEEDS_PARENTHESES || precedence < state.expressionsPrecedence.CallExpression || hasCallExpression(node.callee) ) { state.write('('); this[node.callee.type](node.callee, state); state.write(')'); } else { this[node.callee.type](node.callee, state); } if (node.typeParameters) { typescriptGenerator[node.typeParameters.type](node.typeParameters, state); } if (node.typeArguments) { typescriptGenerator[node.typeArguments.type](node.typeArguments, state); } formatSequence(state, node['arguments']); }, ClassDeclaration(node, state) { if (node.decorators) { node.decorators.forEach(decorator => { typescriptGenerator[decorator.type](decorator, state); state.write('\n'); }); } if (node.abstract) { state.write('abstract '); } state.write('class ' + (node.id ? `${node.id.name} ` : ''), node); if (node.superClass) { state.write('extends '); const { superClass } = node; const { type } = superClass; const precedence = state.expressionsPrecedence[type]; if ( (type[0] !== 'C' || type[1] !== 'l' || type[5] !== 'E') && (precedence === NEEDS_PARENTHESES || precedence < state.expressionsPrecedence.ClassExpression) ) { state.write('('); this[node.superClass.type](superClass, state); state.write(')'); } else { this[superClass.type](superClass, state); } state.write(' '); } typescriptGenerator.ClassBody(node.body, state); }, RestElement(node, state) { state.write('...'); this[node.argument.type](node.argument, state); if (node.typeAnnotation) { state.write(': '); typescriptGenerator[node.typeAnnotation.type](node.typeAnnotation, state); } }, TSTypeAnnotation(node, state) { typescriptGenerator[node.typeAnnotation.type](node.typeAnnotation, state); }, TSLiteralType(node, state) { typescriptGenerator[node.literal.type](node.literal, state); }, TSNumberKeyword(node, state) { state.write('number'); }, TSStringKeyword(node, state) { state.write('string'); }, TSBooleanKeyword(node, state) { state.write('boolean'); }, TSAnyKeyword(node, state) { state.write('any'); }, TSNeverKeyword(node, state) { state.write('never'); }, TSNullKeyword(node, state) { state.write('null'); }, TSObjectKeyword(node, state) { state.write('object'); }, TSSymbolKeyword(node, state) { state.write('symbol'); }, TSUndefinedKeyword(node, state) { state.write('undefined'); }, TSUnknownKeyword(node, state) { state.write('unknown'); }, TSVoidKeyword(node, state) { state.write('void'); }, TSAnyKeyword(node, state) { state.write('any'); }, TSBigIntKeyword(node, state) { state.write('bigint'); }, TSBooleanKeyword(node, state) { state.write('boolean'); }, TSTypeParameterInstantiation(node, state) { state.write('<'); node.params.forEach((param, index) => { if (index > 0) state.write(', '); this[param.type](param, state); }); state.write('>'); }, TSTypeReference(node, state) { typescriptGenerator[node.typeName.type](node.typeName, state); if (node.typeArguments) { state.write('<'); for (let i = 0; i < node.typeArguments.params.length; i++) { if (i > 0) state.write(', '); typescriptGenerator[node.typeArguments.params[i].type](node.typeArguments.params[i], state); } state.write('>'); } //Acorn Typescript if (node.typeParameters) { state.write('<'); for (let i = 0; i < node.typeParameters.params.length; i++) { if (i > 0) state.write(', '); typescriptGenerator[node.typeParameters.params[i].type](node.typeParameters.params[i], state); } state.write('>'); } }, TSUnionType(node, state) { node.types.forEach((type, index) => { if (index > 0) state.write(' | '); if (type.type === 'TSFunctionType') { state.write('('); } typescriptGenerator[type.type](type, state); if (type.type === 'TSFunctionType') { state.write(')'); } }); }, TSIntersectionType(node, state) { node.types.forEach((type, index) => { if (index > 0) state.write(' & '); typescriptGenerator[type.type](type, state); }); }, TSFunctionType(node, state) { state.write('('); if (node.parameters) { for (let i = 0; i < node.parameters.length; i++) { if (i > 0) state.write(', '); typescriptGenerator[node.parameters[i].type](node.parameters[i], state); } } if (node.params) { for (let i = 0; i < node.params.length; i++) { if (i > 0) state.write(', '); typescriptGenerator[node.params[i].type](node.params[i], state); } } state.write(') => '); if (node.typeAnnotation) { typescriptGenerator[node.typeAnnotation.type](node.typeAnnotation, state); } if (node.returnType) { typescriptGenerator[node.returnType.type](node.returnType, state); } }, TSTypeAliasDeclaration(node, state) { state.write(`type ${node.id.name} = `); typescriptGenerator[node.typeAnnotation.type](node.typeAnnotation, state); state.write(';'); }, TSInterfaceDeclaration(node, state) { state.write(`interface ${node.id.name} `); if (node.extends && node.extends.length) { state.write('extends '); node.extends.forEach((ext, index) => { if (index > 0) state.write(', '); typescriptGenerator[ext.type](ext, state); }); } typescriptGenerator[node.body.type](node.body, state); }, TSInterfaceBody(node, state) { state.write('{'); node.body.forEach(member => { typescriptGenerator[member.type](member, state); state.write(';'); }); state.write('}'); }, TSPropertySignature(node, state) { typescriptGenerator[node.key.type](node.key, state); if (node.optional) state.write('?'); if (node.typeAnnotation) state.write(': '); typescriptGenerator[node.typeAnnotation.type](node.typeAnnotation, state); }, TSConditionalType(node, state) { typescriptGenerator[node.checkType.type](node.checkType, state); state.write(' extends '); typescriptGenerator[node.extendsType.type](node.extendsType, state); state.write(' ? '); typescriptGenerator[node.trueType.type](node.trueType, state); state.write(' : '); typescriptGenerator[node.falseType.type](node.falseType, state); }, TSIndexedAccessType(node, state) { typescriptGenerator[node.objectType.type](node.objectType, state); state.write('['); typescriptGenerator[node.indexType.type](node.indexType, state); state.write(']'); }, TSMappedType(node, state) { state.write('{ '); state.write('['); this[node.typeParameter.type](node.typeParameter, state, true); state.write(' in '); if (node.typeParameter.constraint) { this[node.typeParameter.constraint.type](node.typeParameter.constraint, state); } state.write(']'); if (node.optional) { state.write('?'); } state.write(': '); this[node.typeAnnotation.type](node.typeAnnotation, state); state.write(' }'); }, TSEnumDeclaration(node, state) { state.write(`enum ${node.id.name} {`); node.members.forEach((member, index) => { if (index > 0) state.write(', '); typescriptGenerator[member.type](member, state); }); state.write('}'); }, TSEnumMember(node, state) { typescriptGenerator[node.id.type](node.id, state); if (node.initializer) { state.write(' = '); typescriptGenerator[node.initializer.type](node.initializer, state); } }, Decorator(node, state) { state.write('@'); typescriptGenerator[node.expression.type](node.expression, state); }, TSTupleType(node, state) { state.write('['); node.elementTypes.forEach((type, index) => { if (index > 0) state.write(', '); typescriptGenerator[type.type](type, state); }); state.write(']'); }, TSTypeAssertion(node, state) { state.write('<'); typescriptGenerator[node.typeAnnotation.type](node.typeAnnotation, state); state.write('>'); typescriptGenerator[node.expression.type](node.expression, state); }, TSTypeLiteral(node, state) { state.write('{'); node.members.forEach((member, index) => { if (index > 0) state.write(';'); typescriptGenerator[member.type](member, state); }); state.write('}'); }, TSPropertySignature(node, state) { typescriptGenerator[node.key.type](node.key, state); if (node.optional) state.write('?'); if (node.typeAnnotation) { state.write(': '); typescriptGenerator[node.typeAnnotation.type](node.typeAnnotation, state); } }, TSArrayType(node, state) { if (node.elementType.type === 'TSUnionType' || node.elementType.type === 'TSIntersectionType') { state.write('('); } typescriptGenerator[node.elementType.type](node.elementType, state); if (node.elementType.type === 'TSUnionType' || node.elementType.type === 'TSIntersectionType') { state.write(')'); } state.write('[]'); }, TSParameterProperty(node, state) { if (node.accessibility) { state.write(`${node.accessibility} `); } if (node.readonly) { state.write('readonly '); } this[node.parameter.type](node.parameter, state); }, TSPropertySignature(node, state) { this[node.key.type](node.key, state); if (node.optional) state.write('?'); if (node.typeAnnotation) { state.write(': '); this[node.typeAnnotation.type](node.typeAnnotation, state); } }, TSTypeQuery(node, state) { state.write('typeof '); this[node.exprName.type](node.exprName, state); }, TSQualifiedName(node, state) { this[node.left.type](node.left, state); state.write('.'); this[node.right.type](node.right, state); }, TSTypeOperator(node, state) { state.write(`${node.operator} `); this[node.typeAnnotation.type](node.typeAnnotation, state); }, TSTypeParameterDeclaration(node, state) { state.write('<'); node.params.forEach((param, index) => { if (index > 0) state.write(', '); this[param.type](param, state); }); state.write('>'); }, TSTypeParameter(node, state, noConstrain) { if (node.name?.type === 'Identifier') { this[node.name.type](node.name, state); } else { // Acorn Typescript state.write(node.name); } if (node.constraint && !noConstrain) { state.write(' extends '); this[node.constraint.type](node.constraint, state); } }, TSParenthesizedType(node, state) { state.write('('); this[node.typeAnnotation.type](node.typeAnnotation, state); state.write(')'); }, TSNonNullExpression(node, state) { this[node.expression.type](node.expression, state); state.write('!'); }, Decorator(node, state) { state.write('@'); this[node.expression.type](node.expression, state); }, TSConstructSignatureDeclaration(node, state) { state.write('new '); formatSequence(state, node.parameters ?? node.params); if (node.typeAnnotation) { state.write(': '); this[node.typeAnnotation.type](node.typeAnnotation, state); } if (node.returnType) { state.write(': '); this[node.returnType.type](node.returnType, state); } }, TSDeclareFunction(node, state) { if (node.declare) { state.write('declare '); } state.write('function '); if (node.id) { this[node.id.type](node.id, state); } formatSequence(state, node.params); if (node.returnType) { state.write(': '); this[node.returnType.type](node.returnType, state); } }, TSExpressionWithTypeArguments(node, state) { this[node.expression.type](node.expression, state); if (node.typeParameters) { this[node.typeParameters.type](node.typeParameters, state); } }, TSModuleDeclaration(node, state) { if (node.declare) { state.write('declare '); } if (node.global) { state.write('global '); } if (node.id.type === 'Literal') { state.write(`module "${node.id.value}" `); } else { state.write(`namespace ${node.id.name} `); } if (node.body) { this[node.body.type](node.body, state); } }, TSModuleBlock(node, state) { state.write('{'); node.body.forEach(statement => { this[statement.type](statement, state); state.write('\n'); }); state.write('}'); }, TSAsExpression(node, state) { state.write('('); this[node.expression.type](node.expression, state); state.write(' as '); this[node.typeAnnotation.type](node.typeAnnotation, state); state.write(')'); }, TSSatisfiesExpression(node, state) { this[node.expression.type](node.expression, state); state.write(' satisfies '); this[node.typeAnnotation.type](node.typeAnnotation, state); }, TSAbstractMethodDefinition(node, state) { state.write('abstract '); if (node.key.type === 'Identifier') { this[node.key.type](node.key, state); } else { state.write('['); this[node.key.type](node.key, state); state.write(']'); } if (node.typeParameters) { this[node.typeParameters.type](node.typeParameters, state); } state.write('('); node.value.params.forEach((param, index) => { if (index > 0) state.write(', '); this[param.type](param, state); }); state.write(')'); if (node.value.returnType) { state.write(': '); this[node.value.returnType.type](node.value.returnType, state); } }, TSInterfaceHeritage(node, state) { this[node.expression.type](node.expression, state); if (node.typeParameters) { this[node.typeParameters.type](node.typeParameters, state); } }, TSImportType(node, state) { state.write('import('); this[node.argument.type](node.argument, state); state.write(')'); if (node.qualifier) { state.write('.'); this[node.qualifier.type](node.qualifier, state); } }, TSIndexSignature(node, state) { if (node.readonly) { state.write('readonly '); } state.write('['); node.parameters.forEach((param, index) => { if (index > 0) state.write(', '); this[param.type](param, state); }); state.write(']'); if (node.typeAnnotation) { state.write(': '); this[node.typeAnnotation.type](node.typeAnnotation, state); } } }; export default typescriptGenerator;