@wneng/create-keel 0.2.1 → 0.3.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/README.md +26 -1
- package/dist/index.js +612 -40
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/standards/templates/coding-style-dart.md.eta +49 -0
- package/src/standards/templates/coding-style-go.md.eta +52 -0
- package/src/standards/templates/coding-style-java.md.eta +50 -0
- package/src/standards/templates/coding-style-python.md.eta +51 -0
- package/src/standards/templates/coding-style-rust.md.eta +52 -0
- package/src/standards/templates/coding-style-typescript.md.eta +50 -0
- package/src/standards/templates/dependency-cruiser.config.cjs.eta +57 -0
- package/src/standards/templates/design-tokens.ts.eta +37 -0
- package/src/standards/templates/module-boundaries.md.eta +82 -0
- package/src/standards/templates/tech-stack-agent.md.eta +35 -0
- package/src/standards/templates/tech-stack-miniapp.md.eta +34 -0
- package/src/standards/templates/tech-stack-mobile.md.eta +36 -0
- package/src/standards/templates/tech-stack-server.md.eta +50 -0
- package/src/standards/templates/tech-stack-web.md.eta +36 -0
- package/src/standards/templates/ui-design-system.md.eta +70 -0
- package/src/templates/ci-gitee/files/PULL_REQUEST_TEMPLATE.md +62 -0
- package/src/templates/ci-gitee/fragment.yaml +4 -1
- package/src/templates/ci-github/files/PULL_REQUEST_TEMPLATE.md +62 -0
- package/src/templates/ci-github/fragment.yaml +4 -1
- package/src/templates/docs-skeleton/files/README.md +3 -3
- package/src/templates/docs-skeleton/files/governance-checklists.md +3 -3
- package/src/templates/docs-skeleton/files/governance-security.md +6 -2
- package/src/templates/docs-skeleton/files/usage-quickstart.md +11 -0
- package/src/templates/root-files/files/CODEOWNERS +40 -0
- package/src/templates/root-files/fragment.yaml +3 -0
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/version.ts
|
|
4
|
-
var SCAFFOLDER_VERSION = "0.2
|
|
4
|
+
var SCAFFOLDER_VERSION = "0.3.2";
|
|
5
5
|
|
|
6
6
|
// src/schema/options.ts
|
|
7
7
|
import Ajv from "ajv";
|
|
@@ -34,7 +34,8 @@ var OPTIONS_FIELD_ORDER = [
|
|
|
34
34
|
"gitLfs",
|
|
35
35
|
"integrations",
|
|
36
36
|
"ci",
|
|
37
|
-
"roles"
|
|
37
|
+
"roles",
|
|
38
|
+
"multiApp"
|
|
38
39
|
];
|
|
39
40
|
var OPTIONS_SCHEMA = {
|
|
40
41
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
@@ -56,7 +57,8 @@ var OPTIONS_SCHEMA = {
|
|
|
56
57
|
"gitLfs",
|
|
57
58
|
"integrations",
|
|
58
59
|
"ci",
|
|
59
|
-
"roles"
|
|
60
|
+
"roles",
|
|
61
|
+
"multiApp"
|
|
60
62
|
],
|
|
61
63
|
properties: {
|
|
62
64
|
projectName: {
|
|
@@ -79,7 +81,8 @@ var OPTIONS_SCHEMA = {
|
|
|
79
81
|
type: "array",
|
|
80
82
|
items: { type: "string", enum: [...ROLE_KINDS] },
|
|
81
83
|
uniqueItems: true
|
|
82
|
-
}
|
|
84
|
+
},
|
|
85
|
+
multiApp: { type: "boolean" }
|
|
83
86
|
}
|
|
84
87
|
};
|
|
85
88
|
var ajv = new Ajv({ allErrors: true, strict: true });
|
|
@@ -334,6 +337,27 @@ function parseLayerArg(raw) {
|
|
|
334
337
|
return out;
|
|
335
338
|
}
|
|
336
339
|
|
|
340
|
+
// src/standards/tier.ts
|
|
341
|
+
var ADOPTION_TIERS = ["lite", "standard", "full"];
|
|
342
|
+
function isAdoptionTier(value) {
|
|
343
|
+
return ADOPTION_TIERS.includes(value);
|
|
344
|
+
}
|
|
345
|
+
function parseTier(input) {
|
|
346
|
+
if (typeof input !== "string" || input.length === 0) {
|
|
347
|
+
throw new UserInputError(
|
|
348
|
+
`invalid --engineering-standards value: ${JSON.stringify(input)}`,
|
|
349
|
+
`\u53EF\u9009\u503C\uFF1A${ADOPTION_TIERS.join(" | ")}`
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
if (!isAdoptionTier(input)) {
|
|
353
|
+
throw new UserInputError(
|
|
354
|
+
`invalid --engineering-standards value: ${JSON.stringify(input)}`,
|
|
355
|
+
`\u53EF\u9009\u503C\uFF1A${ADOPTION_TIERS.join(" | ")}`
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
return input;
|
|
359
|
+
}
|
|
360
|
+
|
|
337
361
|
// src/cli.ts
|
|
338
362
|
async function run(io) {
|
|
339
363
|
const args = io.argv.slice(2);
|
|
@@ -387,6 +411,35 @@ function parseCreateArgs(args) {
|
|
|
387
411
|
let ci;
|
|
388
412
|
let roles;
|
|
389
413
|
let sampleFeature = false;
|
|
414
|
+
let engineeringStandards;
|
|
415
|
+
let engineeringStandardsExplicit = false;
|
|
416
|
+
let multiApp = false;
|
|
417
|
+
let backend;
|
|
418
|
+
let frontend;
|
|
419
|
+
let mobile;
|
|
420
|
+
let miniapp;
|
|
421
|
+
let agent;
|
|
422
|
+
let deploy;
|
|
423
|
+
let contract;
|
|
424
|
+
let ai;
|
|
425
|
+
let license;
|
|
426
|
+
let gitLfs;
|
|
427
|
+
let integrations;
|
|
428
|
+
function takeEnum(flag, next, enumValues) {
|
|
429
|
+
if (next === void 0 || next.startsWith("--")) {
|
|
430
|
+
throw new UserInputError(
|
|
431
|
+
`${flag} requires a value`,
|
|
432
|
+
`\u53EF\u9009\u503C\uFF1A${enumValues.join(" | ")}`
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
if (!enumValues.includes(next)) {
|
|
436
|
+
throw new UserInputError(
|
|
437
|
+
`invalid ${flag} value: ${JSON.stringify(next)}`,
|
|
438
|
+
`\u53EF\u9009\u503C\uFF1A${enumValues.join(" | ")}`
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
return next;
|
|
442
|
+
}
|
|
390
443
|
for (let i = 0; i < args.length; i += 1) {
|
|
391
444
|
const a = args[i];
|
|
392
445
|
switch (a) {
|
|
@@ -408,6 +461,74 @@ function parseCreateArgs(args) {
|
|
|
408
461
|
case "--sample-feature":
|
|
409
462
|
sampleFeature = true;
|
|
410
463
|
break;
|
|
464
|
+
case "--multi-app":
|
|
465
|
+
multiApp = true;
|
|
466
|
+
break;
|
|
467
|
+
case "--gitLfs":
|
|
468
|
+
case "--git-lfs":
|
|
469
|
+
gitLfs = true;
|
|
470
|
+
break;
|
|
471
|
+
case "--integrations":
|
|
472
|
+
integrations = true;
|
|
473
|
+
break;
|
|
474
|
+
case "--backend": {
|
|
475
|
+
backend = takeEnum("--backend", args[i + 1], BACKEND_LANGUAGES);
|
|
476
|
+
i += 1;
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
case "--frontend": {
|
|
480
|
+
frontend = takeEnum("--frontend", args[i + 1], FRONTEND_FRAMEWORKS);
|
|
481
|
+
i += 1;
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
case "--mobile": {
|
|
485
|
+
mobile = takeEnum("--mobile", args[i + 1], MOBILE_KINDS);
|
|
486
|
+
i += 1;
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
case "--miniapp": {
|
|
490
|
+
miniapp = takeEnum("--miniapp", args[i + 1], MINIAPP_KINDS);
|
|
491
|
+
i += 1;
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
case "--agent": {
|
|
495
|
+
agent = takeEnum("--agent", args[i + 1], AGENT_KINDS);
|
|
496
|
+
i += 1;
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
case "--deploy": {
|
|
500
|
+
deploy = takeEnum("--deploy", args[i + 1], DEPLOY_TARGETS);
|
|
501
|
+
i += 1;
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
case "--contract": {
|
|
505
|
+
contract = takeEnum("--contract", args[i + 1], CONTRACT_KINDS);
|
|
506
|
+
i += 1;
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
case "--ai": {
|
|
510
|
+
ai = takeEnum("--ai", args[i + 1], AI_TOOLS);
|
|
511
|
+
i += 1;
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
514
|
+
case "--license": {
|
|
515
|
+
license = takeEnum("--license", args[i + 1], LICENSE_KINDS);
|
|
516
|
+
i += 1;
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
case "--engineering-standards": {
|
|
520
|
+
const next = args[i + 1];
|
|
521
|
+
if (next === void 0 || next.startsWith("--")) {
|
|
522
|
+
throw new UserInputError(
|
|
523
|
+
"--engineering-standards requires a tier argument",
|
|
524
|
+
`\u53EF\u9009\u503C\uFF1A${ADOPTION_TIERS.join(" | ")}`
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
engineeringStandards = parseTier(next);
|
|
528
|
+
engineeringStandardsExplicit = true;
|
|
529
|
+
i += 1;
|
|
530
|
+
break;
|
|
531
|
+
}
|
|
411
532
|
case "--config": {
|
|
412
533
|
const next = args[i + 1];
|
|
413
534
|
if (next === void 0 || next.startsWith("--")) {
|
|
@@ -500,7 +621,20 @@ function parseCreateArgs(args) {
|
|
|
500
621
|
...config !== void 0 ? { config } : {},
|
|
501
622
|
...ci !== void 0 ? { ci } : {},
|
|
502
623
|
...roles !== void 0 ? { roles } : {},
|
|
503
|
-
...sampleFeature ? { sampleFeature: true } : {}
|
|
624
|
+
...sampleFeature ? { sampleFeature: true } : {},
|
|
625
|
+
...engineeringStandards !== void 0 ? { engineeringStandards } : {},
|
|
626
|
+
...multiApp ? { multiApp: true } : {},
|
|
627
|
+
...backend !== void 0 ? { backend } : {},
|
|
628
|
+
...frontend !== void 0 ? { frontend } : {},
|
|
629
|
+
...mobile !== void 0 ? { mobile } : {},
|
|
630
|
+
...miniapp !== void 0 ? { miniapp } : {},
|
|
631
|
+
...agent !== void 0 ? { agent } : {},
|
|
632
|
+
...deploy !== void 0 ? { deploy } : {},
|
|
633
|
+
...contract !== void 0 ? { contract } : {},
|
|
634
|
+
...ai !== void 0 ? { ai } : {},
|
|
635
|
+
...license !== void 0 ? { license } : {},
|
|
636
|
+
...gitLfs !== void 0 ? { gitLfs } : {},
|
|
637
|
+
...integrations !== void 0 ? { integrations } : {}
|
|
504
638
|
};
|
|
505
639
|
if (sampleFeature && dryRun) {
|
|
506
640
|
throw new UserInputError(
|
|
@@ -508,6 +642,12 @@ function parseCreateArgs(args) {
|
|
|
508
642
|
"\u8BF7\u53BB\u6389\u4E00\u9879\u540E\u91CD\u8BD5"
|
|
509
643
|
);
|
|
510
644
|
}
|
|
645
|
+
if (!engineeringStandardsExplicit) {
|
|
646
|
+
return {
|
|
647
|
+
projectName,
|
|
648
|
+
flags: { ...flags, engineeringStandards: "standard" }
|
|
649
|
+
};
|
|
650
|
+
}
|
|
511
651
|
return { projectName, flags };
|
|
512
652
|
}
|
|
513
653
|
async function dispatchFeature(io, args) {
|
|
@@ -569,6 +709,21 @@ function helpText() {
|
|
|
569
709
|
" --roles <list> Comma-separated role directories to scaffold",
|
|
570
710
|
" (" + ROLE_KINDS.join("|") + "; default: none)",
|
|
571
711
|
" --sample-feature After create, scaffold the user-signup sample feature",
|
|
712
|
+
" --engineering-standards <tier>",
|
|
713
|
+
" Adoption tier for engineering standards: " + ADOPTION_TIERS.join("|"),
|
|
714
|
+
" (default in --yes mode: standard; omitted in interactive mode)",
|
|
715
|
+
" --multi-app Initialise the project in multi-app mode (<env>/apps/<name>/)",
|
|
716
|
+
" --backend <kind> " + BACKEND_LANGUAGES.join("|"),
|
|
717
|
+
" --frontend <kind> " + FRONTEND_FRAMEWORKS.join("|"),
|
|
718
|
+
" --mobile <kind> " + MOBILE_KINDS.join("|"),
|
|
719
|
+
" --miniapp <kind> " + MINIAPP_KINDS.join("|"),
|
|
720
|
+
" --agent <kind> " + AGENT_KINDS.join("|"),
|
|
721
|
+
" --deploy <kind> " + DEPLOY_TARGETS.join("|"),
|
|
722
|
+
" --contract <kind> " + CONTRACT_KINDS.join("|"),
|
|
723
|
+
" --ai <kind> " + AI_TOOLS.join("|"),
|
|
724
|
+
" --license <kind> " + LICENSE_KINDS.join("|"),
|
|
725
|
+
" --gitLfs Enable Git LFS in the generated project",
|
|
726
|
+
" --integrations Enable docs/06-\u96C6\u6210\u5BF9\u63A5/ at create time",
|
|
572
727
|
" -h, --help Show this help",
|
|
573
728
|
" -v, --version Show the scaffolder version",
|
|
574
729
|
"",
|
|
@@ -603,7 +758,7 @@ function featureHelpText() {
|
|
|
603
758
|
}
|
|
604
759
|
|
|
605
760
|
// src/orchestrator.ts
|
|
606
|
-
import * as
|
|
761
|
+
import * as path7 from "node:path";
|
|
607
762
|
|
|
608
763
|
// src/input/defaults.ts
|
|
609
764
|
var OPTION_DEFAULTS = {
|
|
@@ -619,7 +774,8 @@ var OPTION_DEFAULTS = {
|
|
|
619
774
|
gitLfs: false,
|
|
620
775
|
integrations: false,
|
|
621
776
|
ci: "gitee",
|
|
622
|
-
roles: []
|
|
777
|
+
roles: [],
|
|
778
|
+
multiApp: false
|
|
623
779
|
};
|
|
624
780
|
function buildDefaultOptions(projectName) {
|
|
625
781
|
return { projectName, ...OPTION_DEFAULTS };
|
|
@@ -654,7 +810,8 @@ var PARTIAL_OPTIONS_SCHEMA = {
|
|
|
654
810
|
type: "array",
|
|
655
811
|
items: { type: "string", enum: [...ROLE_KINDS] },
|
|
656
812
|
uniqueItems: true
|
|
657
|
-
}
|
|
813
|
+
},
|
|
814
|
+
multiApp: { type: "boolean" }
|
|
658
815
|
}
|
|
659
816
|
};
|
|
660
817
|
var ajv2 = new Ajv2({ allErrors: true, strict: true });
|
|
@@ -664,8 +821,8 @@ var validate = ajv2.compile(
|
|
|
664
821
|
function formatIssues() {
|
|
665
822
|
const errs = validate.errors ?? [];
|
|
666
823
|
return errs.map((e) => {
|
|
667
|
-
const
|
|
668
|
-
return `${
|
|
824
|
+
const path11 = e.instancePath || (e.params && "missingProperty" in e.params ? `/${String(e.params.missingProperty)}` : "<root>");
|
|
825
|
+
return `${path11}: ${e.message ?? "validation error"}`;
|
|
669
826
|
}).join("; ");
|
|
670
827
|
}
|
|
671
828
|
async function loadConfigFile(filePath) {
|
|
@@ -901,7 +1058,8 @@ async function promptForOptions(input) {
|
|
|
901
1058
|
gitLfs,
|
|
902
1059
|
integrations,
|
|
903
1060
|
ci,
|
|
904
|
-
roles
|
|
1061
|
+
roles,
|
|
1062
|
+
multiApp: OPTION_DEFAULTS.multiApp
|
|
905
1063
|
};
|
|
906
1064
|
}
|
|
907
1065
|
async function chooseAxis(prompter, prefilled, question, domain, def, report, axisName) {
|
|
@@ -1163,7 +1321,8 @@ function buildRenderContext(input) {
|
|
|
1163
1321
|
year: String(now.getUTCFullYear()),
|
|
1164
1322
|
generatedAt: now.toISOString(),
|
|
1165
1323
|
scaffolderVersion: input.scaffolderVersion,
|
|
1166
|
-
...input.feature !== void 0 ? { feature: input.feature } : {}
|
|
1324
|
+
...input.feature !== void 0 ? { feature: input.feature } : {},
|
|
1325
|
+
...input.standards !== void 0 ? { standards: input.standards } : {}
|
|
1167
1326
|
};
|
|
1168
1327
|
}
|
|
1169
1328
|
function buildFeatureContext(slug, nextAdrNumber) {
|
|
@@ -1204,7 +1363,10 @@ function toStrictContext(ctx) {
|
|
|
1204
1363
|
// `feature` is intentionally only attached when the orchestrator
|
|
1205
1364
|
// populated it; non-feature templates that try to read it will hit
|
|
1206
1365
|
// the proxy's "undefined template variable" branch.
|
|
1207
|
-
...ctx.feature !== void 0 ? { feature: ctx.feature } : {}
|
|
1366
|
+
...ctx.feature !== void 0 ? { feature: ctx.feature } : {},
|
|
1367
|
+
// `standards` follows the same pattern; only the engineering-standards
|
|
1368
|
+
// plan populates it.
|
|
1369
|
+
...ctx.standards !== void 0 ? { standards: ctx.standards } : {}
|
|
1208
1370
|
};
|
|
1209
1371
|
return new Proxy(base, {
|
|
1210
1372
|
get(target, prop, receiver) {
|
|
@@ -1386,6 +1548,10 @@ var METADATA_SCHEMA = {
|
|
|
1386
1548
|
type: "array",
|
|
1387
1549
|
items: { type: "string", pattern: FEATURE_SLUG_PATTERN2 },
|
|
1388
1550
|
uniqueItems: true
|
|
1551
|
+
},
|
|
1552
|
+
engineeringStandards: {
|
|
1553
|
+
type: "string",
|
|
1554
|
+
enum: [...ADOPTION_TIERS]
|
|
1389
1555
|
}
|
|
1390
1556
|
}
|
|
1391
1557
|
};
|
|
@@ -1422,7 +1588,8 @@ var METADATA_TOP_ORDER = [
|
|
|
1422
1588
|
"generatedAt",
|
|
1423
1589
|
"options",
|
|
1424
1590
|
"templateFragments",
|
|
1425
|
-
"features"
|
|
1591
|
+
"features",
|
|
1592
|
+
"engineeringStandards"
|
|
1426
1593
|
];
|
|
1427
1594
|
function canonicalOptions(options) {
|
|
1428
1595
|
const out = {};
|
|
@@ -1446,6 +1613,11 @@ function canonicalMetadata(metadata) {
|
|
|
1446
1613
|
if (features !== void 0 && features.length > 0) {
|
|
1447
1614
|
out[key] = [...features];
|
|
1448
1615
|
}
|
|
1616
|
+
} else if (key === "engineeringStandards") {
|
|
1617
|
+
const tier = metadata.engineeringStandards;
|
|
1618
|
+
if (tier !== void 0) {
|
|
1619
|
+
out[key] = tier;
|
|
1620
|
+
}
|
|
1449
1621
|
} else {
|
|
1450
1622
|
out[key] = metadata[key];
|
|
1451
1623
|
}
|
|
@@ -1483,7 +1655,8 @@ function buildMetadata(params) {
|
|
|
1483
1655
|
generatedAt: now.toISOString(),
|
|
1484
1656
|
options: params.options,
|
|
1485
1657
|
templateFragments: [...params.templateFragments],
|
|
1486
|
-
...params.features !== void 0 ? { features: [...params.features] } : {}
|
|
1658
|
+
...params.features !== void 0 ? { features: [...params.features] } : {},
|
|
1659
|
+
...params.engineeringStandards !== void 0 ? { engineeringStandards: params.engineeringStandards } : {}
|
|
1487
1660
|
};
|
|
1488
1661
|
}
|
|
1489
1662
|
|
|
@@ -1493,6 +1666,7 @@ function appendScaffolderMetadata(input) {
|
|
|
1493
1666
|
scaffolderVersion: input.scaffolderVersion,
|
|
1494
1667
|
options: input.options,
|
|
1495
1668
|
templateFragments: input.templateFragments,
|
|
1669
|
+
...input.engineeringStandards !== void 0 ? { engineeringStandards: input.engineeringStandards } : {},
|
|
1496
1670
|
...input.now !== void 0 ? { now: input.now } : {}
|
|
1497
1671
|
});
|
|
1498
1672
|
const file = {
|
|
@@ -1695,6 +1869,375 @@ function verbosityFromFlags(flags) {
|
|
|
1695
1869
|
return "default";
|
|
1696
1870
|
}
|
|
1697
1871
|
|
|
1872
|
+
// src/standards/plan.ts
|
|
1873
|
+
import { accessSync as accessSync2 } from "node:fs";
|
|
1874
|
+
import * as path6 from "node:path";
|
|
1875
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1876
|
+
|
|
1877
|
+
// src/standards/stack-detector.ts
|
|
1878
|
+
function backendManifest(opt) {
|
|
1879
|
+
switch (opt) {
|
|
1880
|
+
case "node":
|
|
1881
|
+
return { env: "server", language: "typescript", manifestPath: "server/package.json", packageManager: "npm" };
|
|
1882
|
+
case "java":
|
|
1883
|
+
return { env: "server", language: "java", manifestPath: "server/pom.xml", packageManager: "maven" };
|
|
1884
|
+
case "go":
|
|
1885
|
+
return { env: "server", language: "go", manifestPath: "server/go.mod", packageManager: "gomod" };
|
|
1886
|
+
case "python":
|
|
1887
|
+
return { env: "server", language: "python", manifestPath: "server/pyproject.toml", packageManager: "pip" };
|
|
1888
|
+
case "none":
|
|
1889
|
+
return null;
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
function frontendManifest(opt) {
|
|
1893
|
+
switch (opt) {
|
|
1894
|
+
case "react":
|
|
1895
|
+
case "vue":
|
|
1896
|
+
return { env: "web", language: "typescript", manifestPath: "web/package.json", packageManager: "npm" };
|
|
1897
|
+
case "none":
|
|
1898
|
+
return null;
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
function mobileManifest(opt) {
|
|
1902
|
+
switch (opt) {
|
|
1903
|
+
case "flutter":
|
|
1904
|
+
return { env: "mobile", language: "dart", manifestPath: "mobile/pubspec.yaml", packageManager: "pub" };
|
|
1905
|
+
case "react-native":
|
|
1906
|
+
return { env: "mobile", language: "typescript", manifestPath: "mobile/package.json", packageManager: "npm" };
|
|
1907
|
+
case "none":
|
|
1908
|
+
return null;
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
function miniappManifest(opt) {
|
|
1912
|
+
switch (opt) {
|
|
1913
|
+
case "wechat":
|
|
1914
|
+
return { env: "miniapp", language: "typescript", manifestPath: "miniapp/package.json", packageManager: "npm" };
|
|
1915
|
+
case "none":
|
|
1916
|
+
return null;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
function agentManifest(opt) {
|
|
1920
|
+
switch (opt) {
|
|
1921
|
+
case "rust-desktop":
|
|
1922
|
+
return { env: "agent", language: "rust", manifestPath: "agent/Cargo.toml", packageManager: "cargo" };
|
|
1923
|
+
case "none":
|
|
1924
|
+
return null;
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
var SEED_DEPS_NODE_SERVER = [
|
|
1928
|
+
{ name: "typescript", version: "5.5.4", policy: "minor" },
|
|
1929
|
+
{ name: "@types/node", version: "20.14.10", policy: "minor" }
|
|
1930
|
+
];
|
|
1931
|
+
var SEED_DEPS_JAVA_SERVER = [
|
|
1932
|
+
{ name: "spring-boot-starter-web", version: "3.3.2", policy: "minor" },
|
|
1933
|
+
{ name: "spring-boot-starter-validation", version: "3.3.2", policy: "minor" }
|
|
1934
|
+
];
|
|
1935
|
+
var SEED_DEPS_GO_SERVER = [
|
|
1936
|
+
{ name: "github.com/gin-gonic/gin", version: "1.10.0", policy: "minor" }
|
|
1937
|
+
];
|
|
1938
|
+
var SEED_DEPS_PYTHON_SERVER = [
|
|
1939
|
+
{ name: "fastapi", version: "0.111.1", policy: "minor" },
|
|
1940
|
+
{ name: "pydantic", version: "2.8.2", policy: "minor" }
|
|
1941
|
+
];
|
|
1942
|
+
var SEED_DEPS_REACT_WEB = [
|
|
1943
|
+
{ name: "react", version: "18.3.1", policy: "minor" },
|
|
1944
|
+
{ name: "react-dom", version: "18.3.1", policy: "minor" },
|
|
1945
|
+
{ name: "typescript", version: "5.5.4", policy: "minor" }
|
|
1946
|
+
];
|
|
1947
|
+
var SEED_DEPS_VUE_WEB = [
|
|
1948
|
+
{ name: "vue", version: "3.4.34", policy: "minor" },
|
|
1949
|
+
{ name: "typescript", version: "5.5.4", policy: "minor" }
|
|
1950
|
+
];
|
|
1951
|
+
var SEED_DEPS_FLUTTER_MOBILE = [
|
|
1952
|
+
{ name: "flutter", version: "3.22.0", policy: "minor" }
|
|
1953
|
+
];
|
|
1954
|
+
var SEED_DEPS_REACT_NATIVE_MOBILE = [
|
|
1955
|
+
{ name: "react-native", version: "0.74.3", policy: "minor" },
|
|
1956
|
+
{ name: "react", version: "18.3.1", policy: "minor" }
|
|
1957
|
+
];
|
|
1958
|
+
var SEED_DEPS_WECHAT_MINIAPP = [
|
|
1959
|
+
{ name: "typescript", version: "5.5.4", policy: "minor" }
|
|
1960
|
+
];
|
|
1961
|
+
var SEED_DEPS_RUST_AGENT = [
|
|
1962
|
+
{ name: "tokio", version: "1.39.2", policy: "minor" },
|
|
1963
|
+
{ name: "serde", version: "1.0.204", policy: "minor" }
|
|
1964
|
+
];
|
|
1965
|
+
function seedDeps(options, env) {
|
|
1966
|
+
switch (env) {
|
|
1967
|
+
case "server":
|
|
1968
|
+
switch (options.backend) {
|
|
1969
|
+
case "node":
|
|
1970
|
+
return SEED_DEPS_NODE_SERVER;
|
|
1971
|
+
case "java":
|
|
1972
|
+
return SEED_DEPS_JAVA_SERVER;
|
|
1973
|
+
case "go":
|
|
1974
|
+
return SEED_DEPS_GO_SERVER;
|
|
1975
|
+
case "python":
|
|
1976
|
+
return SEED_DEPS_PYTHON_SERVER;
|
|
1977
|
+
case "none":
|
|
1978
|
+
return [];
|
|
1979
|
+
}
|
|
1980
|
+
break;
|
|
1981
|
+
case "web":
|
|
1982
|
+
switch (options.frontend) {
|
|
1983
|
+
case "react":
|
|
1984
|
+
return SEED_DEPS_REACT_WEB;
|
|
1985
|
+
case "vue":
|
|
1986
|
+
return SEED_DEPS_VUE_WEB;
|
|
1987
|
+
case "none":
|
|
1988
|
+
return [];
|
|
1989
|
+
}
|
|
1990
|
+
break;
|
|
1991
|
+
case "mobile":
|
|
1992
|
+
switch (options.mobile) {
|
|
1993
|
+
case "flutter":
|
|
1994
|
+
return SEED_DEPS_FLUTTER_MOBILE;
|
|
1995
|
+
case "react-native":
|
|
1996
|
+
return SEED_DEPS_REACT_NATIVE_MOBILE;
|
|
1997
|
+
case "none":
|
|
1998
|
+
return [];
|
|
1999
|
+
}
|
|
2000
|
+
break;
|
|
2001
|
+
case "miniapp":
|
|
2002
|
+
switch (options.miniapp) {
|
|
2003
|
+
case "wechat":
|
|
2004
|
+
return SEED_DEPS_WECHAT_MINIAPP;
|
|
2005
|
+
case "none":
|
|
2006
|
+
return [];
|
|
2007
|
+
}
|
|
2008
|
+
break;
|
|
2009
|
+
case "agent":
|
|
2010
|
+
switch (options.agent) {
|
|
2011
|
+
case "rust-desktop":
|
|
2012
|
+
return SEED_DEPS_RUST_AGENT;
|
|
2013
|
+
case "none":
|
|
2014
|
+
return [];
|
|
2015
|
+
}
|
|
2016
|
+
break;
|
|
2017
|
+
}
|
|
2018
|
+
return [];
|
|
2019
|
+
}
|
|
2020
|
+
function detectRuntimeManifests(options) {
|
|
2021
|
+
const detectors = [
|
|
2022
|
+
backendManifest(options.backend),
|
|
2023
|
+
frontendManifest(options.frontend),
|
|
2024
|
+
mobileManifest(options.mobile),
|
|
2025
|
+
miniappManifest(options.miniapp),
|
|
2026
|
+
agentManifest(options.agent)
|
|
2027
|
+
];
|
|
2028
|
+
return detectors.filter((m) => m !== null).map((m) => ({ ...m, dependencies: seedDeps(options, m.env) }));
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
// src/standards/plan.ts
|
|
2032
|
+
async function buildStandardsPlan(input) {
|
|
2033
|
+
const templatesRoot = input.templatesRoot ?? defaultStandardsTemplatesRoot();
|
|
2034
|
+
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
2035
|
+
const lastReviewed = formatDate(now);
|
|
2036
|
+
const manifests = detectRuntimeManifests(input.options);
|
|
2037
|
+
const files = [];
|
|
2038
|
+
const languages = uniqueLanguages(manifests);
|
|
2039
|
+
for (const language of languages) {
|
|
2040
|
+
files.push(
|
|
2041
|
+
await renderStandardsTemplate({
|
|
2042
|
+
templatesRoot,
|
|
2043
|
+
templateRelPath: `coding-style-${language}.md.eta`,
|
|
2044
|
+
targetPath: `docs/03-\u5DE5\u7A0B\u89C4\u8303\u4E0E\u7814\u53D1\u57FA\u7840\u8BBE\u65BD/coding-style-${language}.md`,
|
|
2045
|
+
contributedBy: `standards:coding-style-${language}`,
|
|
2046
|
+
options: input.options,
|
|
2047
|
+
scaffolderVersion: input.scaffolderVersion,
|
|
2048
|
+
now,
|
|
2049
|
+
standards: { tier: input.tier, language, lastReviewed }
|
|
2050
|
+
})
|
|
2051
|
+
);
|
|
2052
|
+
}
|
|
2053
|
+
if (input.tier === "standard" || input.tier === "full") {
|
|
2054
|
+
for (const m of manifests) {
|
|
2055
|
+
const fileBaseName = `tech-stack-${m.env}.md`;
|
|
2056
|
+
files.push(
|
|
2057
|
+
await renderStandardsTemplate({
|
|
2058
|
+
templatesRoot,
|
|
2059
|
+
templateRelPath: `tech-stack-${m.env}.md.eta`,
|
|
2060
|
+
targetPath: `docs/03-\u5DE5\u7A0B\u89C4\u8303\u4E0E\u7814\u53D1\u57FA\u7840\u8BBE\u65BD/${fileBaseName}`,
|
|
2061
|
+
contributedBy: `standards:tech-stack-${m.env}`,
|
|
2062
|
+
options: input.options,
|
|
2063
|
+
scaffolderVersion: input.scaffolderVersion,
|
|
2064
|
+
now,
|
|
2065
|
+
standards: {
|
|
2066
|
+
tier: input.tier,
|
|
2067
|
+
env: m.env,
|
|
2068
|
+
language: m.language,
|
|
2069
|
+
packageManager: m.packageManager,
|
|
2070
|
+
manifestPath: m.manifestPath,
|
|
2071
|
+
lastReviewed,
|
|
2072
|
+
multiApp: input.options.multiApp
|
|
2073
|
+
// Smuggle dependencies through standards context so the
|
|
2074
|
+
// template can iterate. We attach via Object.assign-style
|
|
2075
|
+
// cast because StandardsRenderContext does not declare it
|
|
2076
|
+
// (deps are only read by the tech-stack templates and the
|
|
2077
|
+
// shape varies per env, so keeping it untyped here is
|
|
2078
|
+
// acceptable).
|
|
2079
|
+
},
|
|
2080
|
+
extraStandardsFields: { dependencies: m.dependencies }
|
|
2081
|
+
})
|
|
2082
|
+
);
|
|
2083
|
+
}
|
|
2084
|
+
files.push(
|
|
2085
|
+
await renderStandardsTemplate({
|
|
2086
|
+
templatesRoot,
|
|
2087
|
+
templateRelPath: "module-boundaries.md.eta",
|
|
2088
|
+
targetPath: "docs/03-\u5DE5\u7A0B\u89C4\u8303\u4E0E\u7814\u53D1\u57FA\u7840\u8BBE\u65BD/module-boundaries.md",
|
|
2089
|
+
contributedBy: "standards:module-boundaries",
|
|
2090
|
+
options: input.options,
|
|
2091
|
+
scaffolderVersion: input.scaffolderVersion,
|
|
2092
|
+
now,
|
|
2093
|
+
standards: {
|
|
2094
|
+
tier: input.tier,
|
|
2095
|
+
multiApp: input.options.multiApp,
|
|
2096
|
+
lastReviewed
|
|
2097
|
+
}
|
|
2098
|
+
})
|
|
2099
|
+
);
|
|
2100
|
+
if (input.options.multiApp && hasJsTsEnvironment(manifests)) {
|
|
2101
|
+
files.push(
|
|
2102
|
+
await renderStandardsTemplate({
|
|
2103
|
+
templatesRoot,
|
|
2104
|
+
templateRelPath: "dependency-cruiser.config.cjs.eta",
|
|
2105
|
+
targetPath: "dependency-cruiser.config.cjs",
|
|
2106
|
+
contributedBy: "standards:dep-cruiser",
|
|
2107
|
+
options: input.options,
|
|
2108
|
+
scaffolderVersion: input.scaffolderVersion,
|
|
2109
|
+
now,
|
|
2110
|
+
standards: {
|
|
2111
|
+
tier: input.tier,
|
|
2112
|
+
multiApp: true,
|
|
2113
|
+
lastReviewed
|
|
2114
|
+
}
|
|
2115
|
+
})
|
|
2116
|
+
);
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
if (input.tier === "full" && hasFrontendSurface(input.options)) {
|
|
2120
|
+
files.push(
|
|
2121
|
+
await renderStandardsTemplate({
|
|
2122
|
+
templatesRoot,
|
|
2123
|
+
templateRelPath: "ui-design-system.md.eta",
|
|
2124
|
+
targetPath: "docs/05-\u524D\u7AEF\u5BA2\u6237\u7AEF\u8BE6\u7EC6\u8BBE\u8BA1/ui-design-system.md",
|
|
2125
|
+
contributedBy: "standards:ui-design-system",
|
|
2126
|
+
options: input.options,
|
|
2127
|
+
scaffolderVersion: input.scaffolderVersion,
|
|
2128
|
+
now,
|
|
2129
|
+
standards: { tier: "full", lastReviewed }
|
|
2130
|
+
})
|
|
2131
|
+
);
|
|
2132
|
+
if (input.options.frontend !== "none") {
|
|
2133
|
+
files.push(
|
|
2134
|
+
await renderStandardsTemplate({
|
|
2135
|
+
templatesRoot,
|
|
2136
|
+
templateRelPath: "design-tokens.ts.eta",
|
|
2137
|
+
targetPath: "web/src/design-tokens.ts",
|
|
2138
|
+
contributedBy: "standards:design-tokens",
|
|
2139
|
+
options: input.options,
|
|
2140
|
+
scaffolderVersion: input.scaffolderVersion,
|
|
2141
|
+
now,
|
|
2142
|
+
standards: { tier: "full", lastReviewed }
|
|
2143
|
+
})
|
|
2144
|
+
);
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
const sortedFiles = [...files].sort(
|
|
2148
|
+
(a, b) => a.targetPath < b.targetPath ? -1 : a.targetPath > b.targetPath ? 1 : 0
|
|
2149
|
+
);
|
|
2150
|
+
const directories = collectDirectories(sortedFiles);
|
|
2151
|
+
return { files: sortedFiles, directories };
|
|
2152
|
+
}
|
|
2153
|
+
async function renderStandardsTemplate(input) {
|
|
2154
|
+
const templatePath = path6.join(input.templatesRoot, input.templateRelPath);
|
|
2155
|
+
const standards = {
|
|
2156
|
+
...input.standards,
|
|
2157
|
+
...input.extraStandardsFields ?? {}
|
|
2158
|
+
};
|
|
2159
|
+
const ctx = buildRenderContext({
|
|
2160
|
+
options: input.options,
|
|
2161
|
+
scaffolderVersion: input.scaffolderVersion,
|
|
2162
|
+
now: input.now,
|
|
2163
|
+
standards
|
|
2164
|
+
});
|
|
2165
|
+
let content;
|
|
2166
|
+
try {
|
|
2167
|
+
content = await renderFile(templatePath, ctx);
|
|
2168
|
+
} catch (e) {
|
|
2169
|
+
throw new TemplateError(
|
|
2170
|
+
`engineering-standards template render failed: ${input.templateRelPath}: ${e.message}`,
|
|
2171
|
+
"\u8BF7\u786E\u8BA4 src/standards/templates/ \u4E0B\u5B58\u5728 " + input.templateRelPath
|
|
2172
|
+
);
|
|
2173
|
+
}
|
|
2174
|
+
return {
|
|
2175
|
+
targetPath: input.targetPath,
|
|
2176
|
+
content,
|
|
2177
|
+
contributedBy: input.contributedBy
|
|
2178
|
+
};
|
|
2179
|
+
}
|
|
2180
|
+
function uniqueLanguages(manifests) {
|
|
2181
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2182
|
+
const out = [];
|
|
2183
|
+
for (const m of manifests) {
|
|
2184
|
+
if (!seen.has(m.language)) {
|
|
2185
|
+
seen.add(m.language);
|
|
2186
|
+
out.push(m.language);
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
return out;
|
|
2190
|
+
}
|
|
2191
|
+
function hasJsTsEnvironment(manifests) {
|
|
2192
|
+
return manifests.some((m) => m.language === "typescript");
|
|
2193
|
+
}
|
|
2194
|
+
function hasFrontendSurface(options) {
|
|
2195
|
+
if (options.frontend !== "none") return true;
|
|
2196
|
+
if (options.mobile === "react-native" || options.mobile === "flutter") return true;
|
|
2197
|
+
if (options.miniapp !== "none") return true;
|
|
2198
|
+
return false;
|
|
2199
|
+
}
|
|
2200
|
+
function formatDate(d) {
|
|
2201
|
+
const y = d.getUTCFullYear();
|
|
2202
|
+
const m = String(d.getUTCMonth() + 1).padStart(2, "0");
|
|
2203
|
+
const day = String(d.getUTCDate()).padStart(2, "0");
|
|
2204
|
+
return `${y}-${m}-${day}`;
|
|
2205
|
+
}
|
|
2206
|
+
function collectDirectories(files) {
|
|
2207
|
+
const set = /* @__PURE__ */ new Set();
|
|
2208
|
+
for (const f of files) {
|
|
2209
|
+
let cur = path6.posix.dirname(f.targetPath);
|
|
2210
|
+
while (cur && cur !== "." && cur !== "/") {
|
|
2211
|
+
set.add(cur);
|
|
2212
|
+
cur = path6.posix.dirname(cur);
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
return [...set].sort();
|
|
2216
|
+
}
|
|
2217
|
+
function defaultStandardsTemplatesRoot() {
|
|
2218
|
+
const here = path6.dirname(fileURLToPath2(import.meta.url));
|
|
2219
|
+
const pkgRoot = findPackageRoot2(here);
|
|
2220
|
+
return path6.join(pkgRoot, "src", "standards", "templates");
|
|
2221
|
+
}
|
|
2222
|
+
function findPackageRoot2(start) {
|
|
2223
|
+
let dir = start;
|
|
2224
|
+
for (let i = 0; i < 10; i += 1) {
|
|
2225
|
+
const candidate = path6.join(dir, "package.json");
|
|
2226
|
+
try {
|
|
2227
|
+
accessSync2(candidate);
|
|
2228
|
+
return dir;
|
|
2229
|
+
} catch {
|
|
2230
|
+
}
|
|
2231
|
+
const parent = path6.dirname(dir);
|
|
2232
|
+
if (parent === dir) break;
|
|
2233
|
+
dir = parent;
|
|
2234
|
+
}
|
|
2235
|
+
throw new TemplateError(
|
|
2236
|
+
`unable to locate package.json above ${start}`,
|
|
2237
|
+
"\u8BF7\u786E\u8BA4 scaffolder \u5B89\u88C5\u5B8C\u6574\uFF0Csrc/standards/templates/ \u4E0E package.json \u4F4D\u4E8E\u540C\u4E00\u5C42\u7EA7"
|
|
2238
|
+
);
|
|
2239
|
+
}
|
|
2240
|
+
|
|
1698
2241
|
// src/orchestrator.ts
|
|
1699
2242
|
async function runCreate(input) {
|
|
1700
2243
|
const reporter = new Reporter(
|
|
@@ -1722,17 +2265,34 @@ async function runCreate(input) {
|
|
|
1722
2265
|
name: f.manifest.name,
|
|
1723
2266
|
version: f.manifest.version
|
|
1724
2267
|
}));
|
|
2268
|
+
if (input.flags.engineeringStandards !== void 0) {
|
|
2269
|
+
const standardsPlan = await buildStandardsPlan({
|
|
2270
|
+
options,
|
|
2271
|
+
tier: input.flags.engineeringStandards,
|
|
2272
|
+
scaffolderVersion: SCAFFOLDER_VERSION,
|
|
2273
|
+
...input.io.now !== void 0 ? { now: input.io.now } : {}
|
|
2274
|
+
});
|
|
2275
|
+
plan = {
|
|
2276
|
+
files: [...plan.files, ...standardsPlan.files].sort(
|
|
2277
|
+
(a, b) => a.targetPath < b.targetPath ? -1 : a.targetPath > b.targetPath ? 1 : 0
|
|
2278
|
+
),
|
|
2279
|
+
directories: [
|
|
2280
|
+
.../* @__PURE__ */ new Set([...plan.directories, ...standardsPlan.directories])
|
|
2281
|
+
].sort()
|
|
2282
|
+
};
|
|
2283
|
+
}
|
|
1725
2284
|
plan = appendScaffolderMetadata({
|
|
1726
2285
|
plan,
|
|
1727
2286
|
scaffolderVersion: SCAFFOLDER_VERSION,
|
|
1728
2287
|
options,
|
|
1729
2288
|
templateFragments: fragmentRefs,
|
|
2289
|
+
...input.flags.engineeringStandards !== void 0 ? { engineeringStandards: input.flags.engineeringStandards } : {},
|
|
1730
2290
|
...input.io.now !== void 0 ? { now: input.io.now } : {}
|
|
1731
2291
|
});
|
|
1732
2292
|
validatePlanSyntax(plan);
|
|
1733
2293
|
reporter.info(`planned ${plan.files.length} file(s) across ${plan.directories.length} directory`);
|
|
1734
2294
|
const cwd = input.io.cwd ?? process.cwd();
|
|
1735
|
-
const targetDirectory =
|
|
2295
|
+
const targetDirectory = path7.resolve(cwd, options.projectName);
|
|
1736
2296
|
if (input.flags.dryRun) {
|
|
1737
2297
|
reporter.stage("dry-run");
|
|
1738
2298
|
reporter.dryRunReport(plan);
|
|
@@ -1763,7 +2323,19 @@ async function resolveOptions(input) {
|
|
|
1763
2323
|
...merged,
|
|
1764
2324
|
projectName,
|
|
1765
2325
|
...flags.ci !== void 0 ? { ci: flags.ci } : {},
|
|
1766
|
-
...flags.roles !== void 0 ? { roles: flags.roles } : {}
|
|
2326
|
+
...flags.roles !== void 0 ? { roles: flags.roles } : {},
|
|
2327
|
+
...flags.backend !== void 0 ? { backend: flags.backend } : {},
|
|
2328
|
+
...flags.frontend !== void 0 ? { frontend: flags.frontend } : {},
|
|
2329
|
+
...flags.mobile !== void 0 ? { mobile: flags.mobile } : {},
|
|
2330
|
+
...flags.miniapp !== void 0 ? { miniapp: flags.miniapp } : {},
|
|
2331
|
+
...flags.agent !== void 0 ? { agent: flags.agent } : {},
|
|
2332
|
+
...flags.deploy !== void 0 ? { deploy: flags.deploy } : {},
|
|
2333
|
+
...flags.contract !== void 0 ? { contract: flags.contract } : {},
|
|
2334
|
+
...flags.ai !== void 0 ? { ai: flags.ai } : {},
|
|
2335
|
+
...flags.license !== void 0 ? { license: flags.license } : {},
|
|
2336
|
+
...flags.gitLfs !== void 0 ? { gitLfs: flags.gitLfs } : {},
|
|
2337
|
+
...flags.integrations !== void 0 ? { integrations: flags.integrations } : {},
|
|
2338
|
+
...flags.multiApp !== void 0 ? { multiApp: flags.multiApp } : {}
|
|
1767
2339
|
};
|
|
1768
2340
|
if (flags.yes) {
|
|
1769
2341
|
const full = { ...buildDefaultOptions(projectName), ...merged };
|
|
@@ -1793,12 +2365,12 @@ async function resolveOptions(input) {
|
|
|
1793
2365
|
|
|
1794
2366
|
// src/feature/orchestrator.ts
|
|
1795
2367
|
import { promises as fs8 } from "node:fs";
|
|
1796
|
-
import * as
|
|
2368
|
+
import * as path10 from "node:path";
|
|
1797
2369
|
|
|
1798
2370
|
// src/feature/plan.ts
|
|
1799
|
-
import { promises as fs7, accessSync as
|
|
1800
|
-
import * as
|
|
1801
|
-
import { fileURLToPath as
|
|
2371
|
+
import { promises as fs7, accessSync as accessSync3 } from "node:fs";
|
|
2372
|
+
import * as path8 from "node:path";
|
|
2373
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1802
2374
|
|
|
1803
2375
|
// src/feature/openapi-edit.ts
|
|
1804
2376
|
import { isMap, isScalar, parseDocument, YAMLMap } from "yaml";
|
|
@@ -1892,7 +2464,7 @@ function slugToOperationId(slug) {
|
|
|
1892
2464
|
// src/feature/plan.ts
|
|
1893
2465
|
async function buildFeaturePlan(input) {
|
|
1894
2466
|
const templatesRoot = input.templatesRoot ?? defaultFeatureTemplatesRoot();
|
|
1895
|
-
const sourceRoot = input.source === "sample" ?
|
|
2467
|
+
const sourceRoot = input.source === "sample" ? path8.join(templatesRoot, "sample", input.slug) : templatesRoot;
|
|
1896
2468
|
const nextAdrNumber = await computeAdrNumberForSlug(input.cwd, input.slug);
|
|
1897
2469
|
const renderContext = buildRenderContext({
|
|
1898
2470
|
options: input.options,
|
|
@@ -1906,7 +2478,7 @@ async function buildFeaturePlan(input) {
|
|
|
1906
2478
|
const artifact = LAYER_ARTIFACTS[layer];
|
|
1907
2479
|
const targetPath = computeTargetPath(layer, input.slug, nextAdrNumber);
|
|
1908
2480
|
outputs.set(layer, targetPath);
|
|
1909
|
-
const templatePath =
|
|
2481
|
+
const templatePath = path8.join(sourceRoot, artifact.placeholderTemplate);
|
|
1910
2482
|
const content = await renderFeatureTemplate(templatePath, renderContext, layer, input.source);
|
|
1911
2483
|
files.push({
|
|
1912
2484
|
targetPath,
|
|
@@ -1918,7 +2490,7 @@ async function buildFeaturePlan(input) {
|
|
|
1918
2490
|
let openapiAlreadyExisted;
|
|
1919
2491
|
if (input.layers.includes("backend") && input.options.contract !== "none") {
|
|
1920
2492
|
const apiPath = "contracts/openapi/api.yaml";
|
|
1921
|
-
const apiAbs =
|
|
2493
|
+
const apiAbs = path8.join(input.cwd, apiPath);
|
|
1922
2494
|
let currentText;
|
|
1923
2495
|
try {
|
|
1924
2496
|
currentText = await fs7.readFile(apiAbs, "utf8");
|
|
@@ -1990,7 +2562,7 @@ async function buildFeaturePlan(input) {
|
|
|
1990
2562
|
const sortedFiles = [...files].sort(
|
|
1991
2563
|
(a, b) => a.targetPath < b.targetPath ? -1 : a.targetPath > b.targetPath ? 1 : 0
|
|
1992
2564
|
);
|
|
1993
|
-
const directories =
|
|
2565
|
+
const directories = collectDirectories2(sortedFiles);
|
|
1994
2566
|
return {
|
|
1995
2567
|
files: sortedFiles,
|
|
1996
2568
|
directories,
|
|
@@ -2017,7 +2589,7 @@ async function renderFeatureTemplate(templatePath, context, layer, source) {
|
|
|
2017
2589
|
}
|
|
2018
2590
|
var ADR_FILE_RE = /^adr-(\d{4,})-/;
|
|
2019
2591
|
async function computeAdrNumberForSlug(cwd, slug) {
|
|
2020
|
-
const dir =
|
|
2592
|
+
const dir = path8.join(cwd, "docs", "02-\u7CFB\u7EDF\u65B9\u6848\u4E0E\u67B6\u6784");
|
|
2021
2593
|
let entries;
|
|
2022
2594
|
try {
|
|
2023
2595
|
entries = await fs7.readdir(dir);
|
|
@@ -2042,32 +2614,32 @@ async function computeAdrNumberForSlug(cwd, slug) {
|
|
|
2042
2614
|
function escapeRegex(s) {
|
|
2043
2615
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2044
2616
|
}
|
|
2045
|
-
function
|
|
2617
|
+
function collectDirectories2(files) {
|
|
2046
2618
|
const set = /* @__PURE__ */ new Set();
|
|
2047
2619
|
for (const f of files) {
|
|
2048
|
-
let cur =
|
|
2620
|
+
let cur = path8.posix.dirname(f.targetPath);
|
|
2049
2621
|
while (cur && cur !== "." && cur !== "/") {
|
|
2050
2622
|
set.add(cur);
|
|
2051
|
-
cur =
|
|
2623
|
+
cur = path8.posix.dirname(cur);
|
|
2052
2624
|
}
|
|
2053
2625
|
}
|
|
2054
2626
|
return [...set].sort();
|
|
2055
2627
|
}
|
|
2056
2628
|
function defaultFeatureTemplatesRoot() {
|
|
2057
|
-
const here =
|
|
2058
|
-
const pkgRoot =
|
|
2059
|
-
return
|
|
2629
|
+
const here = path8.dirname(fileURLToPath3(import.meta.url));
|
|
2630
|
+
const pkgRoot = findPackageRoot3(here);
|
|
2631
|
+
return path8.join(pkgRoot, "src", "feature", "templates");
|
|
2060
2632
|
}
|
|
2061
|
-
function
|
|
2633
|
+
function findPackageRoot3(start) {
|
|
2062
2634
|
let dir = start;
|
|
2063
2635
|
for (let i = 0; i < 10; i += 1) {
|
|
2064
|
-
const candidate =
|
|
2636
|
+
const candidate = path8.join(dir, "package.json");
|
|
2065
2637
|
try {
|
|
2066
|
-
|
|
2638
|
+
accessSync3(candidate);
|
|
2067
2639
|
return dir;
|
|
2068
2640
|
} catch {
|
|
2069
2641
|
}
|
|
2070
|
-
const parent =
|
|
2642
|
+
const parent = path8.dirname(dir);
|
|
2071
2643
|
if (parent === dir) break;
|
|
2072
2644
|
dir = parent;
|
|
2073
2645
|
}
|
|
@@ -2078,11 +2650,11 @@ function findPackageRoot2(start) {
|
|
|
2078
2650
|
}
|
|
2079
2651
|
|
|
2080
2652
|
// src/feature/manifest-update.ts
|
|
2081
|
-
import * as
|
|
2653
|
+
import * as path9 from "node:path";
|
|
2082
2654
|
async function appendFeatureSlug(projectDirectory, slug) {
|
|
2083
2655
|
const manifest = await loadMetadataFile(projectDirectory);
|
|
2084
2656
|
const next = withFeatureSlug(manifest, slug);
|
|
2085
|
-
const metadataPath =
|
|
2657
|
+
const metadataPath = path9.join(projectDirectory, METADATA_FILENAME);
|
|
2086
2658
|
if (next === manifest) {
|
|
2087
2659
|
return { updated: false, metadataPath };
|
|
2088
2660
|
}
|
|
@@ -2115,7 +2687,7 @@ async function runFeatureAdd(input) {
|
|
|
2115
2687
|
const code = e.code;
|
|
2116
2688
|
if (code === "ENOENT") {
|
|
2117
2689
|
throw new UserInputError(
|
|
2118
|
-
`no .scaffolder.json found at ${
|
|
2690
|
+
`no .scaffolder.json found at ${path10.join(input.cwd, METADATA_FILENAME)}`,
|
|
2119
2691
|
"\u8BF7\u5728 keel \u9879\u76EE\u6839\u76EE\u5F55\u8FD0\u884C\uFF1B\u6216\u5148\u7528 create-keel create \u521B\u5EFA\u9879\u76EE"
|
|
2120
2692
|
);
|
|
2121
2693
|
}
|
|
@@ -2170,7 +2742,7 @@ async function splitPlanByExistence(plan, cwd, force) {
|
|
|
2170
2742
|
const toWrite = [];
|
|
2171
2743
|
const skipped = [];
|
|
2172
2744
|
for (const file of plan.files) {
|
|
2173
|
-
const exists = await fileExists(
|
|
2745
|
+
const exists = await fileExists(path10.join(cwd, file.targetPath));
|
|
2174
2746
|
if (exists) {
|
|
2175
2747
|
skipped.push(file.targetPath);
|
|
2176
2748
|
} else {
|