UNPKG

typia

Version:

Superfast runtime validators with only one line

852 lines 41.1 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TypiaGenerateWizard = void 0; const commander_1 = require("commander"); const fs_1 = __importDefault(require("fs")); const inquirer_1 = __importDefault(require("inquirer")); const module_1 = require("module"); const os_1 = __importDefault(require("os")); const path_1 = __importDefault(require("path")); const tinyglobby_1 = require("tinyglobby"); const FileSystemIdentity_1 = require("./FileSystemIdentity"); var TypiaGenerateWizard; (function (TypiaGenerateWizard) { function generate() { return __awaiter(this, void 0, void 0, function* () { console.log("----------------------------------------"); console.log(" Typia Generate Wizard"); console.log("----------------------------------------"); const options = yield parseArguments(); yield build(options); }); } TypiaGenerateWizard.generate = generate; function parseArguments() { return __awaiter(this, void 0, void 0, function* () { const command = (0, commander_1.createCommand)("typia generate"); command.usage("[options] [files...]"); command.argument("[files...]", "input TypeScript source files or globs"); command.option("--input <path>", "input directory"); command.option("--output <directory>", "output directory"); command.option("--project <project>", "tsconfig.json/jsconfig.json file or directory"); const questioned = { value: false }; const prompt = inquirer_1.default.createPromptModule; const input = (name) => (message) => __awaiter(this, void 0, void 0, function* () { questioned.value = true; const result = yield prompt()({ type: "input", name, message, default: "", }); return result[name]; }); const configure = () => __awaiter(this, void 0, void 0, function* () { const file = findProjectConfigFile(process.cwd()); if (file === null) { throw new URIError(`Unable to find "tsconfig.json" or "jsconfig.json" file.`); } return file; }); return new Promise((resolve, reject) => { command.action((files, options) => __awaiter(this, void 0, void 0, function* () { var _a, _b, _c; try { if (files.length !== 0 && options.input !== undefined) { throw new URIError("Error on TypiaGenerateWizard.generate(): file arguments cannot be combined with --input."); } if (files.length === 0) { (_a = options.input) !== null && _a !== void 0 ? _a : (options.input = yield input("input")("input directory")); } if (files.length !== 0 && options.output === undefined) { throw new URIError("Error on TypiaGenerateWizard.generate(): output directory is required when file arguments are used."); } const output = (_b = options.output) !== null && _b !== void 0 ? _b : (yield input("output")("output directory")); const project = (_c = options.project) !== null && _c !== void 0 ? _c : (yield configure()); if (questioned.value) console.log(""); resolve({ input: options.input, output, project, files, }); } catch (exp) { reject(exp); } })); command.parseAsync(process.argv.slice(3), { from: "user" }).catch(reject); }); }); } function build(location) { return __awaiter(this, void 0, void 0, function* () { location.output = path_1.default.resolve(location.output); location.project = resolveProjectConfigFile(location.project); const policy = new FileSystemIdentity_1.FileSystemIdentity.Policy(); const outputProbe = yield nearestExistingAncestor(location.output); yield ensureExistingDirectoryPath({ label: "output parent path", directory: outputProbe, }); policy.observe(yield FileSystemIdentity_1.FileSystemIdentity.probeDirectory(outputProbe), outputProbe); policy.observe(yield FileSystemIdentity_1.FileSystemIdentity.inspectDirectory(path_1.default.dirname(location.project)), path_1.default.dirname(location.project)); const entries = location.files.length === 0 ? yield prepareDirectoryInput(location, policy) : yield prepareFileInputs(location, policy); const identity = policy.get(); yield inspectTargetDirectories({ identity, output: location.output, targets: entries.map((entry) => entry.target), }); const binary = resolveTsgoBinary(); const cwd = path_1.default.dirname(location.project); const temporaryProject = yield createTemporaryProject({ entries, project: location.project, }); let transformed; try { transformed = transformProject({ binary, cwd, projectRoot: cwd, tsconfig: temporaryProject.config, }); } finally { yield fs_1.default.promises.rm(temporaryProject.directory, { force: true, recursive: true, }); } const outputByKey = indexTransformedOutputs(transformed, identity); const outputs = entries.map((entry) => { const output = getTransformedOutput({ cwd, entry, identity, outputByKey, }); if (output === undefined) { throw new URIError(`Error on TypiaGenerateWizard.generate(): no transformed output for ${entry.file}. Check that --project includes the file.`); } return { entry, output }; }); yield ensureOutputDirectory(location.output); yield ensureTargetDirectories({ identity, output: location.output, targets: outputs.map(({ entry }) => entry.target), }); yield ensurePhysicalTargets({ identity, output: location.output, entries: outputs.map(({ entry }) => entry), }); yield ensureTargetFiles(outputs.map(({ entry }) => entry), identity); for (const { entry, output } of outputs) { yield fs_1.default.promises.writeFile(entry.target, formatOutput(output), "utf8"); } }); } function createTemporaryProject(props) { return __awaiter(this, void 0, void 0, function* () { const directory = yield fs_1.default.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), "typia-generate-project-")); const config = path_1.default.join(directory, "tsconfig.json"); try { yield fs_1.default.promises.writeFile(config, JSON.stringify({ extends: props.project, exclude: [], files: props.entries.map((entry) => compilerInputPath(entry.file)), include: [], }), "utf8"); return { config, directory }; } catch (error) { yield fs_1.default.promises.rm(directory, { force: true, recursive: true }); throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to prepare the bounded input project: ${formatUnknownError(error)}`); } }); } function ensureOutputDirectory(output) { return __awaiter(this, void 0, void 0, function* () { if (fs_1.default.existsSync(output) === false) { yield ensureCreatableDirectory(output); yield fs_1.default.promises.mkdir(output, { recursive: true }); } else { yield ensureExistingDirectory({ label: "output path", directory: output, }); } }); } function ensureTargetDirectories(props) { return __awaiter(this, void 0, void 0, function* () { yield inspectTargetDirectories(props); const directories = targetDirectories(props); for (const directory of directories.values()) { try { yield fs_1.default.promises.mkdir(directory, { recursive: true }); } catch (exp) { throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to create output parent directory ${directory}: ${formatUnknownError(exp)}`); } yield ensureExistingDirectory({ label: "output parent path", directory, }); } }); } function inspectTargetDirectories(props) { return __awaiter(this, void 0, void 0, function* () { const directories = targetDirectories(props); for (const directory of directories.values()) { yield ensureOutputAncestorDirectories({ identity: props.identity, output: props.output, directory, }); if (fs_1.default.existsSync(directory)) { yield ensureExistingDirectory({ label: "output parent path", directory, }); } } }); } function targetDirectories(props) { const directories = new Map(); for (const target of props.targets) { const directory = path_1.default.dirname(target); directories.set(props.identity.filesystemKey(directory), directory); } return directories; } function ensureCreatableDirectory(directory) { return __awaiter(this, void 0, void 0, function* () { const parent = yield nearestExistingAncestor(directory); yield ensureExistingDirectoryPath({ label: "output parent path", directory: parent, }); }); } function nearestExistingAncestor(directory) { return __awaiter(this, void 0, void 0, function* () { let current = path_1.default.resolve(directory); while (fs_1.default.existsSync(current) === false) { const parent = path_1.default.dirname(current); if (parent === current) { throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to find existing output parent path: ${directory}`); } current = parent; } return current; }); } function ensureOutputAncestorDirectories(props) { return __awaiter(this, void 0, void 0, function* () { const output = path_1.default.resolve(props.output); const directory = path_1.default.resolve(props.directory); if (props.identity.contains(directory, output) === false) { throw new URIError(`Error on TypiaGenerateWizard.generate(): output parent path escapes output directory: ${props.directory}`); } const relative = path_1.default.relative(output, directory); if (relative === "") { return; } let current = output; for (const segment of relative.split(path_1.default.sep)) { current = path_1.default.join(current, segment); let stat; try { stat = yield fs_1.default.promises.lstat(current); } catch (exp) { if (isMissingFileError(exp)) { return; } throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to inspect output parent path ${current}: ${formatUnknownError(exp)}`); } if (stat.isSymbolicLink()) { throw new URIError(`Error on TypiaGenerateWizard.generate(): output parent path contains a symbolic link: ${current}`); } if (stat.isDirectory() === false) { throw new URIError(`Error on TypiaGenerateWizard.generate(): output parent path is not a directory: ${current}`); } } }); } function ensureExistingDirectory(props) { return __awaiter(this, void 0, void 0, function* () { yield ensureExistingDirectoryPath(props); }); } function ensureExistingDirectoryPath(props) { return __awaiter(this, void 0, void 0, function* () { const directory = path_1.default.resolve(props.directory); const parsed = path_1.default.parse(directory); const relative = path_1.default.relative(parsed.root, directory); let current = parsed.root; for (const segment of relative === "" ? [] : relative.split(path_1.default.sep)) { current = path_1.default.join(current, segment); yield ensureExistingDirectorySegment({ label: path_1.default.normalize(current) === path_1.default.normalize(directory) ? props.label : `${props.label} ancestor`, directory: current, }); } }); } function ensureExistingDirectorySegment(props) { return __awaiter(this, void 0, void 0, function* () { const stat = yield fs_1.default.promises.lstat(props.directory); if (stat.isSymbolicLink()) { throw new URIError(`Error on TypiaGenerateWizard.generate(): ${props.label} is a symbolic link: ${props.directory}`); } if (stat.isDirectory() === false) { throw new URIError(`Error on TypiaGenerateWizard.generate(): ${props.label} is not a directory: ${props.directory}`); } }); } function ensurePhysicalTargets(props) { return __awaiter(this, void 0, void 0, function* () { const output = yield fs_1.default.promises.realpath(props.output); const inputs = new Set(); for (const entry of props.entries) { inputs.add(props.identity.filesystemKey(yield fs_1.default.promises.realpath(entry.file))); } for (const entry of props.entries) { const parent = path_1.default.dirname(entry.target); const directory = yield fs_1.default.promises.realpath(parent); if (props.identity.contains(directory, output) === false) { throw new URIError(`Error on TypiaGenerateWizard.generate(): output parent path escapes output directory through a symbolic link: ${parent}`); } const target = path_1.default.join(directory, path_1.default.basename(entry.target)); if (inputs.has(props.identity.filesystemKey(target))) { throw new URIError(`Error on TypiaGenerateWizard.generate(): output file would overwrite input file through a symbolic link: ${entry.target}`); } } }); } function ensureTargetFiles(entries, identity) { return __awaiter(this, void 0, void 0, function* () { const inputs = new Set(); const files = new Map(); for (const entry of entries) { inputs.add(fileIdentityKey(yield fs_1.default.promises.stat(entry.file, { bigint: true }), yield fs_1.default.promises.realpath(entry.file))); files.set(identity.filesystemKey(entry.target), entry); } for (const entry of files.values()) { let stat; try { stat = yield fs_1.default.promises.lstat(entry.target, { bigint: true }); } catch (exp) { if (isMissingFileError(exp)) { continue; } throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to inspect output file ${entry.target}: ${formatUnknownError(exp)}`); } if (stat.isFile() === false) { throw new URIError(`Error on TypiaGenerateWizard.generate(): output file path is not a regular file: ${entry.target}`); } if (inputs.has(fileIdentityKey(stat, yield fs_1.default.promises.realpath(entry.target)))) { throw new URIError(`Error on TypiaGenerateWizard.generate(): output file would overwrite input file through a physical file alias: ${entry.target}`); } if (stat.nlink > BigInt(1)) { throw new URIError(`Error on TypiaGenerateWizard.generate(): output file has multiple hard links: ${entry.target}`); } } }); } function prepareDirectoryInput(location, policy) { return __awaiter(this, void 0, void 0, function* () { if (location.input === undefined) { throw new URIError("Error on TypiaGenerateWizard.generate(): input path is required."); } const input = path_1.default.resolve(location.input); if (fs_1.default.existsSync(input) === false) { throw new URIError(`Error on TypiaGenerateWizard.generate(): input path does not exist: ${input}`); } if ((yield isDirectory(input)) === false) { throw new URIError("Error on TypiaGenerateWizard.generate(): input path is not a directory."); } const inputReal = yield fs_1.default.promises.realpath(input); const outputReal = yield optionalRealPath(location.output); const files = []; yield gather({ container: files, from: input, inputReal, outputReal, policy, visitedDirectories: new Set(), visitedFiles: new Set(), }); return files.map((file) => ({ file, target: path_1.default.join(location.output, path_1.default.relative(input, file)), })); }); } function prepareFileInputs(location, policy) { return __awaiter(this, void 0, void 0, function* () { const targets = new Set(); const output = []; for (const input of yield expandFileInputs(location.files, location.output, policy)) { const file = path_1.default.resolve(input); policy.observe(yield FileSystemIdentity_1.FileSystemIdentity.inspectDirectory(path_1.default.dirname(file)), path_1.default.dirname(file)); const identity = policy.get(); if (fs_1.default.existsSync(file) === false) { throw new URIError(`Error on TypiaGenerateWizard.generate(): input file does not exist: ${input}`); } else if ((yield isFile(file)) === false) { throw new URIError(`Error on TypiaGenerateWizard.generate(): input path is not a file: ${input}`); } else if (identity.isDeclarationFile(file)) { continue; } else if (identity.isSupportedExtension(file) === false) { throw new URIError(`Error on TypiaGenerateWizard.generate(): input file is not a supported TypeScript source: ${input}`); } const target = path_1.default.join(location.output, path_1.default.basename(file)); if (identity.isSamePath(file, target)) { throw new URIError(`Error on TypiaGenerateWizard.generate(): output file would overwrite input file: ${input}`); } const key = identity.filesystemKey(target); if (targets.has(key)) { throw new URIError(`Error on TypiaGenerateWizard.generate(): duplicate output filename for ${target}`); } targets.add(key); output.push({ file, target }); } if (output.length === 0) { throw new URIError("Error on TypiaGenerateWizard.generate(): input files do not include any supported TypeScript source files outside the output directory."); } return output; }); } function expandFileInputs(inputs, directory, policy) { return __awaiter(this, void 0, void 0, function* () { const output = []; for (const input of inputs) { const pattern = toGlobPattern(input); if ((0, tinyglobby_1.isDynamicPattern)(pattern, { caseSensitiveMatch: true })) { const searchDirectory = yield globSearchDirectory(input); const caseSensitive = yield FileSystemIdentity_1.FileSystemIdentity.inspectDirectory(searchDirectory); if (caseSensitive === undefined) { throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to determine filesystem case behavior for input pattern base ${searchDirectory}.`); } policy.observe(caseSensitive, searchDirectory); const identity = policy.get(); const matches = yield (0, tinyglobby_1.glob)(pattern, { absolute: true, caseSensitiveMatch: identity.caseSensitive, cwd: process.cwd(), onlyFiles: true, }); if (matches.length === 0) { throw new URIError(`Error on TypiaGenerateWizard.generate(): input pattern does not match any files: ${input}`); } output.push(...excludeOutputFiles(matches, directory, identity).filter((file) => identity.isSupportedExtension(file))); } else { const file = path_1.default.resolve(input); policy.observe(yield FileSystemIdentity_1.FileSystemIdentity.inspectDirectory(path_1.default.dirname(file)), path_1.default.dirname(file)); if (policy.get().contains(file, directory) === false) { output.push(file); } } } return output; }); } function excludeOutputFiles(files, directory, identity) { return files.filter((file) => identity.contains(file, directory) === false); } function globSearchDirectory(input) { return __awaiter(this, void 0, void 0, function* () { let current = path_1.default.resolve(input); while ((0, tinyglobby_1.isDynamicPattern)(toGlobPattern(current), { caseSensitiveMatch: true })) { const parent = path_1.default.dirname(current); if (parent === current) break; current = parent; } if (fs_1.default.existsSync(current) && (yield isDirectory(current))) return current; return nearestExistingAncestor(path_1.default.dirname(current)); }); } function toGlobPattern(input) { return input.replace(/\\/g, "/"); } function transformProject(props) { const TtscCompiler = loadTtscCompiler(); const result = new TtscCompiler({ binary: props.binary, cwd: props.cwd, projectRoot: props.projectRoot, tsconfig: props.tsconfig, }).transform(); if (result.type === "success") { return result.typescript; } if (result.type === "failure") { throw new URIError(`Error on TypiaGenerateWizard.generate(): ${formatDiagnostics(result.diagnostics)}`); } throw new URIError(`Error on TypiaGenerateWizard.generate(): ${formatUnknownError(result.error)}`); } function resolveProjectConfigFile(project) { const resolved = path_1.default.resolve(project); if (fs_1.default.existsSync(resolved) === false) { throw new URIError(`Error on TypiaGenerateWizard.generate(): project path does not exist: ${resolved}`); } const stat = fs_1.default.statSync(resolved); if (stat.isDirectory()) { for (const filename of ["tsconfig.json", "jsconfig.json"]) { const candidate = path_1.default.join(resolved, filename); if (fs_1.default.existsSync(candidate) && fs_1.default.statSync(candidate).isFile()) { return resolveRealPath(candidate); } } throw new URIError(`Error on TypiaGenerateWizard.generate(): project directory has no tsconfig.json or jsconfig.json: ${resolved}`); } if (stat.isFile() === false) { throw new URIError(`Error on TypiaGenerateWizard.generate(): project path is not a file: ${resolved}`); } return resolveRealPath(resolved); } function findProjectConfigFile(directory) { let current = path_1.default.resolve(directory); while (true) { for (const filename of ["tsconfig.json", "jsconfig.json"]) { const candidate = path_1.default.join(current, filename); if (fs_1.default.existsSync(candidate) && fs_1.default.statSync(candidate).isFile()) { return resolveRealPath(candidate); } } const parent = path_1.default.dirname(current); if (parent === current) { return null; } current = parent; } } function loadTtscCompiler() { const packageRoot = resolveTypiaPackageRoot(); const resolved = resolveFromRoots("ttsc", resolveRuntimeRoots(packageRoot)); if (resolved === null) { throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to resolve ttsc from the current project, typia package, or workspace root. Run "npm i -D ttsc typescript" before.`); } const imported = (0, module_1.createRequire)(resolved)(resolved); return imported.TtscCompiler; } function resolveTsgoBinary() { const explicit = process.env.TTSC_TSGO_BINARY; if (explicit !== undefined && explicit.length !== 0) { if (path_1.default.isAbsolute(explicit) && fs_1.default.existsSync(explicit)) { return explicit; } throw new URIError(`Error on TypiaGenerateWizard.generate(): TTSC_TSGO_BINARY must be an existing absolute path: ${explicit}`); } const packageRoot = resolveTypiaPackageRoot(); const manifest = resolveFromRoots("typescript/package.json", resolveRuntimeRoots(packageRoot)); if (manifest === null) { throw new URIError("Error on TypiaGenerateWizard.generate(): unable to resolve typescript from the current project, typia package, or workspace root."); } const platform = `@typescript/typescript-${process.platform}-${process.arch}`; const platformManifest = (0, module_1.createRequire)(manifest).resolve(`${platform}/package.json`); const binary = path_1.default.join(path_1.default.dirname(platformManifest), "lib", process.platform === "win32" ? "tsc.exe" : "tsc"); if (fs_1.default.existsSync(binary) === false) { throw new URIError(`Error on TypiaGenerateWizard.generate(): TypeScript-Go executable not found: ${binary}`); } return binary; } function resolveTypiaPackageRoot() { var _a; // The CLI entrypoint (`lib/executable/typia.js`) lives in the same // directory as this module, so its `process.argv[1]` path anchors the // walk-up identically in both the CJS and ESM builds — `__dirname` does // not exist in the transcoded `.mjs`. const current = path_1.default.dirname(path_1.default.resolve((_a = process.argv[1]) !== null && _a !== void 0 ? _a : "")); for (const directory of [ path_1.default.resolve(current, "..", ".."), path_1.default.resolve(current, ".."), ]) { const file = path_1.default.join(directory, "package.json"); if (fs_1.default.existsSync(file) === false) { continue; } try { const pack = JSON.parse(fs_1.default.readFileSync(file, "utf8")); if (pack.name === "typia") { return directory; } } catch (_b) { continue; } } const resolved = resolveFromRoots("typia/package.json", [ process.cwd(), current, ]); if (resolved === null) { throw new URIError("Error on TypiaGenerateWizard.generate(): unable to resolve typia package root."); } return path_1.default.dirname(resolved); } function resolveRuntimeRoots(packageRoot) { return [process.cwd(), packageRoot, path_1.default.resolve(packageRoot, "..", "..")]; } function resolveFromRoots(request, roots) { for (const root of roots) { try { return (0, module_1.createRequire)(path_1.default.join(root, "package.json")).resolve(request); } catch (_a) { continue; } } return null; } function isDirectory(current) { return __awaiter(this, void 0, void 0, function* () { const stat = yield fs_1.default.promises.stat(current); return stat.isDirectory(); }); } function isFile(current) { return __awaiter(this, void 0, void 0, function* () { const stat = yield fs_1.default.promises.stat(current); return stat.isFile(); }); } function gather(props) { return __awaiter(this, void 0, void 0, function* () { const currentReal = yield resolveTraversalPath(props.from); if (props.outputReal !== undefined && isPhysicalSameOrChildPath(currentReal, props.outputReal)) return; ensurePhysicalInputContainment({ file: props.from, input: props.inputReal, real: currentReal, }); const currentStat = yield fs_1.default.promises.stat(props.from, { bigint: true, }); const directoryIdentity = fileIdentityKey(currentStat, currentReal); if (props.visitedDirectories.has(directoryIdentity)) { const lexicalStat = yield fs_1.default.promises.lstat(props.from); if (lexicalStat.isSymbolicLink()) { throw new URIError(`Error on TypiaGenerateWizard.generate(): input directory link revisits a physical directory: ${props.from}.`); } return; } props.visitedDirectories.add(directoryIdentity); props.policy.observe(yield FileSystemIdentity_1.FileSystemIdentity.inspectDirectory(props.from), props.from); const identity = props.policy.get(); const entries = yield Promise.all((yield fs_1.default.promises.readdir(props.from)).map((name) => __awaiter(this, void 0, void 0, function* () { const file = path_1.default.join(props.from, name); try { return { file, name, stat: yield fs_1.default.promises.lstat(file) }; } catch (error) { throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to inspect input path ${file}: ${formatUnknownError(error)}`); } }))); entries.sort((x, y) => { const linkOrder = Number(x.stat.isSymbolicLink()) - Number(y.stat.isSymbolicLink()); return linkOrder !== 0 ? linkOrder : Buffer.compare(Buffer.from(x.name), Buffer.from(y.name)); }); for (const entry of entries) { let stat; let real; try { stat = yield fs_1.default.promises.stat(entry.file, { bigint: true }); real = yield fs_1.default.promises.realpath(entry.file); } catch (error) { throw new URIError(`Error on TypiaGenerateWizard.generate(): input link target is missing or unreadable: ${entry.file}: ${formatUnknownError(error)}`); } if (props.outputReal !== undefined && isPhysicalSameOrChildPath(real, props.outputReal)) continue; ensurePhysicalInputContainment({ file: entry.file, input: props.inputReal, real, }); if (stat.isDirectory()) { yield gather(Object.assign(Object.assign({}, props), { from: entry.file })); continue; } if (stat.isFile() === false || identity.isSupportedExtension(entry.name) === false) continue; const fileIdentity = fileIdentityKey(stat, real); if (props.visitedFiles.has(fileIdentity)) continue; props.visitedFiles.add(fileIdentity); props.container.push(entry.file); } }); } function formatOutput(output) { return output.startsWith("// @ts-nocheck") ? output : `// @ts-nocheck\n${output}`; } function indexTransformedOutputs(outputs, identity) { const map = new Map(); for (const [file, output] of Object.entries(outputs)) { const key = identity.projectFileKey(file); if (map.has(key)) { throw new URIError(`Error on TypiaGenerateWizard.generate(): transformed outputs have ambiguous filesystem identities: ${file}.`); } map.set(key, output); } return map; } function getTransformedOutput(props) { const output = props.outputByKey.get(props.identity.projectFileKey(projectKey(props.cwd, props.entry.file))); if (output !== undefined) { return output; } const compilerFile = compilerInputPath(props.entry.file); if (props.identity.isSamePath(compilerFile, props.entry.file) === false && props.identity.contains(compilerFile, props.cwd)) { const compiled = props.outputByKey.get(props.identity.projectFileKey(projectKey(props.cwd, compilerFile))); if (compiled !== undefined) return compiled; } const real = resolveRealPath(props.entry.file); if (props.identity.isSamePath(real, props.entry.file) || props.identity.contains(real, props.cwd) === false) { return undefined; } return props.outputByKey.get(props.identity.projectFileKey(projectKey(props.cwd, real))); } function projectKey(root, file) { return path_1.default.relative(root, file).replace(/\\/g, "/"); } function resolveRealPath(file) { try { return fs_1.default.realpathSync(file); } catch (_a) { return file; } } function compilerInputPath(file) { try { if (fs_1.default.lstatSync(file).isSymbolicLink()) { return path_1.default.join(resolveRealPath(path_1.default.dirname(file)), path_1.default.basename(file)); } } catch (_a) { return file; } return resolveRealPath(file); } function optionalRealPath(file) { return __awaiter(this, void 0, void 0, function* () { try { return yield fs_1.default.promises.realpath(file); } catch (error) { if (isMissingFileError(error)) return undefined; throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to resolve path ${file}: ${formatUnknownError(error)}`); } }); } function resolveTraversalPath(file) { return __awaiter(this, void 0, void 0, function* () { try { return yield fs_1.default.promises.realpath(file); } catch (error) { throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to resolve input path ${file}: ${formatUnknownError(error)}`); } }); } function ensurePhysicalInputContainment(props) { if (isPhysicalSameOrChildPath(props.real, props.input)) return; throw new URIError(`Error on TypiaGenerateWizard.generate(): input path resolves outside the input directory: ${props.file}.`); } function isPhysicalSameOrChildPath(file, directory) { const relative = path_1.default.relative(directory, file); return (relative === "" || (relative !== ".." && relative.startsWith(`..${path_1.default.sep}`) === false && path_1.default.isAbsolute(relative) === false)); } function isMissingFileError(exp) { return (typeof exp === "object" && exp !== null && "code" in exp && exp.code === "ENOENT"); } /** * Delegates to {@link FileSystemIdentity.identityKey}, which owns the rule and * carries the reasoning for reading the identity as a `bigint`. */ function fileIdentityKey(stat, realpath) { return FileSystemIdentity_1.FileSystemIdentity.identityKey(stat, realpath); } function formatDiagnostics(diagnostics) { return diagnostics.length === 0 ? "transformation failed" : diagnostics .map((diag) => { var _a, _b; return [ (_a = diag.file) !== null && _a !== void 0 ? _a : "ttsc", diag.line === undefined ? undefined : `${diag.line}:${(_b = diag.character) !== null && _b !== void 0 ? _b : 1}`, diag.messageText, ] .filter((part) => part !== undefined && part !== "") .join(": "); }) .join("\n"); } function formatUnknownError(error) { if (error instanceof Error) { return error.message; } if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") { return error.message; } return String(error); } })(TypiaGenerateWizard || (exports.TypiaGenerateWizard = TypiaGenerateWizard = {})); //# sourceMappingURL=TypiaGenerateWizard.js.map