inventive-ui 0.0.9 → 0.0.10

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/dist/index.js CHANGED
@@ -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.9" : "1.0.0";
193
+ return true ? "0.0.10" : "1.0.0";
194
194
  } catch {
195
195
  return "1.0.0";
196
196
  }
@@ -1443,42 +1443,6 @@ function buildProjectConfigSource(cwd = process.cwd()) {
1443
1443
  });
1444
1444
  }
1445
1445
 
1446
- // src/utils/security/identifiers.ts
1447
- var SLUG_RE = /^[a-z][a-z0-9-]*$/;
1448
- var JS_IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
1449
- var NPM_SCOPE_IMPORT_RE = /^@inventive-ui\/[a-z0-9][a-z0-9._-]*$/;
1450
- var NPM_COMPONENT_SUBPATH_RE = /^@inventive-ui\/components\/[A-Za-z][A-Za-z0-9-]*$/;
1451
- function assertComponentSlug(slug) {
1452
- if (!SLUG_RE.test(slug)) {
1453
- throw new CLIError(
1454
- `Invalid component slug: "${slug}"`,
1455
- "Use lowercase letters, numbers, and hyphens (e.g. button, input)."
1456
- );
1457
- }
1458
- }
1459
- function assertJsIdentifier(name, label) {
1460
- if (!JS_IDENTIFIER_RE.test(name)) {
1461
- throw new CLIError(`Invalid ${label}: "${name}"`);
1462
- }
1463
- }
1464
- function assertImportSpecifier(specifier) {
1465
- if (NPM_SCOPE_IMPORT_RE.test(specifier)) return;
1466
- if (NPM_COMPONENT_SUBPATH_RE.test(specifier)) return;
1467
- if (/^@inventive-ui\/[a-z0-9][a-z0-9-]*$/.test(specifier)) return;
1468
- throw new CLIError(`Unsafe import specifier: "${specifier}"`);
1469
- }
1470
- function escapeTsStringLiteral(value) {
1471
- return JSON.stringify(value);
1472
- }
1473
- function sanitizePackageVersionHeader(value) {
1474
- if (!value) return null;
1475
- const trimmed = value.trim();
1476
- if (!/^[0-9A-Za-z.+~^<>= -]+$/.test(trimmed) || trimmed.length > 64) {
1477
- throw new CLIError("Server returned an invalid package version header.");
1478
- }
1479
- return trimmed;
1480
- }
1481
-
1482
1446
  // src/utils/config-patch/vite-config.ts
1483
1447
  import ts from "typescript";
1484
1448
  var IUI_MANAGED_MARKER = "@iui-managed";
