scaffold-engine 0.1.0

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.
Files changed (52) hide show
  1. package/README.md +117 -0
  2. package/engine.project.example.json +23 -0
  3. package/package.json +49 -0
  4. package/scripts/postinstall.cjs +42 -0
  5. package/specs/catalogs/action-templates.yaml +189 -0
  6. package/specs/catalogs/child-templates.yaml +54 -0
  7. package/specs/catalogs/field-fragments.yaml +203 -0
  8. package/specs/catalogs/object-catalog.yaml +35 -0
  9. package/specs/catalogs/object-name-suggestions.yaml +30 -0
  10. package/specs/catalogs/object-templates.yaml +45 -0
  11. package/specs/catalogs/pattern-catalog.yaml +48 -0
  12. package/specs/catalogs/status-templates.yaml +16 -0
  13. package/specs/projects/crm-pilot/customer.yaml +122 -0
  14. package/specs/projects/crm-pilot/lead.from-nl.yaml +76 -0
  15. package/specs/projects/crm-pilot/lead.yaml +82 -0
  16. package/specs/projects/generated-from-nl/crm-customer.yaml +158 -0
  17. package/specs/projects/generated-from-nl/crm-lead.yaml +76 -0
  18. package/specs/projects/generated-from-nl/crm-opportunity.yaml +78 -0
  19. package/specs/projects/generated-from-nl/crm-quote.yaml +78 -0
  20. package/specs/projects/generated-from-nl/custom-documentLines.yaml +125 -0
  21. package/specs/projects/generated-from-nl/custom-treeEntity.yaml +78 -0
  22. package/specs/projects/generated-from-nl/erp-material-pattern-test.yaml +79 -0
  23. package/specs/projects/generated-from-nl/erp-material.yaml +78 -0
  24. package/specs/projects/generated-from-nl/hr-orgUnit.yaml +100 -0
  25. package/specs/projects/pattern-examples/document-lines-demo.yaml +125 -0
  26. package/specs/projects/pattern-examples/tree-entity-demo.yaml +79 -0
  27. package/specs/rules/business-model.schema.json +262 -0
  28. package/specs/rules/extension-boundaries.json +26 -0
  29. package/specs/rules/requirement-draft.schema.json +75 -0
  30. package/specs/rules/spec-governance.json +29 -0
  31. package/specs/templates/crm/customer.template.yaml +121 -0
  32. package/specs/templates/crm/lead.template.yaml +82 -0
  33. package/tools/analyze-requirement.cjs +950 -0
  34. package/tools/cli.cjs +59 -0
  35. package/tools/create-draft.cjs +18 -0
  36. package/tools/engine.cjs +47 -0
  37. package/tools/generate-draft.cjs +33 -0
  38. package/tools/generate-module.cjs +1218 -0
  39. package/tools/init-project.cjs +194 -0
  40. package/tools/lib/draft-toolkit.cjs +357 -0
  41. package/tools/lib/model-toolkit.cjs +482 -0
  42. package/tools/lib/pattern-renderers.cjs +166 -0
  43. package/tools/lib/renderers/detail-page-renderer.cjs +327 -0
  44. package/tools/lib/renderers/form-page-renderer.cjs +553 -0
  45. package/tools/lib/renderers/list-page-renderer.cjs +371 -0
  46. package/tools/lib/runtime-config.cjs +154 -0
  47. package/tools/patch-draft.cjs +57 -0
  48. package/tools/prompts/business-model-prompt.md +58 -0
  49. package/tools/run-requirement.cjs +672 -0
  50. package/tools/validate-draft.cjs +32 -0
  51. package/tools/validate-model.cjs +140 -0
  52. package/tools/verify-patterns.cjs +67 -0
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env node
2
+ const path = require('path');
3
+ const { resolveScaffoldPath, validateModelFile } = require('./lib/model-toolkit.cjs');
4
+
5
+ const args = process.argv.slice(2);
6
+ const options = parseArgs(args);
7
+ const inputArg = options.file;
8
+ const specPath = inputArg
9
+ ? resolveInputPath(inputArg)
10
+ : resolveScaffoldPath('specs', 'projects', 'crm-pilot', 'customer.yaml');
11
+
12
+ try {
13
+ const result = validateModelFile(specPath);
14
+ if (options.format === 'json') {
15
+ console.log(JSON.stringify(buildValidationReport(result), null, 2));
16
+ process.exit(result.valid ? 0 : 1);
17
+ }
18
+
19
+ console.log(`\n📘 模型文件: ${result.absolutePath}`);
20
+ console.log(`📦 对象: ${result.model.meta.domain}/${result.model.meta.object} (${result.model.meta.label})`);
21
+ if (result.location) {
22
+ console.log(`🧭 范围: ${result.location.scope} (${result.location.relativePath})`);
23
+ }
24
+
25
+ if (result.schemaErrors.length > 0) {
26
+ console.error('\n❌ Schema 校验失败:');
27
+ for (const error of result.schemaErrors) {
28
+ console.error(`- ${error}`);
29
+ }
30
+ }
31
+
32
+ if (result.boundaryErrors.length > 0) {
33
+ console.error('\n❌ 业务边界校验失败:');
34
+ for (const error of result.boundaryErrors) {
35
+ console.error(`- ${error}`);
36
+ }
37
+ }
38
+
39
+ if ((result.governanceErrors || []).length > 0) {
40
+ console.error('\n❌ 治理边界校验失败:');
41
+ for (const error of result.governanceErrors) {
42
+ console.error(`- ${error}`);
43
+ }
44
+ }
45
+
46
+ if (result.warnings.length > 0) {
47
+ console.warn('\n⚠️ 提示:');
48
+ for (const warning of result.warnings) {
49
+ console.warn(`- ${warning}`);
50
+ }
51
+ }
52
+
53
+ if (!result.valid) {
54
+ process.exit(1);
55
+ }
56
+
57
+ console.log('\n✅ 模型校验通过');
58
+ } catch (error) {
59
+ console.error(`\n❌ 模型校验失败: ${error.message}`);
60
+ process.exit(1);
61
+ }
62
+
63
+ function resolveInputPath(filePath) {
64
+ if (path.isAbsolute(filePath)) {
65
+ return filePath;
66
+ }
67
+ const normalized = String(filePath).replace(/\\/g, '/');
68
+ if (normalized.startsWith('scaffold/')) {
69
+ return path.resolve(process.cwd(), normalized.slice('scaffold/'.length));
70
+ }
71
+ if (normalized.startsWith('specs/')) {
72
+ return resolveScaffoldPath(...normalized.split('/'));
73
+ }
74
+ return path.resolve(filePath);
75
+ }
76
+
77
+ function parseArgs(argv) {
78
+ const options = {
79
+ file: '',
80
+ format: 'markdown',
81
+ };
82
+
83
+ for (let index = 0; index < argv.length; index += 1) {
84
+ const item = argv[index];
85
+ if (item === '--format') {
86
+ options.format = argv[index + 1] || 'markdown';
87
+ index += 1;
88
+ continue;
89
+ }
90
+ if (!options.file) {
91
+ options.file = item;
92
+ }
93
+ }
94
+
95
+ return options;
96
+ }
97
+
98
+ function buildValidationReport(result) {
99
+ const schemaErrors = result.schemaErrors || [];
100
+ const boundaryErrors = result.boundaryErrors || [];
101
+ const governanceErrors = result.governanceErrors || [];
102
+ const warnings = result.warnings || [];
103
+ const errors = [
104
+ ...schemaErrors.map((message) => ({ stage: 'schema', message })),
105
+ ...boundaryErrors.map((message) => ({ stage: 'boundary', message })),
106
+ ...governanceErrors.map((message) => ({ stage: 'governance', message })),
107
+ ];
108
+
109
+ return {
110
+ file: result.absolutePath,
111
+ scope: result.location?.scope || 'unknown',
112
+ object: {
113
+ domain: result.model?.meta?.domain || '',
114
+ object: result.model?.meta?.object || '',
115
+ label: result.model?.meta?.label || '',
116
+ pattern: result.model?.meta?.pattern || '',
117
+ },
118
+ status: result.valid ? 'passed' : 'failed',
119
+ nextAction: result.valid ? 'generate' : 'clarify',
120
+ stages: [
121
+ {
122
+ stage: 'schema',
123
+ status: schemaErrors.length === 0 ? 'passed' : 'failed',
124
+ errors: schemaErrors,
125
+ },
126
+ {
127
+ stage: 'boundary',
128
+ status: boundaryErrors.length === 0 ? 'passed' : 'failed',
129
+ errors: boundaryErrors,
130
+ },
131
+ {
132
+ stage: 'governance',
133
+ status: governanceErrors.length === 0 ? 'passed' : 'failed',
134
+ errors: governanceErrors,
135
+ },
136
+ ],
137
+ errors,
138
+ warnings,
139
+ };
140
+ }
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ const path = require('path');
3
+ const { spawnSync } = require('child_process');
4
+ const { resolveScaffoldPath, validateModelFile } = require('./lib/model-toolkit.cjs');
5
+
6
+ const patternSpecs = [
7
+ 'specs/projects/pattern-examples/document-lines-demo.yaml',
8
+ 'specs/projects/pattern-examples/tree-entity-demo.yaml',
9
+ ];
10
+
11
+ const objectSpecs = [
12
+ 'specs/projects/crm-pilot/customer.yaml',
13
+ 'specs/projects/crm-pilot/lead.yaml',
14
+ ];
15
+
16
+ const targets = [...patternSpecs, ...objectSpecs].map((item) => resolveScaffoldPath(...item.split('/')));
17
+ const failures = [];
18
+
19
+ for (const specPath of targets) {
20
+ const validation = validateModelFile(specPath);
21
+ if (!validation.valid) {
22
+ failures.push({
23
+ specPath,
24
+ stage: 'validate',
25
+ message: [
26
+ ...(validation.schemaErrors || []),
27
+ ...(validation.boundaryErrors || []),
28
+ ...(validation.governanceErrors || []),
29
+ ].join('\n'),
30
+ });
31
+ continue;
32
+ }
33
+
34
+ const generateResult = spawnSync(process.execPath, [
35
+ path.join(resolveScaffoldPath('tools'), 'generate-module.cjs'),
36
+ specPath,
37
+ '--force',
38
+ '--dry-run',
39
+ ], {
40
+ cwd: resolveScaffoldPath(),
41
+ encoding: 'utf8',
42
+ });
43
+
44
+ if (generateResult.status !== 0) {
45
+ failures.push({
46
+ specPath,
47
+ stage: 'generate',
48
+ message: generateResult.stderr || generateResult.stdout || 'dry-run generation failed',
49
+ });
50
+ continue;
51
+ }
52
+
53
+ console.log(`✅ ${path.relative(resolveScaffoldPath(), specPath)} (${validation.location?.scope || 'unknown'})`);
54
+ }
55
+
56
+ if (failures.length > 0) {
57
+ console.error('\n❌ 模式回归失败:');
58
+ for (const item of failures) {
59
+ console.error(`- [${item.stage}] ${path.relative(resolveScaffoldPath(), item.specPath)}`);
60
+ if (item.message) {
61
+ console.error(item.message.trim());
62
+ }
63
+ }
64
+ process.exit(1);
65
+ }
66
+
67
+ console.log('\n✅ 模式回归通过');