untyped
Version:
<!-- automd:badges bundlejs -->
257 lines (253 loc) • 7.29 kB
JavaScript
export { a as applyDefaults, r as resolveSchema } from './shared/untyped.BTwOq8Jl.mjs';
import { genObjectKey } from 'knitwork';
import { n as normalizeTypes } from './shared/untyped.Br_uXjZG.mjs';
export { d as defineUntypedSchema } from './shared/untyped.Br_uXjZG.mjs';
import 'scule';
const GenerateTypesDefaults = {
interfaceName: "Untyped",
addExport: true,
addDefaults: true,
allowExtraKeys: void 0,
partial: false,
indentation: 0
};
const TYPE_MAP = {
array: "any[]",
bigint: "bigint",
boolean: "boolean",
number: "number",
object: "",
// Will be precisely defined
any: "any",
string: "string",
symbol: "Symbol",
function: "Function"
};
const SCHEMA_KEYS = /* @__PURE__ */ new Set([
"items",
"default",
"resolve",
"properties",
"title",
"description",
"$schema",
"type",
"tsType",
"markdownType",
"tags",
"args",
"id",
"returns"
]);
const DECLARATION_RE = /typeof import\(["'](?<source>[^)]+)["']\)(\.(?<type>\w+)|\[["'](?<type1>\w+)["']])/g;
function extractTypeImports(declarations) {
const typeImports = {};
const aliases = /* @__PURE__ */ new Set();
const imports = [];
for (const match of declarations.matchAll(DECLARATION_RE)) {
const { source, type1, type = type1 } = match.groups || {};
typeImports[source] = typeImports[source] || /* @__PURE__ */ new Set();
typeImports[source].add(type);
}
for (const source in typeImports) {
const sourceImports = [];
for (const type of typeImports[source]) {
let count = 0;
let alias = type;
while (aliases.has(alias)) {
alias = `${type}${count++}`;
}
aliases.add(alias);
sourceImports.push(alias === type ? type : `${type} as ${alias}`);
declarations = declarations.replace(
new RegExp(
`typeof import\\(['"]${source}['"]\\)(\\.${type}|\\[['"]${type}['"]\\])`,
"g"
),
alias
);
}
imports.push(
`import type { ${sourceImports.join(", ")} } from '${source}'`
);
}
return [...imports, declarations].join("\n");
}
function generateTypes(schema, opts = {}) {
opts = { ...GenerateTypesDefaults, ...opts };
const baseIden = " ".repeat(opts.indentation || 0);
const interfaceCode = `interface ${opts.interfaceName} {
` + _genTypes(schema, baseIden + " ", opts).map((l) => l.trim().length > 0 ? l : "").join("\n") + `
${baseIden}}`;
if (!opts.addExport) {
return baseIden + interfaceCode;
}
return extractTypeImports(baseIden + `export ${interfaceCode}`);
}
function _genTypes(schema, spaces, opts) {
const buff = [];
if (!schema) {
return buff;
}
for (const key in schema.properties) {
const val = schema.properties[key];
buff.push(...generateJSDoc(val, opts));
if (val.tsType) {
buff.push(
`${genObjectKey(key)}${isRequired(schema, key, opts) ? "" : "?"}: ${val.tsType},
`
);
} else if (val.type === "object") {
buff.push(
`${genObjectKey(key)}${isRequired(schema, key, opts) ? "" : "?"}: {`,
..._genTypes(val, spaces, opts),
"},\n"
);
} else {
let type;
if (val.type === "array") {
type = `Array<${getTsType(val.items || [], opts)}>`;
} else if (val.type === "function") {
type = genFunctionType(val, opts);
} else {
type = getTsType(val, opts);
}
buff.push(
`${genObjectKey(key)}${isRequired(schema, key, opts) ? "" : "?"}: ${type},
`
);
}
}
if (buff.length > 0) {
const last = buff.pop() || "";
buff.push(last.slice(0, Math.max(0, last.length - 1)));
}
if (opts.allowExtraKeys === true || buff.length === 0 && opts.allowExtraKeys !== false) {
buff.push("[key: string]: any");
}
return buff.flatMap((l) => l.split("\n")).map((l) => spaces + l);
}
function getTsType(type, opts) {
if (Array.isArray(type)) {
return [normalizeTypes(type.map((t) => getTsType(t, opts)))].flat().join("|") || "any";
}
if (!type) {
return "any";
}
if (type.tsType) {
return type.tsType;
}
if (!type.type) {
return "any";
}
if (Array.isArray(type.type)) {
return type.type.map((t) => {
if (t === "object" && type.type.length > 1) {
return `{
` + _genTypes(type, " ", opts).join("\n") + `
}`;
}
return TYPE_MAP[t];
}).join("|");
}
if (type.type === "array") {
return `Array<${getTsType(type.items || [], opts)}>`;
}
if (type.type === "object") {
return `{
` + _genTypes(type, " ", opts).join("\n") + `
}`;
}
return TYPE_MAP[type.type] || type.type;
}
function genFunctionType(schema, opts) {
return `(${genFunctionArgs(schema.args, opts)}) => ${getTsType(
schema.returns || [],
opts
)}`;
}
function genFunctionArgs(args, opts) {
return args?.map((arg) => {
let argStr = arg.name;
if (arg.optional || arg.default) {
argStr += "?";
}
if (arg.type || arg.tsType) {
argStr += `: ${getTsType(arg, opts)}`;
}
return argStr;
}).join(", ") || "";
}
function generateJSDoc(schema, opts) {
opts.defaultDescription = opts.defaultDescription || opts.defaultDescrption;
let buff = [];
if (schema.title) {
buff.push(schema.title, "");
}
if (schema.description) {
buff.push(schema.description, "");
} else if (opts.defaultDescription && schema.type !== "object") {
buff.push(opts.defaultDescription, "");
}
if (opts.addDefaults && schema.type !== "object" && schema.type !== "any" && !(Array.isArray(schema.default) && schema.default.length === 0)) {
const stringified = JSON.stringify(schema.default);
if (stringified) {
buff.push(`@default ${stringified.replace(/\*\//g, String.raw`*\/`)}`);
}
}
for (const key in schema) {
if (!SCHEMA_KEYS.has(key)) {
buff.push("", `@${key} ${schema[key]}`);
}
}
if (Array.isArray(schema.tags)) {
for (const tag of schema.tags) {
if (tag !== "@untyped") {
buff.push("", tag);
}
}
}
buff = buff.flatMap((i) => i.split("\n"));
if (buff.length > 0) {
return buff.length === 1 ? ["/** " + buff[0] + " */"] : ["/**", ...buff.map((i) => ` * ${i}`), "*/"];
}
return [];
}
function isRequired(schema, key, opts) {
if (Array.isArray(schema.required) && schema.required.includes(key)) {
return true;
}
return !opts.partial;
}
function generateMarkdown(schema) {
return _generateMarkdown(schema, "", "").join("\n");
}
function _generateMarkdown(schema, title, level) {
const lines = [];
lines.push(`${level} ${title}`);
if (schema.type === "object") {
for (const key in schema.properties) {
const val = schema.properties[key];
lines.push("", ..._generateMarkdown(val, `\`${key}\``, level + "#"));
}
return lines;
}
lines.push(
`- **Type**: \`${schema.markdownType || schema.tsType || schema.type}\``
);
if ("default" in schema) {
lines.push(`- **Default**: \`${JSON.stringify(schema.default)}\``);
}
lines.push("");
if (schema.title) {
lines.push("> " + schema.title, "");
}
if (schema.type === "function") {
lines.push("```ts", genFunctionType(schema, {}), "```", "");
}
if (schema.description) {
lines.push("", schema.description, "");
}
return lines;
}
export { generateMarkdown, generateTypes };