ui8kit 1.3.8 → 1.4.1

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
@@ -97,10 +97,18 @@ var SCHEMA_CONFIG = {
97
97
  registryVersion: "Registry version",
98
98
  registryUrl: "Explicit registry URL override",
99
99
  strictCdn: "Disable fallback to built-in CDN URLs",
100
+ importStyle: "How component imports are rewritten: alias or package",
100
101
  lastUpdated: "Last update timestamp",
101
102
  categories: "Available component categories",
102
103
  components: "Component metadata for quick lookup",
103
104
  items: "Full component definitions"
105
+ },
106
+ packageAliases: {
107
+ core: "@ui8kit/core"
108
+ },
109
+ importStyle: {
110
+ alias: "alias",
111
+ package: "package"
104
112
  }
105
113
  };
106
114
  var TYPE_TO_FOLDER = {
@@ -191,7 +199,8 @@ var configSchema = z.object({
191
199
  libDir: z.string().default(SCHEMA_CONFIG.defaultDirectories.lib),
192
200
  registryUrl: z.string().url().optional(),
193
201
  registryVersion: z.string().optional(),
194
- strictCdn: z.boolean().default(false).optional()
202
+ strictCdn: z.boolean().default(false).optional(),
203
+ importStyle: z.enum(["alias", "package"]).default("alias").optional()
195
204
  });
196
205
 
197
206
  // src/utils/logger.ts
@@ -580,9 +589,6 @@ async function saveConfig(config) {
580
589
  await fs2.ensureDir(path2.dirname(configPath));
581
590
  await fs2.writeJson(configPath, config, { spaces: 2 });
582
591
  }
583
- async function ensureDir(dirPath) {
584
- await fs2.ensureDir(dirPath);
585
- }
586
592
 
587
593
  // src/utils/registry-validator.ts
588
594
  import fs6 from "fs-extra";
@@ -937,11 +943,15 @@ async function fetchJsonFromRegistry(url) {
937
943
  clearTimeout(timeoutId);
938
944
  }
939
945
  }
