@teambit/typescript 0.0.1101 → 0.0.1102

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +20 -0
  3. package/dist/index.js.map +1 -1
  4. package/dist/{preview-1688959062567.js → preview-1689061040556.js} +2 -2
  5. package/dist/sourceFileTransformers/class.d.ts +2 -0
  6. package/dist/sourceFileTransformers/class.js +38 -0
  7. package/dist/sourceFileTransformers/class.js.map +1 -0
  8. package/dist/sourceFileTransformers/empty-line-encoder.d.ts +14 -0
  9. package/dist/sourceFileTransformers/empty-line-encoder.js +68 -0
  10. package/dist/sourceFileTransformers/empty-line-encoder.js.map +1 -0
  11. package/dist/sourceFileTransformers/export.d.ts +2 -0
  12. package/dist/sourceFileTransformers/export.js +61 -0
  13. package/dist/sourceFileTransformers/export.js.map +1 -0
  14. package/dist/sourceFileTransformers/function.d.ts +2 -0
  15. package/dist/sourceFileTransformers/function.js +110 -0
  16. package/dist/sourceFileTransformers/function.js.map +1 -0
  17. package/dist/sourceFileTransformers/identifier.d.ts +2 -0
  18. package/dist/sourceFileTransformers/identifier.js +38 -0
  19. package/dist/sourceFileTransformers/identifier.js.map +1 -0
  20. package/dist/sourceFileTransformers/import.d.ts +2 -0
  21. package/dist/sourceFileTransformers/import.js +74 -0
  22. package/dist/sourceFileTransformers/import.js.map +1 -0
  23. package/dist/sourceFileTransformers/index.d.ts +11 -0
  24. package/dist/sourceFileTransformers/index.js +124 -0
  25. package/dist/sourceFileTransformers/index.js.map +1 -0
  26. package/dist/sourceFileTransformers/interface.d.ts +2 -0
  27. package/dist/sourceFileTransformers/interface.js +38 -0
  28. package/dist/sourceFileTransformers/interface.js.map +1 -0
  29. package/dist/sourceFileTransformers/transform.d.ts +12 -0
  30. package/dist/sourceFileTransformers/transform.js +113 -0
  31. package/dist/sourceFileTransformers/transform.js.map +1 -0
  32. package/dist/sourceFileTransformers/typeAlias.d.ts +2 -0
  33. package/dist/sourceFileTransformers/typeAlias.js +38 -0
  34. package/dist/sourceFileTransformers/typeAlias.js.map +1 -0
  35. package/dist/sourceFileTransformers/variable.d.ts +2 -0
  36. package/dist/sourceFileTransformers/variable.js +38 -0
  37. package/dist/sourceFileTransformers/variable.js.map +1 -0
  38. package/dist/transform-source-file.spec.d.ts +1 -0
  39. package/dist/transform-source-file.spec.js +109 -0
  40. package/dist/transform-source-file.spec.js.map +1 -0
  41. package/package-tar/teambit-typescript-0.0.1102.tgz +0 -0
  42. package/package.json +19 -19
  43. package/sourceFileTransformers/class.ts +29 -0
  44. package/sourceFileTransformers/empty-line-encoder.ts +56 -0
  45. package/sourceFileTransformers/export.ts +65 -0
  46. package/sourceFileTransformers/function.ts +164 -0
  47. package/sourceFileTransformers/identifier.ts +24 -0
  48. package/sourceFileTransformers/import.ts +103 -0
  49. package/sourceFileTransformers/index.ts +13 -0
  50. package/sourceFileTransformers/interface.ts +29 -0
  51. package/sourceFileTransformers/transform.ts +100 -0
  52. package/sourceFileTransformers/typeAlias.ts +28 -0
  53. package/sourceFileTransformers/variable.ts +28 -0
  54. package/package-tar/teambit-typescript-0.0.1101.tgz +0 -0
