mirror of
https://github.com/earendil-works/pi.git
synced 2026-06-18 15:54:04 +08:00
75 lines
2.3 KiB
JavaScript
75 lines
2.3 KiB
JavaScript
import { readdirSync, readFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import ts from "typescript";
|
|
|
|
const ignoredDirectories = new Set([".git", "coverage", "dist", "node_modules"]);
|
|
const files = [];
|
|
|
|
function collectTypescriptFiles(directory) {
|
|
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
if (entry.isDirectory()) {
|
|
if (!ignoredDirectories.has(entry.name)) {
|
|
collectTypescriptFiles(join(directory, entry.name));
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (entry.isFile() && entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts")) {
|
|
files.push(join(directory, entry.name));
|
|
}
|
|
}
|
|
}
|
|
|
|
function isRelativeJavaScriptSpecifier(specifier) {
|
|
return /^\.\.?\//.test(specifier) && /\.js(?:[?#].*)?$/.test(specifier);
|
|
}
|
|
|
|
function getImportTypeSpecifier(node) {
|
|
if (!ts.isLiteralTypeNode(node.argument)) return undefined;
|
|
if (!ts.isStringLiteralLike(node.argument.literal)) return undefined;
|
|
return node.argument.literal;
|
|
}
|
|
|
|
const failures = [];
|
|
|
|
collectTypescriptFiles(".");
|
|
|
|
for (const file of files.sort()) {
|
|
const sourceText = readFileSync(file, "utf8");
|
|
const sourceFile = ts.createSourceFile(file, sourceText, ts.ScriptTarget.Latest, true);
|
|
|
|
function checkSpecifier(node) {
|
|
if (!isRelativeJavaScriptSpecifier(node.text)) return;
|
|
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
failures.push(`${file}:${line + 1}:${character + 1}: ${node.text}`);
|
|
}
|
|
|
|
function visit(node) {
|
|
if (ts.isImportDeclaration(node) && ts.isStringLiteralLike(node.moduleSpecifier)) {
|
|
checkSpecifier(node.moduleSpecifier);
|
|
} else if (ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteralLike(node.moduleSpecifier)) {
|
|
checkSpecifier(node.moduleSpecifier);
|
|
} else if (
|
|
ts.isCallExpression(node) &&
|
|
node.expression.kind === ts.SyntaxKind.ImportKeyword &&
|
|
node.arguments[0] &&
|
|
ts.isStringLiteralLike(node.arguments[0])
|
|
) {
|
|
checkSpecifier(node.arguments[0]);
|
|
} else if (ts.isImportTypeNode(node)) {
|
|
const specifier = getImportTypeSpecifier(node);
|
|
if (specifier) checkSpecifier(specifier);
|
|
}
|
|
|
|
ts.forEachChild(node, visit);
|
|
}
|
|
|
|
visit(sourceFile);
|
|
}
|
|
|
|
if (failures.length > 0) {
|
|
console.error("Relative .js imports are not allowed in non-declaration .ts files:");
|
|
for (const failure of failures) console.error(` ${failure}`);
|
|
process.exit(1);
|
|
}
|