inventive-ui 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -27
- package/dist/index.js +367 -1125
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/assets.config.defaults.json +0 -28
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import
|
|
4
|
+
import path25 from "path";
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
|
|
7
7
|
// src/utils/ui.ts
|
|
@@ -190,7 +190,7 @@ var BANNER_COMPACT = [
|
|
|
190
190
|
var FULL_BANNER_WIDTH = 101;
|
|
191
191
|
function resolveCliVersion() {
|
|
192
192
|
try {
|
|
193
|
-
return true ? "0.0.
|
|
193
|
+
return true ? "0.0.12" : "1.0.0";
|
|
194
194
|
} catch {
|
|
195
195
|
return "1.0.0";
|
|
196
196
|
}
|
|
@@ -373,8 +373,8 @@ function resolveApiBaseUrl() {
|
|
|
373
373
|
);
|
|
374
374
|
}
|
|
375
375
|
if (parsed.pathname && parsed.pathname !== "/" && parsed.pathname !== "") {
|
|
376
|
-
const
|
|
377
|
-
if (
|
|
376
|
+
const path26 = parsed.pathname.replace(/\/+$/, "");
|
|
377
|
+
if (path26 && !/^\/[a-zA-Z0-9._/-]+$/.test(path26)) {
|
|
378
378
|
throw new CLIError(
|
|
379
379
|
"IUI_API_URL path contains invalid characters.",
|
|
380
380
|
"Use a simple path prefix such as /v1"
|
|
@@ -434,7 +434,7 @@ var COMPONENTS_PACKAGE = "@inventive-ui/components";
|
|
|
434
434
|
var NPM_SCOPE = "@inventive-ui";
|
|
435
435
|
var IUI_DIR = ".iui";
|
|
436
436
|
var GLOBAL_CONFIG_DIR = ".iui";
|
|
437
|
-
var PROJECT_CONFIG_FILE = "
|
|
437
|
+
var PROJECT_CONFIG_FILE = "theme.config.ts";
|
|
438
438
|
var REQUIRED_REACT_MAJOR = 19;
|
|
439
439
|
var REACT_SAFE_VERSION = "^19.0.0";
|
|
440
440
|
var REQUIRED_VITE_MAJOR = 6;
|
|
@@ -596,7 +596,7 @@ var EMOJI_FAMILIES = [
|
|
|
596
596
|
"twitter",
|
|
597
597
|
"native"
|
|
598
598
|
];
|
|
599
|
-
var DEFAULT_EMOJI_SKIN_TONE = "
|
|
599
|
+
var DEFAULT_EMOJI_SKIN_TONE = "mediumLight";
|
|
600
600
|
var EMOJI_FAMILY_LABELS = {
|
|
601
601
|
apple: "Apple",
|
|
602
602
|
google: "Google",
|
|
@@ -763,22 +763,6 @@ function writeJsonRestricted(filePath, data) {
|
|
|
763
763
|
|
|
764
764
|
// src/utils/security/paths.ts
|
|
765
765
|
import path4 from "path";
|
|
766
|
-
function assertWithinRoot(rootDir, targetPath, label) {
|
|
767
|
-
const root = path4.resolve(rootDir);
|
|
768
|
-
const target = path4.resolve(targetPath);
|
|
769
|
-
const rel = path4.relative(root, target);
|
|
770
|
-
if (rel.startsWith("..") || path4.isAbsolute(rel)) {
|
|
771
|
-
throw new CLIError(
|
|
772
|
-
`Unsafe ${label} path: ${targetPath}`,
|
|
773
|
-
`Path must stay within ${rootDir}`
|
|
774
|
-
);
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
function resolveWithinRoot(rootDir, ...segments) {
|
|
778
|
-
const joined = path4.join(rootDir, ...segments);
|
|
779
|
-
assertWithinRoot(rootDir, joined, "file");
|
|
780
|
-
return joined;
|
|
781
|
-
}
|
|
782
766
|
|
|
783
767
|
// src/utils/security/process.ts
|
|
784
768
|
import fs5 from "fs-extra";
|
|
@@ -1428,7 +1412,7 @@ function resolveFrameworkScriptsDir(startCwd) {
|
|
|
1428
1412
|
if (existsSync(loader)) return scriptsDir;
|
|
1429
1413
|
}
|
|
1430
1414
|
throw new CLIError(
|
|
1431
|
-
`Cannot scaffold
|
|
1415
|
+
`Cannot scaffold theme.config.ts: ${FRAMEWORK_PACKAGE} is not installed or is missing scripts/load-framework-theme-defaults.mjs.`
|
|
1432
1416
|
);
|
|
1433
1417
|
}
|
|
1434
1418
|
function buildProjectConfigSource(cwd = process.cwd()) {
|
|
@@ -1934,32 +1918,12 @@ function patchProjectConfigBuildBlock(content) {
|
|
|
1934
1918
|
import ts2 from "typescript";
|
|
1935
1919
|
|
|
1936
1920
|
// src/utils/security/identifiers.ts
|
|
1937
|
-
var SLUG_RE = /^[a-z][a-z0-9-]*$/;
|
|
1938
1921
|
var JS_IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
1939
|
-
var NPM_SCOPE_IMPORT_RE = /^@inventive-ui\/[a-z0-9][a-z0-9._-]*$/;
|
|
1940
|
-
var NPM_COMPONENT_SUBPATH_RE = /^@inventive-ui\/components\/[A-Za-z][A-Za-z0-9-]*$/;
|
|
1941
|
-
function assertComponentSlug(slug) {
|
|
1942
|
-
if (!SLUG_RE.test(slug)) {
|
|
1943
|
-
throw new CLIError(
|
|
1944
|
-
`Invalid component slug: "${slug}"`,
|
|
1945
|
-
"Use lowercase letters, numbers, and hyphens (e.g. button, input)."
|
|
1946
|
-
);
|
|
1947
|
-
}
|
|
1948
|
-
}
|
|
1949
1922
|
function assertJsIdentifier(name, label) {
|
|
1950
1923
|
if (!JS_IDENTIFIER_RE.test(name)) {
|
|
1951
1924
|
throw new CLIError(`Invalid ${label}: "${name}"`);
|
|
1952
1925
|
}
|
|
1953
1926
|
}
|
|
1954
|
-
function assertImportSpecifier(specifier) {
|
|
1955
|
-
if (NPM_SCOPE_IMPORT_RE.test(specifier)) return;
|
|
1956
|
-
if (NPM_COMPONENT_SUBPATH_RE.test(specifier)) return;
|
|
1957
|
-
if (/^@inventive-ui\/[a-z0-9][a-z0-9-]*$/.test(specifier)) return;
|
|
1958
|
-
throw new CLIError(`Unsafe import specifier: "${specifier}"`);
|
|
1959
|
-
}
|
|
1960
|
-
function escapeTsStringLiteral(value) {
|
|
1961
|
-
return JSON.stringify(value);
|
|
1962
|
-
}
|
|
1963
1927
|
function sanitizePackageVersionHeader(value) {
|
|
1964
1928
|
if (!value) return null;
|
|
1965
1929
|
const trimmed = value.trim();
|
|
@@ -2043,7 +2007,6 @@ function mergeComponentConfigContent(source, manifest) {
|
|
|
2043
2007
|
// src/utils/config-patch/tsconfig-iui.ts
|
|
2044
2008
|
import path7 from "path";
|
|
2045
2009
|
import fs6 from "fs-extra";
|
|
2046
|
-
var IUI_TS_ROOT_FILES = ["iui.config.ts", "component.config.ts"];
|
|
2047
2010
|
function isSolutionStyleTsconfig(config) {
|
|
2048
2011
|
const refs = config.references;
|
|
2049
2012
|
return Array.isArray(refs) && refs.length > 0;
|
|
@@ -2101,7 +2064,8 @@ function patchSolutionStyleTsconfigForIui(cwd) {
|
|
|
2101
2064
|
if (!isSolutionStyleTsconfig(existing)) return false;
|
|
2102
2065
|
const repairedRoot = repairSolutionStyleRootTsconfig(cwd);
|
|
2103
2066
|
const appPath = resolveAppTsconfigPath(cwd, existing);
|
|
2104
|
-
const
|
|
2067
|
+
const themeFile = fs6.existsSync(path7.join(cwd, "iui.config.ts")) && !fs6.existsSync(path7.join(cwd, "theme.config.ts")) ? "iui.config.ts" : "theme.config.ts";
|
|
2068
|
+
const patchedApp = appPath ? patchJsonInclude(appPath, [themeFile, "component.config.ts"]) : false;
|
|
2105
2069
|
return repairedRoot || patchedApp;
|
|
2106
2070
|
}
|
|
2107
2071
|
|
|
@@ -2119,10 +2083,9 @@ var iuiThemeConfigSchema = z2.object({
|
|
|
2119
2083
|
}).strict();
|
|
2120
2084
|
var IuiThemeConfigSchema = iuiThemeConfigSchema.refine(
|
|
2121
2085
|
(data) => !("assets" in data),
|
|
2122
|
-
{ message: "
|
|
2086
|
+
{ message: "theme.config must not contain an assets key \u2014 use assets.config.json" }
|
|
2123
2087
|
);
|
|
2124
2088
|
var AssetsConfigSchema = z2.object({
|
|
2125
|
-
binding: z2.enum(["lazy", "scanned"]).optional(),
|
|
2126
2089
|
preload: z2.enum(["none", "configured", "scanned"]).optional(),
|
|
2127
2090
|
icon: z2.object({
|
|
2128
2091
|
library: z2.string().optional(),
|
|
@@ -2195,11 +2158,14 @@ function stripAssetsFromIuiConfig(content) {
|
|
|
2195
2158
|
return next;
|
|
2196
2159
|
}
|
|
2197
2160
|
function checkIuiConfigTierBleed(cwd = process.cwd(), options = {}) {
|
|
2198
|
-
const configPath = path8.join(
|
|
2161
|
+
const configPath = path8.join(
|
|
2162
|
+
cwd,
|
|
2163
|
+
fs7.existsSync(path8.join(cwd, PROJECT_CONFIG_FILE)) || !fs7.existsSync(path8.join(cwd, "iui.config.ts")) ? PROJECT_CONFIG_FILE : "iui.config.ts"
|
|
2164
|
+
);
|
|
2199
2165
|
if (!fs7.existsSync(configPath)) {
|
|
2200
2166
|
return {
|
|
2201
2167
|
ok: false,
|
|
2202
|
-
summary: "
|
|
2168
|
+
summary: "theme.config.ts not found",
|
|
2203
2169
|
details: "Run iui init to scaffold project config."
|
|
2204
2170
|
};
|
|
2205
2171
|
}
|
|
@@ -2214,7 +2180,7 @@ function checkIuiConfigTierBleed(cwd = process.cwd(), options = {}) {
|
|
|
2214
2180
|
}
|
|
2215
2181
|
}
|
|
2216
2182
|
if (issues.length === 0) {
|
|
2217
|
-
return { ok: true, summary: "
|
|
2183
|
+
return { ok: true, summary: "theme.config.ts tier boundaries are valid" };
|
|
2218
2184
|
}
|
|
2219
2185
|
if (options.autoFix) {
|
|
2220
2186
|
const fixed = stripAssetsFromIuiConfig(content);
|
|
@@ -2227,14 +2193,14 @@ function checkIuiConfigTierBleed(cwd = process.cwd(), options = {}) {
|
|
|
2227
2193
|
if (remaining.length === 0 && /\bbuild\s*:\s*\{/.test(content)) {
|
|
2228
2194
|
return {
|
|
2229
2195
|
ok: true,
|
|
2230
|
-
summary: "
|
|
2196
|
+
summary: "theme.config.ts repaired (removed assets tier bleed)"
|
|
2231
2197
|
};
|
|
2232
2198
|
}
|
|
2233
2199
|
}
|
|
2234
2200
|
}
|
|
2235
2201
|
return {
|
|
2236
2202
|
ok: false,
|
|
2237
|
-
summary: "
|
|
2203
|
+
summary: "theme.config.ts violates three-config tier boundaries",
|
|
2238
2204
|
details: issues.map((i) => `- ${i}`).join("\n")
|
|
2239
2205
|
};
|
|
2240
2206
|
}
|
|
@@ -2441,9 +2407,6 @@ function componentManifestPath(cwd) {
|
|
|
2441
2407
|
function packageManifestPath(cwd) {
|
|
2442
2408
|
return metaPath("packages.json", cwd);
|
|
2443
2409
|
}
|
|
2444
|
-
function slotManifestPath(cwd) {
|
|
2445
|
-
return metaPath("slots.json", cwd);
|
|
2446
|
-
}
|
|
2447
2410
|
function readProjectJsonStrict(p, label) {
|
|
2448
2411
|
if (!fs8.existsSync(p)) {
|
|
2449
2412
|
throw new CLIError(`Missing ${label}.`, "Run iui init to initialize the project.");
|
|
@@ -2528,12 +2491,6 @@ function mergeAssetSlotWithTemplate(slot, templateSlot) {
|
|
|
2528
2491
|
function seedAssetsOutputFromTemplate(output) {
|
|
2529
2492
|
const template = loadAssetsConfigTemplate();
|
|
2530
2493
|
for (const [key, tplVal] of Object.entries(template)) {
|
|
2531
|
-
if (key === "binding") {
|
|
2532
|
-
if (output.binding === void 0 && tplVal !== void 0) {
|
|
2533
|
-
output.binding = tplVal;
|
|
2534
|
-
}
|
|
2535
|
-
continue;
|
|
2536
|
-
}
|
|
2537
2494
|
if (typeof tplVal === "object" && tplVal !== null && !Array.isArray(tplVal)) {
|
|
2538
2495
|
output[key] = mergeAssetSlotWithTemplate(
|
|
2539
2496
|
output[key],
|
|
@@ -2541,13 +2498,6 @@ function seedAssetsOutputFromTemplate(output) {
|
|
|
2541
2498
|
);
|
|
2542
2499
|
}
|
|
2543
2500
|
}
|
|
2544
|
-
if (output.binding === "scanned") {
|
|
2545
|
-
output.preload = output.preload ?? "scanned";
|
|
2546
|
-
const icon = output.icon;
|
|
2547
|
-
if (icon && typeof icon === "object" && !Array.isArray(icon)) {
|
|
2548
|
-
icon.preload = icon.preload ?? "scanned";
|
|
2549
|
-
}
|
|
2550
|
-
}
|
|
2551
2501
|
}
|
|
2552
2502
|
function assetsConfigPath(cwd) {
|
|
2553
2503
|
return path10.join(resolveIuiProjectRoot(cwd ?? process.cwd()), ASSETS_CONFIG_FILE);
|
|
@@ -2707,9 +2657,6 @@ function writeAssetsConfig(cwd = process.cwd()) {
|
|
|
2707
2657
|
delete output[legacyKey];
|
|
2708
2658
|
}
|
|
2709
2659
|
}
|
|
2710
|
-
if (output.binding === void 0 && Object.keys(assets2).length > 0 && projectHasViteTooling(cwd)) {
|
|
2711
|
-
output.binding = "scanned";
|
|
2712
|
-
}
|
|
2713
2660
|
seedAssetsOutputFromTemplate(output);
|
|
2714
2661
|
writeJson(assetsConfigPath(cwd), output);
|
|
2715
2662
|
try {
|
|
@@ -2718,14 +2665,6 @@ function writeAssetsConfig(cwd = process.cwd()) {
|
|
|
2718
2665
|
} catch {
|
|
2719
2666
|
}
|
|
2720
2667
|
}
|
|
2721
|
-
function readSlotManifest(cwd) {
|
|
2722
|
-
const p = slotManifestPath(cwd);
|
|
2723
|
-
if (!fs8.existsSync(p)) return {};
|
|
2724
|
-
return readProjectJsonStrict(p, ".iui/slots.json");
|
|
2725
|
-
}
|
|
2726
|
-
function writeSlotManifest(manifest, cwd) {
|
|
2727
|
-
writeJson(slotManifestPath(cwd), manifest);
|
|
2728
|
-
}
|
|
2729
2668
|
function readComponentPackageManifest(cwd = process.cwd()) {
|
|
2730
2669
|
const pkgDir = resolvePackageDir("@inventive-ui/components", cwd);
|
|
2731
2670
|
if (!pkgDir) return null;
|
|
@@ -2762,12 +2701,19 @@ function registryItemsMap(manifest) {
|
|
|
2762
2701
|
}
|
|
2763
2702
|
return map;
|
|
2764
2703
|
}
|
|
2704
|
+
function resolveProjectConfigPath(root) {
|
|
2705
|
+
const current = path10.join(root, PROJECT_CONFIG_FILE);
|
|
2706
|
+
if (fs8.existsSync(current)) return current;
|
|
2707
|
+
const previous = path10.join(root, "iui.config.ts");
|
|
2708
|
+
if (fs8.existsSync(previous)) return previous;
|
|
2709
|
+
return current;
|
|
2710
|
+
}
|
|
2765
2711
|
function writeProjectConfig(cwd = process.cwd()) {
|
|
2766
2712
|
const configPath = path10.join(cwd, PROJECT_CONFIG_FILE);
|
|
2767
2713
|
atomicWriteFile(configPath, buildProjectConfigSource(cwd));
|
|
2768
2714
|
}
|
|
2769
2715
|
function ensureProjectConfigBuildBlock(cwd = process.cwd()) {
|
|
2770
|
-
const configPath =
|
|
2716
|
+
const configPath = resolveProjectConfigPath(resolveIuiProjectRoot(cwd));
|
|
2771
2717
|
if (!fs8.existsSync(configPath)) return false;
|
|
2772
2718
|
const before = fs8.readFileSync(configPath, "utf-8");
|
|
2773
2719
|
const result = patchProjectConfigBuildBlock(before);
|
|
@@ -2777,7 +2723,7 @@ function ensureProjectConfigBuildBlock(cwd = process.cwd()) {
|
|
|
2777
2723
|
}
|
|
2778
2724
|
function ensureProjectConfig(cwd = process.cwd()) {
|
|
2779
2725
|
const root = resolveIuiProjectRoot(cwd);
|
|
2780
|
-
const configPath =
|
|
2726
|
+
const configPath = resolveProjectConfigPath(root);
|
|
2781
2727
|
if (!fs8.existsSync(configPath)) {
|
|
2782
2728
|
writeProjectConfig(root);
|
|
2783
2729
|
return "scaffolded";
|
|
@@ -2907,7 +2853,8 @@ function writeFlatProjectTsConfig(framework, cwd = process.cwd()) {
|
|
|
2907
2853
|
}
|
|
2908
2854
|
const include = Array.isArray(existing.include) ? [...existing.include.map(String)] : [];
|
|
2909
2855
|
if (!include.includes("src")) include.push("src");
|
|
2910
|
-
const
|
|
2856
|
+
const themeConfigFile = fs8.existsSync(path10.join(cwd, "iui.config.ts")) && !fs8.existsSync(path10.join(cwd, PROJECT_CONFIG_FILE)) ? "iui.config.ts" : PROJECT_CONFIG_FILE;
|
|
2857
|
+
const rootConfigFiles = [themeConfigFile, "component.config.ts"];
|
|
2911
2858
|
for (const rootFile of rootConfigFiles) {
|
|
2912
2859
|
if (!include.includes(rootFile)) include.push(rootFile);
|
|
2913
2860
|
}
|
|
@@ -3371,13 +3318,13 @@ function ensureInventiveUiViteConfig(cwd = process.cwd()) {
|
|
|
3371
3318
|
}
|
|
3372
3319
|
|
|
3373
3320
|
// src/services/auth.ts
|
|
3374
|
-
async function api(
|
|
3375
|
-
const res = await fetch(`${API_BASE_URL}${
|
|
3321
|
+
async function api(path26, opts) {
|
|
3322
|
+
const res = await fetch(`${API_BASE_URL}${path26}`, {
|
|
3376
3323
|
...opts,
|
|
3377
3324
|
signal: opts?.signal ?? AbortSignal.timeout(API_REQUEST_TIMEOUT_MS),
|
|
3378
3325
|
headers: { "Content-Type": "application/json", ...opts?.headers }
|
|
3379
3326
|
});
|
|
3380
|
-
throwIfRateLimited(res, `calling ${
|
|
3327
|
+
throwIfRateLimited(res, `calling ${path26}`);
|
|
3381
3328
|
if (!res.ok) {
|
|
3382
3329
|
const body = await res.text().catch(() => "");
|
|
3383
3330
|
throw new CLIError(`API error ${res.status}: ${body || res.statusText}`);
|
|
@@ -3629,10 +3576,12 @@ async function promptAssetSelection(installedPackages = []) {
|
|
|
3629
3576
|
const choices = [];
|
|
3630
3577
|
for (const cat of categories) {
|
|
3631
3578
|
const inCategory = catalogue.filter((p) => p.category === cat);
|
|
3579
|
+
if (choices.length > 0) {
|
|
3580
|
+
choices.push(new inquirer.Separator(" "));
|
|
3581
|
+
}
|
|
3632
3582
|
choices.push(
|
|
3633
3583
|
new inquirer.Separator(
|
|
3634
|
-
`
|
|
3635
|
-
${brand.bold(ASSET_CATEGORY_LABELS[cat])} ${dim(`(${inCategory.length})`)}`
|
|
3584
|
+
` ${brand.bold(ASSET_CATEGORY_LABELS[cat])} ${dim(`(${inCategory.length})`)}`
|
|
3636
3585
|
)
|
|
3637
3586
|
);
|
|
3638
3587
|
for (const pkg of inCategory) {
|
|
@@ -3644,6 +3593,8 @@ async function promptAssetSelection(installedPackages = []) {
|
|
|
3644
3593
|
}
|
|
3645
3594
|
}
|
|
3646
3595
|
console.log();
|
|
3596
|
+
const terminalRows = process.stdout.rows ?? 0;
|
|
3597
|
+
const pageSize = terminalRows > 0 ? Math.max(10, Math.min(choices.length, terminalRows - 4)) : choices.length;
|
|
3647
3598
|
const { selected } = await inquirer.prompt([
|
|
3648
3599
|
{
|
|
3649
3600
|
type: "checkbox",
|
|
@@ -3651,7 +3602,7 @@ async function promptAssetSelection(installedPackages = []) {
|
|
|
3651
3602
|
message: chalk2.dim("Toggle packages to install"),
|
|
3652
3603
|
prefix: PROMPT_PREFIX,
|
|
3653
3604
|
choices,
|
|
3654
|
-
pageSize
|
|
3605
|
+
pageSize,
|
|
3655
3606
|
loop: false
|
|
3656
3607
|
}
|
|
3657
3608
|
]);
|
|
@@ -3733,7 +3684,7 @@ async function promptChooseEmojiFamily(fallbackCurrent) {
|
|
|
3733
3684
|
assertInteractivePrompt("emoji family choice");
|
|
3734
3685
|
inputBox(
|
|
3735
3686
|
"Emoji Family",
|
|
3736
|
-
"Choose the default CDN style for emoji slots. Skin tone defaults to medium-light."
|
|
3687
|
+
"Choose the default CDN style for emoji slots. Skin tone defaults to medium-light (`mediumLight`)."
|
|
3737
3688
|
);
|
|
3738
3689
|
const { chosen } = await inquirer.prompt([
|
|
3739
3690
|
{
|
|
@@ -3825,7 +3776,7 @@ async function promptText(title, hint2, placeholder, validate) {
|
|
|
3825
3776
|
}
|
|
3826
3777
|
|
|
3827
3778
|
// src/commands/init.ts
|
|
3828
|
-
import
|
|
3779
|
+
import path21 from "path";
|
|
3829
3780
|
import ora3 from "ora";
|
|
3830
3781
|
|
|
3831
3782
|
// src/services/license.ts
|
|
@@ -4792,8 +4743,8 @@ function getMajorFromVersion(version) {
|
|
|
4792
4743
|
import ora2 from "ora";
|
|
4793
4744
|
|
|
4794
4745
|
// src/services/slot-registry.ts
|
|
4795
|
-
import
|
|
4796
|
-
import
|
|
4746
|
+
import fs16 from "fs-extra";
|
|
4747
|
+
import path20 from "path";
|
|
4797
4748
|
|
|
4798
4749
|
// src/services/registry-lock.ts
|
|
4799
4750
|
import fs11 from "fs";
|
|
@@ -4879,113 +4830,107 @@ async function withRegistryLock(cwd, operation) {
|
|
|
4879
4830
|
}
|
|
4880
4831
|
}
|
|
4881
4832
|
|
|
4882
|
-
// src/services/
|
|
4883
|
-
import
|
|
4884
|
-
import
|
|
4833
|
+
// src/services/legacy-slot-cleanup.ts
|
|
4834
|
+
import fs12 from "fs-extra";
|
|
4835
|
+
import path16 from "path";
|
|
4885
4836
|
|
|
4886
|
-
// src/
|
|
4837
|
+
// src/services/generated-paths.ts
|
|
4887
4838
|
import path15 from "path";
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4839
|
+
function iuiProjectRoot2(cwd) {
|
|
4840
|
+
return resolveIuiProjectRoot(cwd);
|
|
4841
|
+
}
|
|
4842
|
+
function generatedIuiDir(cwd) {
|
|
4843
|
+
return path15.join(iuiProjectRoot2(cwd), ".iui", "generated");
|
|
4844
|
+
}
|
|
4845
|
+
|
|
4846
|
+
// src/services/legacy-slot-cleanup.ts
|
|
4847
|
+
var MANAGED_MARKER = /@iui-managed|Managed by iui/;
|
|
4848
|
+
function isManagedFile(filePath) {
|
|
4895
4849
|
try {
|
|
4896
|
-
return fs12.
|
|
4850
|
+
return MANAGED_MARKER.test(fs12.readFileSync(filePath, "utf-8"));
|
|
4897
4851
|
} catch {
|
|
4898
|
-
return
|
|
4852
|
+
return false;
|
|
4899
4853
|
}
|
|
4900
4854
|
}
|
|
4901
|
-
function
|
|
4902
|
-
if (
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
function contractEntryToBootstrapPolicy(entry) {
|
|
4908
|
-
return slotRequiresPrefetch(entry) ? "core" : "optional";
|
|
4909
|
-
}
|
|
4910
|
-
function validateSlotPrefetchPolicy(entry) {
|
|
4911
|
-
const type = entry.type ?? "?";
|
|
4912
|
-
const requires = slotRequiresPrefetch(entry);
|
|
4913
|
-
if (requires && entry.prefetch === false) {
|
|
4914
|
-
return `slot "${type}" is core/critical but prefetch is false`;
|
|
4915
|
-
}
|
|
4916
|
-
if ((entry.bootstrap === "sync" || Array.isArray(entry.profile) && entry.profile.includes("critical")) && entry.prefetch !== true) {
|
|
4917
|
-
return `slot "${type}" must declare prefetch: true (sync/critical peer hub)`;
|
|
4918
|
-
}
|
|
4919
|
-
if (!requires && entry.prefetch === true) {
|
|
4920
|
-
return `slot "${type}" declares prefetch: true but is not sync/critical`;
|
|
4855
|
+
function listFiles(dir, match) {
|
|
4856
|
+
if (!fs12.existsSync(dir)) return [];
|
|
4857
|
+
try {
|
|
4858
|
+
return fs12.readdirSync(dir).filter(match).map((file) => path16.join(dir, file));
|
|
4859
|
+
} catch {
|
|
4860
|
+
return [];
|
|
4921
4861
|
}
|
|
4922
|
-
return null;
|
|
4923
|
-
}
|
|
4924
|
-
|
|
4925
|
-
// src/utils/slot-emitters.ts
|
|
4926
|
-
function contractEntryToEmitter(entry) {
|
|
4927
|
-
const lazyAccess = entry.lazyAccess.startsWith(".") ? entry.lazyAccess : `.${entry.lazyAccess}`;
|
|
4928
|
-
return {
|
|
4929
|
-
type: entry.type,
|
|
4930
|
-
parentSlug: entry.parent,
|
|
4931
|
-
componentName: entry.component ?? entry.type,
|
|
4932
|
-
propsName: entry.props,
|
|
4933
|
-
importSpecifier: entry.import,
|
|
4934
|
-
lazyImportSpecifier: entry.lazyImport ?? entry.import,
|
|
4935
|
-
lazyAccess
|
|
4936
|
-
};
|
|
4937
4862
|
}
|
|
4938
|
-
function
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4863
|
+
function ownedDirs(iuiRoot2, packageDirs) {
|
|
4864
|
+
const generated = generatedIuiDir(iuiRoot2);
|
|
4865
|
+
return [
|
|
4866
|
+
path16.join(generated, "slots"),
|
|
4867
|
+
path16.join(generated, "assets"),
|
|
4868
|
+
...packageDirs.map((dir) => path16.join(dir, "src", "iui", "slots"))
|
|
4869
|
+
];
|
|
4943
4870
|
}
|
|
4944
|
-
function
|
|
4945
|
-
const
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
const
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
(
|
|
4871
|
+
function findStaleComponentSlotOutput(cwd, packageDirs = []) {
|
|
4872
|
+
const iuiRoot2 = iuiProjectRoot2(cwd);
|
|
4873
|
+
const generated = generatedIuiDir(iuiRoot2);
|
|
4874
|
+
const packages = [...new Set([iuiRoot2, ...packageDirs].map((dir) => path16.resolve(dir)))];
|
|
4875
|
+
const stale = [];
|
|
4876
|
+
stale.push(
|
|
4877
|
+
...listFiles(
|
|
4878
|
+
path16.join(generated, "slots"),
|
|
4879
|
+
(file) => file.endsWith(".generated.tsx") || file.endsWith(".slot.tsx")
|
|
4880
|
+
)
|
|
4881
|
+
);
|
|
4882
|
+
const helper = path16.join(generated, "slot.generated.tsx");
|
|
4883
|
+
if (fs12.existsSync(helper) && isManagedFile(helper)) stale.push(helper);
|
|
4884
|
+
stale.push(
|
|
4885
|
+
...listFiles(
|
|
4886
|
+
path16.join(generated, "assets"),
|
|
4887
|
+
(file) => file.endsWith(".bound.ts") || file === "register-bound.ts"
|
|
4888
|
+
)
|
|
4889
|
+
);
|
|
4890
|
+
const manifest = path16.join(iuiRoot2, ".iui", "slots.json");
|
|
4891
|
+
if (fs12.existsSync(manifest)) stale.push(manifest);
|
|
4892
|
+
for (const packageDir of packages) {
|
|
4893
|
+
const bridge = path16.join(packageDir, "src", "iui", "slot.tsx");
|
|
4894
|
+
if (fs12.existsSync(bridge) && isManagedFile(bridge)) stale.push(bridge);
|
|
4895
|
+
stale.push(
|
|
4896
|
+
...listFiles(
|
|
4897
|
+
path16.join(packageDir, "src", "iui", "slots"),
|
|
4898
|
+
(file) => file.endsWith(".slot.tsx")
|
|
4899
|
+
)
|
|
4961
4900
|
);
|
|
4962
|
-
if (!hasPrimary) {
|
|
4963
|
-
issues.push(`${slug}: no public slot contract entry for primary type "${slug}"`);
|
|
4964
|
-
}
|
|
4965
4901
|
}
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4902
|
+
return stale;
|
|
4903
|
+
}
|
|
4904
|
+
function removeStaleComponentSlotOutput(cwd, packageDirs = []) {
|
|
4905
|
+
const iuiRoot2 = iuiProjectRoot2(cwd);
|
|
4906
|
+
const removed = [];
|
|
4907
|
+
for (const file of findStaleComponentSlotOutput(iuiRoot2, packageDirs)) {
|
|
4908
|
+
try {
|
|
4909
|
+
fs12.removeSync(file);
|
|
4910
|
+
removed.push(file);
|
|
4911
|
+
} catch {
|
|
4971
4912
|
}
|
|
4972
|
-
emitters.push(contractEntryToEmitter(entry));
|
|
4973
4913
|
}
|
|
4974
|
-
const
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4914
|
+
for (const dir of ownedDirs(iuiRoot2, [iuiRoot2, ...packageDirs])) {
|
|
4915
|
+
try {
|
|
4916
|
+
if (fs12.existsSync(dir) && fs12.readdirSync(dir).length === 0) fs12.removeSync(dir);
|
|
4917
|
+
} catch {
|
|
4978
4918
|
}
|
|
4979
4919
|
}
|
|
4980
|
-
return
|
|
4981
|
-
emitters: [...deduped.values()].sort((a, b) => a.type.localeCompare(b.type)),
|
|
4982
|
-
issues
|
|
4983
|
-
};
|
|
4920
|
+
return removed;
|
|
4984
4921
|
}
|
|
4985
4922
|
|
|
4923
|
+
// src/services/workspace-bootstrap.ts
|
|
4924
|
+
import path19 from "path";
|
|
4925
|
+
import fs15 from "fs-extra";
|
|
4926
|
+
|
|
4927
|
+
// src/services/bootstrap.ts
|
|
4928
|
+
import fs14 from "fs-extra";
|
|
4929
|
+
import path18 from "path";
|
|
4930
|
+
|
|
4986
4931
|
// src/utils/security/fsSafe.ts
|
|
4987
4932
|
import fs13 from "fs";
|
|
4988
|
-
import
|
|
4933
|
+
import path17 from "path";
|
|
4989
4934
|
function assertNotSymlink(filePath, label) {
|
|
4990
4935
|
try {
|
|
4991
4936
|
const stat = fs13.lstatSync(filePath);
|
|
@@ -4999,11 +4944,11 @@ function assertNotSymlink(filePath, label) {
|
|
|
4999
4944
|
}
|
|
5000
4945
|
}
|
|
5001
4946
|
function safeWriteFile(filePath, content) {
|
|
5002
|
-
const dir =
|
|
4947
|
+
const dir = path17.dirname(filePath);
|
|
5003
4948
|
if (fs13.existsSync(dir)) {
|
|
5004
4949
|
assertNotSymlink(dir, "directory");
|
|
5005
4950
|
}
|
|
5006
|
-
const parent =
|
|
4951
|
+
const parent = path17.dirname(filePath);
|
|
5007
4952
|
fs13.mkdirSync(parent, { recursive: true });
|
|
5008
4953
|
if (fs13.existsSync(filePath)) {
|
|
5009
4954
|
assertNotSymlink(filePath, "file");
|
|
@@ -5011,700 +4956,13 @@ function safeWriteFile(filePath, content) {
|
|
|
5011
4956
|
atomicWriteFile(filePath, content);
|
|
5012
4957
|
}
|
|
5013
4958
|
|
|
5014
|
-
// src/services/asset-bound.ts
|
|
5015
|
-
import fs14 from "fs-extra";
|
|
5016
|
-
import path18 from "path";
|
|
5017
|
-
import { pathToFileURL } from "url";
|
|
5018
|
-
|
|
5019
|
-
// src/services/generated-paths.ts
|
|
5020
|
-
import path17 from "path";
|
|
5021
|
-
function iuiProjectRoot2(cwd) {
|
|
5022
|
-
return resolveIuiProjectRoot(cwd);
|
|
5023
|
-
}
|
|
5024
|
-
function generatedIuiDir(cwd) {
|
|
5025
|
-
return path17.join(iuiProjectRoot2(cwd), ".iui", "generated");
|
|
5026
|
-
}
|
|
5027
|
-
function generatedSlotsDir(cwd) {
|
|
5028
|
-
return path17.join(generatedIuiDir(cwd), "slots");
|
|
5029
|
-
}
|
|
5030
|
-
function generatedAssetsDir(cwd) {
|
|
5031
|
-
return path17.join(generatedIuiDir(cwd), "assets");
|
|
5032
|
-
}
|
|
5033
|
-
|
|
5034
|
-
// src/services/asset-bound.ts
|
|
5035
|
-
var LIBRARY_TO_PKG = {
|
|
5036
|
-
lucide: "icons-lucide",
|
|
5037
|
-
phosphor: "icons-phosphor",
|
|
5038
|
-
material: "icons-material",
|
|
5039
|
-
"material-icons": "icons-material",
|
|
5040
|
-
materialSymbols: "material-symbols",
|
|
5041
|
-
"material-symbols": "material-symbols"
|
|
5042
|
-
};
|
|
5043
|
-
var PKG_LOOKUP_PREFIX = {
|
|
5044
|
-
"icons-lucide": "icons/",
|
|
5045
|
-
"icons-phosphor": "icons/",
|
|
5046
|
-
"icons-material": "icons/",
|
|
5047
|
-
"material-symbols": "icons/",
|
|
5048
|
-
logos: "logos/",
|
|
5049
|
-
"color-logos": "logos/",
|
|
5050
|
-
flags: "flags/",
|
|
5051
|
-
"file-types": "types/",
|
|
5052
|
-
loaders: "loaders/",
|
|
5053
|
-
illustrations: ""
|
|
5054
|
-
};
|
|
5055
|
-
var BOUND_SPECS = [
|
|
5056
|
-
{
|
|
5057
|
-
slotType: "icon",
|
|
5058
|
-
fileName: "icons.bound.ts",
|
|
5059
|
-
exportName: "BOUND_ICONS",
|
|
5060
|
-
packages: /* @__PURE__ */ new Set([
|
|
5061
|
-
"material-symbols",
|
|
5062
|
-
"icons-lucide",
|
|
5063
|
-
"icons-phosphor",
|
|
5064
|
-
"icons-material"
|
|
5065
|
-
]),
|
|
5066
|
-
filterByDefaultIconLibrary: true
|
|
5067
|
-
},
|
|
5068
|
-
{
|
|
5069
|
-
slotType: "logo",
|
|
5070
|
-
fileName: "logos.bound.ts",
|
|
5071
|
-
exportName: "BOUND_LOGOS",
|
|
5072
|
-
packages: /* @__PURE__ */ new Set(["logos"])
|
|
5073
|
-
},
|
|
5074
|
-
{
|
|
5075
|
-
slotType: "color-logo",
|
|
5076
|
-
fileName: "color-logos.bound.ts",
|
|
5077
|
-
exportName: "BOUND_COLOR_LOGOS",
|
|
5078
|
-
packages: /* @__PURE__ */ new Set(["color-logos"])
|
|
5079
|
-
},
|
|
5080
|
-
{
|
|
5081
|
-
slotType: "flag",
|
|
5082
|
-
fileName: "flags.bound.ts",
|
|
5083
|
-
exportName: "BOUND_FLAGS",
|
|
5084
|
-
packages: /* @__PURE__ */ new Set(["flags"])
|
|
5085
|
-
},
|
|
5086
|
-
{
|
|
5087
|
-
slotType: "file-type",
|
|
5088
|
-
fileName: "file-types.bound.ts",
|
|
5089
|
-
exportName: "BOUND_FILE_TYPES",
|
|
5090
|
-
packages: /* @__PURE__ */ new Set(["file-types"])
|
|
5091
|
-
},
|
|
5092
|
-
{
|
|
5093
|
-
slotType: "loader",
|
|
5094
|
-
fileName: "loaders.bound.ts",
|
|
5095
|
-
exportName: "BOUND_LOADERS",
|
|
5096
|
-
packages: /* @__PURE__ */ new Set(["loaders"])
|
|
5097
|
-
},
|
|
5098
|
-
{
|
|
5099
|
-
slotType: "illustration",
|
|
5100
|
-
fileName: "illustrations.bound.ts",
|
|
5101
|
-
exportName: "BOUND_ILLUSTRATIONS",
|
|
5102
|
-
packages: /* @__PURE__ */ new Set(["illustrations"])
|
|
5103
|
-
}
|
|
5104
|
-
];
|
|
5105
|
-
function isAssetPackageInstalled(cwd, pkgId) {
|
|
5106
|
-
return resolvePackageDir(`@inventive-ui/${pkgId}`, cwd) !== null;
|
|
5107
|
-
}
|
|
5108
|
-
var DEFAULT_SCAN = {
|
|
5109
|
-
scanDirs: ["src", ".storybook", "stories", ".iui"],
|
|
5110
|
-
include: [
|
|
5111
|
-
"**/*.stories.*",
|
|
5112
|
-
"**/*.mdx",
|
|
5113
|
-
"**/src/**/*.tsx",
|
|
5114
|
-
"**/src/**/*.ts",
|
|
5115
|
-
"**/src/**/*.jsx",
|
|
5116
|
-
"**/src/**/*.js",
|
|
5117
|
-
"**/.storybook/**/*.tsx",
|
|
5118
|
-
"**/.storybook/**/*.ts",
|
|
5119
|
-
"**/.storybook/**/*.jsx",
|
|
5120
|
-
"**/.storybook/**/*.js"
|
|
5121
|
-
],
|
|
5122
|
-
exclude: ["**/*.test.*", "**/*.spec.*"]
|
|
5123
|
-
};
|
|
5124
|
-
function resolveFrameworkModule(cwd, relativePath) {
|
|
5125
|
-
const searchRoots = /* @__PURE__ */ new Set();
|
|
5126
|
-
for (const candidate of [
|
|
5127
|
-
resolveDependencyInstallRoot(cwd),
|
|
5128
|
-
path18.resolve(cwd),
|
|
5129
|
-
iuiProjectRoot2(cwd)
|
|
5130
|
-
]) {
|
|
5131
|
-
searchRoots.add(path18.resolve(candidate));
|
|
5132
|
-
}
|
|
5133
|
-
for (const start of searchRoots) {
|
|
5134
|
-
const frameworkDir = resolvePackageDir("@inventive-ui/framework", start);
|
|
5135
|
-
if (!frameworkDir) continue;
|
|
5136
|
-
const installed = path18.join(frameworkDir, relativePath);
|
|
5137
|
-
if (fs14.existsSync(installed)) return installed;
|
|
5138
|
-
}
|
|
5139
|
-
const root = iuiProjectRoot2(cwd);
|
|
5140
|
-
for (const candidate of [
|
|
5141
|
-
path18.join(root, "..", "Framework", relativePath),
|
|
5142
|
-
path18.join(root, "..", "..", "Framework", relativePath)
|
|
5143
|
-
]) {
|
|
5144
|
-
if (fs14.existsSync(candidate)) return candidate;
|
|
5145
|
-
}
|
|
5146
|
-
return null;
|
|
5147
|
-
}
|
|
5148
|
-
async function loadScanUtils(cwd) {
|
|
5149
|
-
const scanPath = resolveFrameworkModule(
|
|
5150
|
-
cwd,
|
|
5151
|
-
"integrations/vite/scan-used-slot-assets.mjs"
|
|
5152
|
-
);
|
|
5153
|
-
const resolvePath = resolveFrameworkModule(
|
|
5154
|
-
cwd,
|
|
5155
|
-
"integrations/shared/resolve-scanned-icon-name.mjs"
|
|
5156
|
-
);
|
|
5157
|
-
if (!scanPath || !resolvePath) {
|
|
5158
|
-
const installRoot = resolveDependencyInstallRoot(cwd);
|
|
5159
|
-
const frameworkDir = resolvePackageDir("@inventive-ui/framework", installRoot);
|
|
5160
|
-
const hint2 = frameworkDir && !scanPath ? "Update @inventive-ui/framework to the latest version (iui update) \u2014 scan utilities require a current Framework release." : "Install @inventive-ui/framework and run iui doctor again.";
|
|
5161
|
-
throw new CLIError("Could not load Framework scan utilities.", hint2);
|
|
5162
|
-
}
|
|
5163
|
-
const scanMod = await import(pathToFileURL(scanPath).href);
|
|
5164
|
-
const resolveMod = await import(pathToFileURL(resolvePath).href);
|
|
5165
|
-
return { ...scanMod, ...resolveMod };
|
|
5166
|
-
}
|
|
5167
|
-
function lookupKeyToGlyphKey(pkg, lookupKey) {
|
|
5168
|
-
let subpath = lookupKey.replace(/^\.\//, "").replace(/\.js$/, "");
|
|
5169
|
-
if (pkg === "illustrations") {
|
|
5170
|
-
return subpath;
|
|
5171
|
-
}
|
|
5172
|
-
const prefix = PKG_LOOKUP_PREFIX[pkg];
|
|
5173
|
-
if (prefix && subpath.startsWith(prefix)) {
|
|
5174
|
-
subpath = subpath.slice(prefix.length);
|
|
5175
|
-
}
|
|
5176
|
-
return subpath;
|
|
5177
|
-
}
|
|
5178
|
-
function glyphToIdentifier(name, used) {
|
|
5179
|
-
let base = name.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
5180
|
-
if (!base || !/^[A-Za-z_$]/.test(base)) {
|
|
5181
|
-
base = `Glyph${base}`;
|
|
5182
|
-
}
|
|
5183
|
-
let id = base;
|
|
5184
|
-
let suffix = 2;
|
|
5185
|
-
while (used.has(id)) {
|
|
5186
|
-
id = `${base}${suffix++}`;
|
|
5187
|
-
}
|
|
5188
|
-
used.add(id);
|
|
5189
|
-
return id;
|
|
5190
|
-
}
|
|
5191
|
-
function resolveIconPkg(library) {
|
|
5192
|
-
return LIBRARY_TO_PKG[library] ?? library;
|
|
5193
|
-
}
|
|
5194
|
-
function buildBoundFileContent(exportName, entries) {
|
|
5195
|
-
const lines = [
|
|
5196
|
-
"// Managed by iui. Do not edit manually.",
|
|
5197
|
-
'// Static glyph bindings for scanned assets (`binding: "scanned"`).',
|
|
5198
|
-
"",
|
|
5199
|
-
'import type { ComponentType } from "react";'
|
|
5200
|
-
];
|
|
5201
|
-
for (const entry of entries) {
|
|
5202
|
-
lines.push(`import ${entry.identifier} from "${entry.moduleId}";`);
|
|
5203
|
-
}
|
|
5204
|
-
lines.push("");
|
|
5205
|
-
lines.push(
|
|
5206
|
-
`export const ${exportName}: Record<string, ComponentType<Record<string, unknown>>> = {`
|
|
5207
|
-
);
|
|
5208
|
-
for (const entry of entries) {
|
|
5209
|
-
lines.push(` ${JSON.stringify(entry.key)}: ${entry.identifier},`);
|
|
5210
|
-
}
|
|
5211
|
-
lines.push("};");
|
|
5212
|
-
lines.push("");
|
|
5213
|
-
return lines.join("\n");
|
|
5214
|
-
}
|
|
5215
|
-
function cleanupAssetBoundFiles(cwd) {
|
|
5216
|
-
const assetsDir = generatedAssetsDir(cwd);
|
|
5217
|
-
if (!fs14.existsSync(assetsDir)) return;
|
|
5218
|
-
for (const file of fs14.readdirSync(assetsDir)) {
|
|
5219
|
-
if (file.endsWith(".bound.ts") || file === "register-bound.ts") {
|
|
5220
|
-
fs14.removeSync(path18.join(assetsDir, file));
|
|
5221
|
-
}
|
|
5222
|
-
}
|
|
5223
|
-
const remaining = fs14.readdirSync(assetsDir);
|
|
5224
|
-
if (remaining.length === 0) {
|
|
5225
|
-
fs14.removeSync(assetsDir);
|
|
5226
|
-
}
|
|
5227
|
-
}
|
|
5228
|
-
function hasAssetBoundRegistration(cwd) {
|
|
5229
|
-
return fs14.existsSync(path18.join(generatedAssetsDir(cwd), "register-bound.ts"));
|
|
5230
|
-
}
|
|
5231
|
-
async function writeAssetBoundFiles(cwd = process.cwd()) {
|
|
5232
|
-
const root = iuiProjectRoot2(cwd);
|
|
5233
|
-
const scanUtils = await loadScanUtils(cwd);
|
|
5234
|
-
const activeSpecs = BOUND_SPECS.filter(
|
|
5235
|
-
(spec) => scanUtils.isScannedAssetBindingEnabled(root, spec.slotType)
|
|
5236
|
-
);
|
|
5237
|
-
if (activeSpecs.length === 0) {
|
|
5238
|
-
cleanupAssetBoundFiles(root);
|
|
5239
|
-
return;
|
|
5240
|
-
}
|
|
5241
|
-
const registry = scanUtils.scanUsedSlotAssets(root, DEFAULT_SCAN);
|
|
5242
|
-
const defaultIconLibrary = scanUtils.readDefaultIconLibraryFromConfig(root);
|
|
5243
|
-
const defaultIconPkg = resolveIconPkg(defaultIconLibrary);
|
|
5244
|
-
const assetsDir = generatedAssetsDir(root);
|
|
5245
|
-
fs14.ensureDirSync(assetsDir);
|
|
5246
|
-
const generatedFiles = /* @__PURE__ */ new Set();
|
|
5247
|
-
const registrationSpecs = [];
|
|
5248
|
-
for (const spec of activeSpecs) {
|
|
5249
|
-
const entries = [];
|
|
5250
|
-
const usedIdentifiers = /* @__PURE__ */ new Set();
|
|
5251
|
-
for (const [pkg, keys] of registry.entries()) {
|
|
5252
|
-
if (!spec.packages.has(pkg)) continue;
|
|
5253
|
-
if ("filterByDefaultIconLibrary" in spec && spec.filterByDefaultIconLibrary && pkg !== defaultIconPkg) {
|
|
5254
|
-
continue;
|
|
5255
|
-
}
|
|
5256
|
-
if (!isAssetPackageInstalled(cwd, pkg)) continue;
|
|
5257
|
-
for (const lookupKey of keys) {
|
|
5258
|
-
const key = lookupKeyToGlyphKey(pkg, lookupKey);
|
|
5259
|
-
const moduleId = scanUtils.lookupKeyToModuleId(pkg, lookupKey);
|
|
5260
|
-
const identifier = glyphToIdentifier(key, usedIdentifiers);
|
|
5261
|
-
if (entries.some((entry) => entry.key === key)) continue;
|
|
5262
|
-
entries.push({ key, moduleId, identifier });
|
|
5263
|
-
}
|
|
5264
|
-
}
|
|
5265
|
-
entries.sort((a, b) => a.key.localeCompare(b.key));
|
|
5266
|
-
if (entries.length === 0) {
|
|
5267
|
-
continue;
|
|
5268
|
-
}
|
|
5269
|
-
const content = buildBoundFileContent(spec.exportName, entries);
|
|
5270
|
-
const outPath = resolveWithinRoot(
|
|
5271
|
-
root,
|
|
5272
|
-
".iui",
|
|
5273
|
-
"generated",
|
|
5274
|
-
"assets",
|
|
5275
|
-
spec.fileName
|
|
5276
|
-
);
|
|
5277
|
-
safeWriteFile(outPath, content);
|
|
5278
|
-
generatedFiles.add(spec.fileName);
|
|
5279
|
-
registrationSpecs.push({
|
|
5280
|
-
slotType: spec.slotType,
|
|
5281
|
-
exportName: spec.exportName,
|
|
5282
|
-
fileName: spec.fileName
|
|
5283
|
-
});
|
|
5284
|
-
}
|
|
5285
|
-
const existing = fs14.existsSync(assetsDir) ? fs14.readdirSync(assetsDir).filter((f) => f.endsWith(".bound.ts")) : [];
|
|
5286
|
-
for (const file of existing) {
|
|
5287
|
-
if (!generatedFiles.has(file)) {
|
|
5288
|
-
fs14.removeSync(path18.join(assetsDir, file));
|
|
5289
|
-
}
|
|
5290
|
-
}
|
|
5291
|
-
if (registrationSpecs.length === 0) {
|
|
5292
|
-
cleanupAssetBoundFiles(root);
|
|
5293
|
-
return;
|
|
5294
|
-
}
|
|
5295
|
-
const registerLines = [
|
|
5296
|
-
"// Managed by iui. Do not edit manually.",
|
|
5297
|
-
"",
|
|
5298
|
-
'import { registerBoundAssetComponents } from "@inventive-ui/framework/slots";'
|
|
5299
|
-
];
|
|
5300
|
-
for (const spec of registrationSpecs) {
|
|
5301
|
-
registerLines.push(
|
|
5302
|
-
`import { ${spec.exportName} } from "./${spec.fileName.replace(/\.ts$/, "")}";`
|
|
5303
|
-
);
|
|
5304
|
-
}
|
|
5305
|
-
registerLines.push("");
|
|
5306
|
-
for (const spec of registrationSpecs) {
|
|
5307
|
-
registerLines.push(
|
|
5308
|
-
`registerBoundAssetComponents(${JSON.stringify(spec.slotType)}, ${spec.exportName});`
|
|
5309
|
-
);
|
|
5310
|
-
}
|
|
5311
|
-
registerLines.push("");
|
|
5312
|
-
safeWriteFile(
|
|
5313
|
-
resolveWithinRoot(root, ".iui", "generated", "assets", "register-bound.ts"),
|
|
5314
|
-
registerLines.join("\n")
|
|
5315
|
-
);
|
|
5316
|
-
}
|
|
5317
|
-
function assetModuleCandidates(pkgRoot, moduleId) {
|
|
5318
|
-
const pkgName = moduleId.split("/").slice(0, 2).join("/");
|
|
5319
|
-
const subpath = moduleId.slice(pkgName.length + 1);
|
|
5320
|
-
const pkgId = pkgName.replace("@inventive-ui/", "");
|
|
5321
|
-
if (!subpath || subpath.includes("..")) return [];
|
|
5322
|
-
if (pkgId === "loaders") {
|
|
5323
|
-
return [path18.join(pkgRoot, "dist", "loaders", `${subpath}.js`)];
|
|
5324
|
-
}
|
|
5325
|
-
if (pkgId === "illustrations") {
|
|
5326
|
-
const [family, scene] = subpath.split("/");
|
|
5327
|
-
if (family && scene) {
|
|
5328
|
-
return [path18.join(pkgRoot, "dist", family, `${scene}.js`)];
|
|
5329
|
-
}
|
|
5330
|
-
return [path18.join(pkgRoot, "dist", `${subpath}.js`)];
|
|
5331
|
-
}
|
|
5332
|
-
const prefix = PKG_LOOKUP_PREFIX[pkgId];
|
|
5333
|
-
if (prefix) {
|
|
5334
|
-
const dir = prefix.replace(/\/$/, "");
|
|
5335
|
-
return [
|
|
5336
|
-
path18.join(pkgRoot, "dist", dir, `${subpath}.js`),
|
|
5337
|
-
path18.join(pkgRoot, "dist", `${subpath}.js`),
|
|
5338
|
-
path18.join(pkgRoot, "dist", subpath, "index.js")
|
|
5339
|
-
];
|
|
5340
|
-
}
|
|
5341
|
-
return [
|
|
5342
|
-
path18.join(pkgRoot, "dist", `${subpath}.js`),
|
|
5343
|
-
path18.join(pkgRoot, "dist", subpath, "index.js")
|
|
5344
|
-
];
|
|
5345
|
-
}
|
|
5346
|
-
function validateGeneratedAssetBoundImports(cwd = process.cwd()) {
|
|
5347
|
-
const assetsDir = generatedAssetsDir(cwd);
|
|
5348
|
-
if (!fs14.existsSync(assetsDir)) return [];
|
|
5349
|
-
const issues = [];
|
|
5350
|
-
const boundFiles = fs14.readdirSync(assetsDir).filter((file) => file.endsWith(".bound.ts"));
|
|
5351
|
-
for (const file of boundFiles) {
|
|
5352
|
-
const content = fs14.readFileSync(path18.join(assetsDir, file), "utf8");
|
|
5353
|
-
const importRe = /from\s+["'](@inventive-ui\/[^"']+)["']/g;
|
|
5354
|
-
let match;
|
|
5355
|
-
while ((match = importRe.exec(content)) !== null) {
|
|
5356
|
-
const moduleId = match[1];
|
|
5357
|
-
const pkgName = moduleId.split("/").slice(0, 2).join("/");
|
|
5358
|
-
const pkgRoot = resolvePackageDir(pkgName, cwd);
|
|
5359
|
-
if (!pkgRoot) {
|
|
5360
|
-
issues.push(`${file}: missing asset package ${pkgName}`);
|
|
5361
|
-
continue;
|
|
5362
|
-
}
|
|
5363
|
-
const candidates = assetModuleCandidates(pkgRoot, moduleId);
|
|
5364
|
-
if (!candidates.some((candidate) => fs14.existsSync(candidate))) {
|
|
5365
|
-
issues.push(`${file}: missing asset module ${moduleId}`);
|
|
5366
|
-
}
|
|
5367
|
-
}
|
|
5368
|
-
}
|
|
5369
|
-
return issues;
|
|
5370
|
-
}
|
|
5371
|
-
|
|
5372
|
-
// src/services/slots.ts
|
|
5373
|
-
var SLOT_GROUP_CORE_FILE = "slot-core.generated.tsx";
|
|
5374
|
-
var SLOT_GROUP_OPTIONAL_FILE = "slot-optional.generated.tsx";
|
|
5375
|
-
function bridgeSlotFilePath(cwd) {
|
|
5376
|
-
return path19.join(cwd, "src", "iui", "slot.tsx");
|
|
5377
|
-
}
|
|
5378
|
-
function cleanupLegacySourceSlotFiles(cwd) {
|
|
5379
|
-
const legacySlotsDir = path19.join(cwd, "src", "iui", "slots");
|
|
5380
|
-
if (!fs15.existsSync(legacySlotsDir)) return;
|
|
5381
|
-
try {
|
|
5382
|
-
const files = fs15.readdirSync(legacySlotsDir);
|
|
5383
|
-
for (const file of files) {
|
|
5384
|
-
if (file.endsWith(".slot.tsx")) {
|
|
5385
|
-
fs15.removeSync(path19.join(legacySlotsDir, file));
|
|
5386
|
-
}
|
|
5387
|
-
}
|
|
5388
|
-
const remaining = fs15.readdirSync(legacySlotsDir);
|
|
5389
|
-
if (remaining.length === 0) {
|
|
5390
|
-
fs15.removeSync(legacySlotsDir);
|
|
5391
|
-
}
|
|
5392
|
-
} catch {
|
|
5393
|
-
}
|
|
5394
|
-
}
|
|
5395
|
-
function loadSlotBootstrapPolicy(cwd) {
|
|
5396
|
-
const policy = /* @__PURE__ */ new Map();
|
|
5397
|
-
const contract = loadPublicSlotContract(cwd);
|
|
5398
|
-
if (!contract) return policy;
|
|
5399
|
-
for (const entry of contract.slots ?? []) {
|
|
5400
|
-
if (!entry?.type || !entry.public) continue;
|
|
5401
|
-
policy.set(entry.type, contractEntryToBootstrapPolicy(entry));
|
|
5402
|
-
}
|
|
5403
|
-
return policy;
|
|
5404
|
-
}
|
|
5405
|
-
function validateGeneratedSlotImports(cwd = process.cwd()) {
|
|
5406
|
-
const components = readComponentManifest(cwd);
|
|
5407
|
-
const pkgManifest = readComponentPackageManifest(cwd);
|
|
5408
|
-
if (!pkgManifest) {
|
|
5409
|
-
return ["@inventive-ui/components manifest is missing from node_modules."];
|
|
5410
|
-
}
|
|
5411
|
-
const itemsLookup = registryItemsMap(pkgManifest);
|
|
5412
|
-
const installedItems = Object.keys(components).map((slug) => itemsLookup[slug]).filter((item) => Boolean(item));
|
|
5413
|
-
const { issues } = collectInstalledSlotEmitters(
|
|
5414
|
-
installedItems,
|
|
5415
|
-
new Set(Object.keys(components)),
|
|
5416
|
-
cwd
|
|
5417
|
-
);
|
|
5418
|
-
return issues.map((issue) => issue);
|
|
5419
|
-
}
|
|
5420
|
-
function renderGetComponentExpr(emitter, _slotPropsType = "unknown") {
|
|
5421
|
-
const access = emitter.lazyAccess.replace(/^\./, "").trim();
|
|
5422
|
-
const parts = access.split(".").filter(Boolean);
|
|
5423
|
-
const compName = emitter.componentName;
|
|
5424
|
-
if (parts.length === 0) {
|
|
5425
|
-
assertJsIdentifier(compName, "component export");
|
|
5426
|
-
return `resolveComponentExport(mod, ${JSON.stringify(compName)})`;
|
|
5427
|
-
}
|
|
5428
|
-
if (parts.length === 1) {
|
|
5429
|
-
const name = parts[0] === "default" ? compName : parts[0];
|
|
5430
|
-
assertJsIdentifier(name, "component export");
|
|
5431
|
-
return `resolveComponentExport(mod, ${JSON.stringify(name)})`;
|
|
5432
|
-
}
|
|
5433
|
-
const [root, ...rest] = parts;
|
|
5434
|
-
if (root !== "default") {
|
|
5435
|
-
assertJsIdentifier(root, "component export");
|
|
5436
|
-
}
|
|
5437
|
-
for (const part of rest) {
|
|
5438
|
-
assertJsIdentifier(part, "component export member");
|
|
5439
|
-
}
|
|
5440
|
-
const rootName = root === "default" ? compName : root;
|
|
5441
|
-
if (rest.length === 1) {
|
|
5442
|
-
return `resolveComponentExport(mod, ${JSON.stringify(rootName)}, ${JSON.stringify(rest[0])})`;
|
|
5443
|
-
}
|
|
5444
|
-
const rootExpr = `resolveComponentExport(mod, ${JSON.stringify(rootName)})`;
|
|
5445
|
-
return `${rootExpr}?.${rest.join(".")}`;
|
|
5446
|
-
}
|
|
5447
|
-
function writeComponentSlotFiles(cwd = process.cwd()) {
|
|
5448
|
-
const components = readComponentManifest(cwd);
|
|
5449
|
-
const pkgManifest = readComponentPackageManifest(cwd);
|
|
5450
|
-
const slotsDir = generatedSlotsDir(cwd);
|
|
5451
|
-
const generationIssues = [];
|
|
5452
|
-
cleanupLegacySourceSlotFiles(cwd);
|
|
5453
|
-
if (Object.keys(components).length === 0) {
|
|
5454
|
-
if (fs15.existsSync(slotsDir)) {
|
|
5455
|
-
const existingSlots2 = fs15.readdirSync(slotsDir).filter((f) => f.endsWith(".slot.tsx"));
|
|
5456
|
-
for (const file of existingSlots2) {
|
|
5457
|
-
try {
|
|
5458
|
-
fs15.removeSync(path19.join(slotsDir, file));
|
|
5459
|
-
} catch {
|
|
5460
|
-
}
|
|
5461
|
-
}
|
|
5462
|
-
}
|
|
5463
|
-
return;
|
|
5464
|
-
}
|
|
5465
|
-
fs15.ensureDirSync(slotsDir);
|
|
5466
|
-
if (!pkgManifest) return;
|
|
5467
|
-
const itemsLookup = registryItemsMap(pkgManifest);
|
|
5468
|
-
const installedItems = Object.entries(components).map(([slug]) => itemsLookup[slug]).filter((item) => Boolean(item));
|
|
5469
|
-
const { emitters, issues: emitterIssues } = collectInstalledSlotEmitters(
|
|
5470
|
-
installedItems,
|
|
5471
|
-
new Set(Object.keys(components)),
|
|
5472
|
-
cwd
|
|
5473
|
-
);
|
|
5474
|
-
generationIssues.push(...emitterIssues.map((issue) => `- ${issue}`));
|
|
5475
|
-
const contract = loadPublicSlotContract(cwd);
|
|
5476
|
-
if (contract) {
|
|
5477
|
-
for (const entry of contract.slots ?? []) {
|
|
5478
|
-
if (!entry.public) continue;
|
|
5479
|
-
const prefetchError = validateSlotPrefetchPolicy(entry);
|
|
5480
|
-
if (prefetchError) {
|
|
5481
|
-
generationIssues.push(prefetchError);
|
|
5482
|
-
}
|
|
5483
|
-
}
|
|
5484
|
-
}
|
|
5485
|
-
const slotPolicy = loadSlotBootstrapPolicy(cwd);
|
|
5486
|
-
const coreEmitters = [];
|
|
5487
|
-
const optionalEmitters = [];
|
|
5488
|
-
for (const emitter of emitters) {
|
|
5489
|
-
assertComponentSlug(emitter.type);
|
|
5490
|
-
assertJsIdentifier(emitter.componentName, "component export");
|
|
5491
|
-
if (emitter.propsName !== "Props") assertJsIdentifier(emitter.propsName, "props type");
|
|
5492
|
-
assertImportSpecifier(emitter.importSpecifier);
|
|
5493
|
-
assertImportSpecifier(emitter.lazyImportSpecifier);
|
|
5494
|
-
const policy = slotPolicy.get(emitter.type) ?? "optional";
|
|
5495
|
-
if (policy === "core") coreEmitters.push(emitter);
|
|
5496
|
-
else optionalEmitters.push(emitter);
|
|
5497
|
-
}
|
|
5498
|
-
const root = iuiProjectRoot2(cwd);
|
|
5499
|
-
const renderedGroups = [
|
|
5500
|
-
{ fileName: SLOT_GROUP_CORE_FILE, emitters: coreEmitters },
|
|
5501
|
-
{ fileName: SLOT_GROUP_OPTIONAL_FILE, emitters: optionalEmitters }
|
|
5502
|
-
];
|
|
5503
|
-
for (const group of renderedGroups) {
|
|
5504
|
-
const outPath = resolveWithinRoot(root, ".iui", "generated", "slots", group.fileName);
|
|
5505
|
-
if (group.emitters.length === 0) {
|
|
5506
|
-
if (fs15.existsSync(outPath)) fs15.removeSync(outPath);
|
|
5507
|
-
continue;
|
|
5508
|
-
}
|
|
5509
|
-
safeWriteFile(
|
|
5510
|
-
outPath,
|
|
5511
|
-
renderGroupedSlotFileContent(group.emitters, {
|
|
5512
|
-
prefetch: group.fileName === SLOT_GROUP_CORE_FILE
|
|
5513
|
-
})
|
|
5514
|
-
);
|
|
5515
|
-
}
|
|
5516
|
-
const existingSlots = fs15.existsSync(slotsDir) ? fs15.readdirSync(slotsDir).filter((f) => f.endsWith(".slot.tsx") || f.endsWith(".generated.tsx")) : [];
|
|
5517
|
-
for (const file of existingSlots) {
|
|
5518
|
-
if (file === SLOT_GROUP_CORE_FILE || file === SLOT_GROUP_OPTIONAL_FILE) continue;
|
|
5519
|
-
if (file.endsWith(".slot.tsx")) {
|
|
5520
|
-
try {
|
|
5521
|
-
fs15.removeSync(path19.join(slotsDir, file));
|
|
5522
|
-
} catch {
|
|
5523
|
-
}
|
|
5524
|
-
continue;
|
|
5525
|
-
}
|
|
5526
|
-
if (file.endsWith(".generated.tsx")) {
|
|
5527
|
-
try {
|
|
5528
|
-
fs15.removeSync(path19.join(slotsDir, file));
|
|
5529
|
-
} catch {
|
|
5530
|
-
}
|
|
5531
|
-
}
|
|
5532
|
-
}
|
|
5533
|
-
if (generationIssues.length > 0) {
|
|
5534
|
-
throw new CLIError(
|
|
5535
|
-
[
|
|
5536
|
-
"Component public slot contract mismatch while generating slot files:",
|
|
5537
|
-
...generationIssues
|
|
5538
|
-
].join("\n"),
|
|
5539
|
-
"Reinstall @inventive-ui/components and run iui doctor to repair the slot registry."
|
|
5540
|
-
);
|
|
5541
|
-
}
|
|
5542
|
-
}
|
|
5543
|
-
function renderGroupedSlotFileContent(emitters, options = {}) {
|
|
5544
|
-
const needsComponentProps = emitters.some((emitter) => emitter.propsName === "Props");
|
|
5545
|
-
const lines = [
|
|
5546
|
-
"// Managed by iui. Do not edit manually.",
|
|
5547
|
-
'import React from "react";',
|
|
5548
|
-
'import { registerSlot, createEagerComponent, resolveComponentExport } from "@inventive-ui/framework/slots";'
|
|
5549
|
-
];
|
|
5550
|
-
if (needsComponentProps) {
|
|
5551
|
-
lines.push('import type { ComponentProps } from "react";');
|
|
5552
|
-
}
|
|
5553
|
-
lines.push("");
|
|
5554
|
-
const imports = /* @__PURE__ */ new Set();
|
|
5555
|
-
let idx = 0;
|
|
5556
|
-
for (const emitter of emitters) {
|
|
5557
|
-
idx += 1;
|
|
5558
|
-
const alias = `Comp${idx}`;
|
|
5559
|
-
if (emitter.propsName === "Props") {
|
|
5560
|
-
imports.add(
|
|
5561
|
-
`import type { ${emitter.componentName} as ${alias}Type } from "${emitter.importSpecifier}";`
|
|
5562
|
-
);
|
|
5563
|
-
} else {
|
|
5564
|
-
imports.add(`import type { ${emitter.propsName} } from "${emitter.importSpecifier}";`);
|
|
5565
|
-
}
|
|
5566
|
-
}
|
|
5567
|
-
lines.push(...[...imports].sort(), "");
|
|
5568
|
-
idx = 0;
|
|
5569
|
-
for (const emitter of emitters) {
|
|
5570
|
-
idx += 1;
|
|
5571
|
-
const alias = `Comp${idx}`;
|
|
5572
|
-
const slotType = emitter.propsName === "Props" ? `ComponentProps<typeof ${alias}Type>` : emitter.propsName;
|
|
5573
|
-
lines.push(`type ${alias}Slot = { type: "${emitter.type}" } & Omit<${slotType}, "type">;`);
|
|
5574
|
-
lines.push(`type ${alias}SlotProps = Omit<${alias}Slot, "type">;`);
|
|
5575
|
-
}
|
|
5576
|
-
lines.push("", 'declare module "@inventive-ui/framework/slots" {', " interface SlotMap {");
|
|
5577
|
-
idx = 0;
|
|
5578
|
-
for (const emitter of emitters) {
|
|
5579
|
-
idx += 1;
|
|
5580
|
-
lines.push(` "${emitter.type}": Comp${idx}Slot;`);
|
|
5581
|
-
}
|
|
5582
|
-
lines.push(" }", "}", "");
|
|
5583
|
-
idx = 0;
|
|
5584
|
-
for (const emitter of emitters) {
|
|
5585
|
-
idx += 1;
|
|
5586
|
-
const alias = `Comp${idx}`;
|
|
5587
|
-
const renderer = `${alias}Renderer`;
|
|
5588
|
-
lines.push(`const ${renderer} = createEagerComponent<${alias}SlotProps>(`);
|
|
5589
|
-
lines.push(` () => import(${escapeTsStringLiteral(emitter.lazyImportSpecifier)}),`);
|
|
5590
|
-
lines.push(` (mod) => ${renderGetComponentExpr(emitter, `${alias}SlotProps`)} as React.ComponentType<${alias}SlotProps>,`);
|
|
5591
|
-
if (options.prefetch) {
|
|
5592
|
-
lines.push(" { prefetch: true },");
|
|
5593
|
-
}
|
|
5594
|
-
lines.push(");", "");
|
|
5595
|
-
lines.push(`registerSlot(${escapeTsStringLiteral(emitter.type)}, (slot) => {`);
|
|
5596
|
-
lines.push(" const { type, ...props } = slot;");
|
|
5597
|
-
lines.push(` return <${renderer} {...props} />;`);
|
|
5598
|
-
lines.push("});", "");
|
|
5599
|
-
}
|
|
5600
|
-
return `${lines.join("\n")}
|
|
5601
|
-
`;
|
|
5602
|
-
}
|
|
5603
|
-
function writeSlotHelperFile(cwd = process.cwd()) {
|
|
5604
|
-
const manifest = readSlotManifest(cwd);
|
|
5605
|
-
const components = readComponentManifest(cwd);
|
|
5606
|
-
const pkgManifest = readComponentPackageManifest(cwd);
|
|
5607
|
-
const slotTypes = /* @__PURE__ */ new Set();
|
|
5608
|
-
for (const record of Object.values(manifest)) {
|
|
5609
|
-
if (record.slotType && record.slotType !== "component") {
|
|
5610
|
-
slotTypes.add(record.slotType);
|
|
5611
|
-
}
|
|
5612
|
-
if (Array.isArray(record.supportedSlots)) {
|
|
5613
|
-
for (const t of record.supportedSlots) slotTypes.add(t);
|
|
5614
|
-
}
|
|
5615
|
-
}
|
|
5616
|
-
let emitterSlotTypes = [];
|
|
5617
|
-
if (pkgManifest) {
|
|
5618
|
-
const itemsLookup = registryItemsMap(pkgManifest);
|
|
5619
|
-
const installedItems = Object.keys(components).map((slug) => itemsLookup[slug]).filter((item) => Boolean(item));
|
|
5620
|
-
const { emitters } = collectInstalledSlotEmitters(
|
|
5621
|
-
installedItems,
|
|
5622
|
-
new Set(Object.keys(components)),
|
|
5623
|
-
cwd
|
|
5624
|
-
);
|
|
5625
|
-
emitterSlotTypes = emitters.map((emitter) => emitter.type);
|
|
5626
|
-
for (const type of emitterSlotTypes) slotTypes.add(type);
|
|
5627
|
-
} else {
|
|
5628
|
-
for (const slug of Object.keys(components)) slotTypes.add(slug);
|
|
5629
|
-
}
|
|
5630
|
-
const typesArray = Array.from(slotTypes).sort();
|
|
5631
|
-
const slotImports = [];
|
|
5632
|
-
const coreSlotsPath = path19.join(generatedSlotsDir(cwd), SLOT_GROUP_CORE_FILE);
|
|
5633
|
-
const optionalSlotsPath = path19.join(generatedSlotsDir(cwd), SLOT_GROUP_OPTIONAL_FILE);
|
|
5634
|
-
if (fs15.existsSync(coreSlotsPath)) slotImports.push(`import "./slots/${SLOT_GROUP_CORE_FILE.replace(/\.tsx$/, "")}";`);
|
|
5635
|
-
if (fs15.existsSync(optionalSlotsPath)) slotImports.push(`import "./slots/${SLOT_GROUP_OPTIONAL_FILE.replace(/\.tsx$/, "")}";`);
|
|
5636
|
-
const componentSlotImports = slotImports.join("\n");
|
|
5637
|
-
const includeAssetBindings = hasAssetBoundRegistration(cwd);
|
|
5638
|
-
const outDir = generatedIuiDir(cwd);
|
|
5639
|
-
fs15.ensureDirSync(outDir);
|
|
5640
|
-
const outPath = path19.join(outDir, "slot.generated.tsx");
|
|
5641
|
-
const sections = [
|
|
5642
|
-
`// Managed by iui. Do not edit manually.`,
|
|
5643
|
-
`// Rebuilt automatically when the CLI validates the project.`
|
|
5644
|
-
];
|
|
5645
|
-
if (includeAssetBindings) {
|
|
5646
|
-
sections.push("");
|
|
5647
|
-
sections.push("// Scanned asset bindings (static glyph imports)");
|
|
5648
|
-
sections.push(`import "./assets/register-bound";`);
|
|
5649
|
-
}
|
|
5650
|
-
if (componentSlotImports) {
|
|
5651
|
-
sections.push("");
|
|
5652
|
-
sections.push("// Component slot registrations");
|
|
5653
|
-
sections.push(componentSlotImports);
|
|
5654
|
-
}
|
|
5655
|
-
sections.push("");
|
|
5656
|
-
sections.push(`// Framework slot system \u2014 flag, icon, loader, etc. registrations run as side effects`);
|
|
5657
|
-
sections.push(`// when @inventive-ui/framework is first imported. No explicit registration needed here.`);
|
|
5658
|
-
sections.push(`import { SlotRenderer, useSlotRenderer } from "@inventive-ui/framework/slots";`);
|
|
5659
|
-
sections.push(`import slotManifest from "../slots.json";`);
|
|
5660
|
-
sections.push("");
|
|
5661
|
-
sections.push(
|
|
5662
|
-
typesArray.length > 0 ? `export type IUISlotType =
|
|
5663
|
-
${typesArray.map((t) => ` | "${t}"`).join("\n")};` : `export type IUISlotType = never;`
|
|
5664
|
-
);
|
|
5665
|
-
sections.push("");
|
|
5666
|
-
sections.push(`export { SlotRenderer, useSlotRenderer };`);
|
|
5667
|
-
sections.push("");
|
|
5668
|
-
sections.push(`export const slots = slotManifest;`);
|
|
5669
|
-
sections.push("");
|
|
5670
|
-
const content = sections.join("\n");
|
|
5671
|
-
safeWriteFile(outPath, content);
|
|
5672
|
-
}
|
|
5673
|
-
function writeSlotBridge(packageDir, iuiRoot2) {
|
|
5674
|
-
const bridgePath = bridgeSlotFilePath(packageDir);
|
|
5675
|
-
const generatedFile = path19.join(iuiRoot2, ".iui", "generated", "slot.generated.tsx");
|
|
5676
|
-
const importBase = relativeImportPath(path19.dirname(bridgePath), generatedFile);
|
|
5677
|
-
fs15.ensureDirSync(path19.dirname(bridgePath));
|
|
5678
|
-
if (fs15.existsSync(bridgePath)) {
|
|
5679
|
-
const existing = fs15.readFileSync(bridgePath, "utf-8");
|
|
5680
|
-
if (existing.length > 0 && !/@iui-managed/.test(existing)) {
|
|
5681
|
-
return;
|
|
5682
|
-
}
|
|
5683
|
-
}
|
|
5684
|
-
const bridgeContent = `// Managed by iui. Do not edit manually.
|
|
5685
|
-
// @iui-managed
|
|
5686
|
-
// Compatibility bridge: keep project imports stable at src/iui/slot.tsx.
|
|
5687
|
-
|
|
5688
|
-
export { SlotRenderer, useSlotRenderer, slots } from "${importBase}";
|
|
5689
|
-
export type { IUISlotType } from "${importBase}";
|
|
5690
|
-
`;
|
|
5691
|
-
safeWriteFile(bridgePath, bridgeContent);
|
|
5692
|
-
cleanupLegacySourceSlotFiles(packageDir);
|
|
5693
|
-
}
|
|
5694
|
-
|
|
5695
|
-
// src/services/workspace-bootstrap.ts
|
|
5696
|
-
import path21 from "path";
|
|
5697
|
-
import fs17 from "fs-extra";
|
|
5698
|
-
|
|
5699
4959
|
// src/services/bootstrap.ts
|
|
5700
|
-
import fs16 from "fs-extra";
|
|
5701
|
-
import path20 from "path";
|
|
5702
4960
|
var BOOTSTRAP_GENERATED_FILE = "bootstrap.generated.tsx";
|
|
5703
4961
|
function bridgeBootstrapFilePath(cwd) {
|
|
5704
|
-
return
|
|
4962
|
+
return path18.join(cwd, "src", "iui", "bootstrap.ts");
|
|
5705
4963
|
}
|
|
5706
4964
|
function bootstrapGeneratedPath(cwd = process.cwd()) {
|
|
5707
|
-
return
|
|
4965
|
+
return path18.join(generatedIuiDir(cwd), BOOTSTRAP_GENERATED_FILE);
|
|
5708
4966
|
}
|
|
5709
4967
|
function resolveProjectConfigPaths(cwd) {
|
|
5710
4968
|
const meta = readProjectMeta(cwd);
|
|
@@ -5719,8 +4977,8 @@ function resolveProjectConfigPaths(cwd) {
|
|
|
5719
4977
|
};
|
|
5720
4978
|
}
|
|
5721
4979
|
function configImportFromGenerated(cwd, configRel) {
|
|
5722
|
-
const generatedDir =
|
|
5723
|
-
const abs =
|
|
4980
|
+
const generatedDir = path18.dirname(bootstrapGeneratedPath(cwd));
|
|
4981
|
+
const abs = path18.resolve(cwd, configRel.replace(/^\.\//, ""));
|
|
5724
4982
|
return relativeImportPath(generatedDir, abs);
|
|
5725
4983
|
}
|
|
5726
4984
|
function expectedBootstrapImportPaths(cwd) {
|
|
@@ -5733,13 +4991,13 @@ function expectedBootstrapImportPaths(cwd) {
|
|
|
5733
4991
|
}
|
|
5734
4992
|
function writeBootstrapGenerated(cwd = process.cwd()) {
|
|
5735
4993
|
const outPath = bootstrapGeneratedPath(cwd);
|
|
5736
|
-
|
|
4994
|
+
fs14.ensureDirSync(path18.dirname(outPath));
|
|
5737
4995
|
const imports = expectedBootstrapImportPaths(cwd);
|
|
5738
4996
|
const content = `// @iui-managed
|
|
5739
4997
|
|
|
5740
4998
|
// Generated by iui CLI \u2014 do not edit manually.
|
|
5741
4999
|
|
|
5742
|
-
// Connects
|
|
5000
|
+
// Connects theme.config.ts + assets.config.json + component.config.ts for standard bootstrap.
|
|
5743
5001
|
|
|
5744
5002
|
|
|
5745
5003
|
|
|
@@ -5759,16 +5017,12 @@ import {
|
|
|
5759
5017
|
|
|
5760
5018
|
} from "@inventive-ui/framework";
|
|
5761
5019
|
|
|
5762
|
-
import { initConfig as
|
|
5020
|
+
import { initConfig as initAssetsConfig } from "@inventive-ui/framework/assets";
|
|
5763
5021
|
|
|
5764
5022
|
import type { IUIAssetsConfig } from "@inventive-ui/framework/config";
|
|
5765
5023
|
|
|
5766
5024
|
|
|
5767
5025
|
|
|
5768
|
-
import "./slot.generated";
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
5026
|
const themeConfig = (theme as { default?: typeof theme }).default ?? theme;
|
|
5773
5027
|
|
|
5774
5028
|
|
|
@@ -5795,7 +5049,7 @@ registerBootstrapState({
|
|
|
5795
5049
|
|
|
5796
5050
|
initFramework(frameworkConfig);
|
|
5797
5051
|
|
|
5798
|
-
|
|
5052
|
+
initAssetsConfig(frameworkConfig);
|
|
5799
5053
|
|
|
5800
5054
|
|
|
5801
5055
|
|
|
@@ -5807,10 +5061,10 @@ export { projectComponentConfig as componentConfig };
|
|
|
5807
5061
|
function writeBootstrapBridge(packageDir, iuiRoot2) {
|
|
5808
5062
|
const bridgePath = bridgeBootstrapFilePath(packageDir);
|
|
5809
5063
|
const generatedFile = bootstrapGeneratedPath(iuiRoot2);
|
|
5810
|
-
const importBase = relativeImportPath(
|
|
5811
|
-
|
|
5812
|
-
if (
|
|
5813
|
-
const existing =
|
|
5064
|
+
const importBase = relativeImportPath(path18.dirname(bridgePath), generatedFile);
|
|
5065
|
+
fs14.ensureDirSync(path18.dirname(bridgePath));
|
|
5066
|
+
if (fs14.existsSync(bridgePath)) {
|
|
5067
|
+
const existing = fs14.readFileSync(bridgePath, "utf-8");
|
|
5814
5068
|
if (existing.length > 0 && !/@iui-managed/.test(existing)) {
|
|
5815
5069
|
return;
|
|
5816
5070
|
}
|
|
@@ -5831,17 +5085,18 @@ import "${importBase}";
|
|
|
5831
5085
|
function writeProjectBootstrapArtifacts(packageDir, iuiRoot2) {
|
|
5832
5086
|
writeBootstrapGenerated(iuiRoot2);
|
|
5833
5087
|
writeBootstrapBridge(packageDir, iuiRoot2);
|
|
5088
|
+
removeStaleComponentSlotOutput(iuiRoot2, [packageDir]);
|
|
5834
5089
|
}
|
|
5835
5090
|
|
|
5836
5091
|
// src/services/workspace-bootstrap.ts
|
|
5837
5092
|
function workspaceManifestPath(iuiRoot2) {
|
|
5838
|
-
return
|
|
5093
|
+
return path19.join(iuiRoot2, IUI_DIR, "workspace.json");
|
|
5839
5094
|
}
|
|
5840
5095
|
function readWorkspaceManifest(iuiRoot2) {
|
|
5841
5096
|
const p = workspaceManifestPath(iuiRoot2);
|
|
5842
|
-
if (!
|
|
5097
|
+
if (!fs15.existsSync(p)) return null;
|
|
5843
5098
|
try {
|
|
5844
|
-
const raw =
|
|
5099
|
+
const raw = fs15.readJsonSync(p);
|
|
5845
5100
|
if (!Array.isArray(raw.packages)) return null;
|
|
5846
5101
|
return {
|
|
5847
5102
|
iuiRoot: raw.iuiRoot ?? iuiRoot2,
|
|
@@ -5853,40 +5108,45 @@ function readWorkspaceManifest(iuiRoot2) {
|
|
|
5853
5108
|
}
|
|
5854
5109
|
}
|
|
5855
5110
|
function writeWorkspaceManifest(iuiRoot2, packageDirs) {
|
|
5856
|
-
const unique = [...new Set(packageDirs.map((dir) =>
|
|
5111
|
+
const unique = [...new Set(packageDirs.map((dir) => path19.resolve(dir)))];
|
|
5857
5112
|
atomicWriteJson(workspaceManifestPath(iuiRoot2), {
|
|
5858
|
-
packages: unique.map((dir) =>
|
|
5113
|
+
packages: unique.map((dir) => path19.relative(iuiRoot2, dir) || "."),
|
|
5859
5114
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5860
5115
|
});
|
|
5861
5116
|
}
|
|
5862
5117
|
function resolveRegisteredPackageDirs(iuiRoot2) {
|
|
5863
|
-
const resolvedRoot =
|
|
5118
|
+
const resolvedRoot = path19.resolve(iuiRoot2);
|
|
5864
5119
|
const manifest = readWorkspaceManifest(resolvedRoot);
|
|
5865
5120
|
if (!manifest) return [resolvedRoot];
|
|
5866
5121
|
const dirs = manifest.packages.map(
|
|
5867
|
-
(rel) =>
|
|
5122
|
+
(rel) => path19.resolve(resolvedRoot, rel === "." ? "" : rel)
|
|
5868
5123
|
);
|
|
5869
|
-
if (!dirs.some((dir) =>
|
|
5124
|
+
if (!dirs.some((dir) => path19.resolve(dir) === resolvedRoot)) {
|
|
5870
5125
|
dirs.unshift(resolvedRoot);
|
|
5871
5126
|
}
|
|
5872
5127
|
return dirs;
|
|
5873
5128
|
}
|
|
5129
|
+
function registeredPackageDirs(iuiRoot2) {
|
|
5130
|
+
return resolveRegisteredPackageDirs(resolveIuiProjectRoot(iuiRoot2)).filter(
|
|
5131
|
+
(dir) => fs15.existsSync(path19.join(dir, "package.json"))
|
|
5132
|
+
);
|
|
5133
|
+
}
|
|
5874
5134
|
function registerWorkspacePackage(iuiRoot2, packageDir) {
|
|
5875
|
-
const resolvedRoot =
|
|
5876
|
-
const resolvedPackage =
|
|
5135
|
+
const resolvedRoot = path19.resolve(iuiRoot2);
|
|
5136
|
+
const resolvedPackage = path19.resolve(packageDir);
|
|
5877
5137
|
const existing = resolveRegisteredPackageDirs(resolvedRoot);
|
|
5878
|
-
if (!existing.some((dir) =>
|
|
5138
|
+
if (!existing.some((dir) => path19.resolve(dir) === resolvedPackage)) {
|
|
5879
5139
|
existing.push(resolvedPackage);
|
|
5880
5140
|
}
|
|
5881
5141
|
writeWorkspaceManifest(resolvedRoot, existing);
|
|
5882
5142
|
}
|
|
5883
5143
|
function registerAllWorkspacePackages(iuiRoot2) {
|
|
5884
|
-
const resolvedRoot =
|
|
5144
|
+
const resolvedRoot = path19.resolve(iuiRoot2);
|
|
5885
5145
|
const workspaceRoot = findWorkspaceRoot(resolvedRoot);
|
|
5886
5146
|
const targets = /* @__PURE__ */ new Set([resolvedRoot]);
|
|
5887
5147
|
if (workspaceRoot) {
|
|
5888
5148
|
for (const pkgDir of listWorkspacePackageDirs(workspaceRoot)) {
|
|
5889
|
-
targets.add(
|
|
5149
|
+
targets.add(path19.resolve(pkgDir));
|
|
5890
5150
|
}
|
|
5891
5151
|
}
|
|
5892
5152
|
const dirs = [...targets];
|
|
@@ -5897,18 +5157,17 @@ function bootstrapRegisteredPackages(iuiRoot2) {
|
|
|
5897
5157
|
const resolvedRoot = resolveIuiProjectRoot(iuiRoot2);
|
|
5898
5158
|
const bootstrapped = [];
|
|
5899
5159
|
for (const packageDir of resolveRegisteredPackageDirs(resolvedRoot)) {
|
|
5900
|
-
if (!
|
|
5160
|
+
if (!fs15.existsSync(path19.join(packageDir, "package.json"))) continue;
|
|
5901
5161
|
ensureProjectNpmrc(packageDir);
|
|
5902
|
-
writeSlotBridge(packageDir, resolvedRoot);
|
|
5903
5162
|
writeProjectBootstrapArtifacts(packageDir, resolvedRoot);
|
|
5904
5163
|
bootstrapped.push(packageDir);
|
|
5905
5164
|
}
|
|
5906
5165
|
return bootstrapped;
|
|
5907
5166
|
}
|
|
5908
5167
|
async function bootstrapWorkspacePackage(packageDir, iuiRoot2) {
|
|
5909
|
-
const resolvedPackage =
|
|
5168
|
+
const resolvedPackage = path19.resolve(packageDir);
|
|
5910
5169
|
const resolvedIuiRoot = resolveIuiProjectRoot(iuiRoot2);
|
|
5911
|
-
if (!
|
|
5170
|
+
if (!fs15.existsSync(path19.join(resolvedPackage, "package.json"))) {
|
|
5912
5171
|
throw new CLIError(
|
|
5913
5172
|
`No package.json found in ${resolvedPackage}.`,
|
|
5914
5173
|
"Run iui init from a workspace app directory that contains package.json."
|
|
@@ -5921,7 +5180,7 @@ async function bootstrapWorkspacePackage(packageDir, iuiRoot2) {
|
|
|
5921
5180
|
}
|
|
5922
5181
|
registerWorkspacePackage(resolvedIuiRoot, resolvedPackage);
|
|
5923
5182
|
bootstrapRegisteredPackages(resolvedIuiRoot);
|
|
5924
|
-
ok("
|
|
5183
|
+
ok("Bootstrap bridge ready");
|
|
5925
5184
|
hint(
|
|
5926
5185
|
"This app is linked to an existing IUI setup \u2014 packages and configs stay at the IUI root."
|
|
5927
5186
|
);
|
|
@@ -5933,28 +5192,28 @@ async function bootstrapWorkspacePackage(packageDir, iuiRoot2) {
|
|
|
5933
5192
|
}
|
|
5934
5193
|
|
|
5935
5194
|
// src/services/slot-registry.ts
|
|
5936
|
-
var STATE_SCHEMA_VERSION =
|
|
5195
|
+
var STATE_SCHEMA_VERSION = 2;
|
|
5937
5196
|
function statePath(cwd) {
|
|
5938
5197
|
return iuiCacheFile(cwd, "slotState");
|
|
5939
5198
|
}
|
|
5940
5199
|
function now() {
|
|
5941
5200
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
5942
5201
|
}
|
|
5943
|
-
function checksumFor(components,
|
|
5944
|
-
return sha256(JSON.stringify({ components,
|
|
5202
|
+
function checksumFor(components, packages) {
|
|
5203
|
+
return sha256(JSON.stringify({ components, packages }));
|
|
5945
5204
|
}
|
|
5946
5205
|
function backupCorruptFile(filePath) {
|
|
5947
|
-
if (!
|
|
5206
|
+
if (!fs16.existsSync(filePath)) return;
|
|
5948
5207
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
5949
5208
|
try {
|
|
5950
|
-
|
|
5209
|
+
fs16.moveSync(filePath, `${filePath}.corrupt-${stamp}`, { overwrite: false });
|
|
5951
5210
|
} catch {
|
|
5952
5211
|
}
|
|
5953
5212
|
}
|
|
5954
5213
|
function readJsonObject(filePath, fallback, issues, label) {
|
|
5955
|
-
if (!
|
|
5214
|
+
if (!fs16.existsSync(filePath)) return fallback;
|
|
5956
5215
|
try {
|
|
5957
|
-
const value =
|
|
5216
|
+
const value = fs16.readJsonSync(filePath);
|
|
5958
5217
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
5959
5218
|
return value;
|
|
5960
5219
|
}
|
|
@@ -5966,9 +5225,9 @@ function readJsonObject(filePath, fallback, issues, label) {
|
|
|
5966
5225
|
}
|
|
5967
5226
|
function readState(cwd, issues) {
|
|
5968
5227
|
const filePath = statePath(cwd);
|
|
5969
|
-
if (!
|
|
5228
|
+
if (!fs16.existsSync(filePath)) return null;
|
|
5970
5229
|
try {
|
|
5971
|
-
const raw =
|
|
5230
|
+
const raw = fs16.readJsonSync(filePath);
|
|
5972
5231
|
if (raw.schemaVersion !== STATE_SCHEMA_VERSION) {
|
|
5973
5232
|
issues.push("registration state schema was upgraded");
|
|
5974
5233
|
return null;
|
|
@@ -5997,37 +5256,15 @@ function updateState(cwd, state, phase, patch = {}) {
|
|
|
5997
5256
|
writeState(cwd, next);
|
|
5998
5257
|
return next;
|
|
5999
5258
|
}
|
|
6000
|
-
function
|
|
5259
|
+
function buildDesiredComponents(registry, packageVersion) {
|
|
6001
5260
|
const components = {};
|
|
6002
|
-
const slots = {};
|
|
6003
|
-
const timestamp = now();
|
|
6004
5261
|
for (const item of registry.items) {
|
|
6005
5262
|
components[item.name] = packageVersion;
|
|
6006
|
-
slots[item.name] = {
|
|
6007
|
-
component: item.name,
|
|
6008
|
-
slotType: "component",
|
|
6009
|
-
registeredAt: currentSlots[item.name]?.registeredAt ?? timestamp,
|
|
6010
|
-
version: packageVersion
|
|
6011
|
-
};
|
|
6012
|
-
if (item.slots.length > 0) {
|
|
6013
|
-
slots[item.name].supportedSlots = [...item.slots].sort();
|
|
6014
|
-
}
|
|
6015
|
-
}
|
|
6016
|
-
for (const [packageId, meta] of Object.entries(packages)) {
|
|
6017
|
-
const def = ASSET_PACKAGES_MAP[packageId];
|
|
6018
|
-
if (!def) continue;
|
|
6019
|
-
const key = `asset:${packageId}`;
|
|
6020
|
-
slots[key] = {
|
|
6021
|
-
component: packageId,
|
|
6022
|
-
slotType: def.slotType,
|
|
6023
|
-
registeredAt: currentSlots[key]?.registeredAt ?? timestamp,
|
|
6024
|
-
version: meta.version
|
|
6025
|
-
};
|
|
6026
5263
|
}
|
|
6027
|
-
return
|
|
5264
|
+
return components;
|
|
6028
5265
|
}
|
|
6029
|
-
function hasManifestDrift(currentComponents,
|
|
6030
|
-
return JSON.stringify(currentComponents) !== JSON.stringify(desiredComponents)
|
|
5266
|
+
function hasManifestDrift(currentComponents, desiredComponents) {
|
|
5267
|
+
return JSON.stringify(currentComponents) !== JSON.stringify(desiredComponents);
|
|
6031
5268
|
}
|
|
6032
5269
|
function shouldSkipWritesFastPath(params) {
|
|
6033
5270
|
const {
|
|
@@ -6072,7 +5309,7 @@ async function ensureSlotRegistry(options = {}) {
|
|
|
6072
5309
|
}
|
|
6073
5310
|
const iuiRoot2 = resolveIuiProjectRoot(cwd);
|
|
6074
5311
|
return withRegistryLock(iuiRoot2, async () => {
|
|
6075
|
-
const iuiPath =
|
|
5312
|
+
const iuiPath = path20.join(iuiRoot2, IUI_DIR);
|
|
6076
5313
|
const issues = [];
|
|
6077
5314
|
cleanupTempFiles(iuiPath);
|
|
6078
5315
|
const registry = ensureInstalledManifest(
|
|
@@ -6098,37 +5335,25 @@ async function ensureSlotRegistry(options = {}) {
|
|
|
6098
5335
|
issues,
|
|
6099
5336
|
".iui/packages.json"
|
|
6100
5337
|
);
|
|
6101
|
-
const
|
|
6102
|
-
|
|
6103
|
-
{},
|
|
6104
|
-
issues,
|
|
6105
|
-
".iui/slots.json"
|
|
6106
|
-
);
|
|
6107
|
-
const desired = buildDesiredState(
|
|
6108
|
-
registry,
|
|
6109
|
-
packageVersion,
|
|
6110
|
-
currentSlots,
|
|
6111
|
-
currentPackages
|
|
6112
|
-
);
|
|
6113
|
-
const checksum = checksumFor(desired.components, desired.slots);
|
|
5338
|
+
const desiredComponents = buildDesiredComponents(registry, packageVersion);
|
|
5339
|
+
const checksum = checksumFor(desiredComponents, currentPackages);
|
|
6114
5340
|
if (previousState?.status === "running" || previousState?.status === "failed") {
|
|
6115
5341
|
issues.push("interrupted registration was resumed");
|
|
6116
5342
|
}
|
|
6117
5343
|
if (previousState?.checksum && previousState.checksum !== checksum) {
|
|
6118
|
-
issues.push("
|
|
5344
|
+
issues.push("registry checksum changed");
|
|
6119
5345
|
}
|
|
6120
|
-
const driftDetected = hasManifestDrift(
|
|
6121
|
-
currentComponents,
|
|
6122
|
-
currentSlots,
|
|
6123
|
-
desired.components,
|
|
6124
|
-
desired.slots
|
|
6125
|
-
);
|
|
5346
|
+
const driftDetected = hasManifestDrift(currentComponents, desiredComponents);
|
|
6126
5347
|
if (driftDetected) {
|
|
6127
|
-
issues.push("
|
|
5348
|
+
issues.push("component manifest drifted");
|
|
6128
5349
|
}
|
|
6129
|
-
const
|
|
6130
|
-
|
|
6131
|
-
|
|
5350
|
+
const staleSlotOutput = findStaleComponentSlotOutput(
|
|
5351
|
+
iuiRoot2,
|
|
5352
|
+
registeredPackageDirs(iuiRoot2)
|
|
5353
|
+
);
|
|
5354
|
+
const integrityIssues = staleSlotOutput.map(
|
|
5355
|
+
(file) => `stale component-slot output: ${path20.relative(iuiRoot2, file) || file}`
|
|
5356
|
+
);
|
|
6132
5357
|
if (shouldSkipWritesFastPath({
|
|
6133
5358
|
mode,
|
|
6134
5359
|
previousState,
|
|
@@ -6146,8 +5371,8 @@ async function ensureSlotRegistry(options = {}) {
|
|
|
6146
5371
|
if (mode === "validate") {
|
|
6147
5372
|
if (integrityIssues.length > 0) {
|
|
6148
5373
|
throw new CLIError(
|
|
6149
|
-
"
|
|
6150
|
-
|
|
5374
|
+
"Stale component-slot files from an older iui version were found.",
|
|
5375
|
+
"Run iui doctor --fix (or iui update) to regenerate .iui/generated and remove them."
|
|
6151
5376
|
);
|
|
6152
5377
|
}
|
|
6153
5378
|
return {
|
|
@@ -6170,32 +5395,32 @@ async function ensureSlotRegistry(options = {}) {
|
|
|
6170
5395
|
writeState(iuiRoot2, state);
|
|
6171
5396
|
updateState(iuiRoot2, state, "state-loaded");
|
|
6172
5397
|
await retry(() => {
|
|
6173
|
-
writeComponentManifest(
|
|
5398
|
+
writeComponentManifest(desiredComponents, iuiRoot2);
|
|
6174
5399
|
writePackageManifest(currentPackages, iuiRoot2);
|
|
6175
|
-
writeSlotManifest(desired.slots, iuiRoot2);
|
|
6176
5400
|
});
|
|
6177
5401
|
let next = updateState(iuiRoot2, state, "manifests-written", {
|
|
6178
5402
|
checksum,
|
|
6179
5403
|
repairedIssues: issues
|
|
6180
5404
|
});
|
|
6181
5405
|
await retry(async () => {
|
|
6182
|
-
writeComponentSlotFiles(iuiRoot2);
|
|
6183
5406
|
writeAssetsConfig(iuiRoot2);
|
|
6184
5407
|
ensureProjectConfig(iuiRoot2);
|
|
6185
|
-
await writeAssetBoundFiles(iuiRoot2);
|
|
6186
|
-
writeSlotHelperFile(iuiRoot2);
|
|
6187
5408
|
if (projectHasViteTooling(cwd)) {
|
|
6188
5409
|
ensureInventiveUiViteConfig(cwd);
|
|
6189
5410
|
}
|
|
6190
5411
|
});
|
|
6191
5412
|
bootstrapRegisteredPackages(iuiRoot2);
|
|
6192
|
-
next = updateState(iuiRoot2, next, "
|
|
6193
|
-
|
|
5413
|
+
next = updateState(iuiRoot2, next, "generated-files-written", { repairedIssues: issues });
|
|
5414
|
+
const leftover = findStaleComponentSlotOutput(iuiRoot2, registeredPackageDirs(iuiRoot2));
|
|
5415
|
+
if (leftover.length > 0) {
|
|
6194
5416
|
throw new CLIError(
|
|
6195
|
-
"
|
|
6196
|
-
|
|
5417
|
+
"Could not remove stale component-slot output.",
|
|
5418
|
+
leftover.map((file) => `- ${path20.relative(iuiRoot2, file) || file}`).join("\n")
|
|
6197
5419
|
);
|
|
6198
5420
|
}
|
|
5421
|
+
if (integrityIssues.length > 0) {
|
|
5422
|
+
issues.push(...integrityIssues.map((issue) => `removed ${issue}`));
|
|
5423
|
+
}
|
|
6199
5424
|
next = updateState(iuiRoot2, next, "integrity-verified", { repairedIssues: issues });
|
|
6200
5425
|
updateState(iuiRoot2, next, "complete", {
|
|
6201
5426
|
status: "complete",
|
|
@@ -6204,7 +5429,7 @@ async function ensureSlotRegistry(options = {}) {
|
|
|
6204
5429
|
repairedIssues: issues
|
|
6205
5430
|
});
|
|
6206
5431
|
if (!options.quiet && issues.length > 0) {
|
|
6207
|
-
ok("
|
|
5432
|
+
ok("Project registry repaired");
|
|
6208
5433
|
}
|
|
6209
5434
|
return {
|
|
6210
5435
|
status: issues.length > 0 ? "repaired" : "valid",
|
|
@@ -6212,7 +5437,7 @@ async function ensureSlotRegistry(options = {}) {
|
|
|
6212
5437
|
repairedIssues: issues
|
|
6213
5438
|
};
|
|
6214
5439
|
} catch (error) {
|
|
6215
|
-
const message = error instanceof Error ? error.message : "
|
|
5440
|
+
const message = error instanceof Error ? error.message : "Project registry update failed";
|
|
6216
5441
|
if (state) {
|
|
6217
5442
|
updateState(iuiRoot2, state, "state-loaded", {
|
|
6218
5443
|
status: "failed",
|
|
@@ -6286,15 +5511,15 @@ async function installComponentsPackage(opts) {
|
|
|
6286
5511
|
mode: "repair"
|
|
6287
5512
|
});
|
|
6288
5513
|
if (result.status === "skipped") {
|
|
6289
|
-
warn("Component
|
|
5514
|
+
warn("Component registry was not generated.");
|
|
6290
5515
|
hint(
|
|
6291
5516
|
"Run iui init in this package (or iui doctor). Hoisted node_modules are supported \u2014 a root-level install is not required."
|
|
6292
5517
|
);
|
|
6293
5518
|
} else {
|
|
6294
5519
|
ok(
|
|
6295
|
-
result.status === "repaired" ? `
|
|
5520
|
+
result.status === "repaired" ? `Components registry repaired for ${COMPONENTS_PACKAGE} ${dim(`v${pkgVersion}`)}` : `Components ready for ${COMPONENTS_PACKAGE} ${dim(`v${pkgVersion}`)}`
|
|
6296
5521
|
);
|
|
6297
|
-
hint('Import components from "@inventive-ui/components"
|
|
5522
|
+
hint('Import components from "@inventive-ui/components".');
|
|
6298
5523
|
}
|
|
6299
5524
|
return { previousVersion, version: pkgVersion };
|
|
6300
5525
|
}
|
|
@@ -6367,7 +5592,7 @@ async function initCommand(opts) {
|
|
|
6367
5592
|
try {
|
|
6368
5593
|
heading("Initialize Project");
|
|
6369
5594
|
const existingIuiRoot = findIuiProjectRoot(invocationCwd);
|
|
6370
|
-
if (existingIuiRoot &&
|
|
5595
|
+
if (existingIuiRoot && path21.resolve(existingIuiRoot) !== path21.resolve(invocationCwd)) {
|
|
6371
5596
|
await bootstrapWorkspacePackage(invocationCwd, existingIuiRoot);
|
|
6372
5597
|
return;
|
|
6373
5598
|
}
|
|
@@ -6386,10 +5611,10 @@ async function initCommand(opts) {
|
|
|
6386
5611
|
return;
|
|
6387
5612
|
}
|
|
6388
5613
|
const originalCwd = process.cwd();
|
|
6389
|
-
if (
|
|
5614
|
+
if (path21.resolve(initRoot) !== path21.resolve(originalCwd)) {
|
|
6390
5615
|
process.chdir(initRoot);
|
|
6391
5616
|
hint(
|
|
6392
|
-
`Monorepo --workspace: initializing at ${
|
|
5617
|
+
`Monorepo --workspace: initializing at ${path21.relative(invocationCwd, initRoot) || initRoot}`
|
|
6393
5618
|
);
|
|
6394
5619
|
} else if (!sharedWorkspace && findIuiProjectRoot(initRoot) === null) {
|
|
6395
5620
|
hint("Initializing this package only \u2014 other monorepo apps are untouched.");
|
|
@@ -6450,7 +5675,7 @@ async function initCommand(opts) {
|
|
|
6450
5675
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6451
5676
|
initScope: sharedWorkspace ? "workspace" : "package",
|
|
6452
5677
|
configs: {
|
|
6453
|
-
theme: "./
|
|
5678
|
+
theme: "./theme.config.ts",
|
|
6454
5679
|
assets: "./assets.config.json",
|
|
6455
5680
|
components: "./component.config.ts"
|
|
6456
5681
|
}
|
|
@@ -6514,12 +5739,12 @@ async function initCommand(opts) {
|
|
|
6514
5739
|
ensureTsConfigForIui(framework.framework, initRoot);
|
|
6515
5740
|
if (framework.framework === "vite") {
|
|
6516
5741
|
ensureInventiveUiViteConfig(initRoot);
|
|
6517
|
-
ok("Config files ready (
|
|
5742
|
+
ok("Config files ready (theme.config.ts, tsconfig.json, tsconfig.node.json, vite.config.ts)");
|
|
6518
5743
|
} else {
|
|
6519
5744
|
if (removeStaleIuiViteConfig(initRoot)) {
|
|
6520
5745
|
hint("Removed vite.config.ts (React-only preset \u2014 no Vite tooling required).");
|
|
6521
5746
|
}
|
|
6522
|
-
ok("Config files ready (
|
|
5747
|
+
ok("Config files ready (theme.config.ts, tsconfig.json)");
|
|
6523
5748
|
}
|
|
6524
5749
|
step("Scaffolding component.config.ts\u2026");
|
|
6525
5750
|
const fetchedRegistry = await fetchComponentRegistry(auth.token);
|
|
@@ -7272,17 +6497,17 @@ async function deployTokenRevokeCommand(tokenId) {
|
|
|
7272
6497
|
}
|
|
7273
6498
|
|
|
7274
6499
|
// src/commands/setup.ts
|
|
7275
|
-
import
|
|
7276
|
-
import
|
|
6500
|
+
import path24 from "path";
|
|
6501
|
+
import fs18 from "fs-extra";
|
|
7277
6502
|
import ora6 from "ora";
|
|
7278
6503
|
|
|
7279
6504
|
// src/commands/doctor.ts
|
|
7280
|
-
import
|
|
6505
|
+
import path23 from "path";
|
|
7281
6506
|
|
|
7282
6507
|
// src/services/health.ts
|
|
7283
6508
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
7284
|
-
import
|
|
7285
|
-
import
|
|
6509
|
+
import path22 from "path";
|
|
6510
|
+
import fs17 from "fs-extra";
|
|
7286
6511
|
function installDevTypeScript(cwd) {
|
|
7287
6512
|
const pm = detectPackageManager(cwd);
|
|
7288
6513
|
try {
|
|
@@ -7310,23 +6535,24 @@ function checkPackageCompatibility(cwd = process.cwd()) {
|
|
|
7310
6535
|
summary: `Core packages installed (framework ${frameworkVersion}, components ${componentsVersion})`
|
|
7311
6536
|
};
|
|
7312
6537
|
}
|
|
7313
|
-
function
|
|
7314
|
-
const
|
|
7315
|
-
|
|
6538
|
+
function checkStaleComponentSlotOutput(cwd = process.cwd()) {
|
|
6539
|
+
const iuiRoot2 = resolveIuiProjectRoot(cwd);
|
|
6540
|
+
const stale = findStaleComponentSlotOutput(iuiRoot2, [cwd]);
|
|
6541
|
+
if (stale.length > 0) {
|
|
7316
6542
|
return {
|
|
7317
6543
|
ok: false,
|
|
7318
|
-
summary:
|
|
7319
|
-
details:
|
|
6544
|
+
summary: `${stale.length} stale component-slot file${stale.length === 1 ? "" : "s"} from an older iui version`,
|
|
6545
|
+
details: stale.slice(0, 8).map((file) => `- ${path22.relative(iuiRoot2, file) || file}`).join("\n")
|
|
7320
6546
|
};
|
|
7321
6547
|
}
|
|
7322
6548
|
return {
|
|
7323
6549
|
ok: true,
|
|
7324
|
-
summary: "
|
|
6550
|
+
summary: "No stale component-slot output"
|
|
7325
6551
|
};
|
|
7326
6552
|
}
|
|
7327
6553
|
function checkComponentConfigValidity(cwd = process.cwd(), options = {}) {
|
|
7328
|
-
const configPath =
|
|
7329
|
-
if (!
|
|
6554
|
+
const configPath = path22.join(cwd, COMPONENT_CONFIG_FILE);
|
|
6555
|
+
if (!fs17.existsSync(configPath)) {
|
|
7330
6556
|
return {
|
|
7331
6557
|
ok: false,
|
|
7332
6558
|
summary: "component.config.ts not found",
|
|
@@ -7334,8 +6560,8 @@ function checkComponentConfigValidity(cwd = process.cwd(), options = {}) {
|
|
|
7334
6560
|
};
|
|
7335
6561
|
}
|
|
7336
6562
|
const tsPkgDir = resolvePackageDir("typescript", cwd);
|
|
7337
|
-
const tscPath = tsPkgDir ?
|
|
7338
|
-
if (!
|
|
6563
|
+
const tscPath = tsPkgDir ? path22.join(tsPkgDir, "bin", "tsc") : path22.join(cwd, "node_modules", "typescript", "bin", "tsc");
|
|
6564
|
+
if (!fs17.existsSync(tscPath)) {
|
|
7339
6565
|
if (!options.autoFix) {
|
|
7340
6566
|
return {
|
|
7341
6567
|
ok: false,
|
|
@@ -7403,33 +6629,36 @@ ${stderr}`.trim() };
|
|
|
7403
6629
|
function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
|
|
7404
6630
|
const warnings = [];
|
|
7405
6631
|
const hints = [];
|
|
7406
|
-
const configPath =
|
|
7407
|
-
|
|
7408
|
-
|
|
6632
|
+
const configPath = path22.join(
|
|
6633
|
+
cwd,
|
|
6634
|
+
fs17.existsSync(path22.join(cwd, PROJECT_CONFIG_FILE)) || !fs17.existsSync(path22.join(cwd, "iui.config.ts")) ? PROJECT_CONFIG_FILE : "iui.config.ts"
|
|
6635
|
+
);
|
|
6636
|
+
if (fs17.existsSync(configPath)) {
|
|
6637
|
+
const configContent = fs17.readFileSync(configPath, "utf-8");
|
|
7409
6638
|
if (/packageSafelist\s*:\s*false/.test(configContent)) {
|
|
7410
6639
|
warnings.push(
|
|
7411
|
-
"Deprecated
|
|
6640
|
+
"Deprecated theme.config build.packageSafelist \u2014 remove it; Framework always merges IUI package compile contracts"
|
|
7412
6641
|
);
|
|
7413
6642
|
}
|
|
7414
6643
|
if (/includeShadeMatrix\s*:/.test(configContent)) {
|
|
7415
6644
|
warnings.push(
|
|
7416
|
-
"Deprecated compiler flags in
|
|
6645
|
+
"Deprecated compiler flags in theme.config build.* \u2014 remove them; compile policy is Framework-internal"
|
|
7417
6646
|
);
|
|
7418
6647
|
hints.push("Use theme + optional scan.dirs only. See Framework docs/01-compile-first-guide.md");
|
|
7419
6648
|
}
|
|
7420
6649
|
if (/scanPackages\s*:/.test(configContent) || /scan\.packages\s*:/.test(configContent)) {
|
|
7421
6650
|
warnings.push(
|
|
7422
|
-
"Deprecated scanPackages in
|
|
6651
|
+
"Deprecated scanPackages in theme.config \u2014 IUI packages are discovered from package.json dependencies"
|
|
7423
6652
|
);
|
|
7424
6653
|
}
|
|
7425
6654
|
}
|
|
7426
6655
|
if (projectHasViteTooling(cwd)) {
|
|
7427
6656
|
const viteCandidates = ["vite.config.ts", "vite.config.mjs", "vite.config.js"];
|
|
7428
|
-
const vitePath = viteCandidates.map((name) =>
|
|
6657
|
+
const vitePath = viteCandidates.map((name) => path22.join(cwd, name)).find((p) => fs17.existsSync(p));
|
|
7429
6658
|
if (!vitePath) {
|
|
7430
6659
|
warnings.push("Vite tooling detected but no vite.config.* found");
|
|
7431
6660
|
} else {
|
|
7432
|
-
const viteContent =
|
|
6661
|
+
const viteContent = fs17.readFileSync(vitePath, "utf-8");
|
|
7433
6662
|
if (!/inventiveUiVite\s*\(/.test(viteContent)) {
|
|
7434
6663
|
warnings.push("vite.config is missing inventiveUiVite() \u2014 compile-first CSS will not generate");
|
|
7435
6664
|
hints.push("Wire plugins: [...inventiveUiVite({ root: import.meta.dirname }), react()]");
|
|
@@ -7443,11 +6672,11 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
|
|
|
7443
6672
|
"webpack.config.mjs",
|
|
7444
6673
|
"webpack.config.ts"
|
|
7445
6674
|
];
|
|
7446
|
-
const webpackPath = webpackCandidates.map((name) =>
|
|
6675
|
+
const webpackPath = webpackCandidates.map((name) => path22.join(cwd, name)).find((p) => fs17.existsSync(p));
|
|
7447
6676
|
if (!webpackPath) {
|
|
7448
6677
|
warnings.push("Webpack tooling detected but no webpack.config.* found");
|
|
7449
6678
|
} else {
|
|
7450
|
-
const webpackContent =
|
|
6679
|
+
const webpackContent = fs17.readFileSync(webpackPath, "utf-8");
|
|
7451
6680
|
if (!/inventiveUiWebpack\s*\(/.test(webpackContent)) {
|
|
7452
6681
|
warnings.push("webpack.config is missing inventiveUiWebpack() \u2014 compile-first CSS will not generate");
|
|
7453
6682
|
hints.push('Wire plugins: [...inventiveUiWebpack()] from "@inventive-ui/framework/webpack"');
|
|
@@ -7457,11 +6686,11 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
|
|
|
7457
6686
|
}
|
|
7458
6687
|
if (projectHasNextTooling(cwd)) {
|
|
7459
6688
|
const nextCandidates = ["next.config.ts", "next.config.mjs", "next.config.js", "next.config.cjs"];
|
|
7460
|
-
const nextPath = nextCandidates.map((name) =>
|
|
6689
|
+
const nextPath = nextCandidates.map((name) => path22.join(cwd, name)).find((p) => fs17.existsSync(p));
|
|
7461
6690
|
if (!nextPath) {
|
|
7462
6691
|
warnings.push("Next.js detected but no next.config.* found");
|
|
7463
6692
|
} else {
|
|
7464
|
-
const nextContent =
|
|
6693
|
+
const nextContent = fs17.readFileSync(nextPath, "utf-8");
|
|
7465
6694
|
if (!/withIUI\s*\(/.test(nextContent)) {
|
|
7466
6695
|
warnings.push("next.config is missing withIUI() \u2014 compile-first CSS will not generate");
|
|
7467
6696
|
hints.push('Wrap config: export default withIUI({ ... }) from "@inventive-ui/framework/next"');
|
|
@@ -7474,18 +6703,18 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
|
|
|
7474
6703
|
"src/app/layout.jsx",
|
|
7475
6704
|
"app/providers.tsx",
|
|
7476
6705
|
"src/app/providers.tsx"
|
|
7477
|
-
].map((rel) =>
|
|
7478
|
-
const readableLayouts = layoutCandidates.filter((file) =>
|
|
6706
|
+
].map((rel) => path22.join(cwd, rel));
|
|
6707
|
+
const readableLayouts = layoutCandidates.filter((file) => fs17.existsSync(file));
|
|
7479
6708
|
const hasRegistry = readableLayouts.some((file) => {
|
|
7480
6709
|
try {
|
|
7481
|
-
return /\bIUIRegistry\b/.test(
|
|
6710
|
+
return /\bIUIRegistry\b/.test(fs17.readFileSync(file, "utf-8"));
|
|
7482
6711
|
} catch {
|
|
7483
6712
|
return false;
|
|
7484
6713
|
}
|
|
7485
6714
|
});
|
|
7486
6715
|
const hasBootstrapImport = readableLayouts.some((file) => {
|
|
7487
6716
|
try {
|
|
7488
|
-
const content =
|
|
6717
|
+
const content = fs17.readFileSync(file, "utf-8");
|
|
7489
6718
|
return /next\/bootstrap/.test(content) || /["']iui-bootstrap["']/.test(content) || /iui\/bootstrap/.test(content);
|
|
7490
6719
|
} catch {
|
|
7491
6720
|
return false;
|
|
@@ -7493,7 +6722,7 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
|
|
|
7493
6722
|
});
|
|
7494
6723
|
const hasProvider = readableLayouts.some((file) => {
|
|
7495
6724
|
try {
|
|
7496
|
-
return /\bIUIProvider\b/.test(
|
|
6725
|
+
return /\bIUIProvider\b/.test(fs17.readFileSync(file, "utf-8"));
|
|
7497
6726
|
} catch {
|
|
7498
6727
|
return false;
|
|
7499
6728
|
}
|
|
@@ -7524,14 +6753,14 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
|
|
|
7524
6753
|
"src/app/providers.tsx",
|
|
7525
6754
|
"app/layout.tsx",
|
|
7526
6755
|
"src/app/layout.tsx"
|
|
7527
|
-
].map((rel) =>
|
|
6756
|
+
].map((rel) => path22.join(cwd, rel));
|
|
7528
6757
|
for (const file of entryCandidates) {
|
|
7529
|
-
if (!
|
|
6758
|
+
if (!fs17.existsSync(file)) continue;
|
|
7530
6759
|
try {
|
|
7531
|
-
const content =
|
|
6760
|
+
const content = fs17.readFileSync(file, "utf-8");
|
|
7532
6761
|
if (/from\s+['"][^'"]*\.generated['"]/.test(content) || /import\s+['"][^'"]*\.generated['"]/.test(content)) {
|
|
7533
6762
|
warnings.push(
|
|
7534
|
-
`Do not import .generated style-map files into the browser (${
|
|
6763
|
+
`Do not import .generated style-map files into the browser (${path22.relative(cwd, file)})`
|
|
7535
6764
|
);
|
|
7536
6765
|
hints.push(
|
|
7537
6766
|
"Keep style maps on the scanner path (default src + .iui/generated, or override build.scanDirs) \u2014 see Framework compile-first docs"
|
|
@@ -7551,9 +6780,9 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
|
|
|
7551
6780
|
hints.push(
|
|
7552
6781
|
"Compile-first: avoid dynamic utility templates like `p-${n}` \u2014 use static strings, style maps, or safelist (ESLint: customPlugin/no-dynamic-utility-class)"
|
|
7553
6782
|
);
|
|
7554
|
-
const giPath =
|
|
7555
|
-
if (
|
|
7556
|
-
const gi =
|
|
6783
|
+
const giPath = path22.join(cwd, ".gitignore");
|
|
6784
|
+
if (fs17.existsSync(giPath)) {
|
|
6785
|
+
const gi = fs17.readFileSync(giPath, "utf-8");
|
|
7557
6786
|
if (!gi.includes(".iui/cache/")) {
|
|
7558
6787
|
warnings.push(".gitignore missing IUI cache directory (.iui/cache/)");
|
|
7559
6788
|
hints.push("Run iui init or append .iui/cache/ from the IUI docs");
|
|
@@ -7564,11 +6793,11 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
|
|
|
7564
6793
|
function checkMetadataPortability(cwd = process.cwd()) {
|
|
7565
6794
|
const warnings = [];
|
|
7566
6795
|
const hints = [];
|
|
7567
|
-
const iuiPath =
|
|
7568
|
-
const projectPath =
|
|
7569
|
-
if (
|
|
6796
|
+
const iuiPath = path22.join(cwd, IUI_DIR);
|
|
6797
|
+
const projectPath = path22.join(iuiPath, "project.json");
|
|
6798
|
+
if (fs17.existsSync(projectPath)) {
|
|
7570
6799
|
try {
|
|
7571
|
-
const meta =
|
|
6800
|
+
const meta = fs17.readJsonSync(projectPath);
|
|
7572
6801
|
const repoUrl = meta.repoUrl ?? "";
|
|
7573
6802
|
if (/^[A-Za-z]:[\\/]/.test(repoUrl) || repoUrl.startsWith("/") && !repoUrl.startsWith("//") || repoUrl.startsWith("file:")) {
|
|
7574
6803
|
warnings.push("project.json repoUrl is a local filesystem path \u2014 use a git remote URL");
|
|
@@ -7577,15 +6806,15 @@ function checkMetadataPortability(cwd = process.cwd()) {
|
|
|
7577
6806
|
} catch {
|
|
7578
6807
|
}
|
|
7579
6808
|
}
|
|
7580
|
-
const workspacePath =
|
|
7581
|
-
if (
|
|
6809
|
+
const workspacePath = path22.join(iuiPath, "workspace.json");
|
|
6810
|
+
if (fs17.existsSync(workspacePath)) {
|
|
7582
6811
|
try {
|
|
7583
|
-
const ws =
|
|
6812
|
+
const ws = fs17.readJsonSync(workspacePath);
|
|
7584
6813
|
if (ws.iuiRoot) {
|
|
7585
6814
|
warnings.push("workspace.json contains deprecated iuiRoot \u2014 remove it (root is implicit)");
|
|
7586
6815
|
}
|
|
7587
6816
|
for (const pkg of ws.packages ?? []) {
|
|
7588
|
-
if (/^[A-Za-z]:[\\/]/.test(pkg) ||
|
|
6817
|
+
if (/^[A-Za-z]:[\\/]/.test(pkg) || path22.isAbsolute(pkg)) {
|
|
7589
6818
|
warnings.push(`workspace.json packages entry is absolute: ${pkg}`);
|
|
7590
6819
|
hints.push("packages should be relative paths from the IUI root");
|
|
7591
6820
|
}
|
|
@@ -7594,9 +6823,9 @@ function checkMetadataPortability(cwd = process.cwd()) {
|
|
|
7594
6823
|
}
|
|
7595
6824
|
}
|
|
7596
6825
|
const scanCachePath = iuiCacheFile(cwd, "scan");
|
|
7597
|
-
if (
|
|
6826
|
+
if (fs17.existsSync(scanCachePath)) {
|
|
7598
6827
|
try {
|
|
7599
|
-
const cache =
|
|
6828
|
+
const cache = fs17.readJsonSync(scanCachePath);
|
|
7600
6829
|
const absoluteKeys = Object.keys(cache.files ?? {}).filter(
|
|
7601
6830
|
(key) => /^[A-Za-z]:[\\/]/.test(key) || key.startsWith("/") && !key.startsWith("//")
|
|
7602
6831
|
);
|
|
@@ -7613,38 +6842,70 @@ function checkMetadataPortability(cwd = process.cwd()) {
|
|
|
7613
6842
|
}
|
|
7614
6843
|
return { warnings, hints };
|
|
7615
6844
|
}
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
6845
|
+
var ICON_LIBRARY_PACKAGES = {
|
|
6846
|
+
"material-symbols": "material-symbols",
|
|
6847
|
+
materialSymbols: "material-symbols",
|
|
6848
|
+
"material-icons": "icons-material",
|
|
6849
|
+
lucide: "icons-lucide",
|
|
6850
|
+
phosphor: "icons-phosphor"
|
|
6851
|
+
};
|
|
6852
|
+
function checkAssetPipeline(cwd = process.cwd()) {
|
|
6853
|
+
const assetsPath = path22.join(cwd, ASSETS_CONFIG_FILE);
|
|
6854
|
+
if (!fs17.existsSync(assetsPath)) {
|
|
6855
|
+
return { ok: true, summary: "Asset check skipped (no assets.config.json)" };
|
|
7620
6856
|
}
|
|
7621
6857
|
let assets2;
|
|
7622
6858
|
try {
|
|
7623
|
-
assets2 =
|
|
6859
|
+
assets2 = fs17.readJsonSync(assetsPath);
|
|
7624
6860
|
} catch {
|
|
7625
6861
|
return { ok: false, summary: "assets.config.json is not valid JSON" };
|
|
7626
6862
|
}
|
|
7627
|
-
|
|
7628
|
-
|
|
6863
|
+
const packagesDir = path22.join(cwd, "node_modules", "@inventive-ui");
|
|
6864
|
+
const frameworkPkg = path22.join(packagesDir, "framework", "package.json");
|
|
6865
|
+
if (fs17.existsSync(frameworkPkg)) {
|
|
6866
|
+
const framework = fs17.readJsonSync(frameworkPkg);
|
|
6867
|
+
if (!framework.exports?.["./assets"]) {
|
|
6868
|
+
return {
|
|
6869
|
+
ok: false,
|
|
6870
|
+
summary: "Installed @inventive-ui/framework has no asset pipeline",
|
|
6871
|
+
details: "Update it: iui update"
|
|
6872
|
+
};
|
|
6873
|
+
}
|
|
6874
|
+
}
|
|
6875
|
+
const library = assets2.icon?.library;
|
|
6876
|
+
const pkg = library ? ICON_LIBRARY_PACKAGES[library] : void 0;
|
|
6877
|
+
if (!pkg) return { ok: true, summary: "Asset config valid" };
|
|
6878
|
+
const iconsDir = path22.join(packagesDir, pkg, "dist", "icons");
|
|
6879
|
+
if (!fs17.existsSync(iconsDir)) {
|
|
6880
|
+
return {
|
|
6881
|
+
ok: false,
|
|
6882
|
+
summary: `Icon library "${library}" is configured but @inventive-ui/${pkg} is not installed`,
|
|
6883
|
+
details: `Install it: iui install assets @inventive-ui/${pkg}`
|
|
6884
|
+
};
|
|
7629
6885
|
}
|
|
7630
|
-
const
|
|
7631
|
-
|
|
6886
|
+
const glyphs = [
|
|
6887
|
+
...Object.entries(assets2.icon?.globalIcons ?? {}).map(([alias, glyph]) => [`@${alias}`, glyph]),
|
|
6888
|
+
["placeholder", assets2.icon?.placeholder?.name],
|
|
6889
|
+
["fallback", assets2.icon?.fallback]
|
|
6890
|
+
].filter((entry) => typeof entry[1] === "string" && entry[1].length > 0);
|
|
6891
|
+
const missing = glyphs.filter(([, glyph]) => !fs17.existsSync(path22.join(iconsDir, `${glyph}.js`)));
|
|
6892
|
+
if (missing.length > 0) {
|
|
7632
6893
|
return {
|
|
7633
6894
|
ok: false,
|
|
7634
|
-
summary:
|
|
7635
|
-
details:
|
|
6895
|
+
summary: `${missing.length} icon alias${missing.length === 1 ? "" : "es"} point at glyphs "${library}" does not have`,
|
|
6896
|
+
details: missing.slice(0, 8).map(([name, glyph]) => `${name} \u2192 ${glyph}`).join(", ")
|
|
7636
6897
|
};
|
|
7637
6898
|
}
|
|
7638
|
-
return { ok: true, summary:
|
|
6899
|
+
return { ok: true, summary: `Asset config valid (${glyphs.length} icon names checked in ${library})` };
|
|
7639
6900
|
}
|
|
7640
6901
|
function checkBootstrapSync(cwd = process.cwd(), options = {}) {
|
|
7641
6902
|
const iuiRoot2 = resolveIuiProjectRoot(cwd);
|
|
7642
6903
|
const generatedPath = bootstrapGeneratedPath(iuiRoot2);
|
|
7643
|
-
const bridgePath =
|
|
7644
|
-
if (!
|
|
6904
|
+
const bridgePath = path22.join(cwd, "src", "iui", "bootstrap.ts");
|
|
6905
|
+
if (!fs17.existsSync(generatedPath)) {
|
|
7645
6906
|
if (options.autoFix) {
|
|
7646
6907
|
writeProjectBootstrapArtifacts(cwd, iuiRoot2);
|
|
7647
|
-
if (
|
|
6908
|
+
if (fs17.existsSync(generatedPath)) {
|
|
7648
6909
|
return { ok: true, summary: "Generated bootstrap artifacts repaired" };
|
|
7649
6910
|
}
|
|
7650
6911
|
}
|
|
@@ -7654,10 +6915,10 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
|
|
|
7654
6915
|
details: "Expected .iui/generated/bootstrap.generated.tsx \u2014 run iui doctor --fix."
|
|
7655
6916
|
};
|
|
7656
6917
|
}
|
|
7657
|
-
if (!
|
|
6918
|
+
if (!fs17.existsSync(bridgePath)) {
|
|
7658
6919
|
if (options.autoFix) {
|
|
7659
6920
|
writeProjectBootstrapArtifacts(cwd, iuiRoot2);
|
|
7660
|
-
if (
|
|
6921
|
+
if (fs17.existsSync(bridgePath)) {
|
|
7661
6922
|
return { ok: true, summary: "Bootstrap bridge repaired" };
|
|
7662
6923
|
}
|
|
7663
6924
|
}
|
|
@@ -7670,8 +6931,8 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
|
|
|
7670
6931
|
const configs = resolveProjectConfigPaths(iuiRoot2);
|
|
7671
6932
|
const missing = [];
|
|
7672
6933
|
for (const [key, rel] of Object.entries(configs)) {
|
|
7673
|
-
const abs =
|
|
7674
|
-
if (!
|
|
6934
|
+
const abs = path22.resolve(iuiRoot2, rel.replace(/^\.\//, ""));
|
|
6935
|
+
if (!fs17.existsSync(abs)) missing.push(`${key}: ${rel}`);
|
|
7675
6936
|
}
|
|
7676
6937
|
if (missing.length > 0) {
|
|
7677
6938
|
return {
|
|
@@ -7681,8 +6942,11 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
|
|
|
7681
6942
|
};
|
|
7682
6943
|
}
|
|
7683
6944
|
const expected = expectedBootstrapImportPaths(iuiRoot2);
|
|
7684
|
-
const generated =
|
|
6945
|
+
const generated = fs17.readFileSync(generatedPath, "utf8");
|
|
7685
6946
|
const stale = [];
|
|
6947
|
+
if (/["']\.\/slot\.generated["']|@inventive-ui\/framework\/slots/.test(generated)) {
|
|
6948
|
+
stale.push("bootstrap still imports removed component-slot output");
|
|
6949
|
+
}
|
|
7686
6950
|
for (const [key, importPath] of Object.entries(expected)) {
|
|
7687
6951
|
if (!generated.includes(`"${importPath}"`)) {
|
|
7688
6952
|
stale.push(`${key} import should be "${importPath}"`);
|
|
@@ -7691,11 +6955,11 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
|
|
|
7691
6955
|
if (stale.length > 0) {
|
|
7692
6956
|
if (options.autoFix) {
|
|
7693
6957
|
writeProjectBootstrapArtifacts(cwd, iuiRoot2);
|
|
7694
|
-
const refreshed =
|
|
6958
|
+
const refreshed = fs17.readFileSync(bootstrapGeneratedPath(iuiRoot2), "utf8");
|
|
7695
6959
|
const stillStale = Object.entries(expected).filter(
|
|
7696
6960
|
([, importPath]) => !refreshed.includes(`"${importPath}"`)
|
|
7697
6961
|
);
|
|
7698
|
-
if (stillStale.length === 0) {
|
|
6962
|
+
if (stillStale.length === 0 && !/slot\.generated/.test(refreshed)) {
|
|
7699
6963
|
return { ok: true, summary: "Generated bootstrap refreshed from project.json" };
|
|
7700
6964
|
}
|
|
7701
6965
|
}
|
|
@@ -7709,6 +6973,24 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
|
|
|
7709
6973
|
}
|
|
7710
6974
|
|
|
7711
6975
|
// src/commands/doctor.ts
|
|
6976
|
+
function repairStaleSlotOutput(targetCwd) {
|
|
6977
|
+
if (!isInsideProject(targetCwd)) return;
|
|
6978
|
+
writeProjectBootstrapArtifacts(targetCwd, resolveIuiProjectRoot(targetCwd));
|
|
6979
|
+
}
|
|
6980
|
+
function reportStaleSlotOutput(targetCwd, pass, fail2) {
|
|
6981
|
+
const staleSlots = checkStaleComponentSlotOutput(targetCwd);
|
|
6982
|
+
if (staleSlots.ok) {
|
|
6983
|
+
pass(staleSlots.summary);
|
|
6984
|
+
return;
|
|
6985
|
+
}
|
|
6986
|
+
fail2(staleSlots.summary);
|
|
6987
|
+
if (staleSlots.details) {
|
|
6988
|
+
for (const line of staleSlots.details.split("\n")) {
|
|
6989
|
+
hint(line);
|
|
6990
|
+
}
|
|
6991
|
+
}
|
|
6992
|
+
hint("Fix: run iui doctor --fix to remove it and regenerate bootstrap");
|
|
6993
|
+
}
|
|
7712
6994
|
async function runConfigTierDiagnostics(targetCwd, opts, counters, options = {}) {
|
|
7713
6995
|
const pass = (label) => {
|
|
7714
6996
|
checkPass(label);
|
|
@@ -7719,7 +7001,7 @@ async function runConfigTierDiagnostics(targetCwd, opts, counters, options = {})
|
|
|
7719
7001
|
counters.failed++;
|
|
7720
7002
|
};
|
|
7721
7003
|
const includePackageJson = options.includePackageJson !== false;
|
|
7722
|
-
const
|
|
7004
|
+
const includeStaleSlotCheck = options.includeStaleSlotCheck === true;
|
|
7723
7005
|
if (includePackageJson) {
|
|
7724
7006
|
if (hasPackageJson(targetCwd)) pass("package.json found");
|
|
7725
7007
|
else fail2("package.json missing");
|
|
@@ -7734,20 +7016,10 @@ async function runConfigTierDiagnostics(targetCwd, opts, counters, options = {})
|
|
|
7734
7016
|
}
|
|
7735
7017
|
ensureComponentConfig(readComponentPackageManifest(targetCwd), targetCwd);
|
|
7736
7018
|
await ensureSlotRegistry({ cwd: targetCwd, quiet: true, mode: "repair" });
|
|
7019
|
+
repairStaleSlotOutput(targetCwd);
|
|
7737
7020
|
}
|
|
7738
|
-
if (
|
|
7739
|
-
|
|
7740
|
-
if (slotValidity.ok) {
|
|
7741
|
-
pass(slotValidity.summary);
|
|
7742
|
-
} else {
|
|
7743
|
-
fail2(slotValidity.summary);
|
|
7744
|
-
if (slotValidity.details) {
|
|
7745
|
-
for (const line of slotValidity.details.split("\n")) {
|
|
7746
|
-
hint(line);
|
|
7747
|
-
}
|
|
7748
|
-
}
|
|
7749
|
-
hint("Fix: reinstall @inventive-ui/components and rerun iui doctor");
|
|
7750
|
-
}
|
|
7021
|
+
if (includeStaleSlotCheck && isInsideProject(targetCwd)) {
|
|
7022
|
+
reportStaleSlotOutput(targetCwd, pass, fail2);
|
|
7751
7023
|
}
|
|
7752
7024
|
const configValidity = checkComponentConfigValidity(targetCwd, {
|
|
7753
7025
|
autoFix: opts?.fix === true
|
|
@@ -7817,12 +7089,12 @@ async function runConfigTierDiagnostics(targetCwd, opts, counters, options = {})
|
|
|
7817
7089
|
hint(hint2);
|
|
7818
7090
|
}
|
|
7819
7091
|
}
|
|
7820
|
-
const
|
|
7821
|
-
if (
|
|
7822
|
-
pass(
|
|
7092
|
+
const assetPipeline = checkAssetPipeline(targetCwd);
|
|
7093
|
+
if (assetPipeline.ok) {
|
|
7094
|
+
pass(assetPipeline.summary);
|
|
7823
7095
|
} else {
|
|
7824
|
-
warn(
|
|
7825
|
-
if (
|
|
7096
|
+
warn(assetPipeline.summary);
|
|
7097
|
+
if (assetPipeline.details) hint(assetPipeline.details);
|
|
7826
7098
|
}
|
|
7827
7099
|
}
|
|
7828
7100
|
async function runPackageDiagnostics(targetCwd, opts, counters) {
|
|
@@ -7837,7 +7109,7 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
|
|
|
7837
7109
|
if (opts?.configOnly) {
|
|
7838
7110
|
await runConfigTierDiagnostics(targetCwd, opts, counters, {
|
|
7839
7111
|
includePackageJson: true,
|
|
7840
|
-
|
|
7112
|
+
includeStaleSlotCheck: true
|
|
7841
7113
|
});
|
|
7842
7114
|
return;
|
|
7843
7115
|
}
|
|
@@ -7852,6 +7124,7 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
|
|
|
7852
7124
|
}
|
|
7853
7125
|
ensureComponentConfig(readComponentPackageManifest(targetCwd), targetCwd);
|
|
7854
7126
|
await ensureSlotRegistry({ cwd: targetCwd, quiet: true, mode: "repair" });
|
|
7127
|
+
repairStaleSlotOutput(targetCwd);
|
|
7855
7128
|
}
|
|
7856
7129
|
if (isInsideProject(targetCwd)) {
|
|
7857
7130
|
pass("Inventive UI project initialized");
|
|
@@ -7899,9 +7172,6 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
|
|
|
7899
7172
|
const packages = readPackageManifest(targetCwd);
|
|
7900
7173
|
const pkgCount = Object.keys(packages).length;
|
|
7901
7174
|
pass(`${pkgCount} asset package${pkgCount !== 1 ? "s" : ""} installed`);
|
|
7902
|
-
const slots = readSlotManifest(targetCwd);
|
|
7903
|
-
const slotCount = Object.keys(slots).length;
|
|
7904
|
-
pass(`${slotCount} slot${slotCount !== 1 ? "s" : ""} registered`);
|
|
7905
7175
|
const compatibility = checkPackageCompatibility(targetCwd);
|
|
7906
7176
|
if (compatibility.ok) {
|
|
7907
7177
|
pass(compatibility.summary);
|
|
@@ -7942,18 +7212,7 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
|
|
|
7942
7212
|
pass("Inventive UI packages are on the latest version");
|
|
7943
7213
|
}
|
|
7944
7214
|
}
|
|
7945
|
-
|
|
7946
|
-
if (slotValidity.ok) {
|
|
7947
|
-
pass(slotValidity.summary);
|
|
7948
|
-
} else {
|
|
7949
|
-
fail2(slotValidity.summary);
|
|
7950
|
-
if (slotValidity.details) {
|
|
7951
|
-
for (const line of slotValidity.details.split("\n")) {
|
|
7952
|
-
hint(line);
|
|
7953
|
-
}
|
|
7954
|
-
}
|
|
7955
|
-
hint("Fix: reinstall @inventive-ui/components and rerun iui doctor");
|
|
7956
|
-
}
|
|
7215
|
+
reportStaleSlotOutput(targetCwd, pass, fail2);
|
|
7957
7216
|
const bootstrapSync = checkBootstrapSync(targetCwd, {
|
|
7958
7217
|
autoFix: opts?.fix === true
|
|
7959
7218
|
});
|
|
@@ -7972,13 +7231,13 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
|
|
|
7972
7231
|
}
|
|
7973
7232
|
await runConfigTierDiagnostics(targetCwd, opts, counters, {
|
|
7974
7233
|
includePackageJson: false,
|
|
7975
|
-
|
|
7234
|
+
includeStaleSlotCheck: false
|
|
7976
7235
|
});
|
|
7977
7236
|
}
|
|
7978
7237
|
async function doctorCommand(opts) {
|
|
7979
7238
|
try {
|
|
7980
7239
|
const invocationCwd = process.cwd();
|
|
7981
|
-
const targets = opts?.cwd ? [
|
|
7240
|
+
const targets = opts?.cwd ? [path23.resolve(opts.cwd)] : resolveSetupDoctorTargets(invocationCwd);
|
|
7982
7241
|
const installRoot = resolveDependencyInstallRoot(invocationCwd);
|
|
7983
7242
|
const multiPackage = targets.length > 1;
|
|
7984
7243
|
heading("Diagnostics");
|
|
@@ -8021,7 +7280,7 @@ async function doctorCommand(opts) {
|
|
|
8021
7280
|
for (const targetCwd of targets) {
|
|
8022
7281
|
if (multiPackage) {
|
|
8023
7282
|
newline();
|
|
8024
|
-
const label =
|
|
7283
|
+
const label = path23.relative(installRoot, targetCwd) || path23.basename(targetCwd);
|
|
8025
7284
|
kv("Package", label);
|
|
8026
7285
|
}
|
|
8027
7286
|
await runPackageDiagnostics(targetCwd, opts, counters);
|
|
@@ -8034,7 +7293,7 @@ async function doctorCommand(opts) {
|
|
|
8034
7293
|
} else {
|
|
8035
7294
|
fail(`${counters.failed} issue${counters.failed > 1 ? "s" : ""} found`);
|
|
8036
7295
|
hint("Resolve the issues above and re-run iui doctor");
|
|
8037
|
-
hint("Checklist: compatibility,
|
|
7296
|
+
hint("Checklist: compatibility, generated bootstrap, config validity, required types");
|
|
8038
7297
|
if (!opts?.fix) {
|
|
8039
7298
|
hint("Use iui doctor --fix to apply safe automatic repairs");
|
|
8040
7299
|
}
|
|
@@ -8049,9 +7308,9 @@ async function doctorCommand(opts) {
|
|
|
8049
7308
|
|
|
8050
7309
|
// src/commands/setup.ts
|
|
8051
7310
|
function detectDevScript(cwd) {
|
|
8052
|
-
const pkgPath =
|
|
7311
|
+
const pkgPath = path24.join(cwd, "package.json");
|
|
8053
7312
|
try {
|
|
8054
|
-
const pkg =
|
|
7313
|
+
const pkg = fs18.readJsonSync(pkgPath);
|
|
8055
7314
|
if (pkg.scripts?.dev) return "npm run dev";
|
|
8056
7315
|
if (pkg.scripts?.start) return "npm run start";
|
|
8057
7316
|
} catch {
|
|
@@ -8060,8 +7319,8 @@ function detectDevScript(cwd) {
|
|
|
8060
7319
|
return null;
|
|
8061
7320
|
}
|
|
8062
7321
|
function relativePackageLabel(installRoot, packageDir) {
|
|
8063
|
-
const rel =
|
|
8064
|
-
return rel && rel !== "." ? rel :
|
|
7322
|
+
const rel = path24.relative(installRoot, packageDir);
|
|
7323
|
+
return rel && rel !== "." ? rel : path24.basename(packageDir);
|
|
8065
7324
|
}
|
|
8066
7325
|
async function setupCommand(opts) {
|
|
8067
7326
|
try {
|
|
@@ -8070,7 +7329,7 @@ async function setupCommand(opts) {
|
|
|
8070
7329
|
const installRoot = resolveDependencyInstallRoot(cwd);
|
|
8071
7330
|
const workspaceRoot = findWorkspaceRoot(cwd);
|
|
8072
7331
|
const inMonorepo = workspaceRoot !== null;
|
|
8073
|
-
const installFromChild = inMonorepo &&
|
|
7332
|
+
const installFromChild = inMonorepo && path24.resolve(installRoot) !== path24.resolve(cwd);
|
|
8074
7333
|
if (!hasPackageJson(cwd) && !hasPackageJson(installRoot)) {
|
|
8075
7334
|
throw new CLIError(
|
|
8076
7335
|
"No package.json found in the current directory.",
|
|
@@ -8104,7 +7363,7 @@ async function setupCommand(opts) {
|
|
|
8104
7363
|
for (const w of warnings) warn(w);
|
|
8105
7364
|
kv("Package manager", `${pm} (${source})`);
|
|
8106
7365
|
if (installFromChild) {
|
|
8107
|
-
const rel =
|
|
7366
|
+
const rel = path24.relative(cwd, installRoot) || ".";
|
|
8108
7367
|
kv("Install directory", rel === ".." || rel.includes("..") ? installRoot : rel);
|
|
8109
7368
|
}
|
|
8110
7369
|
const installCmd2 = syncInstallCommand(pm);
|
|
@@ -8118,7 +7377,7 @@ async function setupCommand(opts) {
|
|
|
8118
7377
|
} catch (err) {
|
|
8119
7378
|
installSpinner.fail("Dependency install failed");
|
|
8120
7379
|
const detail = formatExecSyncError(err);
|
|
8121
|
-
const manual =
|
|
7380
|
+
const manual = path24.resolve(installRoot) === path24.resolve(cwd) ? installCmd2 : `cd ${JSON.stringify(installRoot)} && ${installCmd2}`;
|
|
8122
7381
|
throw new CLIError(
|
|
8123
7382
|
detail ? `Could not install project dependencies.
|
|
8124
7383
|
${detail}` : "Could not install project dependencies.",
|
|
@@ -8245,23 +7504,6 @@ async function listCommand(opts) {
|
|
|
8245
7504
|
newline();
|
|
8246
7505
|
info(`${pkgKeys.length} asset package${pkgKeys.length !== 1 ? "s" : ""} installed`);
|
|
8247
7506
|
}
|
|
8248
|
-
heading("Slot Registry");
|
|
8249
|
-
const slots = readSlotManifest();
|
|
8250
|
-
const slotKeys = Object.keys(slots);
|
|
8251
|
-
if (slotKeys.length === 0) {
|
|
8252
|
-
info("No component slots available yet.");
|
|
8253
|
-
} else {
|
|
8254
|
-
for (const [key, record] of Object.entries(slots)) {
|
|
8255
|
-
const displayName = itemsLookup[key]?.title ?? key;
|
|
8256
|
-
const slotInfo = record.supportedSlots?.length ? `${record.slotType} \xB7 slots: ${record.supportedSlots.join(", ")}` : `${record.slotType}`;
|
|
8257
|
-
bulletItem(
|
|
8258
|
-
displayName.padEnd(26),
|
|
8259
|
-
`${slotInfo} \xB7 v${record.version}`
|
|
8260
|
-
);
|
|
8261
|
-
}
|
|
8262
|
-
newline();
|
|
8263
|
-
info(`${slotKeys.length} slot${slotKeys.length !== 1 ? "s" : ""} registered`);
|
|
8264
|
-
}
|
|
8265
7507
|
newline();
|
|
8266
7508
|
} catch (error) {
|
|
8267
7509
|
handleError(error);
|
|
@@ -8276,7 +7518,7 @@ async function updateCommand(opts = {}) {
|
|
|
8276
7518
|
const auth = await ensureAuthSession();
|
|
8277
7519
|
await ensureLicenseSession();
|
|
8278
7520
|
const inProject = isInsideProject();
|
|
8279
|
-
const currentCliVersion = true ? "0.0.
|
|
7521
|
+
const currentCliVersion = true ? "0.0.12" : "unknown";
|
|
8280
7522
|
const latestCliVersion = await fetchLatestCliVersion(auth.token);
|
|
8281
7523
|
const cliUpdateAvailable = latestCliVersion !== null && isVersionGreater(latestCliVersion, currentCliVersion);
|
|
8282
7524
|
if (latestCliVersion && cliUpdateAvailable) {
|
|
@@ -8558,7 +7800,7 @@ var AUTH_EXEMPT_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
8558
7800
|
"doctor",
|
|
8559
7801
|
"list"
|
|
8560
7802
|
]);
|
|
8561
|
-
program.name("iui").description("The official CLI for the Inventive UI Design System").version(true ? "0.0.
|
|
7803
|
+
program.name("iui").description("The official CLI for the Inventive UI Design System").version(true ? "0.0.12" : "1.0.0").option("-C, --cwd <dir>", "Run as if started in the given directory").option("-q, --quiet", "Minimal output (also respects IUI_QUIET=1)").option("--no-color", "Disable ANSI colors");
|
|
8562
7804
|
program.command("login").description("Authenticate with GitHub and link your license").option("-f, --force", "Force re-authentication and register this device").option("--bootstrap", "After login, run optional setup prompts").action((opts) => loginCommand(opts));
|
|
8563
7805
|
program.command("logout").description("Remove stored credentials").action(logoutCommand);
|
|
8564
7806
|
program.command("whoami").description("Show authenticated identity and license details").action(whoamiCommand);
|
|
@@ -8641,7 +7883,7 @@ program.command("update").description("Check for and apply framework, component,
|
|
|
8641
7883
|
var assets = program.command("assets").description("Manage asset packages (icons, illustrations, logos, etc.)");
|
|
8642
7884
|
assets.command("remove <package>").description("Remove an installed asset package").action((pkg) => assetsRemoveCommand(pkg));
|
|
8643
7885
|
assets.command("list").description("Show all available and installed asset packages").action(assetsListCommand);
|
|
8644
|
-
program.command("doctor").description("Run project health diagnostics (read-only by default)").option("--fix", "Apply safe config patches (
|
|
7886
|
+
program.command("doctor").description("Run project health diagnostics (read-only by default)").option("--fix", "Apply safe config patches (theme.config, vite.config, component.config)").option("--config-only", "Validate project config tiers only (no auth/registry)").action((opts) => doctorCommand(opts));
|
|
8645
7887
|
if (shouldShowBanner()) {
|
|
8646
7888
|
printBanner();
|
|
8647
7889
|
}
|
|
@@ -8656,7 +7898,7 @@ program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
8656
7898
|
const root = topLevelCommandName(actionCommand);
|
|
8657
7899
|
const globalOpts = program.opts();
|
|
8658
7900
|
if (globalOpts.cwd) {
|
|
8659
|
-
process.chdir(
|
|
7901
|
+
process.chdir(path25.resolve(globalOpts.cwd));
|
|
8660
7902
|
}
|
|
8661
7903
|
if (isInsideProject()) {
|
|
8662
7904
|
try {
|
|
@@ -8670,14 +7912,14 @@ program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
8670
7912
|
mode: slotPolicy.mode
|
|
8671
7913
|
});
|
|
8672
7914
|
if (result.status === "repaired") {
|
|
8673
|
-
info("
|
|
7915
|
+
info("Project registry repaired");
|
|
8674
7916
|
}
|
|
8675
7917
|
} catch (error) {
|
|
8676
7918
|
if (error instanceof CLIError) {
|
|
8677
7919
|
warn(error.message);
|
|
8678
7920
|
if (error.hint) hint(error.hint);
|
|
8679
7921
|
} else {
|
|
8680
|
-
warn("
|
|
7922
|
+
warn("Project registry validation failed; run iui doctor for diagnostics.");
|
|
8681
7923
|
}
|
|
8682
7924
|
}
|
|
8683
7925
|
}
|