Skip to content

Commit e9d67a9

Browse files
authored
chore: Parse identifiers for __ctHelpers usage rather than a naive string check (#1896)
1 parent c097738 commit e9d67a9

File tree

2 files changed

+58
-8
lines changed

2 files changed

+58
-8
lines changed

packages/ts-transformers/src/core/ct-helpers.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,8 @@ export class CTHelpers {
7979
export function transformCtDirective(
8080
source: string,
8181
): string {
82-
// Throw when this symbol name is already in use
83-
// for some reason.
84-
if (source.indexOf(CT_HELPERS_IDENTIFIER) !== -1) {
85-
throw new Error(
86-
`Source cannot contain reserved '${CT_HELPERS_IDENTIFIER}' symbol.`,
87-
);
88-
}
82+
checkCTHelperVar(source);
83+
8984
const lines = source.split("\n");
9085
if (!lines[0] || !isCTSEnabled(lines[0])) {
9186
return source;
@@ -101,6 +96,27 @@ function isCTSEnabled(line: string) {
10196
return /^\/\/\/\s*<cts-enable\s*\/>/m.test(line);
10297
}
10398

99+
// Throws if `__ctHelpers` was found as an Identifier
100+
// in the source code.
101+
function checkCTHelperVar(source: string) {
102+
const sourceFile = ts.createSourceFile(
103+
"source.tsx",
104+
source,
105+
ts.ScriptTarget.ES2023,
106+
);
107+
const visitor = (node: ts.Node): ts.Node => {
108+
if (ts.isIdentifier(node)) {
109+
if (node.text === CT_HELPERS_IDENTIFIER) {
110+
throw new Error(
111+
`Source cannot contain reserved '${CT_HELPERS_IDENTIFIER}' symbol.`,
112+
);
113+
}
114+
}
115+
return ts.visitEachChild(node, visitor, undefined);
116+
};
117+
ts.visitNode(sourceFile, visitor);
118+
}
119+
104120
function getCTHelpersIdentifier(
105121
statement: ts.Statement,
106122
): ts.Identifier | undefined {

packages/ts-transformers/test/transform.test.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, it } from "@std/testing/bdd";
2-
import { assert } from "@std/assert";
2+
import { assert, assertRejects } from "@std/assert";
33
import { transformFiles } from "./utils.ts";
44

55
const fixture = `
@@ -34,3 +34,37 @@ describe("CommonToolsTransformerPipeline", () => {
3434
);
3535
});
3636
});
37+
38+
describe("CTHelpers handling", () => {
39+
it("Throws if __ctHelpers variable is used in source", async () => {
40+
const statements = [
41+
"function __ctHelpers() {}",
42+
"function foo(): number { var __ctHelpers = 5; return __ctHelpers; }",
43+
"var __ctHelpers: number = 5;",
44+
"declare global { var __ctHelpers: any; }\nglobalThis.__ctHelpers = 5;",
45+
];
46+
47+
for (const statement of statements) {
48+
await assertRejects(() =>
49+
transformFiles({
50+
"/main.ts": fixture + `\n${statement}`,
51+
})
52+
);
53+
}
54+
});
55+
56+
it("Allows '__ctHelpers' in comments and in other forms", async () => {
57+
const statements = [
58+
"var x = 5; // __ctHelpers",
59+
"// __ctHelpers",
60+
"/* __ctHelpers */",
61+
"var __ctHelpers123: number = 5;",
62+
"declare global {\nvar __ctHelpers1: any;\n}\nglobalThis.__ctHelpers1 = 5;",
63+
];
64+
for (const statement of statements) {
65+
await transformFiles({
66+
"/main.ts": fixture + `\n${statement}`,
67+
});
68+
}
69+
});
70+
});

0 commit comments

Comments
 (0)