chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
1 parent
719370c8f7
commit
6081e3e325
1743 files changed
+205459
-131704
No files matched your search
+62
-31
@@ -1,6 +1,16 @@
|
||||
import { readdirSync, readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import ts from "typescript";
|
||||
import { readdirSync } from "node:fs";
|
||||
import { join, relative, resolve } from "node:path";
|
||||
import { SyntaxKind } from "typescript/unstable/ast";
|
||||
import {
|
||||
isCallExpression,
|
||||
isExportDeclaration,
|
||||
isImportDeclaration,
|
||||
isImportTypeNode,
|
||||
isLiteralTypeNode,
|
||||
isNoSubstitutionTemplateLiteral,
|
||||
isStringLiteral,
|
||||
} from "typescript/unstable/ast/is";
|
||||
import { API } from "typescript/unstable/sync";
|
||||
|
||||
const ignoredDirectories = new Set([".git", "coverage", "dist", "node_modules"]);
|
||||
const files = [];
|
||||
@@ -20,13 +30,17 @@ function collectTypescriptFiles(directory) {
|
||||
}
|
||||
}
|
||||
|
||||
function isStringLiteralLike(node) {
|
||||
return node !== undefined && (isStringLiteral(node) || isNoSubstitutionTemplateLiteral(node));
|
||||
}
|
||||
|
||||
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;
|
||||
if (!isLiteralTypeNode(node.argument)) return undefined;
|
||||
if (!isStringLiteralLike(node.argument.literal)) return undefined;
|
||||
return node.argument.literal;
|
||||
}
|
||||
|
||||
@@ -34,37 +48,54 @@ const failures = [];
|
||||
|
||||
collectTypescriptFiles(".");
|
||||
|
||||
for (const file of files.sort()) {
|
||||
const sourceText = readFileSync(file, "utf8");
|
||||
const sourceFile = ts.createSourceFile(file, sourceText, ts.ScriptTarget.Latest, true);
|
||||
// Parse every file through one synthetic project. noResolve keeps the program to exactly these files.
|
||||
const configPath = resolve("tsconfig.check-ts-relative-imports.json");
|
||||
const config = JSON.stringify({
|
||||
compilerOptions: { noResolve: true, noLib: true, types: [] },
|
||||
files: files.map((file) => resolve(file)),
|
||||
});
|
||||
const api = new API({
|
||||
cwd: process.cwd(),
|
||||
fs: {
|
||||
fileExists: (fileName) => (resolve(fileName) === configPath ? true : undefined),
|
||||
readFile: (fileName) => (resolve(fileName) === configPath ? config : undefined),
|
||||
},
|
||||
});
|
||||
|
||||
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}`);
|
||||
}
|
||||
try {
|
||||
const program = api.updateSnapshot({ openProjects: [configPath] }).getProject(configPath).program;
|
||||
for (const file of files.sort()) {
|
||||
const sourceFile = program.getSourceFile(resolve(file));
|
||||
|
||||
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);
|
||||
function checkSpecifier(node) {
|
||||
if (!isRelativeJavaScriptSpecifier(node.text)) return;
|
||||
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
||||
failures.push(`${relative(".", file)}:${line + 1}:${character + 1}: ${node.text}`);
|
||||
}
|
||||
|
||||
ts.forEachChild(node, visit);
|
||||
}
|
||||
function visit(node) {
|
||||
if (isImportDeclaration(node) && isStringLiteralLike(node.moduleSpecifier)) {
|
||||
checkSpecifier(node.moduleSpecifier);
|
||||
} else if (isExportDeclaration(node) && isStringLiteralLike(node.moduleSpecifier)) {
|
||||
checkSpecifier(node.moduleSpecifier);
|
||||
} else if (
|
||||
isCallExpression(node) &&
|
||||
node.expression.kind === SyntaxKind.ImportKeyword &&
|
||||
isStringLiteralLike(node.arguments[0])
|
||||
) {
|
||||
checkSpecifier(node.arguments[0]);
|
||||
} else if (isImportTypeNode(node)) {
|
||||
const specifier = getImportTypeSpecifier(node);
|
||||
if (specifier) checkSpecifier(specifier);
|
||||
}
|
||||
|
||||
visit(sourceFile);
|
||||
node.forEachChild(visit);
|
||||
}
|
||||
|
||||
visit(sourceFile);
|
||||
}
|
||||
} finally {
|
||||
api.close();
|
||||
}
|
||||
|
||||
if (failures.length > 0) {
|
||||
|
||||
Reference in new issue
Block a user