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/README.md +10 -0
- package/dist/index.js +367 -65
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
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
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
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 ${
|
|
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
|
|
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
|
|
1417
|
-
if (!
|
|
1554
|
+
const rewrittenAlias = normalizeAliasImportPath(specifierText, aliasesMap);
|
|
1555
|
+
if (!rewrittenAlias) {
|
|
1418
1556
|
return specifierText;
|
|
1419
1557
|
}
|
|
1420
|
-
if (
|
|
1421
|
-
return
|
|
1558
|
+
if (importStyle === "package" && isComponentAliasImport(rewrittenAlias)) {
|
|
1559
|
+
return SCHEMA_CONFIG.packageAliases.core;
|
|
1422
1560
|
}
|
|
1423
|
-
return
|
|
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);
|