@@ -0,0 +1,29 @@
1
+ import ts from 'typescript';
2
+
3
+ export function classNamesTransformer(nameMapping: Record<string, string>): ts.TransformerFactory<ts.SourceFile> {
4
+ return (context) => {
5
+ const { factory } = context;
6
+ const visit: ts.Visitor = (node) => {
7
+ if (ts.isClassDeclaration(node) && node.name) {
8
+ const oldName = node.name.text;
9
+ const newName = Object.keys(nameMapping).find((key) => oldName.startsWith(key) || oldName.endsWith(key));
10
+ if (newName) {
11
+ const replacedName = oldName.startsWith(newName)
12
+ ? oldName.replace(newName, nameMapping[newName])
13
+ : oldName.replace(new RegExp(`${newName}$`), nameMapping[newName]);
14
+ return factory.updateClassDeclaration(
15
+ node,
16
+ node.decorators,
17
+ node.modifiers,
18
+ factory.createIdentifier(replacedName),
19
+ node.typeParameters,
20
+ node.heritageClauses,
21
+ node.members
22
+ );
23
+ }
24
+ }
25
+ return ts.visitEachChild(node, (child) => visit(child), context);
26
+ };
27
+ return (node) => ts.visitNode(node, visit);
28
+ };
29
+ }
@@ -0,0 +1,56 @@
1
+ import ts from 'typescript';
2
+
3
+ export class EmptyLineEncoder {
4
+ static readonly defaultEmptyLineMarker: string = '!--empty-line--!';
5
+ static readonly defaultNewLine: string = '\r\n';
6
+ constructor(emptyLineMarker?: string, newLine?: string) {
7
+ this.emptyLineMarker = emptyLineMarker || EmptyLineEncoder.defaultEmptyLineMarker;
8
+ this.newLine = newLine || EmptyLineEncoder.defaultNewLine;
9
+ }
10
+ emptyLineMarker: string;
11
+ newLine: string;
12
+
13
+ encode(text: string) {
14
+ return encodeEmptyLines(text, this.emptyLineMarker, this.newLine);
15
+ }
16
+ decode(text: string) {
17
+ return decodeEmptyLines(text, this.emptyLineMarker, this.newLine);
18
+ }
19
+ addLeadingEmptyLineMarker<T extends ts.Node>(node: T) {
20
+ return addLeadingEmptyLineMarker(node, this.emptyLineMarker);
21
+ }
22
+ }
23
+
24
+ export function encodeEmptyLines(text: string, emptyLineMarker?: string, newLine?: string) {
25
+ const marker = toComment(emptyLineMarker || EmptyLineEncoder.defaultEmptyLineMarker);
26
+
27
+ const lines = text.split(/\r?\n/);
28
+
29
+ const commentedLines = lines.map((line) => (line.trim() === '' ? marker : line));
30
+
31
+ return commentedLines.join(newLine || EmptyLineEncoder.defaultNewLine);
32
+ }
33
+
34
+ export function decodeEmptyLines(text: string, emptyLineMarker?: string, newLine?: string) {
35
+ const marker = toComment(emptyLineMarker || EmptyLineEncoder.defaultEmptyLineMarker);
36
+
37
+ const lines = text.split(/\r?\n/);
38
+
39
+ const uncommentedLines = lines.map((line) => (line === marker ? '' : line));
40
+
41
+ return uncommentedLines.join(newLine || EmptyLineEncoder.defaultNewLine);
42
+ }
43
+
44
+ export function addLeadingEmptyLineMarker<T extends ts.Node>(node: T, emptyLineMarker?: string) {
45
+ return ts.addSyntheticLeadingComment(
46
+ node,
47
+ ts.SyntaxKind.MultiLineCommentTrivia,
48
+ emptyLineMarker || EmptyLineEncoder.defaultEmptyLineMarker,
49
+ // hasTrailingNewLine
50
+ true
51
+ );
52
+ }
53
+
54
+ function toComment(marker: string) {
55
+ return `/*${marker}*/`;
56
+ }
@@ -0,0 +1,65 @@
1
+ import ts from 'typescript';
2
+ import { SourceFileTransformer } from '.';
3
+
4
+ export const exportTransformer: SourceFileTransformer = (mapping: Record<string, string>) => {
5
+ return (context) => {
6
+ const visit: ts.Visitor = (node) => {
7
+ if (ts.isExportDeclaration(node)) {
8
+ let moduleSpecifier = node.moduleSpecifier?.getText().slice(1, -1);
9
+ for (const [oldName, newName] of Object.entries(mapping)) {
10
+ if (moduleSpecifier && moduleSpecifier.includes(oldName)) {
11
+ moduleSpecifier = moduleSpecifier.replace(oldName, newName);
12
+ }
13
+ }
14
+
15
+ if (node.exportClause && ts.isNamedExports(node.exportClause)) {
16
+ const transformedElements = node.exportClause.elements.map((element) => {
17
+ let newElementName = element.name.text;
18
+
19
+ for (const [oldName, newName] of Object.entries(mapping)) {
20
+ if (newElementName.startsWith(oldName) || newElementName.endsWith(oldName)) {
21
+ newElementName = newElementName.replace(oldName, newName);
22
+ }
23
+ }
24
+
25
+ return ts.factory.updateExportSpecifier(
26
+ element,
27
+ false,
28
+ element.propertyName,
29
+ ts.factory.createIdentifier(newElementName)
30
+ );
31
+ });
32
+
33
+ const updatedExportClause = ts.factory.updateNamedExports(node.exportClause, transformedElements);
34
+
35
+ return ts.factory.updateExportDeclaration(
36
+ node,
37
+ node.decorators,
38
+ node.modifiers,
39
+ node.isTypeOnly,
40
+ updatedExportClause,
41
+ node.moduleSpecifier ? ts.factory.createStringLiteral(moduleSpecifier || '') : undefined,
42
+ undefined
43
+ );
44
+ }
45
+ }
46
+
47
+ if (ts.isExportAssignment(node)) {
48
+ let expression = node.expression;
49
+
50
+ if (ts.isIdentifier(expression)) {
51
+ for (const [oldName, newName] of Object.entries(mapping)) {
52
+ if (expression.getText().startsWith(oldName) || expression.getText().endsWith(oldName)) {
53
+ expression = ts.factory.createIdentifier(expression.getText().replace(oldName, newName));
54
+ }
55
+ }
56
+ }
57
+
58
+ return ts.factory.updateExportAssignment(node, node.decorators, node.modifiers, expression);
59
+ }
60
+
61
+ return ts.visitEachChild(node, visit, context);
62
+ };
63
+ return (node) => ts.visitNode(node, visit);
64
+ };
65
+ };
@@ -0,0 +1,164 @@
1
+ import ts from 'typescript';
2
+ import { SourceFileTransformer } from '.';
3
+
4
+ export const functionNamesTransformer: SourceFileTransformer = (mapping: Record<string, string>) => {
5
+ return (context) => {
6
+ const updateTypeReference: ts.Visitor = (node) => {
7
+ if (ts.isTypeReferenceNode(node)) {
8
+ const typeName = node.typeName.getText();
9
+ const newTypeName = mapping[typeName];
10
+ if (newTypeName) {
11
+ return ts.factory.updateTypeReferenceNode(node, ts.factory.createIdentifier(newTypeName), node.typeArguments);
12
+ }
13
+ }
14
+ return ts.visitEachChild(node, updateTypeReference, context);
15
+ };
16
+
17
+ const visit: ts.Visitor = (node) => {
18
+ if (ts.isFunctionDeclaration(node) || ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
19
+ const functionName = node.name?.getText() ?? '';
20
+ const newName = Object.entries(mapping).find(([key]) => functionName.includes(key))?.[1] ?? functionName;
21
+ const parameters = node.parameters.map((param) => {
22
+ const newParamType = param.type ? ts.visitNode(param.type, updateTypeReference) : param.type;
23
+ if (ts.isIdentifier(param.name)) {
24
+ const oldName = param.name.getText();
25
+ const newParamName = Object.keys(mapping).find((key) => oldName.includes(key));
26
+ if (newParamName) {
27
+ return ts.factory.updateParameterDeclaration(
28
+ param,
29
+ param.decorators,
30
+ param.modifiers,
31
+ param.dotDotDotToken,
32
+ ts.factory.createIdentifier(newParamName),
33
+ param.questionToken,
34
+ newParamType,
35
+ param.initializer
36
+ );
37
+ }
38
+ } else if (ts.isObjectBindingPattern(param.name)) {
39
+ const elements = param.name.elements.map((element) => {
40
+ const newElementName = mapping[element.name.getText()];
41
+ if (newElementName) {
42
+ return ts.factory.updateBindingElement(
43
+ element,
44
+ element.dotDotDotToken,
45
+ element.propertyName,
46
+ ts.factory.createIdentifier(newElementName),
47
+ element.initializer
48
+ );
49
+ }
50
+ return element;
51
+ });
52
+ const newParamName = ts.factory.createObjectBindingPattern(elements);
53
+ return ts.factory.updateParameterDeclaration(
54
+ param,
55
+ param.decorators,
56
+ param.modifiers,
57
+ param.dotDotDotToken,
58
+ newParamName,
59
+ param.questionToken,
60
+ newParamType,
61
+ param.initializer
62
+ );
63
+ }
64
+ return param;
65
+ });
66
+
67
+ if (ts.isFunctionDeclaration(node)) {
68
+ const updatedBody = node.body && ts.isBlock(node.body) ? updateReturnStatement(node.body) : node.body;
69
+ return ts.factory.updateFunctionDeclaration(
70
+ node,
71
+ node.decorators,
72
+ node.modifiers,
73
+ node.asteriskToken,
74
+ newName ? ts.factory.createIdentifier(newName) : node.name,
75
+ node.typeParameters,
76
+ parameters,
77
+ node.type,
78
+ updatedBody
79
+ );
80
+ }
81
+ if (ts.isArrowFunction(node)) {
82
+ const updatedBody = node.body && ts.isBlock(node.body) ? updateReturnStatement(node.body) : node.body;
83
+ return ts.factory.updateArrowFunction(
84
+ node,
85
+ node.modifiers,
86
+ node.typeParameters,
87
+ parameters,
88
+ node.type,
89
+ node.equalsGreaterThanToken,
90
+ updatedBody
91
+ );
92
+ }
93
+ if (ts.isFunctionExpression(node)) {
94
+ const updatedBody = node.body && ts.isBlock(node.body) ? updateReturnStatement(node.body) : node.body;
95
+ return ts.factory.updateFunctionExpression(
96
+ node,
97
+ node.modifiers,
98
+ node.asteriskToken,
99
+ newName ? ts.factory.createIdentifier(newName) : node.name,
100
+ node.typeParameters,
101
+ parameters,
102
+ node.type,
103
+ updatedBody
104
+ );
105
+ }
106
+ }
107
+ return ts.visitEachChild(node, visit, context);
108
+ };
109
+
110
+ function updateReturnStatement(body: ts.ConciseBody): ts.Block {
111
+ if (ts.isBlock(body)) {
112
+ const updatedStatements: ts.Statement[] = [];
113
+ for (const statement of body.statements) {
114
+ if (ts.isReturnStatement(statement) && statement.expression && ts.isJsxElement(statement.expression)) {
115
+ const jsxElement = statement.expression;
116
+ const openingElement = jsxElement.openingElement;
117
+ const tagName = openingElement.tagName.getText();
118
+ const newTagName = mapping[tagName];
119
+ if (newTagName) {
120
+ const updatedTagName = ts.factory.createIdentifier(newTagName);
121
+ const updatedOpeningElement = ts.factory.updateJsxOpeningElement(
122
+ openingElement,
123
+ updatedTagName,
124
+ openingElement.typeArguments,
125
+ openingElement.attributes
126
+ );
127
+ const updatedClosingElement = jsxElement.closingElement
128
+ ? ts.factory.updateJsxClosingElement(jsxElement.closingElement, updatedTagName)
129
+ : ts.factory.createJsxClosingElement(updatedTagName);
130
+ const updatedJsxElement = ts.factory.createJsxElement(
131
+ updatedOpeningElement,
132
+ jsxElement.children,
133
+ updatedClosingElement
134
+ );
135
+ const updatedStatement = ts.factory.createReturnStatement(updatedJsxElement);
136
+ updatedStatements.push(updatedStatement);
137
+ } else {
138
+ updatedStatements.push(statement);
139
+ }
140
+ } else {
141
+ updatedStatements.push(statement);
142
+ }
143
+ }
144
+ return ts.factory.updateBlock(body, updatedStatements);
145
+ }
146
+ if (
147
+ ts.isExpressionStatement(body) &&
148
+ ts.isReturnStatement(body.expression) &&
149
+ body.expression.expression &&
150
+ ts.isIdentifier(body.expression.expression)
151
+ ) {
152
+ const oldName = body.expression.expression.text;
153
+ const newName = mapping[oldName];
154
+ if (newName) {
155
+ const updatedExpression = ts.factory.createIdentifier(newName);
156
+ const updatedReturnStatement = ts.factory.createReturnStatement(updatedExpression);
157
+ return ts.factory.createBlock([updatedReturnStatement], true);
158
+ }
159
+ }
160
+ return ts.factory.createBlock([], true);
161
+ }
162
+ return (node) => ts.visitNode(node, visit);
163
+ };
164
+ };
@@ -0,0 +1,24 @@
1
+ import ts from 'typescript';
2
+ import { SourceFileTransformer } from '.';
3
+
4
+ export const identifierTransformer: SourceFileTransformer = (mapping: Record<string, string>) => {
5
+ return (context) => {
6
+ const visit: ts.Visitor = (node) => {
7
+ if (ts.isIdentifier(node)) {
8
+ const identifierName = node.text;
9
+ let newIdentifierName = mapping[identifierName] || identifierName;
10
+
11
+ for (const [oldName, newName] of Object.entries(mapping)) {
12
+ if (identifierName.startsWith(oldName) || identifierName.endsWith(oldName)) {
13
+ newIdentifierName = identifierName.replace(oldName, newName);
14
+ }
15
+ }
16
+
17
+ return ts.factory.createIdentifier(newIdentifierName);
18
+ }
19
+
20
+ return ts.visitEachChild(node, visit, context);
21
+ };
22
+ return (node) => ts.visitNode(node, visit);
23
+ };
24
+ };
@@ -0,0 +1,103 @@
1
+ import ts from 'typescript';
2
+ import { SourceFileTransformer } from '.';
3
+
4
+ export const importTransformer: SourceFileTransformer = (mapping: Record<string, string>) => {
5
+ return (context) => {
6
+ const visit: ts.Visitor = (node) => {
7
+ if (ts.isImportDeclaration(node)) {
8
+ let moduleSpecifier = node.moduleSpecifier.getText().slice(1, -1);
9
+ for (const [oldName, newName] of Object.entries(mapping)) {
10
+ if (moduleSpecifier.includes(oldName)) {
11
+ moduleSpecifier = moduleSpecifier.replace(oldName, newName);
12
+ }
13
+ }
14
+
15
+ if (node.importClause?.namedBindings && ts.isNamedImports(node.importClause.namedBindings)) {
16
+ const transformedBindings = node.importClause.namedBindings.elements.map((element) => {
17
+ let newElementName = element.name.text;
18
+
19
+ for (const [oldName, newName] of Object.entries(mapping)) {
20
+ if (newElementName.startsWith(oldName) || newElementName.endsWith(oldName)) {
21
+ newElementName = newElementName.replace(oldName, newName);
22
+ }
23
+ }
24
+
25
+ return ts.factory.updateImportSpecifier(
26
+ element,
27
+ false,
28
+ element.propertyName ? ts.factory.createIdentifier(newElementName) : undefined,
29
+ ts.factory.createIdentifier(newElementName)
30
+ );
31
+ });
32
+
33
+ const updatedImportClause = ts.factory.updateImportClause(
34
+ node.importClause,
35
+ node.importClause.isTypeOnly,
36
+ node.importClause.name,
37
+ ts.factory.createNamedImports(transformedBindings)
38
+ );
39
+
40
+ return ts.factory.updateImportDeclaration(
41
+ node,
42
+ node.decorators,
43
+ node.modifiers,
44
+ updatedImportClause,
45
+ ts.factory.createStringLiteral(moduleSpecifier),
46
+ undefined
47
+ );
48
+ }
49
+
50
+ return ts.factory.updateImportDeclaration(
51
+ node,
52
+ node.decorators,
53
+ node.modifiers,
54
+ node.importClause,
55
+ ts.factory.createStringLiteral(moduleSpecifier),
56
+ undefined
57
+ );
58
+ }
59
+ if (ts.isImportEqualsDeclaration(node)) {
60
+ let moduleSpecifier = node.moduleReference.getText().slice(1, -1);
61
+ for (const [oldName, newName] of Object.entries(mapping)) {
62
+ if (moduleSpecifier.includes(oldName)) {
63
+ moduleSpecifier = moduleSpecifier.replace(oldName, newName);
64
+ }
65
+ }
66
+
67
+ const updatedImportEqualsDeclaration = ts.factory.updateImportEqualsDeclaration(
68
+ node,
69
+ node.decorators,
70
+ node.modifiers,
71
+ node.isTypeOnly,
72
+ node.name,
73
+ ts.factory.createExternalModuleReference(ts.factory.createStringLiteral(moduleSpecifier))
74
+ );
75
+
76
+ return updatedImportEqualsDeclaration;
77
+ }
78
+
79
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === 'require') {
80
+ const [firstArg] = node.arguments;
81
+
82
+ if (ts.isStringLiteral(firstArg)) {
83
+ let moduleSpecifier = firstArg.text;
84
+
85
+ for (const [oldName, newName] of Object.entries(mapping)) {
86
+ if (moduleSpecifier.includes(oldName)) {
87
+ moduleSpecifier = moduleSpecifier.replace(oldName, newName);
88
+ }
89
+ }
90
+
91
+ const updatedArg = ts.factory.createStringLiteral(moduleSpecifier);
92
+ return ts.factory.updateCallExpression(node, node.expression, node.typeArguments, [
93
+ updatedArg,
94
+ ...node.arguments.slice(1),
95
+ ]);
96
+ }
97
+ }
98
+
99
+ return ts.visitEachChild(node, visit, context);
100
+ };
101
+ return (node) => ts.visitNode(node, visit);
102
+ };
103
+ };
@@ -0,0 +1,13 @@
1
+ import ts from 'typescript';
2
+
3
+ export type SourceFileTransformer = (mapping: Record<string, string>) => ts.TransformerFactory<ts.SourceFile>;
4
+
5
+ export { classNamesTransformer } from './class';
6
+ export { interfaceNamesTransformer } from './interface';
7
+ export { variableNamesTransformer } from './variable';
8
+ export { functionNamesTransformer } from './function';
9
+ export { typeAliasNamesTransformer } from './typeAlias';
10
+ export { importTransformer } from './import';
11
+ export { identifierTransformer } from './identifier';
12
+ export { exportTransformer } from './export';
13
+ export { transformSourceFile } from './transform';
@@ -0,0 +1,29 @@
1
+ import ts from 'typescript';
2
+
3
+ export function interfaceNamesTransformer(nameMapping: Record<string, string>): ts.TransformerFactory<ts.SourceFile> {
4
+ return (context) => {
5
+ const { factory } = context;
6
+ const visit: ts.Visitor = (node) => {
7
+ if (ts.isInterfaceDeclaration(node)) {
8
+ const oldName = node.name.text;
9
+ const newName = Object.keys(nameMapping).find((key) => oldName.startsWith(key) || oldName.endsWith(key));
10
+ if (newName) {
11
+ const replacedName = oldName.startsWith(newName)
12
+ ? oldName.replace(newName, nameMapping[newName])
13
+ : oldName.replace(new RegExp(`${newName}$`), nameMapping[newName]);
14
+ return factory.updateInterfaceDeclaration(
15
+ node,
16
+ node.decorators,
17
+ node.modifiers,
18
+ factory.createIdentifier(replacedName),
19
+ node.typeParameters,
20
+ node.heritageClauses,
21
+ node.members
22
+ );
23
+ }
24
+ }
25
+ return ts.visitEachChild(node, (child) => visit(child), context);
26
+ };
27
+ return (node) => ts.visitNode(node, visit);
28
+ };
29
+ }
@@ -0,0 +1,100 @@
1
+ import { Formatter } from '@teambit/formatter';
2
+ import ts from 'typescript';
3
+ import * as path from 'path';
4
+ import { EmptyLineEncoder } from './empty-line-encoder';
5
+ /**
6
+ * Transforms a TypeScript source file using the provided transformer.
7
+ *
8
+ * @param sourceFilePath Path to the TypeScript source file.
9
+ * @param sourceFileContent The content of the source file.
10
+ * @param transformers The transformers to be applied on the source file.
11
+ * @param formatter (Optional) An optional formatter to format the transformed code. If no formatter is provided, the function returns the transformed source file as a string without any formatting.
12
+ * @returns A promise that resolves to the transformed source file as a string.
13
+ */
14
+ export async function transformSourceFile(
15
+ sourceFilePath: string,
16
+ sourceFileContent: string,
17
+ transformers: ts.TransformerFactory<ts.SourceFile>[],
18
+ formatter?: Formatter,
19
+ updates?: Record<string, string>
20
+ ): Promise<string> {
21
+ const ext = path.extname(sourceFilePath);
22
+ const compatibleExts = ['.ts', '.tsx', '.js', '.jsx'];
23
+ if (!compatibleExts.includes(ext)) {
24
+ if (!updates) return sourceFileContent;
25
+ let transformed = sourceFileContent;
26
+ Object.entries(updates).forEach(([oldStr, newStr]) => {
27
+ const oldStringRegex = new RegExp(oldStr, 'g');
28
+ transformed = transformed.replace(oldStringRegex, newStr);
29
+ });
30
+ return transformed;
31
+ }
32
+
33
+ const encoder = new EmptyLineEncoder();
34
+ sourceFileContent = encoder.encode(sourceFileContent);
35
+
36
+ const sourceFile = ts.createSourceFile(
37
+ sourceFilePath,
38
+ sourceFileContent,
39
+ ts.ScriptTarget.Latest,
40
+ true,
41
+ ts.ScriptKind.TSX
42
+ );
43
+
44
+ const transformedResult: ts.TransformationResult<ts.SourceFile> = ts.transform<ts.SourceFile>(
45
+ sourceFile,
46
+ transformers
47
+ );
48
+ const transformedSourceFile: ts.SourceFile = transformedResult.transformed[0] as ts.SourceFile;
49
+
50
+ // const _identifierTransformer = identifierTransformer(updates || {});
51
+
52
+ // const transformedResultWithIdentifiers: ts.TransformationResult<ts.SourceFile> =
53
+ // ts.transform<ts.SourceFile>(transformedSourceFile, []);
54
+ // const transformedSourceFileWithIdentifiers: ts.SourceFile
55
+ // = transformedResultWithIdentifiers.transformed[0] as ts.SourceFile;
56
+
57
+ const printer: ts.Printer = ts.createPrinter({
58
+ removeComments: false,
59
+ });
60
+
61
+ let transformedSourceFileStr = printer.printFile(transformedSourceFile);
62
+ transformedSourceFileStr = encoder.decode(transformedSourceFileStr);
63
+ // Remove trailing empty line markers
64
+ const emptyLineComment = `\\s*\\/\\*${encoder.emptyLineMarker}\\*\\/\\s*$`;
65
+ const regex = new RegExp(emptyLineComment, 'g');
66
+ transformedSourceFileStr = transformedSourceFileStr.replace(regex, '');
67
+
68
+ const formattedSourceFileStr = await formatter?.formatSnippet(transformedSourceFileStr);
69
+ return formattedSourceFileStr || transformedSourceFileStr;
70
+ }
71
+
72
+ // function createMarkingTransformer<T extends ts.Node>(innerTransformer: ts.TransformerFactory<T>)
73
+ // : ts.TransformerFactory<T> {
74
+ // return context => {
75
+ // const innerTransform = innerTransformer(context);
76
+
77
+ // return node => {
78
+ // const result = innerTransform(node);
79
+
80
+ // // Add a custom property to the node to mark it as transformed
81
+ // // Note: this relies on TypeScript's internal behavior and may not be stable across versions
82
+ // (result as any).__transformed = true;
83
+
84
+ // return result;
85
+ // };
86
+ // };
87
+ // }
88
+
89
+ // const defaultTransformer: ts.TransformerFactory<ts.SourceFile> = () => {
90
+ // const visit: ts.Visitor = node => {
91
+ // // If the node has been marked as transformed by a specific transformer, don't transform it
92
+ // if ((node as any).__transformed) {
93
+ // return node;
94
+ // }
95
+
96
+ // // Your transformation logic goes here...
97
+ // };
98
+
99
+ // return node => ts.visitNode(node, visit);
100
+ // };
@@ -0,0 +1,28 @@
1
+ import ts from 'typescript';
2
+
3
+ export function typeAliasNamesTransformer(nameMapping: Record<string, string>): ts.TransformerFactory<ts.SourceFile> {
4
+ return (context) => {
5
+ const { factory } = context;
6
+ const visit: ts.Visitor = (node) => {
7
+ if (ts.isTypeAliasDeclaration(node)) {
8
+ const oldName = node.name.text;
9
+ const newName = Object.keys(nameMapping).find((key) => oldName.startsWith(key) || oldName.endsWith(key));
10
+ if (newName) {
11
+ const replacedName = oldName.startsWith(newName)
12
+ ? oldName.replace(newName, nameMapping[newName])
13
+ : oldName.replace(new RegExp(`${newName}$`), nameMapping[newName]);
14
+ return factory.updateTypeAliasDeclaration(
15
+ node,
16
+ node.decorators,
17
+ node.modifiers,
18
+ factory.createIdentifier(replacedName),
19
+ node.typeParameters,
20
+ node.type
21
+ );
22
+ }
23
+ }
24
+ return ts.visitEachChild(node, (child) => visit(child), context);
25
+ };
26
+ return (node) => ts.visitNode(node, visit);
27
+ };
28
+ }
@@ -0,0 +1,28 @@
1
+ import ts from 'typescript';
2
+
3
+ export function variableNamesTransformer(nameMapping: Record<string, string>): ts.TransformerFactory<ts.SourceFile> {
4
+ return (context) => {
5
+ const { factory } = context;
6
+ const visit: ts.Visitor = (node) => {
7
+ if (ts.isVariableDeclaration(node) && node.name.kind === ts.SyntaxKind.Identifier) {
8
+ const oldName = node.name.text;
9
+ const newName = Object.keys(nameMapping).find((key) => oldName.startsWith(key) || oldName.endsWith(key));
10
+ if (newName) {
11
+ const replacedName = oldName.startsWith(newName)
12
+ ? oldName.replace(newName, nameMapping[newName])
13
+ : oldName.replace(new RegExp(`${newName}$`), nameMapping[newName]);
14
+
15
+ return factory.updateVariableDeclaration(
16
+ node,
17
+ factory.createIdentifier(replacedName),
18
+ node.exclamationToken,
19
+ node.type,
20
+ node.initializer
21
+ );
22
+ }
23
+ }
24
+ return ts.visitEachChild(node, (child) => visit(child), context);
25
+ };
26
+ return (node) => ts.visitNode(node, visit);
27
+ };
28
+ }