@tbox.cn/app-cli 0.1.0 → 0.1.2
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 +289 -67
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -383,8 +383,8 @@ async function createApp(opts) {
|
|
|
383
383
|
}
|
|
384
384
|
|
|
385
385
|
// src/commands/add.ts
|
|
386
|
-
import { existsSync as
|
|
387
|
-
import
|
|
386
|
+
import { existsSync as existsSync20, readFileSync as readFileSync9, readdirSync as readdirSync2 } from "fs";
|
|
387
|
+
import path24 from "path";
|
|
388
388
|
|
|
389
389
|
// src/expand.ts
|
|
390
390
|
import { mkdir as mkdir2, rm, writeFile as writeFile3 } from "fs/promises";
|
|
@@ -405,15 +405,32 @@ function rewritePlatformRefs(deps) {
|
|
|
405
405
|
if (isWorkspacePkg(name)) deps[name] = "catalog:";
|
|
406
406
|
}
|
|
407
407
|
}
|
|
408
|
+
function deriveModuleId(pkgName) {
|
|
409
|
+
return pkgName.replace(/^@tbox\.cn\/app-/, "").replace(/^@[^/]+\//, "");
|
|
410
|
+
}
|
|
411
|
+
function escapeRegExp(s) {
|
|
412
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
413
|
+
}
|
|
414
|
+
function rewriteLoadModuleSkillsCall(content, fromName, toName) {
|
|
415
|
+
return content.replaceAll(
|
|
416
|
+
new RegExp(`loadModuleSkills\\(\\s*['"]${escapeRegExp(fromName)}['"]`, "g"),
|
|
417
|
+
`loadModuleSkills('${toName}'`
|
|
418
|
+
);
|
|
419
|
+
}
|
|
408
420
|
function rewriteExportsToSrc(pkg) {
|
|
409
421
|
const exports = pkg.exports;
|
|
410
422
|
if (!exports || typeof exports !== "object") return;
|
|
411
423
|
const next = {};
|
|
412
424
|
for (const [sub, val] of Object.entries(exports)) {
|
|
425
|
+
if (sub === "./package.json") {
|
|
426
|
+
next[sub] = val;
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
413
429
|
if (typeof val !== "object" || val === null) continue;
|
|
414
430
|
const base = sub === "." ? "./src/index.ts" : `./src/${sub.replace(/^\.\//, "")}/index.ts`;
|
|
415
431
|
next[sub] = { types: base, import: base };
|
|
416
432
|
}
|
|
433
|
+
if (next["./package.json"] === void 0) next["./package.json"] = "./package.json";
|
|
417
434
|
pkg.exports = next;
|
|
418
435
|
}
|
|
419
436
|
async function expandCodegen(appDir, sourceDir, entry) {
|
|
@@ -421,16 +438,21 @@ async function expandCodegen(appDir, sourceDir, entry) {
|
|
|
421
438
|
const targetDir = path5.join(appDir, "packages", entry.id);
|
|
422
439
|
await rm(targetDir, { recursive: true, force: true });
|
|
423
440
|
await mkdir2(targetDir, { recursive: true });
|
|
441
|
+
const rawPkg = JSON.parse(await src.readFile("package.json"));
|
|
442
|
+
const fromName = rawPkg.name ?? "";
|
|
443
|
+
const toName = `@app/${entry.id}`;
|
|
424
444
|
for (const rel of await src.listFiles()) {
|
|
425
445
|
if (rel === "package.json") continue;
|
|
426
|
-
|
|
446
|
+
let content = await src.readFile(rel);
|
|
447
|
+
if (fromName && fromName !== toName && rel.endsWith(".ts")) {
|
|
448
|
+
content = rewriteLoadModuleSkillsCall(content, fromName, toName);
|
|
449
|
+
}
|
|
427
450
|
const out = path5.join(targetDir, rel);
|
|
428
451
|
await mkdir2(path5.dirname(out), { recursive: true });
|
|
429
452
|
await writeFile3(out, content);
|
|
430
453
|
}
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
pkg.name = `@app/${entry.id}`;
|
|
454
|
+
const pkg = rawPkg;
|
|
455
|
+
pkg.name = toName;
|
|
434
456
|
pkg.private = true;
|
|
435
457
|
if (pkg.dependencies && typeof pkg.dependencies === "object") {
|
|
436
458
|
rewritePlatformRefs(pkg.dependencies);
|
|
@@ -522,7 +544,9 @@ async function createLocalSkeleton(appDir, shortName) {
|
|
|
522
544
|
exports: {
|
|
523
545
|
".": { types: "./src/index.ts", import: "./src/index.ts" },
|
|
524
546
|
"./server": { types: "./src/server/index.ts", import: "./src/server/index.ts" },
|
|
525
|
-
"./client": { types: "./src/client/index.ts", import: "./src/client/index.ts" }
|
|
547
|
+
"./client": { types: "./src/client/index.ts", import: "./src/client/index.ts" },
|
|
548
|
+
// 009 模块文件化前置:loadModuleSkills 包名解析需 exports 放行元数据子路径
|
|
549
|
+
"./package.json": "./package.json"
|
|
526
550
|
},
|
|
527
551
|
// 本地模块自带工具链:typecheck/test 可在生成应用内直接跑(pnpm verify 全 @app/* 范围)
|
|
528
552
|
scripts: { typecheck: "tsc --noEmit", test: "vitest run --passWithNoTests" },
|
|
@@ -932,6 +956,19 @@ function probeModuleObjectExport(dir, sub, symbol) {
|
|
|
932
956
|
return false;
|
|
933
957
|
}
|
|
934
958
|
}
|
|
959
|
+
function readServerSource(dir) {
|
|
960
|
+
const file = path7.join(dir, "src", "server", "index.ts");
|
|
961
|
+
if (!existsSync5(file)) return "";
|
|
962
|
+
try {
|
|
963
|
+
return readFileSync4(file, "utf8");
|
|
964
|
+
} catch {
|
|
965
|
+
return "";
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
function extractComponentId(source) {
|
|
969
|
+
const match = source.match(/declaration\s*:\s*\{[\s\S]*?componentId\s*:\s*['"]([^'"]+)['"]/);
|
|
970
|
+
return match?.[1];
|
|
971
|
+
}
|
|
935
972
|
async function listLocalModules(appDir) {
|
|
936
973
|
const packagesDir = path7.join(appDir, "packages");
|
|
937
974
|
const result = [];
|
|
@@ -968,25 +1005,31 @@ async function collectDeclared(appDir) {
|
|
|
968
1005
|
const descriptor = readComponentFile(local) ?? readDescriptorFromNodeModules(appDir, entry.package);
|
|
969
1006
|
const probeDir = existsSync5(path7.join(local, "src")) ? local : path7.join(appDir, "node_modules", ...entry.package.split("/"));
|
|
970
1007
|
const c = descriptor?.contributes;
|
|
1008
|
+
const hasServerEntry = descriptor !== null && probeModuleObjectExport(probeDir, "server", "serverModule");
|
|
971
1009
|
declared.push({
|
|
972
1010
|
id: entry.id,
|
|
973
1011
|
pkg: entry.mode === "sdk" ? entry.package : `@app/${entry.id}`,
|
|
974
1012
|
mode: entry.mode,
|
|
975
|
-
hasServerEntry
|
|
1013
|
+
hasServerEntry,
|
|
976
1014
|
hasClientEntry: descriptor !== null && probeModuleObjectExport(probeDir, "client", "clientModule"),
|
|
977
|
-
hasCards: (c?.cards?.length ?? 0) > 0
|
|
1015
|
+
hasCards: (c?.cards?.length ?? 0) > 0,
|
|
1016
|
+
// 011 评审 M3:declaration.componentId(deployment 对账真源;老模块无 declaration → undefined)
|
|
1017
|
+
...hasServerEntry ? { componentId: extractComponentId(readServerSource(probeDir)) } : {}
|
|
978
1018
|
});
|
|
979
1019
|
}
|
|
980
1020
|
for (const mod of await listLocalModules(appDir)) {
|
|
981
1021
|
if (seen.has(mod.id)) continue;
|
|
982
1022
|
const c = mod.descriptor.contributes;
|
|
1023
|
+
const hasServerEntry = probeModuleObjectExport(mod.dir, "server", "serverModule");
|
|
983
1024
|
declared.push({
|
|
984
1025
|
id: mod.id,
|
|
985
1026
|
pkg: `@app/${mod.id}`,
|
|
986
1027
|
mode: "local",
|
|
987
|
-
hasServerEntry
|
|
1028
|
+
hasServerEntry,
|
|
988
1029
|
hasClientEntry: probeModuleObjectExport(mod.dir, "client", "clientModule"),
|
|
989
|
-
hasCards: (c.cards?.length ?? 0) > 0
|
|
1030
|
+
hasCards: (c.cards?.length ?? 0) > 0,
|
|
1031
|
+
// 011 评审 M3:declaration.componentId(同 npmModules 路径)
|
|
1032
|
+
...hasServerEntry ? { componentId: extractComponentId(readServerSource(mod.dir)) } : {}
|
|
990
1033
|
});
|
|
991
1034
|
}
|
|
992
1035
|
return declared;
|
|
@@ -2093,6 +2136,181 @@ function legacyPlatformFilesRule(ctx) {
|
|
|
2093
2136
|
return issues;
|
|
2094
2137
|
}
|
|
2095
2138
|
|
|
2139
|
+
// src/doctor/rules/mall-deployment.ts
|
|
2140
|
+
import { existsSync as existsSync19, readFileSync as readFileSync8 } from "fs";
|
|
2141
|
+
import { readdir as readdir11 } from "fs/promises";
|
|
2142
|
+
import { createRequire as createRequire2 } from "module";
|
|
2143
|
+
import path23 from "path";
|
|
2144
|
+
function resolveModuleRoot(ctx, pkg) {
|
|
2145
|
+
try {
|
|
2146
|
+
const req = createRequire2(path23.join(ctx.appDir, "package.json"));
|
|
2147
|
+
const resolved = req.resolve(`${pkg}/package.json`);
|
|
2148
|
+
return path23.dirname(resolved);
|
|
2149
|
+
} catch {
|
|
2150
|
+
return void 0;
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
function readServerSource2(moduleRoot) {
|
|
2154
|
+
const candidates = [
|
|
2155
|
+
path23.join(moduleRoot, "src/server/index.ts"),
|
|
2156
|
+
path23.join(moduleRoot, "src/server/index.tsx")
|
|
2157
|
+
];
|
|
2158
|
+
for (const c of candidates) {
|
|
2159
|
+
if (existsSync19(c)) return readFileSync8(c, "utf8");
|
|
2160
|
+
}
|
|
2161
|
+
return "";
|
|
2162
|
+
}
|
|
2163
|
+
function extractFeatures(source) {
|
|
2164
|
+
const match = source.match(/features\s*:\s*\[([^\]]*)\]/);
|
|
2165
|
+
if (!match) return [];
|
|
2166
|
+
return [...match[1].matchAll(/['"]([^'"]+)['"]/g)].map((m) => m[1]);
|
|
2167
|
+
}
|
|
2168
|
+
function extractIntentPatterns(source) {
|
|
2169
|
+
const patterns = [];
|
|
2170
|
+
for (const block of source.matchAll(/patterns\s*:\s*\[([^\]]*)\]/g)) {
|
|
2171
|
+
for (const m of block[1].matchAll(/['"]([^'"]+)['"]/g)) {
|
|
2172
|
+
patterns.push(m[1]);
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
return patterns;
|
|
2176
|
+
}
|
|
2177
|
+
function extractFeatureRefs(source) {
|
|
2178
|
+
return [...source.matchAll(/isFeatureEnabled\s*\(\s*['"]([^'"]+)['"]\s*\)/g)].map((m) => m[1]);
|
|
2179
|
+
}
|
|
2180
|
+
async function deploymentConsistencyRule(ctx) {
|
|
2181
|
+
const issues = [];
|
|
2182
|
+
const deploymentDir = path23.join(ctx.appDir, "config/deployments");
|
|
2183
|
+
if (!existsSync19(deploymentDir)) return issues;
|
|
2184
|
+
const entries = await readdir11(deploymentDir);
|
|
2185
|
+
const jsonFiles = entries.filter((e) => e.endsWith(".json"));
|
|
2186
|
+
if (jsonFiles.length === 0) return issues;
|
|
2187
|
+
for (const file of jsonFiles) {
|
|
2188
|
+
let parsed;
|
|
2189
|
+
try {
|
|
2190
|
+
parsed = JSON.parse(readFileSync8(path23.join(deploymentDir, file), "utf8"));
|
|
2191
|
+
} catch {
|
|
2192
|
+
issues.push({ rule: "deployment-consistency", level: "error", message: `deployment \u914D\u7F6E\u975E\u6CD5 JSON\uFF1Aconfig/deployments/${file}` });
|
|
2193
|
+
continue;
|
|
2194
|
+
}
|
|
2195
|
+
const components = parsed.deployment?.components ?? [];
|
|
2196
|
+
const declaredPkgs = new Map(ctx.declared.map((d) => [d.componentId ?? d.id, d]));
|
|
2197
|
+
for (const component of components) {
|
|
2198
|
+
const componentId = component.componentId;
|
|
2199
|
+
if (!componentId) {
|
|
2200
|
+
issues.push({
|
|
2201
|
+
rule: "deployment-consistency",
|
|
2202
|
+
level: "error",
|
|
2203
|
+
message: `config/deployments/${file}\uFF1Acomponents \u9879\u7F3A componentId`
|
|
2204
|
+
});
|
|
2205
|
+
continue;
|
|
2206
|
+
}
|
|
2207
|
+
const declared = declaredPkgs.get(componentId);
|
|
2208
|
+
if (!declared) {
|
|
2209
|
+
issues.push({
|
|
2210
|
+
rule: "deployment-consistency",
|
|
2211
|
+
level: component.optional ? "warning" : "error",
|
|
2212
|
+
message: `config/deployments/${file}\uFF1AcomponentId "${componentId}" \u672A\u5B89\u88C5\u5BF9\u5E94\u6A21\u5757` + (component.optional ? "\uFF08optional \u7EC4\u4EF6\uFF0C\u964D\u7EA7 warning\uFF09" : "\uFF08\u5B89\u88C5\u5BF9\u5E94\u6A21\u5757\u6216\u6807\u8BB0 optional\uFF09")
|
|
2213
|
+
});
|
|
2214
|
+
continue;
|
|
2215
|
+
}
|
|
2216
|
+
const moduleRoot = resolveModuleRoot(ctx, declared.pkg);
|
|
2217
|
+
if (moduleRoot && component.enabledFeatures?.length) {
|
|
2218
|
+
const source = readServerSource2(moduleRoot);
|
|
2219
|
+
const declaredFeatures = extractFeatures(source);
|
|
2220
|
+
if (declaredFeatures.length > 0) {
|
|
2221
|
+
for (const feature of component.enabledFeatures) {
|
|
2222
|
+
if (!declaredFeatures.includes(feature)) {
|
|
2223
|
+
issues.push({
|
|
2224
|
+
rule: "deployment-consistency",
|
|
2225
|
+
level: "error",
|
|
2226
|
+
message: `config/deployments/${file}\uFF1Afeature "${feature}" \u4E0D\u5728 ${componentId} \u7684 declaration.features \u5185\uFF08\u5DF2\u58F0\u660E\uFF1A${declaredFeatures.join(", ") || "(\u65E0)"}\uFF09`
|
|
2227
|
+
});
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
return issues;
|
|
2235
|
+
}
|
|
2236
|
+
async function intentOverlapRule(ctx) {
|
|
2237
|
+
const issues = [];
|
|
2238
|
+
const byPattern = /* @__PURE__ */ new Map();
|
|
2239
|
+
for (const declared of ctx.declared) {
|
|
2240
|
+
if (!declared.hasServerEntry) continue;
|
|
2241
|
+
const root = resolveModuleRoot(ctx, declared.pkg);
|
|
2242
|
+
if (!root) continue;
|
|
2243
|
+
const patterns = extractIntentPatterns(readServerSource2(root));
|
|
2244
|
+
for (const p of patterns) {
|
|
2245
|
+
const list = byPattern.get(p) ?? [];
|
|
2246
|
+
list.push(declared.id);
|
|
2247
|
+
byPattern.set(p, list);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
for (const [pattern, modules] of byPattern) {
|
|
2251
|
+
if (modules.length > 1) {
|
|
2252
|
+
issues.push({
|
|
2253
|
+
rule: "intent-overlap",
|
|
2254
|
+
level: "warning",
|
|
2255
|
+
message: `\u610F\u56FE\u8BCD "${pattern}" \u5728\u591A\u4E2A\u6A21\u5757\u58F0\u660E\uFF08${modules.join(", ")}\uFF09\u2014\u2014\u5148\u6CE8\u518C\u5148\u547D\u4E2D`
|
|
2256
|
+
});
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
return issues;
|
|
2260
|
+
}
|
|
2261
|
+
async function skillNameConflictRule(ctx) {
|
|
2262
|
+
const issues = [];
|
|
2263
|
+
const byName = /* @__PURE__ */ new Map();
|
|
2264
|
+
for (const declared of ctx.declared) {
|
|
2265
|
+
if (!declared.hasServerEntry) continue;
|
|
2266
|
+
const root = resolveModuleRoot(ctx, declared.pkg);
|
|
2267
|
+
if (!root) continue;
|
|
2268
|
+
const skillsDir = path23.join(root, "skills");
|
|
2269
|
+
if (!existsSync19(skillsDir)) continue;
|
|
2270
|
+
try {
|
|
2271
|
+
const names = (await readdir11(skillsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
2272
|
+
for (const name of names) {
|
|
2273
|
+
const list = byName.get(name) ?? [];
|
|
2274
|
+
list.push(declared.id);
|
|
2275
|
+
byName.set(name, list);
|
|
2276
|
+
}
|
|
2277
|
+
} catch {
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
for (const [name, modules] of byName) {
|
|
2281
|
+
if (modules.length > 1) {
|
|
2282
|
+
issues.push({
|
|
2283
|
+
rule: "skill-name-conflict",
|
|
2284
|
+
level: "warning",
|
|
2285
|
+
message: `skill "${name}" \u5728\u591A\u4E2A\u6A21\u5757\u58F0\u660E\uFF08${modules.join(", ")}\uFF09\u2014\u2014\u540E\u6CE8\u518C\u8986\u76D6`
|
|
2286
|
+
});
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
return issues;
|
|
2290
|
+
}
|
|
2291
|
+
async function featureDeclarationRule(ctx) {
|
|
2292
|
+
const issues = [];
|
|
2293
|
+
for (const declared of ctx.declared) {
|
|
2294
|
+
if (!declared.hasServerEntry) continue;
|
|
2295
|
+
const root = resolveModuleRoot(ctx, declared.pkg);
|
|
2296
|
+
if (!root) continue;
|
|
2297
|
+
const source = readServerSource2(root);
|
|
2298
|
+
if (!source) continue;
|
|
2299
|
+
const declaredFeatures = extractFeatures(source);
|
|
2300
|
+
const refs = extractFeatureRefs(source);
|
|
2301
|
+
for (const ref of refs) {
|
|
2302
|
+
if (declaredFeatures.length > 0 && !declaredFeatures.includes(ref)) {
|
|
2303
|
+
issues.push({
|
|
2304
|
+
rule: "feature-declaration",
|
|
2305
|
+
level: "error",
|
|
2306
|
+
message: `\u6A21\u5757 ${declared.id}\uFF1AisFeatureEnabled("${ref}") \u4E0D\u5728 declaration.features \u5185\uFF08\u5DF2\u58F0\u660E\uFF1A${declaredFeatures.join(", ") || "(\u65E0)"}\uFF09`
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
return issues;
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2096
2314
|
// src/doctor/index.ts
|
|
2097
2315
|
var DOCTOR_RULES = [
|
|
2098
2316
|
{ name: "workspace-dag", run: workspaceDagRule },
|
|
@@ -2108,7 +2326,11 @@ var DOCTOR_RULES = [
|
|
|
2108
2326
|
{ name: "naked-write-route", run: nakedWriteRouteRule },
|
|
2109
2327
|
{ name: "descriptor-schema", run: descriptorSchemaRule },
|
|
2110
2328
|
{ name: "workspace-ref-resolved", run: workspaceRefResolvedRule },
|
|
2111
|
-
{ name: "legacy-platform-files", run: legacyPlatformFilesRule }
|
|
2329
|
+
{ name: "legacy-platform-files", run: legacyPlatformFilesRule },
|
|
2330
|
+
{ name: "deployment-consistency", run: deploymentConsistencyRule },
|
|
2331
|
+
{ name: "intent-overlap", run: intentOverlapRule },
|
|
2332
|
+
{ name: "skill-name-conflict", run: skillNameConflictRule },
|
|
2333
|
+
{ name: "feature-declaration", run: featureDeclarationRule }
|
|
2112
2334
|
];
|
|
2113
2335
|
async function runDoctor(ctx, opts) {
|
|
2114
2336
|
const issues = [];
|
|
@@ -2244,10 +2466,10 @@ async function resolveDependencies(appDir, rootIds, declared, extraRoots = []) {
|
|
|
2244
2466
|
|
|
2245
2467
|
// src/commands/add.ts
|
|
2246
2468
|
function readSourceDescriptor(sourceDir) {
|
|
2247
|
-
const file =
|
|
2248
|
-
if (!
|
|
2469
|
+
const file = path24.join(sourceDir, "tbox.component.json");
|
|
2470
|
+
if (!existsSync20(file)) return null;
|
|
2249
2471
|
try {
|
|
2250
|
-
const parsed = parseComponentDescriptor(JSON.parse(
|
|
2472
|
+
const parsed = parseComponentDescriptor(JSON.parse(readFileSync9(file, "utf8")));
|
|
2251
2473
|
return parsed.ok ? parsed.value : null;
|
|
2252
2474
|
} catch {
|
|
2253
2475
|
return null;
|
|
@@ -2255,20 +2477,20 @@ function readSourceDescriptor(sourceDir) {
|
|
|
2255
2477
|
}
|
|
2256
2478
|
function resolveDepSource(sourcePath, depId) {
|
|
2257
2479
|
if (!sourcePath) return null;
|
|
2258
|
-
const dir =
|
|
2259
|
-
const siblingDir =
|
|
2260
|
-
if (
|
|
2480
|
+
const dir = path24.dirname(sourcePath);
|
|
2481
|
+
const siblingDir = path24.join(dir, depId);
|
|
2482
|
+
if (existsSync20(path24.join(siblingDir, "package.json"))) return siblingDir;
|
|
2261
2483
|
try {
|
|
2262
2484
|
const tgz = readdirSync2(dir).find(
|
|
2263
2485
|
(f) => f.endsWith(".tgz") && f.includes(`-${depId}-`)
|
|
2264
2486
|
);
|
|
2265
|
-
if (tgz) return
|
|
2487
|
+
if (tgz) return path24.join(dir, tgz);
|
|
2266
2488
|
} catch {
|
|
2267
2489
|
}
|
|
2268
2490
|
return null;
|
|
2269
2491
|
}
|
|
2270
2492
|
function isInstalled(appDir, id) {
|
|
2271
|
-
if (
|
|
2493
|
+
if (existsSync20(path24.join(appDir, "packages", id))) return true;
|
|
2272
2494
|
const manifest = readAppManifest(appDir);
|
|
2273
2495
|
return manifest?.npmModules.some((m) => m.id === id && m.mode === "sdk") ?? false;
|
|
2274
2496
|
}
|
|
@@ -2296,7 +2518,7 @@ async function addModuleWithDepsCore(opts, visited, asDependency, tarballs) {
|
|
|
2296
2518
|
assertValidModuleId(id, `--mode local ${opts.pkg}`);
|
|
2297
2519
|
} else {
|
|
2298
2520
|
if (!opts.source) throw new Error(`--mode ${opts.mode} \u9700\u8981 --source <\u76EE\u5F55\u6216 tgz \u6216 registry \u5305>`);
|
|
2299
|
-
const isRegSource = isReg && !
|
|
2521
|
+
const isRegSource = isReg && !existsSync20(path24.resolve(opts.source));
|
|
2300
2522
|
if (!isRegSource && !opts.source.endsWith(".tgz") && !LocalDirSource.isUsable(opts.source)) {
|
|
2301
2523
|
throw new Error(`\u6A21\u5757\u6E90\u65E0\u6548\uFF08\u7F3A package.json\uFF09: ${opts.source}`);
|
|
2302
2524
|
}
|
|
@@ -2305,7 +2527,7 @@ async function addModuleWithDepsCore(opts, visited, asDependency, tarballs) {
|
|
|
2305
2527
|
tarballs.push(opened.source);
|
|
2306
2528
|
}
|
|
2307
2529
|
const pkgOnly = opts.pkg.replace(/@[^/]+$/, "");
|
|
2308
|
-
id = pkgOnly
|
|
2530
|
+
id = deriveModuleId(pkgOnly);
|
|
2309
2531
|
assertValidModuleId(id, `--mode ${opts.mode} ${opts.pkg}`);
|
|
2310
2532
|
sourceDescriptor = readSourceDescriptor(opened.sourceDir);
|
|
2311
2533
|
}
|
|
@@ -2314,7 +2536,7 @@ async function addModuleWithDepsCore(opts, visited, asDependency, tarballs) {
|
|
|
2314
2536
|
return;
|
|
2315
2537
|
}
|
|
2316
2538
|
if (!asDependency && isInstalled(appDir, id)) {
|
|
2317
|
-
const where =
|
|
2539
|
+
const where = existsSync20(path24.join(appDir, "packages", id)) ? `packages/${id}` : "manifest \u5DF2\u767B\u8BB0\uFF08sdk \u5305\uFF0C\u65E0\u672C\u5730\u76EE\u5F55\uFF09";
|
|
2318
2540
|
throw new Error(`\u6A21\u5757 ${id} \u5DF2\u5B58\u5728\uFF08${where}\uFF09\u3002\u82E5\u8981\u91CD\u65B0\u5C55\u5F00\u8BF7\u5148 remove \u6216\u624B\u52A8\u5904\u7406\uFF1B\u88C5\u914D\u552F\u4E00\u8986\u76D6\u5165\u53E3\u4E3A sync --force`);
|
|
2319
2541
|
}
|
|
2320
2542
|
if (visited.has(id)) return;
|
|
@@ -2345,7 +2567,7 @@ async function addModuleWithDepsCore(opts, visited, asDependency, tarballs) {
|
|
|
2345
2567
|
if (depOpened.source instanceof TarballSource || depOpened.source instanceof RegistrySource) {
|
|
2346
2568
|
tarballs.push(depOpened.source);
|
|
2347
2569
|
}
|
|
2348
|
-
const depIsBusiness =
|
|
2570
|
+
const depIsBusiness = existsSync20(path24.join(depOpened.sourceDir, "tbox.component.json"));
|
|
2349
2571
|
await addModuleWithDeps(
|
|
2350
2572
|
{ pkg: depPkg, mode: depIsBusiness ? "codegen" : "sdk", source: depSource, registry: opts.registry },
|
|
2351
2573
|
visited,
|
|
@@ -2558,9 +2780,9 @@ async function doctorCommand(opts = {}) {
|
|
|
2558
2780
|
}
|
|
2559
2781
|
|
|
2560
2782
|
// src/commands/update.ts
|
|
2561
|
-
import { existsSync as
|
|
2562
|
-
import { readdir as
|
|
2563
|
-
import
|
|
2783
|
+
import { existsSync as existsSync21 } from "fs";
|
|
2784
|
+
import { readdir as readdir12, readFile as readFile6, unlink, writeFile as writeFile7 } from "fs/promises";
|
|
2785
|
+
import path25 from "path";
|
|
2564
2786
|
|
|
2565
2787
|
// src/merge3.ts
|
|
2566
2788
|
import { diffArrays } from "diff";
|
|
@@ -2643,21 +2865,21 @@ function merge3(base, ours, theirs) {
|
|
|
2643
2865
|
// src/commands/update.ts
|
|
2644
2866
|
var EXCLUDED = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", ".tbox"]);
|
|
2645
2867
|
function openSourceDir(source) {
|
|
2646
|
-
if (source.endsWith(".tgz") &&
|
|
2868
|
+
if (source.endsWith(".tgz") && existsSync21(source)) {
|
|
2647
2869
|
const tarball = new TarballSource(source);
|
|
2648
2870
|
return { dir: tarball.getDir(), tarball };
|
|
2649
2871
|
}
|
|
2650
|
-
return { dir:
|
|
2872
|
+
return { dir: path25.resolve(source), tarball: null };
|
|
2651
2873
|
}
|
|
2652
2874
|
async function readPackageFiles(dir) {
|
|
2653
2875
|
const map = /* @__PURE__ */ new Map();
|
|
2654
2876
|
async function walk(rel) {
|
|
2655
|
-
const full =
|
|
2656
|
-
const entries = await
|
|
2877
|
+
const full = path25.join(dir, rel);
|
|
2878
|
+
const entries = await readdir12(full, { withFileTypes: true });
|
|
2657
2879
|
for (const entry of entries) {
|
|
2658
2880
|
if (EXCLUDED.has(entry.name)) continue;
|
|
2659
2881
|
const child = rel ? `${rel}/${entry.name}` : entry.name;
|
|
2660
|
-
const childFull =
|
|
2882
|
+
const childFull = path25.join(full, entry.name);
|
|
2661
2883
|
if (entry.isDirectory()) {
|
|
2662
2884
|
await walk(child);
|
|
2663
2885
|
} else {
|
|
@@ -2687,8 +2909,8 @@ async function updateModule(opts) {
|
|
|
2687
2909
|
console.log(`\u2705 \u5DF2\u5347\u7EA7 ${entry.package}\uFF08sdk \u6A21\u5F0F\uFF09`);
|
|
2688
2910
|
return;
|
|
2689
2911
|
}
|
|
2690
|
-
const pkgDir =
|
|
2691
|
-
if (!
|
|
2912
|
+
const pkgDir = path25.join(appDir, "packages", opts.module);
|
|
2913
|
+
if (!existsSync21(pkgDir)) throw new Error(`\u7F3A\u5C11 packages/${opts.module}`);
|
|
2692
2914
|
const ours = await readPackageFiles(pkgDir);
|
|
2693
2915
|
const tarballs = [];
|
|
2694
2916
|
try {
|
|
@@ -2735,8 +2957,8 @@ async function updateModule(opts) {
|
|
|
2735
2957
|
return;
|
|
2736
2958
|
}
|
|
2737
2959
|
for (const [key, content] of mergedFiles) {
|
|
2738
|
-
const out =
|
|
2739
|
-
if (content === "" &&
|
|
2960
|
+
const out = path25.join(pkgDir, key);
|
|
2961
|
+
if (content === "" && existsSync21(out)) {
|
|
2740
2962
|
await unlink(out);
|
|
2741
2963
|
console.log(` \u{1F5D1} \u5DF2\u5220\u9664 ${key}\uFF08\u5347\u7EA7\u6E90\u5220\u9664\u8BE5\u6587\u4EF6\uFF09`);
|
|
2742
2964
|
continue;
|
|
@@ -2765,27 +2987,27 @@ async function updateModule(opts) {
|
|
|
2765
2987
|
}
|
|
2766
2988
|
|
|
2767
2989
|
// src/commands/publish.ts
|
|
2768
|
-
import { existsSync as
|
|
2990
|
+
import { existsSync as existsSync23, readFileSync as readFileSync11, mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "fs";
|
|
2769
2991
|
import { tmpdir as tmpdir2 } from "os";
|
|
2770
|
-
import
|
|
2992
|
+
import path27 from "path";
|
|
2771
2993
|
|
|
2772
2994
|
// src/commands/pack.ts
|
|
2773
|
-
import { existsSync as
|
|
2995
|
+
import { existsSync as existsSync22, readFileSync as readFileSync10, readdirSync as readdirSync3 } from "fs";
|
|
2774
2996
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
2775
|
-
import
|
|
2997
|
+
import path26 from "path";
|
|
2776
2998
|
function tarballFileName(name, version) {
|
|
2777
2999
|
const plain = name.replace(/^@/, "").replace("/", "-");
|
|
2778
3000
|
return `${plain}-${version}.tgz`;
|
|
2779
3001
|
}
|
|
2780
3002
|
function validatePublishableModule(moduleDir) {
|
|
2781
|
-
if (!
|
|
3003
|
+
if (!existsSync22(moduleDir) || !existsSync22(path26.join(moduleDir, "package.json"))) {
|
|
2782
3004
|
throw new Error(`\u6A21\u5757\u76EE\u5F55\u65E0\u6548\uFF08\u7F3A package.json\uFF09: ${moduleDir}`);
|
|
2783
3005
|
}
|
|
2784
3006
|
let pkg;
|
|
2785
3007
|
try {
|
|
2786
|
-
pkg = JSON.parse(
|
|
3008
|
+
pkg = JSON.parse(readFileSync10(path26.join(moduleDir, "package.json"), "utf8"));
|
|
2787
3009
|
} catch {
|
|
2788
|
-
throw new Error(`package.json \u89E3\u6790\u5931\u8D25: ${
|
|
3010
|
+
throw new Error(`package.json \u89E3\u6790\u5931\u8D25: ${path26.join(moduleDir, "package.json")}`);
|
|
2789
3011
|
}
|
|
2790
3012
|
const name = typeof pkg.name === "string" ? pkg.name : "";
|
|
2791
3013
|
if (!/^@tbox\.cn\//.test(name)) {
|
|
@@ -2799,20 +3021,20 @@ function validatePublishableModule(moduleDir) {
|
|
|
2799
3021
|
}
|
|
2800
3022
|
function packModule(moduleDir, outDir) {
|
|
2801
3023
|
const { name, version } = validatePublishableModule(moduleDir);
|
|
2802
|
-
const absOut =
|
|
3024
|
+
const absOut = path26.resolve(outDir);
|
|
2803
3025
|
execFileSync3("pnpm", ["pack", "--pack-destination", absOut], { stdio: "inherit", cwd: moduleDir });
|
|
2804
|
-
return
|
|
3026
|
+
return path26.join(absOut, tarballFileName(name, version));
|
|
2805
3027
|
}
|
|
2806
3028
|
function detectKind(pkgDir, name) {
|
|
2807
|
-
if (
|
|
2808
|
-
if (
|
|
3029
|
+
if (existsSync22(path26.join(pkgDir, "pnpm-workspace.template.yaml"))) return "template";
|
|
3030
|
+
if (existsSync22(path26.join(pkgDir, "tbox.component.json"))) return "module";
|
|
2809
3031
|
if (/^@[^/]+\/app-contracts/.test(name)) return "contract";
|
|
2810
3032
|
return "generic";
|
|
2811
3033
|
}
|
|
2812
3034
|
function listAllFiles(dir) {
|
|
2813
3035
|
const out = [];
|
|
2814
3036
|
function walk(rel) {
|
|
2815
|
-
const full =
|
|
3037
|
+
const full = path26.join(dir, rel);
|
|
2816
3038
|
for (const entry of readdirSync3(full, { withFileTypes: true })) {
|
|
2817
3039
|
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
2818
3040
|
const child = rel ? `${rel}/${entry.name}` : entry.name;
|
|
@@ -2841,10 +3063,10 @@ function collectExportTargets(exports) {
|
|
|
2841
3063
|
}
|
|
2842
3064
|
function verifyPkgDir(pkgDir, kind) {
|
|
2843
3065
|
const issues = [];
|
|
2844
|
-
const pkgFile =
|
|
3066
|
+
const pkgFile = path26.join(pkgDir, "package.json");
|
|
2845
3067
|
let pkg;
|
|
2846
3068
|
try {
|
|
2847
|
-
pkg = JSON.parse(
|
|
3069
|
+
pkg = JSON.parse(readFileSync10(pkgFile, "utf8"));
|
|
2848
3070
|
} catch {
|
|
2849
3071
|
issues.push({ rule: "pack-manifest", level: "error", message: "\u4EA7\u7269\u7F3A\u5C11\u53EF\u89E3\u6790\u7684 package.json" });
|
|
2850
3072
|
return issues;
|
|
@@ -2872,7 +3094,7 @@ function verifyPkgDir(pkgDir, kind) {
|
|
|
2872
3094
|
level: "error",
|
|
2873
3095
|
message: `exports \u6307\u5411\u5F00\u53D1\u6001\u6E90\u7801 "${t}"\uFF08\u53D1\u5E03\u6001\u5E94\u6307\u5411 dist/\uFF09`
|
|
2874
3096
|
});
|
|
2875
|
-
} else if (t.startsWith("./") && !
|
|
3097
|
+
} else if (t.startsWith("./") && !existsSync22(path26.join(pkgDir, t))) {
|
|
2876
3098
|
issues.push({
|
|
2877
3099
|
rule: "pack-exports",
|
|
2878
3100
|
level: "error",
|
|
@@ -2905,7 +3127,7 @@ function verifyPkgDir(pkgDir, kind) {
|
|
|
2905
3127
|
}
|
|
2906
3128
|
if (kindOf === "module") {
|
|
2907
3129
|
for (const required of ["src", "dist", "tbox.component.json"]) {
|
|
2908
|
-
if (!files.includes(required) && !
|
|
3130
|
+
if (!files.includes(required) && !existsSync22(path26.join(pkgDir, required))) {
|
|
2909
3131
|
issues.push({ rule: "pack-files", level: "error", message: `\u4E1A\u52A1\u6A21\u5757\u4EA7\u7269\u7F3A\u5C11 ${required}` });
|
|
2910
3132
|
}
|
|
2911
3133
|
}
|
|
@@ -2919,12 +3141,12 @@ function verifyPkgDir(pkgDir, kind) {
|
|
|
2919
3141
|
"tsconfig.base.json",
|
|
2920
3142
|
"scripts/verify-generated.mjs"
|
|
2921
3143
|
]) {
|
|
2922
|
-
if (!
|
|
3144
|
+
if (!existsSync22(path26.join(pkgDir, required))) {
|
|
2923
3145
|
issues.push({ rule: "pack-files", level: "error", message: `\u6A21\u677F\u4EA7\u7269\u7F3A\u5C11 ${required}` });
|
|
2924
3146
|
}
|
|
2925
3147
|
}
|
|
2926
3148
|
for (const leaked2 of ["pnpm-workspace.yaml", "pnpm-lock.yaml"]) {
|
|
2927
|
-
if (
|
|
3149
|
+
if (existsSync22(path26.join(pkgDir, leaked2))) {
|
|
2928
3150
|
issues.push({
|
|
2929
3151
|
rule: "pack-files",
|
|
2930
3152
|
level: "error",
|
|
@@ -2967,11 +3189,11 @@ async function verifyTarball(tgzPath) {
|
|
|
2967
3189
|
const issues = verifyPkgDir(pkgDir, kind);
|
|
2968
3190
|
if (pkg.name && pkg.version) {
|
|
2969
3191
|
const expect = tarballFileName(pkg.name, pkg.version);
|
|
2970
|
-
if (
|
|
3192
|
+
if (path26.basename(tgzPath) !== expect) {
|
|
2971
3193
|
issues.push({
|
|
2972
3194
|
rule: "pack-filename",
|
|
2973
3195
|
level: "error",
|
|
2974
|
-
message: `tgz \u6587\u4EF6\u540D ${
|
|
3196
|
+
message: `tgz \u6587\u4EF6\u540D ${path26.basename(tgzPath)} \u4E0E\u5305 ${pkg.name}@${pkg.version} \u671F\u671B ${expect} \u4E0D\u4E00\u81F4`
|
|
2975
3197
|
});
|
|
2976
3198
|
}
|
|
2977
3199
|
}
|
|
@@ -2986,9 +3208,9 @@ function printIssues(issues) {
|
|
|
2986
3208
|
}
|
|
2987
3209
|
}
|
|
2988
3210
|
async function packCommand(opts) {
|
|
2989
|
-
const moduleDir =
|
|
3211
|
+
const moduleDir = path26.resolve(process.cwd(), opts.module);
|
|
2990
3212
|
const tgzPath = packModule(moduleDir, opts.out);
|
|
2991
|
-
console.log(`\u2705 \u5DF2\u6253\u5305 ${
|
|
3213
|
+
console.log(`\u2705 \u5DF2\u6253\u5305 ${path26.basename(tgzPath)} \u2192 ${path26.resolve(opts.out)}`);
|
|
2992
3214
|
if (opts.check) {
|
|
2993
3215
|
const issues = await verifyTarball(tgzPath);
|
|
2994
3216
|
printIssues(issues);
|
|
@@ -2999,19 +3221,19 @@ async function packCommand(opts) {
|
|
|
2999
3221
|
// src/commands/publish.ts
|
|
3000
3222
|
async function publishModule(opts) {
|
|
3001
3223
|
const cwd = process.cwd();
|
|
3002
|
-
const moduleDir =
|
|
3003
|
-
if (!
|
|
3224
|
+
const moduleDir = path27.resolve(cwd, opts.module);
|
|
3225
|
+
if (!existsSync23(moduleDir) || !existsSync23(path27.join(moduleDir, "package.json"))) {
|
|
3004
3226
|
throw new Error(`\u6A21\u5757\u76EE\u5F55\u65E0\u6548\uFF08\u7F3A package.json\uFF09: ${opts.module}`);
|
|
3005
3227
|
}
|
|
3006
3228
|
let tgzPath;
|
|
3007
3229
|
let workDir = null;
|
|
3008
3230
|
if (opts.tgz) {
|
|
3009
|
-
tgzPath =
|
|
3010
|
-
if (!
|
|
3231
|
+
tgzPath = path27.resolve(opts.tgz);
|
|
3232
|
+
if (!existsSync23(tgzPath)) throw new Error(`tgz \u4EA7\u7269\u4E0D\u5B58\u5728: ${opts.tgz}`);
|
|
3011
3233
|
const tarball = new TarballSource(tgzPath);
|
|
3012
3234
|
try {
|
|
3013
3235
|
const tgzPkg = JSON.parse(await tarball.readFile("package.json"));
|
|
3014
|
-
const modulePkg = JSON.parse(
|
|
3236
|
+
const modulePkg = JSON.parse(readFileSync11(path27.join(moduleDir, "package.json"), "utf8"));
|
|
3015
3237
|
if (tgzPkg.name !== modulePkg.name) {
|
|
3016
3238
|
throw new Error(
|
|
3017
3239
|
`--tgz \u5305\u540D ${tgzPkg.name ?? "(\u672A\u77E5)"} \u4E0E\u6A21\u5757 ${modulePkg.name ?? "(\u672A\u77E5)"} \u4E0D\u4E00\u81F4\uFF08\u8BF7\u786E\u8BA4 --tgz \u4E0E\u6A21\u5757\u5339\u914D\uFF09`
|
|
@@ -3021,7 +3243,7 @@ async function publishModule(opts) {
|
|
|
3021
3243
|
tarball.dispose();
|
|
3022
3244
|
}
|
|
3023
3245
|
} else {
|
|
3024
|
-
workDir = mkdtempSync2(
|
|
3246
|
+
workDir = mkdtempSync2(path27.join(tmpdir2(), "tbox-publish-"));
|
|
3025
3247
|
tgzPath = packModule(moduleDir, workDir);
|
|
3026
3248
|
}
|
|
3027
3249
|
try {
|
|
@@ -3029,9 +3251,9 @@ async function publishModule(opts) {
|
|
|
3029
3251
|
if (issues.length > 0) printIssues(issues);
|
|
3030
3252
|
const errors = issues.filter((i) => i.level === "error");
|
|
3031
3253
|
if (errors.length > 0) {
|
|
3032
|
-
throw new Error(`\u4EA7\u7269\u95E8\u7981\u5931\u8D25\uFF08${errors.length} \u5904 error\uFF09\uFF0C\u5DF2\u4E2D\u6B62\u53D1\u5E03: ${
|
|
3254
|
+
throw new Error(`\u4EA7\u7269\u95E8\u7981\u5931\u8D25\uFF08${errors.length} \u5904 error\uFF09\uFF0C\u5DF2\u4E2D\u6B62\u53D1\u5E03: ${path27.basename(tgzPath)}`);
|
|
3033
3255
|
}
|
|
3034
|
-
if (!workDir) workDir = mkdtempSync2(
|
|
3256
|
+
if (!workDir) workDir = mkdtempSync2(path27.join(tmpdir2(), "tbox-publish-"));
|
|
3035
3257
|
const { execFileSync: execFileSync4 } = await import("child_process");
|
|
3036
3258
|
const registryArgs = opts.registry ? ["--registry", opts.registry] : [];
|
|
3037
3259
|
execFileSync4(
|
|
@@ -3040,7 +3262,7 @@ async function publishModule(opts) {
|
|
|
3040
3262
|
{ stdio: "inherit", cwd: workDir }
|
|
3041
3263
|
);
|
|
3042
3264
|
console.log(
|
|
3043
|
-
`\u2705 \u5DF2\u53D1\u5E03 ${
|
|
3265
|
+
`\u2705 \u5DF2\u53D1\u5E03 ${path27.basename(tgzPath)}${opts.registry ? ` \u2192 ${opts.registry}` : ""}${opts.dryRun ? "\uFF08dry-run\uFF09" : ""}`
|
|
3044
3266
|
);
|
|
3045
3267
|
} finally {
|
|
3046
3268
|
if (workDir) {
|