Skip to content

Commit

Permalink
feat: allow TypeScript parsing to be safe related to JSX syntax limit…
Browse files Browse the repository at this point in the history
…ations
  • Loading branch information
antoine-coulon committed Oct 25, 2022
1 parent 96313c5 commit 80fc92f
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 18 deletions.
61 changes: 43 additions & 18 deletions packages/skott/src/modules/walkers/ecmascript/typescript/walker.ts
Expand Up @@ -4,30 +4,55 @@ import { ModuleWalker, ModuleWalkerResult } from "../../common.js";
import { isCommonJSModuleImport } from "../javascript/cjs.js";
import { isEcmaScriptModuleDeclaration } from "../module-declaration.js";

/**
* TypeScript implements the ECMAScript standard module system. This walker
* is nearly the same as the JavaScript walker, minus the CJS support which
* is not needed here.
*/
async function tryOrElse(
tryFn: () => void,
orElseFn: () => void
): Promise<void> {
try {
await tryFn();

return;
} catch {}

try {
orElseFn();
} catch {}
}

export class TypeScriptModuleWalker implements ModuleWalker {
public async walk(fileContent: string): Promise<ModuleWalkerResult> {
const { parse } = await import("@typescript-eslint/typescript-estree");
const moduleDeclarations = new Set<string>();
const node = parse(fileContent, { jsx: true, loc: false, comment: false });
const isRootNode = node.type === "Program";
let jsxEnabled = true;

walk(isRootNode ? node.body : node, {
enter(node) {
if (isCommonJSModuleImport(node)) {
moduleDeclarations.add(node.arguments[0].value);
}
if (isEcmaScriptModuleDeclaration(node)) {
moduleDeclarations.add(node.source.value);
}
if (node.type === "ImportExpression") {
moduleDeclarations.add(node.source.value);
function processWalk(): void {
const node = parse(fileContent, {
jsx: jsxEnabled,
loc: false,
comment: false
});
const isRootNode = node.type === "Program";

walk(isRootNode ? node.body : node, {
enter(node) {
if (isCommonJSModuleImport(node)) {
moduleDeclarations.add(node.arguments[0].value);
}
if (isEcmaScriptModuleDeclaration(node)) {
moduleDeclarations.add(node.source.value);
}
if (node.type === "ImportExpression") {
moduleDeclarations.add(node.source.value);
}
}
}
});
}

await tryOrElse(processWalk, () => {
// Retry without JSX enabled
jsxEnabled = false;

return processWalk();
});

return { moduleDeclarations };
Expand Down
20 changes: 20 additions & 0 deletions packages/skott/test/ecmascript/jsx-and-tsx.ts
Expand Up @@ -165,3 +165,23 @@ export function makeTestSuiteForJsxOrTsx(rawLanguage: "ts" | "js"): void {
});
});
}

describe("When some TypeScript code is not TSX compliant", () => {
it("should be able to parse the script disabling the jsx feature", async () => {
const fileThatCanNotBeParsedAsTSX = `
export const unparsableTSXFunction = async <T>(
x: T
) => {}
`;

mountFakeFileSystem({
"index.ts": fileThatCanNotBeParsedAsTSX
});

const { files } = await buildSkottProjectUsingInMemoryFileExplorer({
entrypoint: "index.ts"
});

expect(files).to.deep.equal(["index.ts"]);
});
});

0 comments on commit 80fc92f

Please sign in to comment.