release: WRNexusJS 0.6.0

This commit is contained in:
2026-08-01 01:09:58 +05:30
parent 3e565e8d03
commit 687d345882
502 changed files with 33038 additions and 11358 deletions
+75 -16
View File
@@ -1,20 +1,14 @@
import { readdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { format, resolveConfig } from "prettier";
const uiRoot = join(import.meta.dirname, "..", "packages", "ui");
const componentsDir = join(uiRoot, "components");
const catalog = JSON.parse(readFileSync(join(uiRoot, "component-catalog.json"), "utf8"));
const catalogPath = join(uiRoot, "component-catalog.json");
const catalog = JSON.parse(readFileSync(catalogPath, "utf8"));
const metadata = new Map(catalog.components.map((entry) => [entry.name, entry]));
async function writeFormatted(path, source, parser) {
const config = (await resolveConfig(path)) ?? {};
const formatted = await format(source, {
...config,
filepath: path,
parser,
});
writeFileSync(path, formatted);
async function writeFormatted(path, source) {
writeFileSync(path, source);
}
function block(source, keyword) {
@@ -34,9 +28,9 @@ function propsOf(source) {
for (const line of block(source, "props").split(/\r?\n/)) {
const match = line
.trim()
.match(/^([A-Za-z][A-Za-z0-9_]*)(?:\s*:\s*([^=]+?))?\s*(?:=\s*(.+))?$/);
.match(/^([A-Za-z][A-Za-z0-9_]*)(\?)?(?:\s*:\s*([^=]+?))?\s*(?:=\s*(.+))?$/);
if (!match) continue;
const [, name, annotation, rawDefault] = match;
const [, name, optional, annotation, rawDefault] = match;
const value = rawDefault?.trim();
const type =
annotation?.trim() ||
@@ -45,11 +39,58 @@ function propsOf(source) {
: /^-?\d+(?:\.\d+)?$/.test(value ?? "")
? "number"
: "string");
props.push({ name, type, required: value === undefined, default: value ?? null });
const options = [...type.matchAll(/["']([^"']+)["']/g)].map((entry) => entry[1]);
props.push({
name,
type,
required: optional !== "?" && value === undefined,
default: value ?? null,
options,
});
}
return props;
}
function outputsOf(source) {
const body = block(source, "outputs");
const outputs = [];
let index = 0;
while (index < body.length) {
while (index < body.length && /\s/.test(body[index])) index++;
if (index >= body.length) break;
const nameMatch = /^[A-Za-z][A-Za-z0-9_]*/.exec(body.slice(index));
if (!nameMatch) {
index++;
continue;
}
const name = nameMatch[0];
index += name.length;
while (index < body.length && /\s/.test(body[index])) index++;
if (body[index] !== "(") {
index++;
continue;
}
const start = ++index;
let depth = 1;
let quote = null;
for (; index < body.length && depth > 0; index++) {
const char = body[index];
if (quote) {
if (char === "\\") index++;
else if (char === quote) quote = null;
continue;
}
if (char === '"' || char === "'" || char === "`") quote = char;
else if (char === "(") depth++;
else if (char === ")") depth--;
}
const parameters = body.slice(start, index - 1).trim();
const payloadMatch = /^payload\??\s*:\s*([\s\S]+)$/.exec(parameters);
outputs.push({ name, payloadType: payloadMatch?.[1]?.trim() ?? null });
}
return outputs;
}
function words(name) {
return name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase();
}
@@ -84,13 +125,19 @@ const components = [...sourceByName.values()]
const slots = [...source.matchAll(/<slot(?:\s+name="([^"]+)")?/g)].map(
(match) => match[1] ?? "default",
);
const events = [
const outputs = outputsOf(source);
const legacyEvents = [
...new Set(
[...source.matchAll(/@event\s+([A-Za-z][A-Za-z0-9_]*)\s*=\s*function/g)].map(
(match) => match[1],
),
),
];
for (const name of legacyEvents) {
if (!outputs.some((output) => output.name === name)) {
outputs.push({ name, payloadType: "unknown" });
}
}
return {
name,
mount: name,
@@ -98,12 +145,24 @@ const components = [...sourceByName.values()]
purpose: entry?.purpose ?? `Reusable ${words(name)} component.`,
props: propsOf(source),
slots: [...new Set(slots)],
events,
outputs,
events: outputs.map((output) => output.name),
source: `components/${file}`,
};
})
.sort((left, right) => left.name.localeCompare(right.name));
const catalogComponents = components.map((component) => ({
name: component.name,
category: component.category,
purpose: component.purpose,
}));
await writeFormatted(
catalogPath,
JSON.stringify({ ...catalog, components: catalogComponents }, null, 2) + "\n",
"json",
);
const referencePath = join(uiRoot, "component-reference.json");
await writeFormatted(
referencePath,
@@ -140,7 +199,7 @@ for (const category of [...new Set(components.map((component) => component.categ
`- Mount: \`data-component="${component.mount}"\``,
`- Props: ${props}`,
`- Slots: ${component.slots.length ? component.slots.map((slot) => `\`${slot}\``).join(", ") : "None"}`,
`- Events: ${component.events.length ? component.events.map((event) => `\`${event}\``).join(", ") : "None"}`,
`- Outputs: ${component.outputs.length ? component.outputs.map((output) => `\`${output.name}(${output.payloadType ?? ""})\``).join(", ") : "None"}`,
"",
);
}