typia
Version:
Superfast runtime validators with only one line
618 lines (617 loc) • 27.2 kB
JavaScript
import { FileSystemIdentity } from "./FileSystemIdentity.mjs";
import fs from "fs";
import path from "path";
import { createCommand } from "commander";
import inquirer from "inquirer";
import { createRequire } from "module";
import os from "os";
import { glob, isDynamicPattern } from "tinyglobby";
//#region src/executable/TypiaGenerateWizard.ts
let TypiaGenerateWizard;
(function(_TypiaGenerateWizard) {
async function generate() {
console.log("----------------------------------------");
console.log(" Typia Generate Wizard");
console.log("----------------------------------------");
await build(await parseArguments());
}
_TypiaGenerateWizard.generate = generate;
async function parseArguments() {
const command = 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.createPromptModule;
const input = (name) => async (message) => {
questioned.value = true;
return (await prompt()({
type: "input",
name,
message,
default: ""
}))[name];
};
const configure = async () => {
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(async (files, options) => {
try {
if (files.length !== 0 && options.input !== void 0) throw new URIError("Error on TypiaGenerateWizard.generate(): file arguments cannot be combined with --input.");
if (files.length === 0) options.input ??= await input("input")("input directory");
if (files.length !== 0 && options.output === void 0) throw new URIError("Error on TypiaGenerateWizard.generate(): output directory is required when file arguments are used.");
const output = options.output ?? await input("output")("output directory");
const project = options.project ?? await 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);
});
}
async function build(location) {
location.output = path.resolve(location.output);
location.project = resolveProjectConfigFile(location.project);
const policy = new FileSystemIdentity.Policy();
const outputProbe = await nearestExistingAncestor(location.output);
await ensureExistingDirectoryPath({
label: "output parent path",
directory: outputProbe
});
policy.observe(await FileSystemIdentity.probeDirectory(outputProbe), outputProbe);
policy.observe(await FileSystemIdentity.inspectDirectory(path.dirname(location.project)), path.dirname(location.project));
const entries = location.files.length === 0 ? await prepareDirectoryInput(location, policy) : await prepareFileInputs(location, policy);
const identity = policy.get();
await inspectTargetDirectories({
identity,
output: location.output,
targets: entries.map((entry) => entry.target)
});
const binary = resolveTsgoBinary();
const cwd = path.dirname(location.project);
const temporaryProject = await createTemporaryProject({
entries,
project: location.project
});
let transformed;
try {
transformed = transformProject({
binary,
cwd,
projectRoot: cwd,
tsconfig: temporaryProject.config
});
} finally {
await fs.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 === void 0) throw new URIError(`Error on TypiaGenerateWizard.generate(): no transformed output for ${entry.file}. Check that --project includes the file.`);
return {
entry,
output
};
});
await ensureOutputDirectory(location.output);
await ensureTargetDirectories({
identity,
output: location.output,
targets: outputs.map(({ entry }) => entry.target)
});
await ensurePhysicalTargets({
identity,
output: location.output,
entries: outputs.map(({ entry }) => entry)
});
await ensureTargetFiles(outputs.map(({ entry }) => entry), identity);
for (const { entry, output } of outputs) await fs.promises.writeFile(entry.target, formatOutput(output), "utf8");
}
async function createTemporaryProject(props) {
const directory = await fs.promises.mkdtemp(path.join(os.tmpdir(), "typia-generate-project-"));
const config = path.join(directory, "tsconfig.json");
try {
await fs.promises.writeFile(config, JSON.stringify({
extends: props.project,
exclude: [],
files: props.entries.map((entry) => compilerInputPath(entry.file)),
include: []
}), "utf8");
return {
config,
directory
};
} catch (error) {
await fs.promises.rm(directory, {
force: true,
recursive: true
});
throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to prepare the bounded input project: ${formatUnknownError(error)}`);
}
}
async function ensureOutputDirectory(output) {
if (fs.existsSync(output) === false) {
await ensureCreatableDirectory(output);
await fs.promises.mkdir(output, { recursive: true });
} else await ensureExistingDirectory({
label: "output path",
directory: output
});
}
async function ensureTargetDirectories(props) {
await inspectTargetDirectories(props);
const directories = targetDirectories(props);
for (const directory of directories.values()) {
try {
await fs.promises.mkdir(directory, { recursive: true });
} catch (exp) {
throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to create output parent directory ${directory}: ${formatUnknownError(exp)}`);
}
await ensureExistingDirectory({
label: "output parent path",
directory
});
}
}
async function inspectTargetDirectories(props) {
const directories = targetDirectories(props);
for (const directory of directories.values()) {
await ensureOutputAncestorDirectories({
identity: props.identity,
output: props.output,
directory
});
if (fs.existsSync(directory)) await ensureExistingDirectory({
label: "output parent path",
directory
});
}
}
function targetDirectories(props) {
const directories = /* @__PURE__ */ new Map();
for (const target of props.targets) {
const directory = path.dirname(target);
directories.set(props.identity.filesystemKey(directory), directory);
}
return directories;
}
async function ensureCreatableDirectory(directory) {
await ensureExistingDirectoryPath({
label: "output parent path",
directory: await nearestExistingAncestor(directory)
});
}
async function nearestExistingAncestor(directory) {
let current = path.resolve(directory);
while (fs.existsSync(current) === false) {
const parent = path.dirname(current);
if (parent === current) throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to find existing output parent path: ${directory}`);
current = parent;
}
return current;
}
async function ensureOutputAncestorDirectories(props) {
const output = path.resolve(props.output);
const directory = path.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.relative(output, directory);
if (relative === "") return;
let current = output;
for (const segment of relative.split(path.sep)) {
current = path.join(current, segment);
let stat;
try {
stat = await fs.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}`);
}
}
async function ensureExistingDirectory(props) {
await ensureExistingDirectoryPath(props);
}
async function ensureExistingDirectoryPath(props) {
const directory = path.resolve(props.directory);
const parsed = path.parse(directory);
const relative = path.relative(parsed.root, directory);
let current = parsed.root;
for (const segment of relative === "" ? [] : relative.split(path.sep)) {
current = path.join(current, segment);
await ensureExistingDirectorySegment({
label: path.normalize(current) === path.normalize(directory) ? props.label : `${props.label} ancestor`,
directory: current
});
}
}
async function ensureExistingDirectorySegment(props) {
const stat = await fs.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}`);
}
async function ensurePhysicalTargets(props) {
const output = await fs.promises.realpath(props.output);
const inputs = /* @__PURE__ */ new Set();
for (const entry of props.entries) inputs.add(props.identity.filesystemKey(await fs.promises.realpath(entry.file)));
for (const entry of props.entries) {
const parent = path.dirname(entry.target);
const directory = await fs.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.join(directory, path.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}`);
}
}
async function ensureTargetFiles(entries, identity) {
const inputs = /* @__PURE__ */ new Set();
const files = /* @__PURE__ */ new Map();
for (const entry of entries) {
inputs.add(fileIdentityKey(await fs.promises.stat(entry.file, { bigint: true }), await fs.promises.realpath(entry.file)));
files.set(identity.filesystemKey(entry.target), entry);
}
for (const entry of files.values()) {
let stat;
try {
stat = await fs.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, await fs.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}`);
}
}
async function prepareDirectoryInput(location, policy) {
if (location.input === void 0) throw new URIError("Error on TypiaGenerateWizard.generate(): input path is required.");
const input = path.resolve(location.input);
if (fs.existsSync(input) === false) throw new URIError(`Error on TypiaGenerateWizard.generate(): input path does not exist: ${input}`);
if (await isDirectory(input) === false) throw new URIError("Error on TypiaGenerateWizard.generate(): input path is not a directory.");
const inputReal = await fs.promises.realpath(input);
const outputReal = await optionalRealPath(location.output);
const files = [];
await gather({
container: files,
from: input,
inputReal,
outputReal,
policy,
visitedDirectories: /* @__PURE__ */ new Set(),
visitedFiles: /* @__PURE__ */ new Set()
});
return files.map((file) => ({
file,
target: path.join(location.output, path.relative(input, file))
}));
}
async function prepareFileInputs(location, policy) {
const targets = /* @__PURE__ */ new Set();
const output = [];
for (const input of await expandFileInputs(location.files, location.output, policy)) {
const file = path.resolve(input);
policy.observe(await FileSystemIdentity.inspectDirectory(path.dirname(file)), path.dirname(file));
const identity = policy.get();
if (fs.existsSync(file) === false) throw new URIError(`Error on TypiaGenerateWizard.generate(): input file does not exist: ${input}`);
else if (await 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.join(location.output, path.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;
}
async function expandFileInputs(inputs, directory, policy) {
const output = [];
for (const input of inputs) {
const pattern = toGlobPattern(input);
if (isDynamicPattern(pattern, { caseSensitiveMatch: true })) {
const searchDirectory = await globSearchDirectory(input);
const caseSensitive = await FileSystemIdentity.inspectDirectory(searchDirectory);
if (caseSensitive === void 0) 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 = await 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.resolve(input);
policy.observe(await FileSystemIdentity.inspectDirectory(path.dirname(file)), path.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);
}
async function globSearchDirectory(input) {
let current = path.resolve(input);
while (isDynamicPattern(toGlobPattern(current), { caseSensitiveMatch: true })) {
const parent = path.dirname(current);
if (parent === current) break;
current = parent;
}
if (fs.existsSync(current) && await isDirectory(current)) return current;
return nearestExistingAncestor(path.dirname(current));
}
function toGlobPattern(input) {
return input.replace(/\\/g, "/");
}
function transformProject(props) {
const result = new (loadTtscCompiler())({
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.resolve(project);
if (fs.existsSync(resolved) === false) throw new URIError(`Error on TypiaGenerateWizard.generate(): project path does not exist: ${resolved}`);
const stat = fs.statSync(resolved);
if (stat.isDirectory()) {
for (const filename of ["tsconfig.json", "jsconfig.json"]) {
const candidate = path.join(resolved, filename);
if (fs.existsSync(candidate) && fs.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.resolve(directory);
while (true) {
for (const filename of ["tsconfig.json", "jsconfig.json"]) {
const candidate = path.join(current, filename);
if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) return resolveRealPath(candidate);
}
const parent = path.dirname(current);
if (parent === current) return null;
current = parent;
}
}
function loadTtscCompiler() {
const resolved = resolveFromRoots("ttsc", resolveRuntimeRoots(resolveTypiaPackageRoot()));
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.`);
return createRequire(resolved)(resolved).TtscCompiler;
}
function resolveTsgoBinary() {
const explicit = process.env.TTSC_TSGO_BINARY;
if (explicit !== void 0 && explicit.length !== 0) {
if (path.isAbsolute(explicit) && fs.existsSync(explicit)) return explicit;
throw new URIError(`Error on TypiaGenerateWizard.generate(): TTSC_TSGO_BINARY must be an existing absolute path: ${explicit}`);
}
const manifest = resolveFromRoots("typescript/package.json", resolveRuntimeRoots(resolveTypiaPackageRoot()));
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 = createRequire(manifest).resolve(`${platform}/package.json`);
const binary = path.join(path.dirname(platformManifest), "lib", process.platform === "win32" ? "tsc.exe" : "tsc");
if (fs.existsSync(binary) === false) throw new URIError(`Error on TypiaGenerateWizard.generate(): TypeScript-Go executable not found: ${binary}`);
return binary;
}
function resolveTypiaPackageRoot() {
const current = path.dirname(path.resolve(process.argv[1] ?? ""));
for (const directory of [path.resolve(current, "..", ".."), path.resolve(current, "..")]) {
const file = path.join(directory, "package.json");
if (fs.existsSync(file) === false) continue;
try {
if (JSON.parse(fs.readFileSync(file, "utf8")).name === "typia") return directory;
} catch {
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.dirname(resolved);
}
function resolveRuntimeRoots(packageRoot) {
return [
process.cwd(),
packageRoot,
path.resolve(packageRoot, "..", "..")
];
}
function resolveFromRoots(request, roots) {
for (const root of roots) try {
return createRequire(path.join(root, "package.json")).resolve(request);
} catch {
continue;
}
return null;
}
async function isDirectory(current) {
return (await fs.promises.stat(current)).isDirectory();
}
async function isFile(current) {
return (await fs.promises.stat(current)).isFile();
}
async function gather(props) {
const currentReal = await resolveTraversalPath(props.from);
if (props.outputReal !== void 0 && isPhysicalSameOrChildPath(currentReal, props.outputReal)) return;
ensurePhysicalInputContainment({
file: props.from,
input: props.inputReal,
real: currentReal
});
const directoryIdentity = fileIdentityKey(await fs.promises.stat(props.from, { bigint: true }), currentReal);
if (props.visitedDirectories.has(directoryIdentity)) {
if ((await fs.promises.lstat(props.from)).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(await FileSystemIdentity.inspectDirectory(props.from), props.from);
const identity = props.policy.get();
const entries = await Promise.all((await fs.promises.readdir(props.from)).map(async (name) => {
const file = path.join(props.from, name);
try {
return {
file,
name,
stat: await fs.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 = await fs.promises.stat(entry.file, { bigint: true });
real = await fs.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 !== void 0 && isPhysicalSameOrChildPath(real, props.outputReal)) continue;
ensurePhysicalInputContainment({
file: entry.file,
input: props.inputReal,
real
});
if (stat.isDirectory()) {
await gather({
...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 = /* @__PURE__ */ 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 !== void 0) 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 !== void 0) return compiled;
}
const real = resolveRealPath(props.entry.file);
if (props.identity.isSamePath(real, props.entry.file) || props.identity.contains(real, props.cwd) === false) return;
return props.outputByKey.get(props.identity.projectFileKey(projectKey(props.cwd, real)));
}
function projectKey(root, file) {
return path.relative(root, file).replace(/\\/g, "/");
}
function resolveRealPath(file) {
try {
return fs.realpathSync(file);
} catch {
return file;
}
}
function compilerInputPath(file) {
try {
if (fs.lstatSync(file).isSymbolicLink()) return path.join(resolveRealPath(path.dirname(file)), path.basename(file));
} catch {
return file;
}
return resolveRealPath(file);
}
async function optionalRealPath(file) {
try {
return await fs.promises.realpath(file);
} catch (error) {
if (isMissingFileError(error)) return void 0;
throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to resolve path ${file}: ${formatUnknownError(error)}`);
}
}
async function resolveTraversalPath(file) {
try {
return await fs.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.relative(directory, file);
return relative === "" || relative !== ".." && relative.startsWith(`..${path.sep}`) === false && path.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.identityKey(stat, realpath);
}
function formatDiagnostics(diagnostics) {
return diagnostics.length === 0 ? "transformation failed" : diagnostics.map((diag) => [
diag.file ?? "ttsc",
diag.line === void 0 ? void 0 : `${diag.line}:${diag.character ?? 1}`,
diag.messageText
].filter((part) => part !== void 0 && 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 || (TypiaGenerateWizard = {}));
//#endregion
export { TypiaGenerateWizard };
//# sourceMappingURL=TypiaGenerateWizard.mjs.map