@mimir-labs/core 0.2.0 → 0.4.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.
- package/README.md +3 -2
- package/dist/implementation/authoring/knowledge-loader.d.ts +10 -0
- package/dist/implementation/authoring/knowledge-loader.js +46 -0
- package/dist/implementation/authoring/knowledge-loader.js.map +1 -0
- package/dist/implementation/authoring/mimir-descriptor-loader.d.ts +2 -0
- package/dist/implementation/authoring/mimir-descriptor-loader.js +7 -0
- package/dist/implementation/authoring/mimir-descriptor-loader.js.map +1 -0
- package/dist/implementation/contracts/descriptor.d.ts +27 -0
- package/dist/implementation/contracts/descriptor.js +3 -0
- package/dist/implementation/contracts/descriptor.js.map +1 -0
- package/dist/implementation/contracts/resource.d.ts +16 -0
- package/dist/implementation/contracts/resource.js +3 -0
- package/dist/implementation/contracts/resource.js.map +1 -0
- package/dist/implementation/descriptors/descriptor-discovery.d.ts +2 -0
- package/dist/implementation/descriptors/descriptor-discovery.js +47 -0
- package/dist/implementation/descriptors/descriptor-discovery.js.map +1 -0
- package/dist/implementation/descriptors/descriptor-repository.d.ts +2 -0
- package/dist/implementation/descriptors/descriptor-repository.js +156 -0
- package/dist/implementation/descriptors/descriptor-repository.js.map +1 -0
- package/dist/implementation/generation/generate-service.d.ts +1 -0
- package/dist/implementation/generation/generate-service.js +68 -52
- package/dist/implementation/generation/generate-service.js.map +1 -1
- package/dist/implementation/generation/provenance/provenance-builder.d.ts +1 -1
- package/dist/implementation/generation/provenance/provenance-builder.js +4 -4
- package/dist/implementation/generation/provenance/provenance-builder.js.map +1 -1
- package/dist/implementation/generation/resource-builders/component-builder.d.ts +2 -1
- package/dist/implementation/generation/resource-builders/component-builder.js +22 -9
- package/dist/implementation/generation/resource-builders/component-builder.js.map +1 -1
- package/dist/implementation/generation/types.d.ts +1 -19
- package/dist/implementation/generators/aps-generator.js +1 -1
- package/dist/implementation/generators/aps-generator.js.map +1 -1
- package/dist/implementation/resource-discovery/storybook-extractor.d.ts +2 -0
- package/dist/implementation/resource-discovery/storybook-extractor.js +63 -0
- package/dist/implementation/resource-discovery/storybook-extractor.js.map +1 -0
- package/dist/implementation/resource-discovery/typescript-extractor.d.ts +2 -0
- package/dist/implementation/resource-discovery/typescript-extractor.js +137 -0
- package/dist/implementation/resource-discovery/typescript-extractor.js.map +1 -0
- package/dist/implementation/services/authoring-service.d.ts +9 -0
- package/dist/implementation/services/authoring-service.js +215 -23
- package/dist/implementation/services/authoring-service.js.map +1 -1
- package/dist/implementation/synchronization/context-generator.js +67 -2
- package/dist/implementation/synchronization/context-generator.js.map +1 -1
- package/package.json +4 -1
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
import type { AuthoredKnowledge } from "../../authoring/knowledge-loader";
|
|
1
2
|
import type { ExtractedComponentFact, GeneratedComponentResource, ReadmeFacts, StorybookFacts } from "../types";
|
|
2
|
-
export declare function buildComponentResource(component: ExtractedComponentFact, storybook: StorybookFacts, readme: ReadmeFacts): GeneratedComponentResource;
|
|
3
|
+
export declare function buildComponentResource(component: ExtractedComponentFact, storybook: StorybookFacts, readme: ReadmeFacts, authored?: AuthoredKnowledge | null): GeneratedComponentResource;
|
|
@@ -3,8 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.buildComponentResource = buildComponentResource;
|
|
4
4
|
const provenance_builder_1 = require("../provenance/provenance-builder");
|
|
5
5
|
const resource_identity_1 = require("../../resource-identity");
|
|
6
|
-
function buildComponentResource(component, storybook, readme) {
|
|
7
|
-
const
|
|
6
|
+
function buildComponentResource(component, storybook, readme, authored = null) {
|
|
7
|
+
const authoredDescription = authored?.knowledge.description.trim() ?? "";
|
|
8
|
+
const description = authoredDescription || readme.descriptionsByComponent[component.name] || "";
|
|
9
|
+
const whenToUse = authored?.knowledge.whenToUse ?? [];
|
|
10
|
+
const whenNotToUse = authored?.knowledge.whenNotToUse ?? [];
|
|
8
11
|
const variants = storybook.variantsByComponent[component.name] ?? [];
|
|
9
12
|
const storyFiles = storybook.storyFilesByComponent[component.name] ?? [];
|
|
10
13
|
const evidenceByField = {
|
|
@@ -13,9 +16,11 @@ function buildComponentResource(component, storybook, readme) {
|
|
|
13
16
|
package: { evidence: [(0, provenance_builder_1.fromPackageJson)()] },
|
|
14
17
|
import: { evidence: [(0, provenance_builder_1.fromTypeScript)(component.filePath)] },
|
|
15
18
|
description: {
|
|
16
|
-
evidence:
|
|
17
|
-
? [(0, provenance_builder_1.
|
|
18
|
-
:
|
|
19
|
+
evidence: authoredDescription !== "" && authored
|
|
20
|
+
? [(0, provenance_builder_1.fromHumanKnowledge)(authored.sourceRef)]
|
|
21
|
+
: description !== ""
|
|
22
|
+
? [(0, provenance_builder_1.fromReadme)("README.md")]
|
|
23
|
+
: [(0, provenance_builder_1.missingHumanSource)("description")]
|
|
19
24
|
},
|
|
20
25
|
props: { evidence: [(0, provenance_builder_1.fromTypeScript)(component.filePath)] },
|
|
21
26
|
variants: {
|
|
@@ -23,8 +28,16 @@ function buildComponentResource(component, storybook, readme) {
|
|
|
23
28
|
? storyFiles.map((file) => (0, provenance_builder_1.fromStorybook)(file))
|
|
24
29
|
: [(0, provenance_builder_1.missingHumanSource)("variants")]
|
|
25
30
|
},
|
|
26
|
-
whenToUse: {
|
|
27
|
-
|
|
31
|
+
whenToUse: {
|
|
32
|
+
evidence: whenToUse.length > 0 && authored
|
|
33
|
+
? [(0, provenance_builder_1.fromHumanKnowledge)(authored.sourceRef)]
|
|
34
|
+
: [(0, provenance_builder_1.missingHumanSource)("whenToUse")]
|
|
35
|
+
},
|
|
36
|
+
whenNotToUse: {
|
|
37
|
+
evidence: whenNotToUse.length > 0 && authored
|
|
38
|
+
? [(0, provenance_builder_1.fromHumanKnowledge)(authored.sourceRef)]
|
|
39
|
+
: [(0, provenance_builder_1.missingHumanSource)("whenNotToUse")]
|
|
40
|
+
}
|
|
28
41
|
};
|
|
29
42
|
return {
|
|
30
43
|
type: "component",
|
|
@@ -35,8 +48,8 @@ function buildComponentResource(component, storybook, readme) {
|
|
|
35
48
|
description,
|
|
36
49
|
props: component.props,
|
|
37
50
|
variants,
|
|
38
|
-
whenToUse
|
|
39
|
-
whenNotToUse
|
|
51
|
+
whenToUse,
|
|
52
|
+
whenNotToUse,
|
|
40
53
|
governance: {
|
|
41
54
|
fields: evidenceByField
|
|
42
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-builder.js","sourceRoot":"","sources":["../../../../src/implementation/generation/resource-builders/component-builder.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"component-builder.js","sourceRoot":"","sources":["../../../../src/implementation/generation/resource-builders/component-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ExtractedProp } from "../contracts/resource";
|
|
1
2
|
export type EvidenceConfidence = "high" | "medium" | "low";
|
|
2
3
|
export type FieldEvidence = {
|
|
3
4
|
sourceType: string;
|
|
@@ -9,25 +10,6 @@ export type GeneratedField<T> = {
|
|
|
9
10
|
value: T;
|
|
10
11
|
evidence: FieldEvidence[];
|
|
11
12
|
};
|
|
12
|
-
export type ExtractedProp = {
|
|
13
|
-
name: string;
|
|
14
|
-
type?: string;
|
|
15
|
-
required?: boolean;
|
|
16
|
-
};
|
|
17
|
-
export type ExtractedComponentFact = {
|
|
18
|
-
name: string;
|
|
19
|
-
filePath: string;
|
|
20
|
-
importName: string;
|
|
21
|
-
packageName: string;
|
|
22
|
-
props: Record<string, ExtractedProp>;
|
|
23
|
-
};
|
|
24
|
-
export type StorybookFacts = {
|
|
25
|
-
variantsByComponent: Record<string, string[]>;
|
|
26
|
-
storyFilesByComponent: Record<string, string[]>;
|
|
27
|
-
};
|
|
28
|
-
export type ReadmeFacts = {
|
|
29
|
-
descriptionsByComponent: Record<string, string>;
|
|
30
|
-
};
|
|
31
13
|
export type GeneratedComponentResource = {
|
|
32
14
|
type: "component";
|
|
33
15
|
id: string;
|
|
@@ -5,7 +5,7 @@ const generate_service_1 = require("../generation/generate-service");
|
|
|
5
5
|
exports.apsGenerator = {
|
|
6
6
|
name: "aps",
|
|
7
7
|
async generate(cwd, options) {
|
|
8
|
-
return (0, generate_service_1.
|
|
8
|
+
return (0, generate_service_1.compileApsFromDescriptors)(cwd, options ?? {});
|
|
9
9
|
}
|
|
10
10
|
};
|
|
11
11
|
//# sourceMappingURL=aps-generator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aps-generator.js","sourceRoot":"","sources":["../../../src/implementation/generators/aps-generator.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"aps-generator.js","sourceRoot":"","sources":["../../../src/implementation/generators/aps-generator.ts"],"names":[],"mappings":";;;AAAA,qEAA2E;AAQ9D,QAAA,YAAY,GAAuD;IAC9E,IAAI,EAAE,KAAK;IACX,KAAK,CAAC,QAAQ,CAAC,GAAW,EAAE,OAA4B;QACtD,OAAO,IAAA,4CAAyB,EAAC,GAAG,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.extractStorybookFacts = extractStorybookFacts;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const promises_1 = require("node:fs/promises");
|
|
9
|
+
const fs_1 = require("../io/fs");
|
|
10
|
+
function normalizeSlashes(value) {
|
|
11
|
+
return value.split(node_path_1.default.sep).join("/");
|
|
12
|
+
}
|
|
13
|
+
async function collectStoryFiles(dir) {
|
|
14
|
+
const entries = await (0, promises_1.readdir)(dir, { withFileTypes: true });
|
|
15
|
+
const files = [];
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
const absolutePath = node_path_1.default.join(dir, entry.name);
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
if (entry.name === "node_modules" || entry.name === "dist" || entry.name.startsWith(".")) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
files.push(...(await collectStoryFiles(absolutePath)));
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (entry.isFile() && entry.name.includes(".stories.")) {
|
|
26
|
+
files.push(absolutePath);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return files;
|
|
30
|
+
}
|
|
31
|
+
async function extractStorybookFacts(cwd) {
|
|
32
|
+
const files = await collectStoryFiles(cwd);
|
|
33
|
+
const variantsByComponent = {};
|
|
34
|
+
const storyFilesByComponent = {};
|
|
35
|
+
for (const file of files) {
|
|
36
|
+
const content = await (0, fs_1.readText)(file);
|
|
37
|
+
const componentMatch = /component\s*:\s*([A-Z][A-Za-z0-9_]*)/.exec(content);
|
|
38
|
+
if (!componentMatch) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const componentName = componentMatch[1];
|
|
42
|
+
if (!variantsByComponent[componentName]) {
|
|
43
|
+
variantsByComponent[componentName] = [];
|
|
44
|
+
storyFilesByComponent[componentName] = [];
|
|
45
|
+
}
|
|
46
|
+
const relativeFile = normalizeSlashes(node_path_1.default.relative(cwd, file));
|
|
47
|
+
storyFilesByComponent[componentName].push(relativeFile);
|
|
48
|
+
const variantPattern = /export\s+const\s+([A-Za-z][A-Za-z0-9_]*)\s*[:=]/g;
|
|
49
|
+
let match;
|
|
50
|
+
while ((match = variantPattern.exec(content)) !== null) {
|
|
51
|
+
const variantName = match[1];
|
|
52
|
+
if (!variantsByComponent[componentName].includes(variantName)) {
|
|
53
|
+
variantsByComponent[componentName].push(variantName);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
variantsByComponent[componentName].sort((a, b) => a.localeCompare(b));
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
variantsByComponent,
|
|
60
|
+
storyFilesByComponent
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=storybook-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storybook-extractor.js","sourceRoot":"","sources":["../../../src/implementation/resource-discovery/storybook-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.extractTypeScriptComponents = extractTypeScriptComponents;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const promises_1 = require("node:fs/promises");
|
|
9
|
+
const fs_1 = require("../io/fs");
|
|
10
|
+
const TS_EXTENSIONS = new Set([".ts", ".tsx"]);
|
|
11
|
+
function isPascalCase(name) {
|
|
12
|
+
return /^[A-Z][A-Za-z0-9]*$/.test(name);
|
|
13
|
+
}
|
|
14
|
+
function normalizeSlashes(value) {
|
|
15
|
+
return value.split(node_path_1.default.sep).join("/");
|
|
16
|
+
}
|
|
17
|
+
async function collectFiles(dir) {
|
|
18
|
+
const entries = await (0, promises_1.readdir)(dir, { withFileTypes: true });
|
|
19
|
+
const files = [];
|
|
20
|
+
for (const entry of entries) {
|
|
21
|
+
const absolutePath = node_path_1.default.join(dir, entry.name);
|
|
22
|
+
if (entry.isDirectory()) {
|
|
23
|
+
if (entry.name === "node_modules" || entry.name === "dist" || entry.name.startsWith(".")) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
files.push(...(await collectFiles(absolutePath)));
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (entry.isFile() &&
|
|
30
|
+
TS_EXTENSIONS.has(node_path_1.default.extname(entry.name)) &&
|
|
31
|
+
!entry.name.includes(".stories.")) {
|
|
32
|
+
files.push(absolutePath);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return files;
|
|
36
|
+
}
|
|
37
|
+
function extractExportedNames(content) {
|
|
38
|
+
const names = new Set();
|
|
39
|
+
const patterns = [
|
|
40
|
+
/export\s+function\s+([A-Z][A-Za-z0-9_]*)\s*\(/g,
|
|
41
|
+
/export\s+const\s+([A-Z][A-Za-z0-9_]*)\s*[:=]/g,
|
|
42
|
+
/export\s+class\s+([A-Z][A-Za-z0-9_]*)\s+/g,
|
|
43
|
+
/export\s+\{\s*([^}]+)\s*\}/g
|
|
44
|
+
];
|
|
45
|
+
for (const pattern of patterns) {
|
|
46
|
+
let match;
|
|
47
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
48
|
+
if (pattern.source.includes("[^}]+")) {
|
|
49
|
+
const tokens = match[1].split(",").map((item) => item.trim());
|
|
50
|
+
for (const token of tokens) {
|
|
51
|
+
const aliasParts = token.split(/\s+as\s+/i).map((part) => part.trim());
|
|
52
|
+
const candidate = aliasParts[aliasParts.length - 1];
|
|
53
|
+
if (isPascalCase(candidate)) {
|
|
54
|
+
names.add(candidate);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
const candidate = match[1];
|
|
60
|
+
if (isPascalCase(candidate)) {
|
|
61
|
+
names.add(candidate);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return [...names].sort((a, b) => a.localeCompare(b));
|
|
67
|
+
}
|
|
68
|
+
function parsePropsBlock(block) {
|
|
69
|
+
const result = {};
|
|
70
|
+
const lines = block.split("\n");
|
|
71
|
+
for (const line of lines) {
|
|
72
|
+
const trimmed = line.trim();
|
|
73
|
+
const match = /^([A-Za-z_][A-Za-z0-9_]*)\??:\s*([^;]+);?$/.exec(trimmed);
|
|
74
|
+
if (!match) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const propName = match[1];
|
|
78
|
+
const propType = match[2].trim();
|
|
79
|
+
const optional = trimmed.includes("?:");
|
|
80
|
+
result[propName] = {
|
|
81
|
+
name: propName,
|
|
82
|
+
type: propType,
|
|
83
|
+
required: !optional
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
function extractProps(content, componentName) {
|
|
89
|
+
const interfacePattern = new RegExp(`interface\\s+${componentName}Props\\s*\\{([\\s\\S]*?)\\}`, "m");
|
|
90
|
+
const typePattern = new RegExp(`type\\s+${componentName}Props\\s*=\\s*\\{([\\s\\S]*?)\\}`, "m");
|
|
91
|
+
const interfaceMatch = interfacePattern.exec(content);
|
|
92
|
+
if (interfaceMatch) {
|
|
93
|
+
return parsePropsBlock(interfaceMatch[1]);
|
|
94
|
+
}
|
|
95
|
+
const typeMatch = typePattern.exec(content);
|
|
96
|
+
if (typeMatch) {
|
|
97
|
+
return parsePropsBlock(typeMatch[1]);
|
|
98
|
+
}
|
|
99
|
+
return {};
|
|
100
|
+
}
|
|
101
|
+
async function extractTypeScriptComponents(cwd, packageName) {
|
|
102
|
+
const files = await collectFiles(cwd);
|
|
103
|
+
const components = [];
|
|
104
|
+
for (const filePath of files) {
|
|
105
|
+
const content = await (0, fs_1.readText)(filePath);
|
|
106
|
+
const exportedNames = extractExportedNames(content);
|
|
107
|
+
if (exportedNames.length === 0) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const relativeFilePath = normalizeSlashes(node_path_1.default.relative(cwd, filePath));
|
|
111
|
+
for (const exportedName of exportedNames) {
|
|
112
|
+
components.push({
|
|
113
|
+
name: exportedName,
|
|
114
|
+
filePath: relativeFilePath,
|
|
115
|
+
importName: exportedName,
|
|
116
|
+
packageName,
|
|
117
|
+
props: extractProps(content, exportedName)
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const unique = new Map();
|
|
122
|
+
for (const component of components) {
|
|
123
|
+
const key = component.name;
|
|
124
|
+
const previous = unique.get(key);
|
|
125
|
+
if (!previous) {
|
|
126
|
+
unique.set(key, component);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const previousScore = Object.keys(previous.props).length + (previous.filePath.endsWith("/index.ts") ? 0 : 1);
|
|
130
|
+
const candidateScore = Object.keys(component.props).length + (component.filePath.endsWith("/index.ts") ? 0 : 1);
|
|
131
|
+
if (candidateScore > previousScore) {
|
|
132
|
+
unique.set(key, component);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return [...unique.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=typescript-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typescript-extractor.js","sourceRoot":"","sources":["../../../src/implementation/resource-discovery/typescript-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
type AuthoringOptions = {
|
|
2
2
|
dryRun?: boolean;
|
|
3
|
+
refreshAuto?: boolean;
|
|
4
|
+
deleteOrphans?: boolean;
|
|
5
|
+
interactive?: boolean;
|
|
6
|
+
ai?: boolean;
|
|
3
7
|
};
|
|
4
8
|
export type AuthoringReport = {
|
|
5
9
|
outputDir: string;
|
|
6
10
|
discoveredResources: number;
|
|
7
11
|
createdFiles: string[];
|
|
12
|
+
updatedFiles: string[];
|
|
8
13
|
existingFiles: string[];
|
|
9
14
|
plannedFiles: string[];
|
|
15
|
+
orphanedResources: string[];
|
|
16
|
+
deletedOrphans: string[];
|
|
17
|
+
pendingHumanResources: string[];
|
|
18
|
+
warnings: string[];
|
|
10
19
|
dryRun: boolean;
|
|
11
20
|
};
|
|
12
21
|
export declare function runAuthoringWorkflow(cwd: string, options?: AuthoringOptions): Promise<AuthoringReport>;
|
|
@@ -5,18 +5,98 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.runAuthoringWorkflow = runAuthoringWorkflow;
|
|
7
7
|
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
-
const
|
|
8
|
+
const yaml_1 = require("yaml");
|
|
9
|
+
const storybook_extractor_1 = require("../resource-discovery/storybook-extractor");
|
|
10
|
+
const typescript_extractor_1 = require("../resource-discovery/typescript-extractor");
|
|
11
|
+
const descriptor_discovery_1 = require("../descriptors/descriptor-discovery");
|
|
9
12
|
const fs_1 = require("../io/fs");
|
|
13
|
+
const json_1 = require("../io/json");
|
|
10
14
|
const resource_identity_1 = require("../resource-identity");
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
function normalizeSlashes(value) {
|
|
16
|
+
return value.split(node_path_1.default.sep).join("/");
|
|
17
|
+
}
|
|
18
|
+
function toDescriptorPath(filePath) {
|
|
19
|
+
const ext = node_path_1.default.extname(filePath);
|
|
20
|
+
const base = node_path_1.default.basename(filePath, ext);
|
|
21
|
+
return node_path_1.default.join(node_path_1.default.dirname(filePath), `${base}.mimir.yaml`);
|
|
22
|
+
}
|
|
23
|
+
function toPropsArray(props) {
|
|
24
|
+
return Object.values(props)
|
|
25
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
26
|
+
.map((prop) => ({
|
|
27
|
+
name: prop.name,
|
|
28
|
+
type: prop.type ?? "unknown",
|
|
29
|
+
required: prop.required !== false
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
function buildManagedAutoBlock(seed) {
|
|
33
|
+
return {
|
|
34
|
+
source: {
|
|
35
|
+
file: seed.sourceFile,
|
|
36
|
+
symbol: seed.name,
|
|
37
|
+
public: true
|
|
38
|
+
},
|
|
39
|
+
props: toPropsArray(seed.props),
|
|
40
|
+
variants: [...new Set(seed.variants)].sort((a, b) => a.localeCompare(b)),
|
|
41
|
+
storyFiles: [...new Set(seed.storyFiles)].sort((a, b) => a.localeCompare(b))
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function patchManagedResourceAuto(existing, seed) {
|
|
45
|
+
// Hard boundary: preserve every field as-is and update only descriptor.auto.
|
|
46
|
+
return {
|
|
47
|
+
...existing,
|
|
48
|
+
auto: buildManagedAutoBlock(seed)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function createManagedResource(seed) {
|
|
52
|
+
return {
|
|
53
|
+
kind: "component",
|
|
54
|
+
name: seed.name,
|
|
55
|
+
id: seed.id,
|
|
56
|
+
auto: buildManagedAutoBlock(seed),
|
|
57
|
+
human: {
|
|
58
|
+
description: "",
|
|
59
|
+
whenToUse: [],
|
|
60
|
+
whenNotToUse: []
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function resourceIdentity(resource) {
|
|
65
|
+
const id = typeof resource.id === "string" ? resource.id : null;
|
|
66
|
+
if (id && id.trim() !== "") {
|
|
67
|
+
return id;
|
|
68
|
+
}
|
|
69
|
+
const kind = typeof resource.kind === "string" ? resource.kind.trim().toLowerCase() : "";
|
|
70
|
+
const name = typeof resource.name === "string" ? resource.name.trim() : "";
|
|
71
|
+
if (kind && name) {
|
|
72
|
+
return `${kind}:${name}`;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
function isComponentResource(resource) {
|
|
77
|
+
return typeof resource.kind === "string" && resource.kind.trim().toLowerCase() === "component";
|
|
78
|
+
}
|
|
79
|
+
function toManagedSeeds(components, storybookFacts) {
|
|
80
|
+
const grouped = new Map();
|
|
81
|
+
for (const component of components) {
|
|
82
|
+
const resourceId = (0, resource_identity_1.createComponentResourceId)(component.packageName, component.name);
|
|
83
|
+
const descriptorRelativePath = normalizeSlashes(toDescriptorPath(component.filePath));
|
|
84
|
+
const seeds = grouped.get(descriptorRelativePath) ?? [];
|
|
85
|
+
seeds.push({
|
|
86
|
+
name: component.name,
|
|
87
|
+
id: resourceId,
|
|
88
|
+
sourceFile: normalizeSlashes(component.filePath),
|
|
89
|
+
props: component.props,
|
|
90
|
+
variants: storybookFacts.variantsByComponent[component.name] ?? [],
|
|
91
|
+
storyFiles: storybookFacts.storyFilesByComponent[component.name] ?? []
|
|
92
|
+
});
|
|
93
|
+
grouped.set(descriptorRelativePath, seeds);
|
|
94
|
+
}
|
|
95
|
+
return grouped;
|
|
96
|
+
}
|
|
97
|
+
function serializeDescriptorDocument(doc) {
|
|
98
|
+
return (0, yaml_1.stringify)(doc, { lineWidth: 120 });
|
|
99
|
+
}
|
|
20
100
|
async function readPackageName(cwd) {
|
|
21
101
|
const packageJson = await (0, fs_1.readJson)(node_path_1.default.join(cwd, "package.json"));
|
|
22
102
|
if (typeof packageJson.name !== "string" || packageJson.name.trim() === "") {
|
|
@@ -25,37 +105,149 @@ async function readPackageName(cwd) {
|
|
|
25
105
|
return packageJson.name;
|
|
26
106
|
}
|
|
27
107
|
async function runAuthoringWorkflow(cwd, options = {}) {
|
|
108
|
+
const shouldRefreshAuto = options.refreshAuto !== false;
|
|
109
|
+
const shouldDeleteOrphans = options.deleteOrphans === true;
|
|
28
110
|
const packageName = await readPackageName(cwd);
|
|
29
|
-
const components = await
|
|
30
|
-
|
|
111
|
+
const [components, storybookFacts] = await Promise.all([
|
|
112
|
+
(0, typescript_extractor_1.extractTypeScriptComponents)(cwd, packageName),
|
|
113
|
+
(0, storybook_extractor_1.extractStorybookFacts)(cwd)
|
|
114
|
+
]);
|
|
115
|
+
const outputDir = cwd;
|
|
31
116
|
const createdFiles = [];
|
|
117
|
+
const updatedFiles = [];
|
|
32
118
|
const existingFiles = [];
|
|
33
119
|
const plannedFiles = [];
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
120
|
+
const orphanedResources = [];
|
|
121
|
+
const deletedOrphans = [];
|
|
122
|
+
const warnings = [];
|
|
123
|
+
if (options.interactive) {
|
|
124
|
+
warnings.push("--interactive is not implemented yet. Running sync-only mode.");
|
|
125
|
+
}
|
|
126
|
+
if (options.ai) {
|
|
127
|
+
warnings.push("--ai is not implemented yet. Running sync-only mode.");
|
|
128
|
+
}
|
|
129
|
+
const groupedDescriptors = toManagedSeeds(components, storybookFacts);
|
|
130
|
+
const existingDescriptorFiles = await (0, descriptor_discovery_1.discoverDescriptorFiles)(cwd);
|
|
131
|
+
const expectedDescriptorPaths = new Set(groupedDescriptors.keys());
|
|
132
|
+
const allDescriptorPaths = new Set([
|
|
133
|
+
...existingDescriptorFiles,
|
|
134
|
+
...expectedDescriptorPaths
|
|
135
|
+
]);
|
|
136
|
+
for (const relativePath of [...allDescriptorPaths].sort((a, b) => a.localeCompare(b))) {
|
|
137
|
+
const filePath = node_path_1.default.join(cwd, relativePath);
|
|
138
|
+
const uniqueSeeds = new Map((groupedDescriptors.get(relativePath) ?? []).map((item) => [item.id, item]));
|
|
139
|
+
const seeds = [...uniqueSeeds.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
140
|
+
const seedByIdentityEntries = [
|
|
141
|
+
...seeds.map((seed) => [seed.id, seed]),
|
|
142
|
+
...seeds.map((seed) => [`component:${seed.name}`, seed])
|
|
143
|
+
];
|
|
144
|
+
const seedByIdentity = new Map(seedByIdentityEntries);
|
|
145
|
+
let existingDoc = {
|
|
146
|
+
schemaVersion: 1,
|
|
147
|
+
resources: []
|
|
148
|
+
};
|
|
149
|
+
const fileAlreadyExists = await (0, fs_1.fileExists)(filePath);
|
|
150
|
+
if (fileAlreadyExists) {
|
|
151
|
+
try {
|
|
152
|
+
const parsed = (0, yaml_1.parse)(await (0, fs_1.readText)(filePath));
|
|
153
|
+
if ((0, json_1.isObject)(parsed)) {
|
|
154
|
+
existingDoc = {
|
|
155
|
+
...parsed
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
throw new Error(`${relativePath}: descriptor must be a YAML object`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
164
|
+
throw new Error(`Invalid descriptor\n\n${relativePath}\n\nYAML parse error.\n${message}\n\nFix the descriptor before running author again.`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const existingResourcesRaw = Array.isArray(existingDoc.resources) ? existingDoc.resources : [];
|
|
168
|
+
const existingResources = existingResourcesRaw.filter((item) => (0, json_1.isObject)(item));
|
|
169
|
+
const nextResources = [];
|
|
170
|
+
const consumedIdentities = new Set();
|
|
171
|
+
for (const existingResource of existingResources) {
|
|
172
|
+
const identity = resourceIdentity(existingResource);
|
|
173
|
+
if (!identity) {
|
|
174
|
+
nextResources.push(existingResource);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const seed = seedByIdentity.get(identity);
|
|
178
|
+
if (seed) {
|
|
179
|
+
const updated = shouldRefreshAuto ? patchManagedResourceAuto(existingResource, seed) : existingResource;
|
|
180
|
+
nextResources.push(updated);
|
|
181
|
+
consumedIdentities.add(identity);
|
|
182
|
+
if (identity === `component:${seed.name}`) {
|
|
183
|
+
consumedIdentities.add(seed.id);
|
|
184
|
+
}
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (isComponentResource(existingResource) && typeof existingResource.id === "string") {
|
|
188
|
+
orphanedResources.push(`${relativePath}#${existingResource.id}`);
|
|
189
|
+
if (shouldDeleteOrphans) {
|
|
190
|
+
deletedOrphans.push(`${relativePath}#${existingResource.id}`);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
nextResources.push(existingResource);
|
|
195
|
+
}
|
|
196
|
+
for (const seed of seeds) {
|
|
197
|
+
if (consumedIdentities.has(seed.id) || consumedIdentities.has(`component:${seed.name}`)) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
nextResources.push(createManagedResource(seed));
|
|
201
|
+
}
|
|
202
|
+
if (!fileAlreadyExists) {
|
|
203
|
+
if (options.dryRun) {
|
|
204
|
+
plannedFiles.push(relativePath);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
const doc = {
|
|
208
|
+
schemaVersion: 1,
|
|
209
|
+
resources: nextResources
|
|
210
|
+
};
|
|
211
|
+
await (0, fs_1.writeText)(filePath, serializeDescriptorDocument(doc));
|
|
212
|
+
createdFiles.push(relativePath);
|
|
213
|
+
}
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const nextDoc = {
|
|
217
|
+
...existingDoc,
|
|
218
|
+
resources: nextResources
|
|
219
|
+
};
|
|
220
|
+
const before = serializeDescriptorDocument(existingDoc).trim();
|
|
221
|
+
const after = serializeDescriptorDocument(nextDoc).trim();
|
|
222
|
+
if (before === after) {
|
|
39
223
|
existingFiles.push(relativePath);
|
|
40
224
|
continue;
|
|
41
225
|
}
|
|
42
226
|
if (options.dryRun) {
|
|
43
227
|
plannedFiles.push(relativePath);
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
if (await (0, fs_1.writeTextIfMissing)(filePath, AUTHORING_TEMPLATE)) {
|
|
47
|
-
createdFiles.push(relativePath);
|
|
48
228
|
}
|
|
49
229
|
else {
|
|
50
|
-
|
|
230
|
+
await (0, fs_1.writeText)(filePath, `${after}\n`);
|
|
231
|
+
updatedFiles.push(relativePath);
|
|
51
232
|
}
|
|
52
233
|
}
|
|
234
|
+
const pendingHumanResources = [...allDescriptorPaths]
|
|
235
|
+
.sort((a, b) => a.localeCompare(b))
|
|
236
|
+
.flatMap((relativePath) => {
|
|
237
|
+
const seeds = groupedDescriptors.get(relativePath) ?? [];
|
|
238
|
+
return seeds.map((seed) => `${relativePath}#${seed.id}`);
|
|
239
|
+
});
|
|
53
240
|
return {
|
|
54
|
-
outputDir:
|
|
241
|
+
outputDir: ".",
|
|
55
242
|
discoveredResources: components.length,
|
|
56
243
|
createdFiles,
|
|
244
|
+
updatedFiles,
|
|
57
245
|
existingFiles,
|
|
58
246
|
plannedFiles,
|
|
247
|
+
orphanedResources,
|
|
248
|
+
deletedOrphans,
|
|
249
|
+
pendingHumanResources,
|
|
250
|
+
warnings,
|
|
59
251
|
dryRun: Boolean(options.dryRun)
|
|
60
252
|
};
|
|
61
253
|
}
|