946
+ function resolveImportStyle(rawImportStyle) {
947
+ return rawImportStyle === "package" ? "package" : "alias";
948
+ }
940
949
  function buildInitConfig(options) {
941
950
  const registryName = options.registry || SCHEMA_CONFIG.defaultRegistryType;
942
951
  const aliases = SCHEMA_CONFIG.defaultAliases;
943
952
  const globalCss = options.globalCss || "src/index.css";
944
953
  const aliasComponents = options.aliasComponents?.trim() || "@/components";
954
+ const importStyle = resolveImportStyle(options.importStyle);
945
955
  if (options.yes) {
946
956
  return {
947
957
  $schema: `${SCHEMA_CONFIG.baseUrl}.json`,
@@ -954,7 +964,8 @@ function buildInitConfig(options) {
954
964
  libDir: SCHEMA_CONFIG.defaultDirectories.lib,
955
965
  registryUrl: options.registryUrl,
956
966
  registryVersion: options.registryVersion,
957
- strictCdn: options.strictCdn
967
+ strictCdn: options.strictCdn,
968
+ importStyle
958
969
  };
959
970
  }
960
971
  return {
@@ -968,7 +979,8 @@ function buildInitConfig(options) {
968
979
  libDir: SCHEMA_CONFIG.defaultDirectories.lib,
969
980
  registryUrl: options.registryUrl,
970
981
  registryVersion: options.registryVersion,
971
- strictCdn: options.strictCdn
982
+ strictCdn: options.strictCdn,
983
+ importStyle
972
984
  };
973
985
  }
974
986
  async function initCommand(options) {
@@ -1005,7 +1017,7 @@ async function initCommand(options) {
1005
1017
  }
1006
1018
  let config;
1007
1019
  if (options.yes) {
1008
- config = buildInitConfig({ yes: true, registry: registryName, ...cdnOptions });
1020
+ config = buildInitConfig({ yes: true, registry: registryName, ...cdnOptions, importStyle: options.importStyle });
1009
1021
  } else {
1010
1022
  const responses = await prompts([
1011
1023
  {
@@ -1019,33 +1031,35 @@ async function initCommand(options) {
1019
1031
  name: "aliasComponents",
1020
1032
  message: CLI_MESSAGES.prompts.aliasComponents,
1021
1033
  initial: "@/components"
1034
+ },
1035
+ {
1036
+ type: "select",
1037
+ name: "importStyle",
1038
+ message: "Import style for installed components",
1039
+ choices: [
1040
+ { title: "Alias imports (recommended)", value: "alias" },
1041
+ { title: "Package imports (@ui8kit/core)", value: "package" }
1042
+ ],
1043
+ initial: 0
1022
1044
  }
1023
1045
  ]);
1024
1046
  const aliasComponents = responses.aliasComponents?.trim() || "@/components";
1025
1047
  const globalCss = responses.globalCss || "src/index.css";
1048
+ const importStyle = resolveImportStyle(responses.importStyle);
1026
1049
  config = buildInitConfig({
1027
1050
  yes: false,
1028
1051
  registry: registryName,
1029
1052
  globalCss,
1030
1053
  aliasComponents,
1054
+ importStyle,
1031
1055
  ...cdnOptions
1032
1056
  });
1033
1057
  }
1034
1058
  const spinner = ora3(CLI_MESSAGES.info.initializing(registryName)).start();
1035
1059
  try {
1036
1060
  await saveConfig(config);
1037
- await ensureDir(config.libDir);
1038
- await ensureDir(config.componentsDir);
1039
- await ensureDir(path5.join(config.componentsDir, "ui"));
1040
- await ensureDir(SCHEMA_CONFIG.defaultDirectories.blocks);
1041
- await ensureDir(SCHEMA_CONFIG.defaultDirectories.layouts);
1042
- await ensureDir(SCHEMA_CONFIG.defaultDirectories.variants);
1043
1061
  spinner.text = "Installing core utilities and variants...";
1044
1062
  await installCoreFiles(registryName, config, spinner, cdnOptions);
1045
- spinner.text = "Installing core dependencies...";
1046
- await installDependencies(["clsx", "tailwind-merge"], {
1047
- useSpinner: false
1048
- });
1049
1063
  spinner.succeed(CLI_MESSAGES.success.initialized(registryName));
1050
1064
  logger.success(`
1051
1065
  \u2705 ${CLI_MESSAGES.success.setupComplete(registryName)}`);
@@ -1063,6 +1077,103 @@ async function initCommand(options) {
1063
1077
  handleError(error);
1064
1078
  }
1065
1079
  }
1080
+ function sortCoreDependencies(descriptors) {
1081
+ const itemByTypeAndName = /* @__PURE__ */ new Map();
1082
+ for (const item of descriptors) {
1083
+ itemByTypeAndName.set(`${item.type}:${item.name}`, item);
1084
+ }
1085
+ const findDependencyByName = (name) => {
1086
+ const dependencyByLib = itemByTypeAndName.get(`registry:lib:${name}`);
1087
+ if (dependencyByLib) {
1088
+ return dependencyByLib;
1089
+ }
1090
+ return descriptors.find((item) => item.name === name);
1091
+ };
1092
+ const indegrees = /* @__PURE__ */ new Map();
1093
+ const graph = /* @__PURE__ */ new Map();
1094
+ const queue = [];
1095
+ for (const item of descriptors) {
1096
+ const key = `${item.type}:${item.name}`;
1097
+ indegrees.set(key, 0);
1098
+ graph.set(key, /* @__PURE__ */ new Set());
1099
+ }
1100
+ for (const item of descriptors) {
1101
+ const itemKey = `${item.type}:${item.name}`;
1102
+ for (const registryDep of item.component.registryDependencies ?? []) {
1103
+ const targetName = registryDep.toLowerCase();
1104
+ const dependency = findDependencyByName(targetName);
1105
+ if (!dependency) {
1106
+ continue;
1107
+ }
1108
+ const dependencyKey = `${dependency.type}:${dependency.name}`;
1109
+ if (dependencyKey === itemKey) {
1110
+ continue;
1111
+ }
1112
+ graph.get(dependencyKey)?.add(itemKey);
1113
+ indegrees.set(itemKey, (indegrees.get(itemKey) ?? 0) + 1);
1114
+ }
1115
+ }
1116
+ for (const [key, inDegree] of indegrees.entries()) {
1117
+ if (inDegree === 0) {
1118
+ queue.push(key);
1119
+ }
1120
+ }
1121
+ const result = [];
1122
+ while (queue.length > 0) {
1123
+ const key = queue.shift();
1124
+ if (!key)
1125
+ break;
1126
+ const item = itemByTypeAndName.get(key);
1127
+ if (!item)
1128
+ continue;
1129
+ result.push(item);
1130
+ for (const dependent of graph.get(key) ?? []) {
1131
+ const nextDegree = Math.max((indegrees.get(dependent) ?? 1) - 1, 0);
1132
+ indegrees.set(dependent, nextDegree);
1133
+ if (nextDegree === 0) {
1134
+ queue.push(dependent);
1135
+ }
1136
+ }
1137
+ }
1138
+ if (result.length === descriptors.length) {
1139
+ return result;
1140
+ }
1141
+ for (const item of descriptors) {
1142
+ if (!result.includes(item)) {
1143
+ result.push(item);
1144
+ }
1145
+ }
1146
+ return result;
1147
+ }
1148
+ async function fetchCoreComponent(name, type, cdnUrls) {
1149
+ const folder = type === "registry:lib" ? "lib" : type === "registry:variants" ? "components/variants" : "components/ui";
1150
+ for (const baseUrl of cdnUrls) {
1151
+ const url = `${baseUrl}/${folder}/${name}.json`;
1152
+ const component = await fetchJsonFromRegistry(url);
1153
+ if (component) {
1154
+ return component;
1155
+ }
1156
+ }
1157
+ return null;
1158
+ }
1159
+ function resolveComponentTargetDir(type, config) {
1160
+ if (type === "registry:lib") {
1161
+ return config.libDir;
1162
+ }
1163
+ if (type === "registry:variants") {
1164
+ return SCHEMA_CONFIG.defaultDirectories.variants;
1165
+ }
1166
+ return path5.join(config.componentsDir, "ui");
1167
+ }
1168
+ async function writeComponentFromDescriptor(component, type, config) {
1169
+ for (const file of component.files) {
1170
+ const fileName = path5.basename(file.path);
1171
+ const targetDir = resolveComponentTargetDir(type, config);
1172
+ const targetPath = path5.join(process.cwd(), targetDir, fileName);
1173
+ await fs5.ensureDir(path5.dirname(targetPath));
1174
+ await fs5.writeFile(targetPath, file.content || "", "utf-8");
1175
+ }
1176
+ }
1066
1177
  async function installCoreFiles(registryType, config, spinner, cdnResolution = {}) {
1067
1178
  const cdnUrls = getCdnUrls(registryType, {
1068
1179
  registryUrl: cdnResolution.registryUrl,
@@ -1089,13 +1200,49 @@ async function installCoreFiles(registryType, config, spinner, cdnResolution = {
1089
1200
  }
1090
1201
  const variantItems = registryIndex.components.filter((c) => c.type === "registry:variants");
1091
1202
  const libItems = registryIndex.components.filter((c) => c.type === "registry:lib");
1092
- for (const item of libItems) {
1093
- spinner.text = `Installing ${item.name}...`;
1094
- await installComponentFromRegistry(item.name, "registry:lib", cdnUrls, config);
1203
+ const coreItems = [
1204
+ ...libItems.map((item) => ({ name: item.name, type: "registry:lib" })),
1205
+ ...variantItems.map((item) => ({ name: item.name, type: "registry:variants" }))
1206
+ ];
1207
+ if (coreItems.length === 0) {
1208
+ spinner.text = "\u26A0\uFE0F Registry index has no core components; creating local utils...";
1209
+ await createUtilsFile(config.libDir, config.typescript);
1210
+ return;
1095
1211
  }
1096
- for (const item of variantItems) {
1097
- spinner.text = `Installing variant: ${item.name}...`;
1098
- await installComponentFromRegistry(item.name, "registry:variants", cdnUrls, config);
1212
+ const loadedComponents = [];
1213
+ const coreDependencies = /* @__PURE__ */ new Set();
1214
+ for (const item of coreItems) {
1215
+ spinner.text = `Fetching ${item.name}...`;
1216
+ const component = await fetchCoreComponent(item.name, item.type, cdnUrls);
1217
+ if (!component) {
1218
+ continue;
1219
+ }
1220
+ loadedComponents.push({
1221
+ ...item,
1222
+ component: {
1223
+ name: component.name || item.name,
1224
+ type: item.type,
1225
+ files: component.files,
1226
+ dependencies: component.dependencies ?? [],
1227
+ devDependencies: component.devDependencies ?? [],
1228
+ registryDependencies: component.registryDependencies ?? [],
1229
+ description: component.description
1230
+ }
1231
+ });
1232
+ for (const dep of component.dependencies ?? []) {
1233
+ coreDependencies.add(dep);
1234
+ }
1235
+ }
1236
+ const orderedCoreComponents = sortCoreDependencies(loadedComponents);
1237
+ for (const descriptor of orderedCoreComponents) {
1238
+ spinner.text = `Installing ${descriptor.name}...`;
1239
+ await writeComponentFromDescriptor(descriptor.component, descriptor.type, config);
1240
+ }
1241
+ if (coreDependencies.size > 0) {
1242
+ spinner.text = "Installing core dependencies...";
1243
+ await installDependencies(Array.from(coreDependencies), {
1244
+ useSpinner: false
1245
+ });
1099
1246
  }
1100
1247
  spinner.text = "Syncing variants index...";
1101
1248
  const variantsIndexStatus = await installVariantsIndex(cdnUrls);
@@ -1108,32 +1255,7 @@ async function installCoreFiles(registryType, config, spinner, cdnResolution = {
1108
1255
  } else {
1109
1256
  spinner.text = "variants/index.ts not found in registry (skipped)";
1110
1257
  }
1111
- spinner.text = `\u2705 Installed ${libItems.length} utilities and ${variantItems.length} variants`;
1112
- }
1113
- async function installComponentFromRegistry(name, type, cdnUrls, config) {
1114
- const folder = type === "registry:lib" ? "lib" : type === "registry:variants" ? "components/variants" : "components/ui";
1115
- for (const baseUrl of cdnUrls) {
1116
- const url = `${baseUrl}/${folder}/${name}.json`;
1117
- const component = await fetchJsonFromRegistry(url);
1118
- if (!component) {
1119
- continue;
1120
- }
1121
- for (const file of component.files) {
1122
- const fileName = path5.basename(file.path);
1123
- let targetDir;
1124
- if (type === "registry:lib") {
1125
- targetDir = config.libDir;
1126
- } else if (type === "registry:variants") {
1127
- targetDir = SCHEMA_CONFIG.defaultDirectories.variants;
1128
- } else {
1129
- targetDir = path5.join(config.componentsDir, "ui");
1130
- }
1131
- const targetPath = path5.join(process.cwd(), targetDir, fileName);
1132
- await fs5.ensureDir(path5.dirname(targetPath));
1133
- await fs5.writeFile(targetPath, file.content || "", "utf-8");
1134
- }
1135
- return;
1136
- }
1258
+ spinner.text = `\u2705 Installed ${loadedComponents.length} core components`;
1137
1259
  }
1138
1260
  async function installVariantsIndex(cdnUrls) {
1139
1261
  for (const baseUrl of cdnUrls) {
@@ -1345,6 +1467,7 @@ function formatDiffPreview(diff, maxLines = 80) {
1345
1467
  import path7 from "path";
1346
1468
  import ts from "typescript";
1347
1469
  var IMPORT_NODE_KIND = ts.SyntaxKind.ImportDeclaration;
1470
+ var PACKAGE_STYLE_IMPORT_GROUPS = ["components", "layouts", "blocks", "variants", "ui"];
1348
1471
  function normalizeAliasKey(alias) {
1349
1472
  return alias.replace(/\\/g, "/").replace(/\/+$/, "");
1350
1473
  }
@@ -1408,21 +1531,36 @@ function pickAliasForImport(importPath, configuredAliases) {
1408
1531
  }
1409
1532
  return void 0;
1410
1533
  }
1411
- function rewriteModuleSpecifier(specifierText, configuredAliases) {
1534
+ function normalizeAliasImportPath(specifierText, aliasesMap) {
1535
+ const rewritten = pickAliasForImport(specifierText, aliasesMap);
1536
+ if (!rewritten || rewritten === normalizeAliasKey(specifierText)) {
1537
+ return void 0;
1538
+ }
1539
+ return rewritten;
1540
+ }
1541
+ function isComponentAliasImport(aliasPath) {
1542
+ const match = aliasPath.startsWith("@/") ? aliasPath.slice(2) : "";
1543
+ if (!match) {
1544
+ return false;
1545
+ }
1546
+ const firstSegment = match.split("/")[0];
1547
+ return PACKAGE_STYLE_IMPORT_GROUPS.includes(firstSegment);
1548
+ }
1549
+ function rewriteModuleSpecifier(specifierText, configuredAliases, importStyle = "alias") {
1412
1550
  if (!specifierText.startsWith("@/")) {
1413
1551
  return specifierText;
1414
1552
  }
1415
1553
  const aliasesMap = normalizeConfiguredAliases(configuredAliases);
1416
- const rewrittenRemainder = pickAliasForImport(specifierText, aliasesMap);
1417
- if (!rewrittenRemainder || rewrittenRemainder === normalizeAliasKey(specifierText)) {
1554
+ const rewrittenAlias = normalizeAliasImportPath(specifierText, aliasesMap);
1555
+ if (!rewrittenAlias) {
1418
1556
  return specifierText;
1419
1557
  }
1420
- if (rewrittenRemainder) {
1421
- return rewrittenRemainder;
1558
+ if (importStyle === "package" && isComponentAliasImport(rewrittenAlias)) {
1559
+ return SCHEMA_CONFIG.packageAliases.core;
1422
1560
  }
1423
- return specifierText;
1561
+ return rewrittenAlias;
1424
1562
  }
1425
- function transformImports(content, aliases) {
1563
+ function transformImports(content, aliases, importStyle = "alias") {
1426
1564
  const sourceFile = ts.createSourceFile("component.tsx", content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
1427
1565
  const importSpans = [];
1428
1566
  const configuredAliases = normalizeConfiguredAliases(aliases);
@@ -1431,7 +1569,7 @@ function transformImports(content, aliases) {
1431
1569
  const moduleSpecifier = node.moduleSpecifier;
1432
1570
  if (ts.isStringLiteral(moduleSpecifier)) {
1433
1571
  const value = moduleSpecifier.text;
1434
- const rewritten = rewriteModuleSpecifier(value, Object.fromEntries(configuredAliases));
1572
+ const rewritten = rewriteModuleSpecifier(value, Object.fromEntries(configuredAliases), importStyle);
1435
1573
  if (rewritten !== value) {
1436
1574
  importSpans.push({
1437
1575
  start: moduleSpecifier.getStart(sourceFile),
@@ -1457,8 +1595,8 @@ function transformImports(content, aliases) {
1457
1595
  function transformCleanup(content) {
1458
1596
  return content.replace(/\r\n/g, "\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
1459
1597
  }
1460
- function applyTransforms(content, aliases) {
1461
- const withImports = transformImports(content, aliases);
1598
+ function applyTransforms(content, aliases, importStyle = "alias") {
1599
+ const withImports = transformImports(content, aliases, importStyle);
1462
1600
  return transformCleanup(withImports);
1463
1601
  }
1464
1602
  function shouldTransformFile(fileName) {
@@ -1531,6 +1669,9 @@ async function addAllComponents(options, registryType, requestOptions) {
1531
1669
  }
1532
1670
  const spinner = ora4(CLI_MESSAGES.info.fetchingComponentList(registryType)).start();
1533
1671
  try {
1672
+ if (!options.dryRun) {
1673
+ await ensureBaseProjectDirectories(config);
1674
+ }
1534
1675
  const allComponents = await getAllComponentsFn(registryType);
1535
1676
  if (allComponents.length === 0) {
1536
1677
  spinner.fail(`No components found in ${registryType} registry`);
@@ -1572,6 +1713,14 @@ async function addAllComponents(options, registryType, requestOptions) {
1572
1713
  process.exit(1);
1573
1714
  }
1574
1715
  }
1716
+ async function ensureBaseProjectDirectories(config) {
1717
+ await fs7.ensureDir(config.libDir);
1718
+ await fs7.ensureDir(config.componentsDir);
1719
+ await fs7.ensureDir(path8.join(config.componentsDir, "ui"));
1720
+ await fs7.ensureDir(SCHEMA_CONFIG.defaultDirectories.blocks);
1721
+ await fs7.ensureDir(SCHEMA_CONFIG.defaultDirectories.layouts);
1722
+ await fs7.ensureDir(SCHEMA_CONFIG.defaultDirectories.variants);
1723
+ }
1575
1724
  async function processComponents(componentNames, registryType, config, getComponentFn, options, preloadedComponents, totalCount) {
1576
1725
  const results = [];
1577
1726
  const componentMap = new Map(preloadedComponents?.map((c) => [c.name.toLowerCase(), c]));
@@ -1610,7 +1759,7 @@ async function processComponents(componentNames, registryType, config, getCompon
1610
1759
  logger.info(` ${status}: ${targetPath}`);
1611
1760
  if (exists) {
1612
1761
  const currentContent = await fs7.readFile(targetPath, "utf-8");
1613
- const transformedIncoming = shouldTransformFile(fileName) ? applyTransforms(file.content, config.aliases) : file.content;
1762
+ const transformedIncoming = shouldTransformFile(fileName) ? applyTransforms(file.content, config.aliases, config.importStyle || "alias") : file.content;
1614
1763
  const changed = hasDiff(currentContent, transformedIncoming);
1615
1764
  if (changed) {
1616
1765
  const patch = buildUnifiedDiff(targetPath, `${component.name}/${fileName}`, currentContent, transformedIncoming);
@@ -1774,7 +1923,7 @@ async function installComponentFiles(component, config, force = false) {
1774
1923
  continue;
1775
1924
  }
1776
1925
  await fs7.ensureDir(path8.dirname(targetPath));
1777
- const preparedContent = shouldTransformFile(fileName) ? applyTransforms(file.content, config.aliases) : file.content;
1926
+ const preparedContent = shouldTransformFile(fileName) ? applyTransforms(file.content, config.aliases, config.importStyle || "alias") : file.content;
1778
1927
  await fs7.writeFile(targetPath, preparedContent, "utf-8");
1779
1928
  }
1780
1929
  }
@@ -2008,6 +2157,12 @@ function generateConfigSchema() {
2008
2157
  "type": "boolean",
2009
2158
  "default": false,
2010
2159
  "description": SCHEMA_CONFIG.fieldDescriptions.strictCdn
2160
+ },
2161
+ "importStyle": {
2162
+ "type": "string",
2163
+ "enum": Object.values(SCHEMA_CONFIG.importStyle),
2164
+ "default": SCHEMA_CONFIG.importStyle.alias,
2165
+ "description": SCHEMA_CONFIG.fieldDescriptions.importStyle
2011
2166
  }
2012
2167
  },
2013
2168
  "required": ["framework"],
@@ -2340,7 +2495,9 @@ async function createIndexFile(registry, outputDir) {
2340
2495
  name: item.name,
2341
2496
  type: item.type,
2342
2497
  title: item.title,
2343
- description: item.description
2498
+ description: item.description,
2499
+ dependencies: item.dependencies ?? [],
2500
+ registryDependencies: item.registryDependencies ?? []
2344
2501
  })),
2345
2502
  categories: SCHEMA_CONFIG.componentCategories,
2346
2503
  version: "1.0.0",
@@ -2464,6 +2621,109 @@ var DEV_PATTERNS = [
2464
2621
  "tailwindcss",
2465
2622
  "autoprefixer"
2466
2623
  ];
2624
+ var PACKAGE_CORE_PREFIX = "@ui8kit/core";
2625
+ var PACKAGE_STYLE_BARS = [
2626
+ "components",
2627
+ "layouts",
2628
+ "blocks",
2629
+ "variants",
2630
+ "ui"
2631
+ ];
2632
+ var PACKAGE_STYLE_ALIASES = ["@/components", "@/components/ui", "@/ui", "@/layouts", "@/blocks", "@/variants"];
2633
+ var REGISTRY_ALIAS_ROOTS = Object.keys(SCHEMA_CONFIG.defaultAliases);
2634
+ function toPosix2(value) {
2635
+ return value.replace(/\\/g, "/");
2636
+ }
2637
+ function toLowerOrEmpty(value) {
2638
+ return value.trim().toLowerCase();
2639
+ }
2640
+ function stripImportExtension(moduleName) {
2641
+ return moduleName.replace(/\.[tj]sx?$/i, "");
2642
+ }
2643
+ function getAliasMatch(moduleName) {
2644
+ const normalized = toPosix2(moduleName);
2645
+ if (!normalized.startsWith("@/")) {
2646
+ return null;
2647
+ }
2648
+ const directMatch = REGISTRY_ALIAS_ROOTS.filter((alias) => normalized === alias || normalized.startsWith(`${alias}/`)).sort((a, b) => b.length - a.length)[0];
2649
+ if (!directMatch) {
2650
+ return null;
2651
+ }
2652
+ const remainder = normalized.slice(directMatch.length).replace(/^\/+/, "");
2653
+ return {
2654
+ alias: directMatch,
2655
+ remainder
2656
+ };
2657
+ }
2658
+ function shouldRewriteAsRegistryDependency(aliasImport) {
2659
+ const match = getAliasMatch(aliasImport);
2660
+ if (!match || !match.remainder) {
2661
+ return false;
2662
+ }
2663
+ if (PACKAGE_STYLE_ALIASES.includes(match.alias)) {
2664
+ return true;
2665
+ }
2666
+ const firstSegment = match.remainder.split("/")[0];
2667
+ return PACKAGE_STYLE_BARS.includes(firstSegment);
2668
+ }
2669
+ function isUi8kitCoreImport(moduleName) {
2670
+ return moduleName === PACKAGE_CORE_PREFIX || moduleName.startsWith(`${PACKAGE_CORE_PREFIX}/`);
2671
+ }
2672
+ function extractCoreImportNames(moduleName, node) {
2673
+ if (!isUi8kitCoreImport(moduleName)) {
2674
+ return [];
2675
+ }
2676
+ const names = [];
2677
+ const importClause = node.importClause;
2678
+ if (importClause?.name) {
2679
+ names.push(importClause.name.text);
2680
+ }
2681
+ const namedBindings = importClause?.namedBindings;
2682
+ if (namedBindings && ts4.isNamedImports(namedBindings)) {
2683
+ namedBindings.elements.forEach((element) => {
2684
+ names.push(element.name.text);
2685
+ });
2686
+ }
2687
+ if (moduleName.startsWith(`${PACKAGE_CORE_PREFIX}/`)) {
2688
+ const explicitComponent = toLowerOrEmpty(stripImportExtension(moduleName.slice(PACKAGE_CORE_PREFIX.length + 1)));
2689
+ if (explicitComponent && !names.includes(explicitComponent)) {
2690
+ names.push(explicitComponent);
2691
+ }
2692
+ }
2693
+ return names;
2694
+ }
2695
+ function mapAliasImportToComponentName(moduleName) {
2696
+ const aliasMatch = getAliasMatch(moduleName);
2697
+ if (!aliasMatch || !aliasMatch.remainder) {
2698
+ return null;
2699
+ }
2700
+ if (!shouldRewriteAsRegistryDependency(moduleName)) {
2701
+ return null;
2702
+ }
2703
+ const componentName = stripImportExtension(aliasMatch.remainder).split("/").at(-1);
2704
+ return componentName ? toLowerOrEmpty(componentName) : null;
2705
+ }
2706
+ function extractRegistryDependenciesFromImport(node) {
2707
+ const moduleSpecifier = node.moduleSpecifier;
2708
+ if (!ts4.isStringLiteral(moduleSpecifier)) {
2709
+ return [];
2710
+ }
2711
+ const moduleName = moduleSpecifier.text;
2712
+ const importedNames = [];
2713
+ if (isUi8kitCoreImport(moduleName)) {
2714
+ for (const name of extractCoreImportNames(moduleName, node)) {
2715
+ importedNames.push(toLowerOrEmpty(name));
2716
+ }
2717
+ return importedNames;
2718
+ }
2719
+ if (moduleName.startsWith("@/")) {
2720
+ const aliasName = mapAliasImportToComponentName(moduleName);
2721
+ if (aliasName) {
2722
+ importedNames.push(aliasName);
2723
+ }
2724
+ }
2725
+ return importedNames;
2726
+ }
2467
2727
  async function scanCommand(options = {}) {
2468
2728
  const registryName = options.registry || SCHEMA_CONFIG.defaultRegistryType;
2469
2729
  const registryPath = `./${registryName}`;
@@ -2502,6 +2762,7 @@ async function scanCommand(options = {}) {
2502
2762
  ];
2503
2763
  const seen = /* @__PURE__ */ new Set();
2504
2764
  const allComponents = [];
2765
+ const localDependencyRefs = /* @__PURE__ */ new Map();
2505
2766
  for (const comp of allComponentsRaw) {
2506
2767
  const key = `${comp.type}:${comp.name}`;
2507
2768
  if (seen.has(key))
@@ -2514,10 +2775,38 @@ async function scanCommand(options = {}) {
2514
2775
  const analysis = await analyzeComponentDependencies(component.files, scanOptions.cwd);
2515
2776
  component.dependencies = analysis.dependencies;
2516
2777
  component.devDependencies = analysis.devDependencies;
2778
+ localDependencyRefs.set(
2779
+ `${component.type}:${component.name}`,
2780
+ new Set(analysis.registryDependencies.map(toLowerOrEmpty))
2781
+ );
2517
2782
  if (analysis.description && !component.description) {
2518
2783
  component.description = analysis.description;
2519
2784
  }
2520
2785
  }
2786
+ const availableComponents = new Set(allComponents.map((item) => item.name.toLowerCase()));
2787
+ allComponents.forEach((item) => {
2788
+ const rawDependencies = localDependencyRefs.get(`${item.type}:${item.name}`) ?? /* @__PURE__ */ new Set();
2789
+ const resolvedDependencies = /* @__PURE__ */ new Set();
2790
+ const unresolvedDependencies = [];
2791
+ for (const candidate of rawDependencies) {
2792
+ const normalized = toLowerOrEmpty(candidate);
2793
+ if (!normalized) {
2794
+ continue;
2795
+ }
2796
+ if (normalized === item.name.toLowerCase()) {
2797
+ continue;
2798
+ }
2799
+ if (!availableComponents.has(normalized)) {
2800
+ unresolvedDependencies.push(normalized);
2801
+ continue;
2802
+ }
2803
+ resolvedDependencies.add(normalized);
2804
+ }
2805
+ if (unresolvedDependencies.length > 0) {
2806
+ console.warn(`\u26A0\uFE0F Missing local component references in ${item.name} (${item.type}): ${unresolvedDependencies.join(", ")}`);
2807
+ }
2808
+ item.registryDependencies = Array.from(resolvedDependencies).sort();
2809
+ });
2521
2810
  const registry = {
2522
2811
  $schema: "https://ui.buildy.tw/schema/registry.json",
2523
2812
  items: allComponents,
@@ -2577,6 +2866,7 @@ async function scanDirectory(dirPath, type, ignorePatterns = []) {
2577
2866
  description,
2578
2867
  dependencies: [],
2579
2868
  devDependencies: [],
2869
+ registryDependencies: [],
2580
2870
  files: [{
2581
2871
  path: relativePath,
2582
2872
  target: getTargetFromType(type)
@@ -2613,6 +2903,7 @@ async function scanDirectoryFlat(dirPath, type, ignoreFiles = []) {
2613
2903
  description,
2614
2904
  dependencies: [],
2615
2905
  devDependencies: [],
2906
+ registryDependencies: [],
2616
2907
  files: [{
2617
2908
  path: relativePath,
2618
2909
  target: getTargetFromType(type)
@@ -2642,6 +2933,7 @@ async function scanSingleFile(filePath, type) {
2642
2933
  description,
2643
2934
  dependencies: [],
2644
2935
  devDependencies: [],
2936
+ registryDependencies: [],
2645
2937
  files: [{
2646
2938
  path: relativePath,
2647
2939
  target: getTargetFromType(type)
@@ -2679,6 +2971,7 @@ function hasValidExports(content) {
2679
2971
  async function analyzeComponentDependencies(files, cwd) {
2680
2972
  const allDependencies = /* @__PURE__ */ new Set();
2681
2973
  const allDevDependencies = /* @__PURE__ */ new Set();
2974
+ const allRegistryDependencies = /* @__PURE__ */ new Set();
2682
2975
  let description;
2683
2976
  for (const file of files) {
2684
2977
  try {
@@ -2693,6 +2986,7 @@ async function analyzeComponentDependencies(files, cwd) {
2693
2986
  const analysis = analyzeAST(sourceFile);
2694
2987
  analysis.dependencies.forEach((dep) => allDependencies.add(dep));
2695
2988
  analysis.devDependencies.forEach((dep) => allDevDependencies.add(dep));
2989
+ analysis.registryDependencies.forEach((dep) => allRegistryDependencies.add(dep));
2696
2990
  if (analysis.description && !description) {
2697
2991
  description = analysis.description;
2698
2992
  }
@@ -2703,12 +2997,14 @@ async function analyzeComponentDependencies(files, cwd) {
2703
2997
  return {
2704
2998
  dependencies: Array.from(allDependencies),
2705
2999
  devDependencies: Array.from(allDevDependencies),
2706
- description
3000
+ description,
3001
+ registryDependencies: Array.from(allRegistryDependencies)
2707
3002
  };
2708
3003
  }
2709
3004
  function analyzeAST(sourceFile) {
2710
3005
  const dependencies = /* @__PURE__ */ new Set();
2711
3006
  const devDependencies = /* @__PURE__ */ new Set();
3007
+ const registryDependencies = /* @__PURE__ */ new Set();
2712
3008
  let description;
2713
3009
  let hasExports = false;
2714
3010
  function visit(node) {
@@ -2716,6 +3012,11 @@ function analyzeAST(sourceFile) {
2716
3012
  const moduleSpecifier = node.moduleSpecifier;
2717
3013
  if (ts4.isStringLiteral(moduleSpecifier)) {
2718
3014
  const moduleName = moduleSpecifier.text;
3015
+ for (const name of extractRegistryDependenciesFromImport(node)) {
3016
+ if (name) {
3017
+ registryDependencies.add(name);
3018
+ }
3019
+ }
2719
3020
  if (isExternalDependency(moduleName)) {
2720
3021
  if (isDevDependency(moduleName)) {
2721
3022
  devDependencies.add(moduleName);
@@ -2743,6 +3044,7 @@ function analyzeAST(sourceFile) {
2743
3044
  dependencies: Array.from(dependencies),
2744
3045
  devDependencies: Array.from(devDependencies),
2745
3046
  description,
3047
+ registryDependencies: Array.from(registryDependencies),
2746
3048
  hasExports
2747
3049
  };
2748
3050
  }
@@ -2947,7 +3249,7 @@ async function compareComponentFiles(installed, remote, config) {
2947
3249
  if (!remoteCandidate) {
2948
3250
  return [{ path: installed.filePath, changed: false }];
2949
3251
  }
2950
- const remoteContent = applyTransforms(remoteCandidate.content, config.aliases);
3252
+ const remoteContent = applyTransforms(remoteCandidate.content, config.aliases, config.importStyle || "alias");
2951
3253
  const changed = hasDiff(localContent, remoteContent);
2952
3254
  return changed ? [{
2953
3255
  path: installed.filePath,
@@ -3400,7 +3702,7 @@ program.command("cache").description("Manage local cache").command("clear").desc
3400
3702
  program.command("registry").description("Manage generated registry artifacts").command("clean").description("Remove generated registry build artifacts").option("--dry-run", "Show what would be removed without deleting").option("--all", "Also remove src/registry.json if it exists").option("-f, --force", "Skip confirmation prompt").action(registryCleanCommand);
3401
3703
  program.command("reset").description("Reset local UI8Kit state").option("--dry-run", "Show what would be removed without deleting").option("--with-cache", "Also clear CLI cache data").option("-y, --yes", "Skip prompts and perform reset").option("-f, --force", "Skip confirmation prompt").action(resetCommand);
3402
3704
  program.command("info").description("Show environment and config diagnostics").option("--json", "Output diagnostics as JSON").option("--cdn", "Show resolved CDN order and active overrides").action(infoCommand);
3403
- program.command("init").description("Initialize UI8Kit structure in your project").option("-y, --yes", "Skip prompts and use defaults").option("-r, --registry <type>", "Registry type: ui", "ui").option("--registry-url <url>", "Override CDN registry base URL").option("--registry-version <version>", "Override registry @latest version").option("--strict-cdn", "Disable fallback CDN providers when override is provided").action(initCommand);
3705
+ program.command("init").description("Initialize UI8Kit structure in your project").option("-y, --yes", "Skip prompts and use defaults").option("-r, --registry <type>", "Registry type: ui", "ui").option("--registry-url <url>", "Override CDN registry base URL").option("--registry-version <version>", "Override registry @latest version").option("--strict-cdn", "Disable fallback CDN providers when override is provided").option("--import-style <alias|package>", "Rewrite imports as alias paths or @ui8kit/core package imports", "alias").action(initCommand);
3404
3706
  program.command("add").description("Add components to your project from the registry").argument("[components...]", "Components to add").option("-a, --all", "Install all available components").option("-f, --force", "Overwrite existing files").option("-r, --registry <type>", "Registry type: ui", "ui").option("--dry-run", "Show what would be installed without installing").option("--retry", "Aggressive retry mode (3 attempts per CDN request)").option("--registry-url <url>", "Override CDN registry base URL").option("--registry-version <version>", "Override registry @latest version").option("--strict-cdn", "Disable fallback CDN providers when override is provided").action(addCommand);
3405
3707
  program.command("scan").description("Scan and generate registry from existing components").option("-r, --registry <type|path>", "Registry type (ui) or custom path", "ui").option("-o, --output <file>", "Output registry file").option("-s, --source <dir>", "Source directory to scan").action(async (options) => {
3406
3708
  await scanCommand(options);