mirror of
https://github.com/huntabyte/shadcn-svelte.git
synced 2026-09-14 19:33:46 +08:00
235 lines
7.6 KiB
TypeScript
235 lines
7.6 KiB
TypeScript
import template from "lodash.template";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import prettier from "prettier";
|
|
import { rimraf } from "rimraf";
|
|
import {
|
|
componentsJsonSchema,
|
|
registryItemSchema,
|
|
registrySchema,
|
|
type Registry,
|
|
type RegistryItem,
|
|
type RegistryItemType,
|
|
} from "@shadcn-svelte/registry";
|
|
import { generateBaseColorTemplate, getColorsData } from "../src/lib/components/colors/colors.js";
|
|
import { buildRegistry } from "./registry.js";
|
|
import { baseColors } from "../src/lib/registry/registry-colors.js";
|
|
import { THEME_STYLES_WITH_VARIABLES } from "../src/lib/registry/templates.js";
|
|
import { baseColorsOKLCH } from "../src/lib/registry/registry-base-colors.js";
|
|
import { toJSONSchema } from "zod/v4";
|
|
|
|
const prettierConfig = await prettier.resolveConfig(import.meta.url);
|
|
if (!prettierConfig) throw new Error("Failed to resolve prettier config.");
|
|
|
|
const REGISTRY_PATH = path.resolve("static", "registry");
|
|
const THEMES_CSS_PATH = path.resolve("static");
|
|
|
|
function writeFileWithDirs(
|
|
filePath: string,
|
|
data: string,
|
|
options: Parameters<typeof fs.writeFileSync>[2] = {}
|
|
): void {
|
|
// Create directory path if it doesn't exist
|
|
const dirname = path.dirname(filePath);
|
|
fs.mkdirSync(dirname, { recursive: true });
|
|
|
|
// Write the file
|
|
fs.writeFileSync(filePath, data, options);
|
|
}
|
|
|
|
export async function build(): Promise<void> {
|
|
const registry = await buildRegistry();
|
|
|
|
const selfReferenced = registry.filter((item) => item.registryDependencies.includes(item.name));
|
|
const selfReferenceError = selfReferenced
|
|
.map((item) => `Registry item '${item.name}' depends on itself`)
|
|
.join("\n");
|
|
if (selfReferenceError) {
|
|
throw new Error(selfReferenceError);
|
|
}
|
|
|
|
const initItem: RegistryItem = {
|
|
name: "init",
|
|
type: "registry:style",
|
|
devDependencies: ["tailwind-variants", "@lucide/svelte", "tw-animate-css"],
|
|
registryDependencies: ["utils"],
|
|
files: [],
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Build `registry.json` file.
|
|
// ----------------------------------------------------------------------------
|
|
const result = registrySchema.parse(
|
|
{
|
|
$schema: "./static/schema/registry.json",
|
|
name: "shadcn-svelte",
|
|
homepage: "https://shadcn-svelte.com",
|
|
aliases: {
|
|
lib: "$lib/registry/lib",
|
|
ui: "$lib/registry/ui",
|
|
components: "./components",
|
|
hooks: "$lib/registry/hooks",
|
|
utils: "$lib/utils",
|
|
},
|
|
// TODO: remove when moving from `next` to `latest`
|
|
overrideDependencies: ["vaul-svelte@next"],
|
|
items: [initItem, ...registry],
|
|
} as Registry,
|
|
// maintains the schema defined property order
|
|
{ jitless: true }
|
|
);
|
|
|
|
const ITEM_TYPES: RegistryItemType[] = [
|
|
"registry:ui",
|
|
"registry:hook",
|
|
"registry:style",
|
|
"registry:lib",
|
|
"registry:block",
|
|
];
|
|
const filteredItems = result.items.filter((item) => ITEM_TYPES.includes(item.type));
|
|
const registryJsonPath = path.resolve("registry.json");
|
|
|
|
const registryJson = JSON.stringify({ ...result, items: filteredItems }, null, "\t");
|
|
const formatted = await prettier.format(registryJson, {
|
|
...prettierConfig,
|
|
filepath: registryJsonPath,
|
|
});
|
|
fs.writeFileSync(registryJsonPath, formatted, "utf8");
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Build __registry__/blocks.ts
|
|
// ----------------------------------------------------------------------------
|
|
rimraf.sync(path.resolve("src", "__registry__"));
|
|
|
|
let blocksIndex = `
|
|
// This file is autogenerated by scripts/build-registry.ts
|
|
// Do not edit this file directly.
|
|
export const blocks = [
|
|
`; // Creates block index files
|
|
for (const block of result.items) {
|
|
if (block.type !== "registry:block" || block.name.startsWith("chart-")) continue;
|
|
|
|
blocksIndex += `"${block.name}",`;
|
|
}
|
|
|
|
blocksIndex += "\n] as const;\n";
|
|
const blocksPath = path.resolve("src", "__registry__", "blocks.ts");
|
|
writeFileWithDirs(blocksPath, blocksIndex);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Build __registry__/index.js.
|
|
// ----------------------------------------------------------------------------
|
|
let index = `
|
|
// This file is autogenerated by scripts/build-registry.ts
|
|
// Do not edit this file directly.
|
|
export const Index = {`;
|
|
|
|
// TODO: fix later - we should either add these calendar examples to
|
|
// the `lib/registry/examples` dir, or... do something else?
|
|
const CALENDAR_EXAMPLES = ["02", "13", "22", "24", "29"].map((n) => `calendar-${n}`);
|
|
|
|
// Build style index.
|
|
for (const item of result.items) {
|
|
if (item.type !== "registry:example" && !CALENDAR_EXAMPLES.includes(item.name)) {
|
|
continue;
|
|
}
|
|
|
|
const resolveFiles = item.files.map((file) => file.path.replace("src/", "../"));
|
|
|
|
index += `
|
|
"${item.name}": {
|
|
files: [${resolveFiles.map((file) => `"${file.replaceAll(path.sep, "/")}"`)}],
|
|
},`;
|
|
}
|
|
|
|
index += `
|
|
}
|
|
`;
|
|
|
|
// Write style index.
|
|
const registryPath = path.resolve("src", "__registry__", "index.js");
|
|
rimraf.sync(registryPath);
|
|
writeFileWithDirs(registryPath, index);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Build registry/colors/index.json.
|
|
// ----------------------------------------------------------------------------
|
|
const colorsTargetPath = path.join(REGISTRY_PATH, "colors");
|
|
rimraf.sync(colorsTargetPath);
|
|
if (!fs.existsSync(colorsTargetPath)) {
|
|
fs.mkdirSync(colorsTargetPath, { recursive: true });
|
|
}
|
|
|
|
const colorsData = getColorsData();
|
|
|
|
writeFileWithDirs(
|
|
path.join(colorsTargetPath, "index.json"),
|
|
JSON.stringify(colorsData, null, "\t"),
|
|
"utf-8"
|
|
);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Build registry/colors/[base].json.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
const themeCSS = [];
|
|
for (const baseColor of baseColors) {
|
|
const base = generateBaseColorTemplate(baseColor);
|
|
const zincCssVars = generateBaseColorTemplate("zinc");
|
|
|
|
themeCSS.push(
|
|
template(THEME_STYLES_WITH_VARIABLES)({
|
|
colors: {
|
|
...zincCssVars.cssVars,
|
|
...baseColorsOKLCH[baseColor as keyof typeof baseColorsOKLCH],
|
|
},
|
|
theme: baseColor,
|
|
})
|
|
);
|
|
|
|
if (["zinc", "stone", "slate", "gray", "neutral"].includes(baseColor)) {
|
|
writeFileWithDirs(
|
|
path.join(REGISTRY_PATH, "colors", `${baseColor}.json`),
|
|
JSON.stringify(base, null, "\t"),
|
|
"utf-8"
|
|
);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Build registry/themes.css
|
|
// ----------------------------------------------------------------------------
|
|
|
|
writeFileWithDirs(path.join(THEMES_CSS_PATH, `themes.css`), themeCSS.join("\n\n"), "utf-8");
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Build static/schema.json
|
|
// ----------------------------------------------------------------------------
|
|
const componentsJSON = toJSONSchema(componentsJsonSchema);
|
|
writeFileWithDirs(
|
|
path.resolve("static", "schema.json"),
|
|
JSON.stringify(componentsJSON, null, "\t")
|
|
);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Build static/schema/registry.json
|
|
// ----------------------------------------------------------------------------
|
|
const SCHEMA_DIR = path.resolve("static", "schema");
|
|
writeFileWithDirs(
|
|
path.resolve(SCHEMA_DIR, "registry.json"),
|
|
JSON.stringify(toJSONSchema(registrySchema), null, "\t")
|
|
);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Build static/schema/registry-item.json
|
|
// ----------------------------------------------------------------------------
|
|
writeFileWithDirs(
|
|
path.resolve(SCHEMA_DIR, "registry-item.json"),
|
|
JSON.stringify(toJSONSchema(registryItemSchema), null, "\t")
|
|
);
|
|
}
|
|
|
|
if (process.argv.includes("build-registry")) {
|
|
build();
|
|
}
|