typia
Version:
Superfast runtime validators with only one line
852 lines • 41.1 kB
JavaScript
;
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