@@ -1969,393 +1933,40 @@ function patchProjectConfigBuildBlock(content) {
1969
1933
  // src/utils/config-patch/component-config.ts
1970
1934
  import ts2 from "typescript";
1971
1935
 
1972
- // src/utils/componentExports.ts
1973
- import path7 from "path";
1974
- import fs6 from "fs-extra";
1975
- function toRecord(value) {
1976
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
1977
- return value;
1978
- }
1979
- function toPascalCase(value) {
1980
- return value.replace(/(^|[-_\s]+)([a-zA-Z0-9])/g, (_m, _p, c) => c.toUpperCase()).replace(/[^a-zA-Z0-9]/g, "");
1981
- }
1982
- function readComponentsPackageInfo(cwd) {
1983
- const packageRoot = resolvePackageDir("@inventive-ui/components", cwd);
1984
- if (!packageRoot) return null;
1985
- const pkgPath = path7.join(packageRoot, "package.json");
1986
- if (!fs6.existsSync(pkgPath)) return null;
1987
- try {
1988
- const pkg = fs6.readJsonSync(pkgPath);
1989
- const exportsField = toRecord(pkg.exports) ?? {};
1990
- const rootExport = toRecord(exportsField["."]);
1991
- const rootTypes = resolveTypesPathFromExportEntry(rootExport) ?? (typeof pkg.types === "string" ? pkg.types : null);
1992
- return {
1993
- packageRoot,
1994
- exportsField,
1995
- rootTypesPath: rootTypes ? path7.join(packageRoot, rootTypes) : null
1996
- };
1997
- } catch {
1998
- return null;
1999
- }
2000
- }
2001
- function resolveTypesPathFromExportEntry(entry) {
2002
- if (!entry) return null;
2003
- if (typeof entry === "string") return null;
2004
- const obj = toRecord(entry);
2005
- if (!obj) return null;
2006
- if (typeof obj.types === "string") return obj.types;
2007
- for (const key of ["import", "require", "default", "node", "browser"]) {
2008
- const nested = toRecord(obj[key]);
2009
- if (!nested) continue;
2010
- if (typeof nested.types === "string") return nested.types;
2011
- }
2012
- return null;
2013
- }
2014
- function parseNamedExportClause(clause, parsed) {
2015
- const parts = clause.split(",").map((p) => p.trim()).filter(Boolean);
2016
- for (const rawPart of parts) {
2017
- let part = rawPart;
2018
- let isTypeOnly = false;
2019
- if (part.startsWith("type ")) {
2020
- isTypeOnly = true;
2021
- part = part.slice("type ".length).trim();
2022
- }
2023
- const asMatch = part.match(/^([A-Za-z_][A-Za-z0-9_]*)\s+as\s+([A-Za-z_][A-Za-z0-9_]*)$/);
2024
- const symbol = asMatch ? asMatch[2] : part;
2025
- if (!symbol) continue;
2026
- if (isTypeOnly) parsed.typeExports.add(symbol);
2027
- else parsed.valueExports.add(symbol);
2028
- }
2029
- }
2030
- function mergeParsedExports(target, source) {
2031
- for (const sym of source.valueExports) target.valueExports.add(sym);
2032
- for (const sym of source.typeExports) target.typeExports.add(sym);
2033
- }
2034
- function resolveRelativeTypesPath(fromFile, rel) {
2035
- const base = path7.dirname(fromFile);
2036
- const noExt = path7.join(base, rel);
2037
- const candidates = [`${noExt}.d.ts`, path7.join(noExt, "index.d.ts")];
2038
- for (const candidate of candidates) {
2039
- if (fs6.existsSync(candidate)) return candidate;
2040
- }
2041
- return null;
2042
- }
2043
- function parseTypeExports(typesFilePath, visited = /* @__PURE__ */ new Set()) {
2044
- const parsed = {
2045
- valueExports: /* @__PURE__ */ new Set(),
2046
- typeExports: /* @__PURE__ */ new Set()
2047
- };
2048
- const abs = path7.resolve(typesFilePath);
2049
- if (visited.has(abs)) return parsed;
2050
- visited.add(abs);
2051
- if (!fs6.existsSync(abs)) return parsed;
2052
- let text = "";
2053
- try {
2054
- text = fs6.readFileSync(abs, "utf-8");
2055
- } catch {
2056
- return parsed;
2057
- }
2058
- applyTypeExportPatterns(text, parsed);
2059
- const reexportFrom = text.matchAll(
2060
- /export\s+(?:type\s+)?(?:\{[^}]*\}|\*)\s+from\s+["'](\.[^"']+)["']/g
2061
- );
2062
- for (const m of reexportFrom) {
2063
- const refPath = resolveRelativeTypesPath(abs, m[1]);
2064
- if (refPath) mergeParsedExports(parsed, parseTypeExports(refPath, visited));
2065
- }
2066
- return parsed;
2067
- }
2068
- function parseTypeExportsLocal(typesFilePath) {
2069
- const parsed = {
2070
- valueExports: /* @__PURE__ */ new Set(),
2071
- typeExports: /* @__PURE__ */ new Set()
2072
- };
2073
- const abs = path7.resolve(typesFilePath);
2074
- if (!fs6.existsSync(abs)) return parsed;
2075
- let text = "";
2076
- try {
2077
- text = fs6.readFileSync(abs, "utf-8");
2078
- } catch {
2079
- return parsed;
2080
- }
2081
- applyTypeExportPatterns(text, parsed);
2082
- return parsed;
2083
- }
2084
- function applyTypeExportPatterns(text, parsed) {
2085
- const valueDecl = /export\s+(?:declare\s+)?(?:const|let|var|function|class)\s+([A-Za-z_][A-Za-z0-9_]*)/g;
2086
- const typeDecl = /export\s+(?:declare\s+)?(?:type|interface)\s+([A-Za-z_][A-Za-z0-9_]*)/g;
2087
- const namedClause = /export\s+(?!type\s*\{)\{([^}]+)\}/g;
2088
- const typeNamedClause = /export\s+type\s*\{([^}]+)\}/g;
2089
- for (const m of text.matchAll(valueDecl)) {
2090
- parsed.valueExports.add(m[1]);
2091
- }
2092
- for (const m of text.matchAll(typeDecl)) {
2093
- parsed.typeExports.add(m[1]);
2094
- }
2095
- for (const m of text.matchAll(namedClause)) {
2096
- parseNamedExportClause(m[1], parsed);
2097
- }
2098
- for (const m of text.matchAll(typeNamedClause)) {
2099
- parseNamedExportClause(m[1], parsed);
2100
- }
2101
- }
2102
- function pickComponentName(item, parsed) {
2103
- const expected = [toPascalCase(item.dirName), toPascalCase(item.name)];
2104
- for (const name of expected) {
2105
- if (parsed.valueExports.has(name)) return name;
2106
- }
2107
- const lowered = new Set(expected.map((n) => n.toLowerCase()));
2108
- for (const exp of parsed.valueExports) {
2109
- if (lowered.has(exp.toLowerCase())) return exp;
2110
- }
2111
- return null;
2112
- }
2113
- function pickPropsName(componentName, parsed) {
2114
- const direct = `${componentName}Props`;
2115
- if (parsed.typeExports.has(direct) || parsed.valueExports.has(direct)) return direct;
2116
- for (const sym of parsed.typeExports) {
2117
- if (sym.toLowerCase() === direct.toLowerCase()) return sym;
2118
- }
2119
- for (const sym of parsed.valueExports) {
2120
- if (sym.toLowerCase() === direct.toLowerCase()) return sym;
2121
- }
2122
- return null;
2123
- }
2124
- function pickDefaultExportComponent(item, typesIndexPath) {
2125
- const expected = [toPascalCase(item.dirName), toPascalCase(item.name)];
2126
- for (const name of expected) {
2127
- const mainTypesPath = findMainComponentTypesPath(typesIndexPath, name);
2128
- if (!mainTypesPath) continue;
2129
- const mainText = readTypesFileText(mainTypesPath);
2130
- const defaultExportMatch = mainText.match(/export\s+default\s+([A-Za-z_][A-Za-z0-9_]*)/);
2131
- if (!defaultExportMatch) continue;
2132
- const symbol = defaultExportMatch[1];
2133
- if (expected.some((candidate) => candidate.toLowerCase() === symbol.toLowerCase())) {
2134
- return symbol;
2135
- }
2136
- }
2137
- return null;
2138
- }
2139
- function readTypesFileText(typesFilePath) {
2140
- try {
2141
- return fs6.readFileSync(typesFilePath, "utf-8");
2142
- } catch {
2143
- return "";
2144
- }
2145
- }
2146
- function findMainComponentTypesPath(typesIndexPath, componentName) {
2147
- const dir = path7.dirname(typesIndexPath);
2148
- const indexText = readTypesFileText(typesIndexPath);
2149
- const fromMatches = indexText.matchAll(/from\s+["']\.\/([^"']+)["']/g);
2150
- for (const match of fromMatches) {
2151
- const candidate = path7.join(dir, `${match[1]}.d.ts`);
2152
- if (fs6.existsSync(candidate)) return candidate;
1936
+ // src/utils/security/identifiers.ts
1937
+ var SLUG_RE = /^[a-z][a-z0-9-]*$/;
1938
+ 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
+ );
2153
1947
  }
2154
- const byName = path7.join(dir, `${componentName}.d.ts`);
2155
- return fs6.existsSync(byName) ? byName : null;
2156
- }
2157
- function isNonCallableCompoundExport(typesText, symbolName) {
2158
- const objectDecl = new RegExp(
2159
- `(?:declare\\s+const|const)\\s+${symbolName}\\s*:\\s*\\{`
2160
- );
2161
- return objectDecl.test(typesText);
2162
1948
  }
2163
- function pickCompoundRenderMember(typesText) {
2164
- if (/\bText\s*:\s*React\./.test(typesText)) return "Text";
2165
- const memberMatch = typesText.match(
2166
- /^\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*React\.(?:ForwardRefExoticComponent|NamedExoticComponent|FC)/m
2167
- );
2168
- return memberMatch?.[1] ?? "Text";
2169
- }
2170
- function resolveLazyAccess(typesIndexPath, componentName) {
2171
- const indexText = readTypesFileText(typesIndexPath);
2172
- const mainTypesPath = findMainComponentTypesPath(typesIndexPath, componentName);
2173
- const mainText = mainTypesPath ? readTypesFileText(mainTypesPath) : "";
2174
- const defaultAsMatch = indexText.match(
2175
- new RegExp(`export\\s*\\{[^}]*\\bdefault\\s+as\\s+${componentName}\\b[^}]*\\}`)
2176
- );
2177
- const namedExportMatch = indexText.match(
2178
- new RegExp(`export\\s*\\{[^}]*\\b${componentName}\\b[^}]*\\}`)
2179
- );
2180
- const defaultExportMatch = mainText.match(/export\s+default\s+([A-Za-z_][A-Za-z0-9_]*)/);
2181
- const defaultSymbol = defaultExportMatch?.[1];
2182
- const compoundSymbol = defaultSymbol && isNonCallableCompoundExport(mainText, defaultSymbol) ? defaultSymbol : isNonCallableCompoundExport(mainText, componentName) ? componentName : null;
2183
- if (compoundSymbol) {
2184
- const member = pickCompoundRenderMember(mainText);
2185
- if (defaultAsMatch || namedExportMatch) {
2186
- return `.${componentName}.${member}`;
2187
- }
2188
- return `.default.${member}`;
2189
- }
2190
- if (defaultAsMatch || namedExportMatch) return `.${componentName}`;
2191
- if (defaultSymbol && defaultSymbol === componentName) {
2192
- return `.default`;
2193
- }
2194
- return `.${componentName}`;
2195
- }
2196
- function subpathExposesLazyBinding(typesIndexPath, componentName) {
2197
- const indexText = readTypesFileText(typesIndexPath);
2198
- if (new RegExp(`export\\s*\\{[^}]*\\bdefault\\s+as\\s+${componentName}\\b[^}]*\\}`).test(
2199
- indexText
2200
- )) {
2201
- return true;
2202
- }
2203
- if (new RegExp(`export\\s*\\{[^}]*\\b${componentName}\\b[^}]*\\}`).test(indexText)) {
2204
- return true;
2205
- }
2206
- if (/export\s+default\b/.test(indexText)) return true;
2207
- return pickComponentName(
2208
- { name: componentName, dirName: componentName },
2209
- parseTypeExportsLocal(typesIndexPath)
2210
- ) !== null;
2211
- }
2212
- function resolveLazyImport(pkgInfo, importSpecifier, typesFilePath, componentName) {
2213
- let lazyImportSpecifier = importSpecifier;
2214
- let lazyAccess = resolveLazyAccess(typesFilePath, componentName);
2215
- if (importSpecifier !== "@inventive-ui/components" && !subpathExposesLazyBinding(typesFilePath, componentName) && pkgInfo.rootTypesPath) {
2216
- lazyImportSpecifier = "@inventive-ui/components";
2217
- lazyAccess = `.${componentName}`;
2218
- }
2219
- return { lazyImportSpecifier, lazyAccess };
2220
- }
2221
- function describeExpected(item) {
2222
- return `${toPascalCase(item.dirName)} / ${toPascalCase(item.name)}`;
2223
- }
2224
- function resolveFromTypesFile(item, importSpecifier, typesFilePath, pkgInfo) {
2225
- const parsed = parseTypeExports(typesFilePath);
2226
- const indexParsed = parseTypeExportsLocal(typesFilePath);
2227
- const componentName = pickComponentName(item, parsed) ?? pickDefaultExportComponent(item, typesFilePath);
2228
- if (!componentName) {
2229
- return {
2230
- ok: false,
2231
- reason: `No matching component export in ${importSpecifier}. Expected ${describeExpected(item)}.`
2232
- };
2233
- }
2234
- const propsName = pickPropsName(componentName, indexParsed) ?? pickPropsName(componentName, parsed) ?? (() => {
2235
- const typesPath = path7.join(path7.dirname(typesFilePath), "types.d.ts");
2236
- if (!fs6.existsSync(typesPath)) return null;
2237
- return pickPropsName(componentName, parseTypeExports(typesPath));
2238
- })();
2239
- const lazyImport = resolveLazyImport(
2240
- pkgInfo,
2241
- importSpecifier,
2242
- typesFilePath,
2243
- componentName
2244
- );
2245
- return {
2246
- ok: true,
2247
- importSpecifier,
2248
- lazyImportSpecifier: lazyImport.lazyImportSpecifier,
2249
- componentName,
2250
- propsName: propsName ?? void 0,
2251
- lazyAccess: lazyImport.lazyAccess
2252
- };
2253
- }
2254
- function exportCandidatesForItem(item) {
2255
- const candidates = [
2256
- `./${item.name}`,
2257
- `./${item.name.toLowerCase()}`,
2258
- `./${item.dirName}`,
2259
- `./${item.dirName.toLowerCase()}`
2260
- ];
2261
- return [...new Set(candidates)];
2262
- }
2263
- function componentFolderCandidates(item) {
2264
- return [
2265
- .../* @__PURE__ */ new Set([
2266
- item.dirName,
2267
- item.name,
2268
- toPascalCase(item.dirName),
2269
- toPascalCase(item.name)
2270
- ])
2271
- ];
2272
- }
2273
- function resolveWildcardTypesPath(pkgInfo, segment) {
2274
- const wildcardEntry = pkgInfo.exportsField["./*"];
2275
- if (!wildcardEntry) return null;
2276
- const typesRel = resolveTypesPathFromExportEntry(wildcardEntry);
2277
- if (!typesRel || !typesRel.includes("*")) return null;
2278
- const resolvedRel = typesRel.replace(/\*/g, segment);
2279
- const fullPath = path7.join(pkgInfo.packageRoot, resolvedRel);
2280
- return fs6.existsSync(fullPath) ? fullPath : null;
2281
- }
2282
- function resolveTypesPathForExportCandidate(pkgInfo, candidate) {
2283
- const entry = pkgInfo.exportsField[candidate];
2284
- if (entry) {
2285
- const typesRel = resolveTypesPathFromExportEntry(entry);
2286
- return typesRel ? path7.join(pkgInfo.packageRoot, typesRel) : null;
2287
- }
2288
- const segment = candidate.replace(/^\.\//, "");
2289
- return resolveWildcardTypesPath(pkgInfo, segment);
2290
- }
2291
- function resolveFromComponentFolders(item, pkgInfo) {
2292
- for (const folder of componentFolderCandidates(item)) {
2293
- const typesPath = resolveWildcardTypesPath(pkgInfo, folder) ?? (() => {
2294
- const directPath = path7.join(
2295
- pkgInfo.packageRoot,
2296
- "dist",
2297
- "components",
2298
- folder,
2299
- "index.d.ts"
2300
- );
2301
- return fs6.existsSync(directPath) ? directPath : null;
2302
- })();
2303
- if (!typesPath) continue;
2304
- const importSpecifier = `@inventive-ui/components/${folder}`;
2305
- try {
2306
- assertImportSpecifier(importSpecifier);
2307
- } catch {
2308
- continue;
2309
- }
2310
- const resolved = resolveFromTypesFile(item, importSpecifier, typesPath, pkgInfo);
2311
- if (resolved.ok) return resolved;
1949
+ function assertJsIdentifier(name, label) {
1950
+ if (!JS_IDENTIFIER_RE.test(name)) {
1951
+ throw new CLIError(`Invalid ${label}: "${name}"`);
2312
1952
  }
2313
- return null;
2314
1953
  }
2315
- function componentBuildExists(item, pkgInfo) {
2316
- return componentFolderCandidates(item).some(
2317
- (folder) => fs6.existsSync(path7.join(pkgInfo.packageRoot, "dist", "components", folder))
2318
- );
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}"`);
2319
1959
  }
2320
- function buildMissingComponentReason(item) {
2321
- return `Component "${item.name}" is listed in iui-manifest.json but is missing from the published @inventive-ui/components build (expected dist/components/${item.dirName}). Run a full components build, export ${describeExpected(item)} from dist/index.d.ts, and republish.`;
1960
+ function escapeTsStringLiteral(value) {
1961
+ return JSON.stringify(value);
2322
1962
  }
2323
- function resolveComponentExport(item, cwd = process.cwd()) {
2324
- const pkgInfo = readComponentsPackageInfo(cwd);
2325
- if (!pkgInfo) {
2326
- return {
2327
- ok: false,
2328
- reason: "@inventive-ui/components is not installed in node_modules."
2329
- };
2330
- }
2331
- const fromFolders = resolveFromComponentFolders(item, pkgInfo);
2332
- if (fromFolders?.ok) return fromFolders;
2333
- for (const candidate of exportCandidatesForItem(item)) {
2334
- const typesPath = resolveTypesPathForExportCandidate(pkgInfo, candidate);
2335
- if (!typesPath) continue;
2336
- const importSpecifier = `@inventive-ui/components/${candidate.replace(/^\.\//, "")}`;
2337
- try {
2338
- assertImportSpecifier(importSpecifier);
2339
- } catch {
2340
- continue;
2341
- }
2342
- const resolved = resolveFromTypesFile(item, importSpecifier, typesPath, pkgInfo);
2343
- if (resolved.ok) return resolved;
2344
- }
2345
- if (pkgInfo.rootTypesPath) {
2346
- const fromRoot = resolveFromTypesFile(item, "@inventive-ui/components", pkgInfo.rootTypesPath, pkgInfo);
2347
- if (fromRoot.ok) return fromRoot;
2348
- }
2349
- if (!componentBuildExists(item, pkgInfo)) {
2350
- return {
2351
- ok: false,
2352
- reason: buildMissingComponentReason(item)
2353
- };
1963
+ function sanitizePackageVersionHeader(value) {
1964
+ if (!value) return null;
1965
+ const trimmed = value.trim();
1966
+ if (!/^[0-9A-Za-z.+~^<>= -]+$/.test(trimmed) || trimmed.length > 64) {
1967
+ throw new CLIError("Server returned an invalid package version header.");
2354
1968
  }
2355
- return {
2356
- ok: false,
2357
- reason: `No matching component export for "${item.name}" in @inventive-ui/components. Expected a value export named ${describeExpected(item)}.`
2358
- };
1969
+ return trimmed;
2359
1970
  }
2360
1971
 
2361
1972
  // src/utils/config-patch/component-config.ts
@@ -2376,19 +1987,6 @@ function findComponentConfigObject(sourceFile) {
2376
1987
  visit(sourceFile);
2377
1988
  return found;
2378
1989
  }
2379
- function findComponentConfigMapType(sourceFile) {
2380
- let found;
2381
- const visit = (node) => {
2382
- if (found) return;
2383
- if (ts2.isTypeAliasDeclaration(node) && ts2.isIdentifier(node.name) && node.name.text === "ComponentConfigMap" && node.type && ts2.isTypeLiteralNode(node.type)) {
2384
- found = node.type;
2385
- return;
2386
- }
2387
- ts2.forEachChild(node, visit);
2388
- };
2389
- visit(sourceFile);
2390
- return found;
2391
- }
2392
1990
  function existingComponentKeys(obj) {
2393
1991
  const keys = /* @__PURE__ */ new Set();
2394
1992
  for (const prop of obj.properties) {
@@ -2398,33 +1996,14 @@ function existingComponentKeys(obj) {
2398
1996
  }
2399
1997
  return keys;
2400
1998
  }
2401
- function formatDefaultConfig(cfg) {
2402
- return JSON.stringify(cfg, null, 6).split("\n").map((line, i) => i === 0 ? line : ` ${line}`).join("\n");
2403
- }
2404
1999
  function buildComponentEntry(item) {
2405
2000
  assertJsIdentifier(item.dirName, "component dirName");
2406
- const cfg = item.meta?.defaultConfig ?? {};
2407
- const cfgStr = formatDefaultConfig(cfg);
2408
2001
  return ` ${item.dirName}: {
2409
- default: ${cfgStr},
2002
+ default: {},
2410
2003
  },
2411
2004
 
2412
2005
  `;
2413
2006
  }
2414
- function buildTypeEntry(item, cwd) {
2415
- const resolved = resolveComponentExport(item, cwd);
2416
- if (resolved.ok && resolved.propsName) {
2417
- return ` ${item.dirName}: { default: Partial<${resolved.propsName}> };`;
2418
- }
2419
- return ` ${item.dirName}: { default: Record<string, unknown> };`;
2420
- }
2421
- function buildTypeImport(item, cwd) {
2422
- const resolved = resolveComponentExport(item, cwd);
2423
- if (resolved.ok && resolved.propsName && resolved.importSpecifier) {
2424
- return `import type { ${resolved.propsName} } from "${resolved.importSpecifier}";`;
2425
- }
2426
- return null;
2427
- }
2428
2007
  function insertBeforeClosingBrace(source, objectEnd, insertion) {
2429
2008
  let pos = objectEnd - 1;
2430
2009
  while (pos >= 0 && /\s/.test(source[pos] ?? "")) pos--;
@@ -2436,7 +2015,7 @@ function insertBeforeClosingBrace(source, objectEnd, insertion) {
2436
2015
  }
2437
2016
  return source;
2438
2017
  }
2439
- function mergeComponentConfigContent(source, manifest, cwd) {
2018
+ function mergeComponentConfigContent(source, manifest) {
2440
2019
  if (!manifest || manifest.items.length === 0) {
2441
2020
  return { content: source, changed: false };
2442
2021
  }
@@ -2452,33 +2031,78 @@ function mergeComponentConfigContent(source, manifest, cwd) {
2452
2031
  const existing = existingComponentKeys(configObject);
2453
2032
  const missing = manifest.items.filter((item) => !existing.has(item.dirName));
2454
2033
  if (missing.length === 0) return { content: source, changed: false };
2455
- let next = source;
2456
2034
  const newEntries = missing.map((item) => buildComponentEntry(item)).join("");
2457
- next = insertBeforeClosingBrace(next, configObject.getEnd(), newEntries);
2458
- const typeLiteral = findComponentConfigMapType(
2459
- ts2.createSourceFile("component.config.ts", next, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS)
2035
+ const next = insertBeforeClosingBrace(
2036
+ source,
2037
+ configObject.getEnd(),
2038
+ newEntries
2460
2039
  );
2461
- if (typeLiteral) {
2462
- const typeLines = `${missing.map((item) => buildTypeEntry(item, cwd)).join("\n")}
2463
- `;
2464
- next = insertBeforeClosingBrace(next, typeLiteral.getEnd(), typeLines);
2465
- }
2466
- const existingImportLines = new Set(next.match(/^import\s.+;$/gm) ?? []);
2467
- const newImports = missing.map((item) => buildTypeImport(item, cwd)).filter((line) => line !== null && !existingImportLines.has(line));
2468
- if (newImports.length > 0) {
2469
- const importMatches = [...next.matchAll(/^import\s.+;$/gm)];
2470
- const lastImport = importMatches.at(-1);
2471
- if (lastImport?.index !== void 0) {
2472
- const insertAt = lastImport.index + lastImport[0].length;
2473
- next = `${next.slice(0, insertAt)}
2474
- ${[...new Set(newImports)].join("\n")}${next.slice(insertAt)}`;
2475
- } else {
2476
- next = `${[...new Set(newImports)].join("\n")}
2040
+ return { content: next, changed: true };
2041
+ }
2477
2042
 
2478
- ${next}`;
2043
+ // src/utils/config-patch/tsconfig-iui.ts
2044
+ import path7 from "path";
2045
+ import fs6 from "fs-extra";
2046
+ var IUI_TS_ROOT_FILES = ["iui.config.ts", "component.config.ts"];
2047
+ function isSolutionStyleTsconfig(config) {
2048
+ const refs = config.references;
2049
+ return Array.isArray(refs) && refs.length > 0;
2050
+ }
2051
+ function patchJsonInclude(filePath, extra) {
2052
+ if (!fs6.existsSync(filePath)) return false;
2053
+ const raw = fs6.readJsonSync(filePath);
2054
+ const include = Array.isArray(raw.include) ? [...raw.include.map(String)] : [];
2055
+ let changed = false;
2056
+ for (const item of extra) {
2057
+ if (!include.includes(item)) {
2058
+ include.push(item);
2059
+ changed = true;
2479
2060
  }
2480
2061
  }
2481
- return { content: next, changed: true };
2062
+ if (!changed) return false;
2063
+ atomicWriteJson(filePath, { ...raw, include });
2064
+ return true;
2065
+ }
2066
+ function resolveAppTsconfigPath(cwd, root) {
2067
+ const refs = root.references;
2068
+ if (!refs) return null;
2069
+ for (const ref of refs) {
2070
+ const p = ref.path?.replace(/^\.\//, "") ?? "";
2071
+ const base = p.replace(/\.json$/i, "");
2072
+ if (/app/i.test(base)) {
2073
+ return path7.join(cwd, p.endsWith(".json") ? p : `${p}.json`);
2074
+ }
2075
+ }
2076
+ for (const ref of refs) {
2077
+ const p = ref.path?.replace(/^\.\//, "") ?? "";
2078
+ if (!/node/i.test(p)) {
2079
+ return path7.join(cwd, p.endsWith(".json") ? p : `${p}.json`);
2080
+ }
2081
+ }
2082
+ return null;
2083
+ }
2084
+ function repairSolutionStyleRootTsconfig(cwd) {
2085
+ const rootPath = path7.join(cwd, "tsconfig.json");
2086
+ if (!fs6.existsSync(rootPath)) return false;
2087
+ const existing = fs6.readJsonSync(rootPath);
2088
+ if (!isSolutionStyleTsconfig(existing)) return false;
2089
+ const polluted = existing.compilerOptions !== void 0 || Array.isArray(existing.include) && existing.include.length > 0 || Array.isArray(existing.exclude) && existing.exclude.length > 0;
2090
+ if (!polluted) return false;
2091
+ atomicWriteJson(rootPath, {
2092
+ files: Array.isArray(existing.files) ? existing.files : [],
2093
+ references: existing.references
2094
+ });
2095
+ return true;
2096
+ }
2097
+ function patchSolutionStyleTsconfigForIui(cwd) {
2098
+ const rootPath = path7.join(cwd, "tsconfig.json");
2099
+ if (!fs6.existsSync(rootPath)) return false;
2100
+ const existing = fs6.readJsonSync(rootPath);
2101
+ if (!isSolutionStyleTsconfig(existing)) return false;
2102
+ const repairedRoot = repairSolutionStyleRootTsconfig(cwd);
2103
+ const appPath = resolveAppTsconfigPath(cwd, existing);
2104
+ const patchedApp = appPath ? patchJsonInclude(appPath, IUI_TS_ROOT_FILES) : false;
2105
+ return repairedRoot || patchedApp;
2482
2106
  }
2483
2107
 
2484
2108
  // src/validation/configTierChecks.ts
@@ -2877,15 +2501,6 @@ function loadAssetsConfigTemplate() {
2877
2501
  return {};
2878
2502
  }
2879
2503
  }
2880
- function loadComponentConfigPresetsTemplate() {
2881
- const templatePath = path10.join(getCliTemplatesDir(), "component.config.presets.json");
2882
- if (!fs8.existsSync(templatePath)) return {};
2883
- try {
2884
- return fs8.readJsonSync(templatePath);
2885
- } catch {
2886
- return {};
2887
- }
2888
- }
2889
2504
  function mergeAssetSlotWithTemplate(slot, templateSlot) {
2890
2505
  if (!templateSlot) return slot ?? {};
2891
2506
  const out = { ...templateSlot, ...slot ?? {} };
@@ -3232,7 +2847,24 @@ function writeTsConfigNode(cwd = process.cwd()) {
3232
2847
  };
3233
2848
  atomicWriteJson(nodeTsPath, content);
3234
2849
  }
3235
- function writeTsConfig(framework, cwd = process.cwd()) {
2850
+ function ensureTsConfigForIui(framework, cwd = process.cwd()) {
2851
+ const tsconfigPath = path10.join(cwd, "tsconfig.json");
2852
+ let existing = {};
2853
+ if (fs8.existsSync(tsconfigPath)) {
2854
+ try {
2855
+ existing = fs8.readJsonSync(tsconfigPath);
2856
+ } catch {
2857
+ existing = {};
2858
+ }
2859
+ }
2860
+ if (framework === "vite" && isSolutionStyleTsconfig(existing)) {
2861
+ patchSolutionStyleTsconfigForIui(cwd);
2862
+ writeTsConfigNode(cwd);
2863
+ return;
2864
+ }
2865
+ writeFlatProjectTsConfig(framework, cwd);
2866
+ }
2867
+ function writeFlatProjectTsConfig(framework, cwd = process.cwd()) {
3236
2868
  const tsconfigPath = path10.join(cwd, "tsconfig.json");
3237
2869
  let existing = {};
3238
2870
  if (fs8.existsSync(tsconfigPath)) {
@@ -3300,56 +2932,22 @@ function writeTsConfig(framework, cwd = process.cwd()) {
3300
2932
  };
3301
2933
  atomicWriteJson(tsconfigPath, output);
3302
2934
  }
3303
- function writeComponentConfig(manifest, cwd = process.cwd()) {
2935
+ function writeComponentConfig(_manifest, cwd = process.cwd()) {
3304
2936
  const configPath = path10.join(cwd, COMPONENT_CONFIG_FILE);
3305
- let entries = "";
3306
- const typedEntries = [];
3307
- const typeImports = [];
3308
- const presetsTemplate = loadComponentConfigPresetsTemplate();
3309
- if (manifest) {
3310
- for (const item of manifest.items) {
3311
- assertJsIdentifier(item.dirName, "component dirName");
3312
- const cfg = item.meta?.defaultConfig ?? {};
3313
- const presetBlock = presetsTemplate[item.dirName];
3314
- const cfgStr = JSON.stringify(cfg, null, 6).split("\n").map((line, i) => i === 0 ? line : ` ${line}`).join("\n");
3315
- let extraBlocks = "";
3316
- if (presetBlock?.presets) {
3317
- const presetsStr = JSON.stringify(presetBlock.presets, null, 6).split("\n").map((line, i) => i === 0 ? line : ` ${line}`).join("\n");
3318
- extraBlocks += `
3319
- presets: ${presetsStr},`;
3320
- }
3321
- entries += ` ${item.dirName}: {
3322
- default: ${cfgStr},${extraBlocks}
3323
- },
3324
-
3325
- `;
3326
- const resolved = resolveComponentExport(item, cwd);
3327
- if (resolved.ok && resolved.propsName && resolved.importSpecifier) {
3328
- typeImports.push(`import type { ${resolved.propsName} } from "${resolved.importSpecifier}";`);
3329
- typedEntries.push(` ${item.dirName}: { default: Partial<${resolved.propsName}> };`);
3330
- } else {
3331
- typedEntries.push(` ${item.dirName}: { default: Record<string, unknown> };`);
3332
- }
3333
- }
3334
- }
3335
- const imports = [...new Set(typeImports)].join("\n");
3336
- const componentConfigType = typedEntries.length > 0 ? `type ComponentConfigMap = {
3337
- ${typedEntries.join("\n")}
3338
- };` : `type ComponentConfigMap = Record<string, { default: Record<string, unknown> }>;`;
3339
2937
  const content = `// \u2500\u2500\u2500 Component Configuration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
3340
2938
  //
3341
- // Default component presets for your Inventive UI project.
3342
- // Customize variants, appearances, and slot assignments below.
3343
- // Entries are rebuilt from the published component registry.
2939
+ // Optional per-component defaults (variant, appearance, presets, cTags).
2940
+ // Only add entries you want to override \u2014 omit components you do not customize.
2941
+ // \`iui update\` may append new registry keys; edit or remove them as needed.
3344
2942
  //
3345
2943
  // Docs: https://inventiveui.com/docs/configuration
3346
2944
 
3347
- ${imports}
3348
-
3349
- ${componentConfigType}
2945
+ import type { ComponentConfig } from "@inventive-ui/components/config";
3350
2946
 
3351
- export const componentConfig: ComponentConfigMap = {
3352
- ${entries}};
2947
+ export const componentConfig = {
2948
+ // Example:
2949
+ // Button: { default: { variant: "solid", appearance: "soft" } },
2950
+ } satisfies ComponentConfig;
3353
2951
  `;
3354
2952
  atomicWriteFile(configPath, content);
3355
2953
  }
@@ -3361,7 +2959,7 @@ function ensureComponentConfig(manifest, cwd = process.cwd(), options = {}) {
3361
2959
  return existed && options.force ? "replaced" : "scaffolded";
3362
2960
  }
3363
2961
  const before = fs8.readFileSync(configPath, "utf-8");
3364
- const result = mergeComponentConfigContent(before, manifest, cwd);
2962
+ const result = mergeComponentConfigContent(before, manifest);
3365
2963
  if (!result.changed) return "noop";
3366
2964
  atomicWriteFile(configPath, result.content);
3367
2965
  return "merged";
@@ -6913,7 +6511,7 @@ async function initCommand(opts) {
6913
6511
  step("Generating config files\u2026");
6914
6512
  writeAssetsConfig(initRoot);
6915
6513
  ensureProjectConfig(initRoot);
6916
- writeTsConfig(framework.framework, initRoot);
6514
+ ensureTsConfigForIui(framework.framework, initRoot);
6917
6515
  if (framework.framework === "vite") {
6918
6516
  ensureInventiveUiViteConfig(initRoot);
6919
6517
  ok("Config files ready (iui.config.ts, tsconfig.json, tsconfig.node.json, vite.config.ts)");
@@ -6923,7 +6521,7 @@ async function initCommand(opts) {
6923
6521
  }
6924
6522
  ok("Config files ready (iui.config.ts, tsconfig.json)");
6925
6523
  }
6926
- step("Generating component.config.ts\u2026");
6524
+ step("Scaffolding component.config.ts\u2026");
6927
6525
  const fetchedRegistry = await fetchComponentRegistry(auth.token);
6928
6526
  if (!fetchedRegistry.registry && fetchedRegistry.apiFailure) {
6929
6527
  warn(`Component registry API: ${fetchedRegistry.apiFailure}`);
@@ -8111,7 +7709,7 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
8111
7709
  }
8112
7710
 
8113
7711
  // src/commands/doctor.ts
8114
- function runConfigTierDiagnostics(targetCwd, opts, counters, options = {}) {
7712
+ async function runConfigTierDiagnostics(targetCwd, opts, counters, options = {}) {
8115
7713
  const pass = (label) => {
8116
7714
  checkPass(label);
8117
7715
  counters.passed++;
@@ -8129,10 +7727,13 @@ function runConfigTierDiagnostics(targetCwd, opts, counters, options = {}) {
8129
7727
  if (opts?.fix === true && includePackageJson) {
8130
7728
  ensureProjectConfig(targetCwd);
8131
7729
  ensureGitignoreHasIuiBuildCache(targetCwd);
8132
- if (projectHasViteTooling(targetCwd)) {
7730
+ const vite = projectHasViteTooling(targetCwd);
7731
+ ensureTsConfigForIui(vite ? "vite" : "react", targetCwd);
7732
+ if (vite) {
8133
7733
  ensureInventiveUiViteConfig(targetCwd);
8134
7734
  }
8135
7735
  ensureComponentConfig(readComponentPackageManifest(targetCwd), targetCwd);
7736
+ await ensureSlotRegistry({ cwd: targetCwd, quiet: true, mode: "repair" });
8136
7737
  }
8137
7738
  if (includeSlotCheck && isInsideProject(targetCwd) && getInstalledPackageVersion(COMPONENTS_PACKAGE, targetCwd)) {
8138
7739
  const slotValidity = checkGeneratedSlotValidity(targetCwd);
@@ -8234,7 +7835,7 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
8234
7835
  counters.failed++;
8235
7836
  };
8236
7837
  if (opts?.configOnly) {
8237
- runConfigTierDiagnostics(targetCwd, opts, counters, {
7838
+ await runConfigTierDiagnostics(targetCwd, opts, counters, {
8238
7839
  includePackageJson: true,
8239
7840
  includeSlotCheck: true
8240
7841
  });
@@ -8244,10 +7845,13 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
8244
7845
  else fail2("package.json missing");
8245
7846
  if (opts?.fix === true) {
8246
7847
  ensureProjectConfig(targetCwd);
8247
- if (projectHasViteTooling(targetCwd)) {
7848
+ const vite2 = projectHasViteTooling(targetCwd);
7849
+ ensureTsConfigForIui(vite2 ? "vite" : "react", targetCwd);
7850
+ if (vite2) {
8248
7851
  ensureInventiveUiViteConfig(targetCwd);
8249
7852
  }
8250
7853
  ensureComponentConfig(readComponentPackageManifest(targetCwd), targetCwd);
7854
+ await ensureSlotRegistry({ cwd: targetCwd, quiet: true, mode: "repair" });
8251
7855
  }
8252
7856
  if (isInsideProject(targetCwd)) {
8253
7857
  pass("Inventive UI project initialized");
@@ -8366,7 +7970,7 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
8366
7970
  hint("Fix: run iui doctor --fix to regenerate bootstrap artifacts");
8367
7971
  }
8368
7972
  }
8369
- runConfigTierDiagnostics(targetCwd, opts, counters, {
7973
+ await runConfigTierDiagnostics(targetCwd, opts, counters, {
8370
7974
  includePackageJson: false,
8371
7975
  includeSlotCheck: false
8372
7976
  });
@@ -8672,7 +8276,7 @@ async function updateCommand(opts = {}) {
8672
8276
  const auth = await ensureAuthSession();
8673
8277
  await ensureLicenseSession();
8674
8278
  const inProject = isInsideProject();
8675
- const currentCliVersion = true ? "0.0.9" : "unknown";
8279
+ const currentCliVersion = true ? "0.0.10" : "unknown";
8676
8280
  const latestCliVersion = await fetchLatestCliVersion(auth.token);
8677
8281
  const cliUpdateAvailable = latestCliVersion !== null && isVersionGreater(latestCliVersion, currentCliVersion);
8678
8282
  if (latestCliVersion && cliUpdateAvailable) {
@@ -8954,7 +8558,7 @@ var AUTH_EXEMPT_COMMANDS = /* @__PURE__ */ new Set([
8954
8558
  "doctor",
8955
8559
  "list"
8956
8560
  ]);
8957
- program.name("iui").description("The official CLI for the Inventive UI Design System").version(true ? "0.0.9" : "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");
8561
+ program.name("iui").description("The official CLI for the Inventive UI Design System").version(true ? "0.0.10" : "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");
8958
8562
  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));
8959
8563
  program.command("logout").description("Remove stored credentials").action(logoutCommand);
8960
8564
  program.command("whoami").description("Show authenticated identity and license details").action(whoamiCommand);