@lssm/module.contractspec-workspace 0.0.0-canary-20251221114240 → 0.0.0-canary-20251221132705
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/analysis/grouping.d.ts +79 -0
- package/dist/analysis/grouping.d.ts.map +1 -0
- package/dist/analysis/grouping.js +115 -0
- package/dist/analysis/grouping.js.map +1 -0
- package/dist/analysis/validate/spec-structure.js +1 -1
- package/dist/analysis/validate/spec-structure.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/package.json +5 -5
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Stability } from "../types/spec-types.js";
|
|
2
|
+
import { FeatureScanResult, SpecScanResult } from "../types/analysis-types.js";
|
|
3
|
+
|
|
4
|
+
//#region src/analysis/grouping.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Filter criteria for spec scan results.
|
|
8
|
+
*/
|
|
9
|
+
interface SpecFilter {
|
|
10
|
+
/** Filter by tags (item must have at least one matching tag) */
|
|
11
|
+
tags?: string[];
|
|
12
|
+
/** Filter by owners (item must have at least one matching owner) */
|
|
13
|
+
owners?: string[];
|
|
14
|
+
/** Filter by stability levels */
|
|
15
|
+
stability?: Stability[];
|
|
16
|
+
/** Filter by spec type */
|
|
17
|
+
specType?: SpecScanResult['specType'][];
|
|
18
|
+
/** Filter by name pattern (glob) */
|
|
19
|
+
namePattern?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Grouping key function type.
|
|
23
|
+
*/
|
|
24
|
+
type GroupKeyFn<T> = (item: T) => string;
|
|
25
|
+
/**
|
|
26
|
+
* Grouped items result.
|
|
27
|
+
*/
|
|
28
|
+
interface GroupedItems<T> {
|
|
29
|
+
key: string;
|
|
30
|
+
items: T[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Pre-built grouping strategies for spec scan results.
|
|
34
|
+
*/
|
|
35
|
+
declare const SpecGroupingStrategies: {
|
|
36
|
+
/** Group by first tag. */
|
|
37
|
+
byTag: (item: SpecScanResult) => string;
|
|
38
|
+
/** Group by first owner. */
|
|
39
|
+
byOwner: (item: SpecScanResult) => string;
|
|
40
|
+
/** Group by domain (first segment of name). */
|
|
41
|
+
byDomain: (item: SpecScanResult) => string;
|
|
42
|
+
/** Group by stability. */
|
|
43
|
+
byStability: (item: SpecScanResult) => string;
|
|
44
|
+
/** Group by spec type. */
|
|
45
|
+
bySpecType: (item: SpecScanResult) => string;
|
|
46
|
+
/** Group by file directory. */
|
|
47
|
+
byDirectory: (item: SpecScanResult) => string;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Filter specs by criteria.
|
|
51
|
+
*/
|
|
52
|
+
declare function filterSpecs(specs: SpecScanResult[], filter: SpecFilter): SpecScanResult[];
|
|
53
|
+
/**
|
|
54
|
+
* Group specs by key function.
|
|
55
|
+
*/
|
|
56
|
+
declare function groupSpecs<T>(items: T[], keyFn: GroupKeyFn<T>): Map<string, T[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Group specs and return as array.
|
|
59
|
+
*/
|
|
60
|
+
declare function groupSpecsToArray<T>(items: T[], keyFn: GroupKeyFn<T>): GroupedItems<T>[];
|
|
61
|
+
/**
|
|
62
|
+
* Get unique tags from spec results.
|
|
63
|
+
*/
|
|
64
|
+
declare function getUniqueSpecTags(specs: SpecScanResult[]): string[];
|
|
65
|
+
/**
|
|
66
|
+
* Get unique owners from spec results.
|
|
67
|
+
*/
|
|
68
|
+
declare function getUniqueSpecOwners(specs: SpecScanResult[]): string[];
|
|
69
|
+
/**
|
|
70
|
+
* Get unique domains from spec results.
|
|
71
|
+
*/
|
|
72
|
+
declare function getUniqueSpecDomains(specs: SpecScanResult[]): string[];
|
|
73
|
+
/**
|
|
74
|
+
* Filter features by criteria.
|
|
75
|
+
*/
|
|
76
|
+
declare function filterFeatures(features: FeatureScanResult[], filter: SpecFilter): FeatureScanResult[];
|
|
77
|
+
//#endregion
|
|
78
|
+
export { GroupKeyFn, GroupedItems, SpecFilter, SpecGroupingStrategies, filterFeatures, filterSpecs, getUniqueSpecDomains, getUniqueSpecOwners, getUniqueSpecTags, groupSpecs, groupSpecsToArray };
|
|
79
|
+
//# sourceMappingURL=grouping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grouping.d.ts","names":[],"sources":["../../src/analysis/grouping.ts"],"sourcesContent":[],"mappings":";;;;;AAgCA;AAQA;;AAKkB,UAlCD,UAAA,CAkCC;EAGC;EASG,IAAA,CAAA,EAAA,MAAA,EAAA;EAGD;EAGC,MAAA,CAAA,EAAA,MAAA,EAAA;EAAc;EAUpB,SAAA,CAAA,EAxDF,SAwDa,EAAA;EAClB;EACC,QAAA,CAAA,EAxDG,cAwDH,CAAA,UAAA,CAAA,EAAA;EACP;EAAc,WAAA,CAAA,EAAA,MAAA;AAiDjB;;;;AAA6E,KAlGjE,UAkGiE,CAAA,CAAA,CAAA,GAAA,CAAA,IAAA,EAlG1C,CAkG0C,EAAA,GAAA,MAAA;;;AAmB7E;AACS,UAjHQ,YAiHR,CAAA,CAAA,CAAA,CAAA;EACW,GAAA,EAAA,MAAA;EAAX,KAAA,EAhHA,CAgHA,EAAA;;;;AAWT;AAagB,cAlIH,sBAkI8B,EAAA;EAa3B;EAWA,KAAA,EAAA,CAAA,IAAA,EAxJA,cAwJc,EAAA,GAAA,MAAA;EAClB;EACF,OAAA,EAAA,CAAA,IAAA,EAvJQ,cAuJR,EAAA,GAAA,MAAA;EACP;EAAiB,QAAA,EAAA,CAAA,IAAA,EArJD,cAqJC,EAAA,GAAA,MAAA;;sBA5IE;;qBAGD;;sBAGC;;;;;iBAUN,WAAA,QACP,0BACC,aACP;;;;iBAiDa,qBAAqB,YAAY,WAAW,KAAK,YAAY;;;;iBAmB7D,4BACP,YACA,WAAW,KACjB,aAAa;;;;iBAUA,iBAAA,QAAyB;;;;iBAazB,mBAAA,QAA2B;;;;iBAa3B,oBAAA,QAA4B;;;;iBAW5B,cAAA,WACJ,6BACF,aACP"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
//#region src/analysis/grouping.ts
|
|
2
|
+
/**
|
|
3
|
+
* Pre-built grouping strategies for spec scan results.
|
|
4
|
+
*/
|
|
5
|
+
const SpecGroupingStrategies = {
|
|
6
|
+
byTag: (item) => item.tags?.[0] ?? "untagged",
|
|
7
|
+
byOwner: (item) => item.owners?.[0] ?? "unowned",
|
|
8
|
+
byDomain: (item) => {
|
|
9
|
+
const name = item.name ?? "";
|
|
10
|
+
if (name.includes(".")) return name.split(".")[0] ?? "default";
|
|
11
|
+
return "default";
|
|
12
|
+
},
|
|
13
|
+
byStability: (item) => item.stability ?? "stable",
|
|
14
|
+
bySpecType: (item) => item.specType,
|
|
15
|
+
byDirectory: (item) => {
|
|
16
|
+
return item.filePath.split("/").slice(0, -1).join("/") || ".";
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Filter specs by criteria.
|
|
21
|
+
*/
|
|
22
|
+
function filterSpecs(specs, filter) {
|
|
23
|
+
return specs.filter((spec) => {
|
|
24
|
+
if (filter.tags?.length) {
|
|
25
|
+
if (!filter.tags.some((tag) => spec.tags?.includes(tag))) return false;
|
|
26
|
+
}
|
|
27
|
+
if (filter.owners?.length) {
|
|
28
|
+
if (!filter.owners.some((owner) => spec.owners?.includes(owner))) return false;
|
|
29
|
+
}
|
|
30
|
+
if (filter.stability?.length) {
|
|
31
|
+
if (!filter.stability.includes(spec.stability ?? "stable")) return false;
|
|
32
|
+
}
|
|
33
|
+
if (filter.specType?.length) {
|
|
34
|
+
if (!filter.specType.includes(spec.specType)) return false;
|
|
35
|
+
}
|
|
36
|
+
if (filter.namePattern) {
|
|
37
|
+
const name = spec.name ?? "";
|
|
38
|
+
const pattern = filter.namePattern.replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
39
|
+
if (!new RegExp(`^${pattern}$`, "i").test(name)) return false;
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Group specs by key function.
|
|
46
|
+
*/
|
|
47
|
+
function groupSpecs(items, keyFn) {
|
|
48
|
+
const groups = /* @__PURE__ */ new Map();
|
|
49
|
+
for (const item of items) {
|
|
50
|
+
const key = keyFn(item);
|
|
51
|
+
const existing = groups.get(key);
|
|
52
|
+
if (existing) existing.push(item);
|
|
53
|
+
else groups.set(key, [item]);
|
|
54
|
+
}
|
|
55
|
+
return groups;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Group specs and return as array.
|
|
59
|
+
*/
|
|
60
|
+
function groupSpecsToArray(items, keyFn) {
|
|
61
|
+
const map = groupSpecs(items, keyFn);
|
|
62
|
+
return Array.from(map.entries()).map(([key, items$1]) => ({
|
|
63
|
+
key,
|
|
64
|
+
items: items$1
|
|
65
|
+
})).sort((a, b) => a.key.localeCompare(b.key));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get unique tags from spec results.
|
|
69
|
+
*/
|
|
70
|
+
function getUniqueSpecTags(specs) {
|
|
71
|
+
const tags = /* @__PURE__ */ new Set();
|
|
72
|
+
for (const spec of specs) for (const tag of spec.tags ?? []) tags.add(tag);
|
|
73
|
+
return Array.from(tags).sort();
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get unique owners from spec results.
|
|
77
|
+
*/
|
|
78
|
+
function getUniqueSpecOwners(specs) {
|
|
79
|
+
const owners = /* @__PURE__ */ new Set();
|
|
80
|
+
for (const spec of specs) for (const owner of spec.owners ?? []) owners.add(owner);
|
|
81
|
+
return Array.from(owners).sort();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get unique domains from spec results.
|
|
85
|
+
*/
|
|
86
|
+
function getUniqueSpecDomains(specs) {
|
|
87
|
+
const domains = /* @__PURE__ */ new Set();
|
|
88
|
+
for (const spec of specs) domains.add(SpecGroupingStrategies.byDomain(spec));
|
|
89
|
+
return Array.from(domains).sort();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Filter features by criteria.
|
|
93
|
+
*/
|
|
94
|
+
function filterFeatures(features, filter) {
|
|
95
|
+
return features.filter((feature) => {
|
|
96
|
+
if (filter.tags?.length) {
|
|
97
|
+
if (!filter.tags.some((tag) => feature.tags?.includes(tag))) return false;
|
|
98
|
+
}
|
|
99
|
+
if (filter.owners?.length) {
|
|
100
|
+
if (!filter.owners.some((owner) => feature.owners?.includes(owner))) return false;
|
|
101
|
+
}
|
|
102
|
+
if (filter.stability?.length) {
|
|
103
|
+
if (!filter.stability.includes(feature.stability ?? "stable")) return false;
|
|
104
|
+
}
|
|
105
|
+
if (filter.namePattern) {
|
|
106
|
+
const pattern = filter.namePattern.replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
107
|
+
if (!new RegExp(`^${pattern}$`, "i").test(feature.key)) return false;
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
//#endregion
|
|
114
|
+
export { SpecGroupingStrategies, filterFeatures, filterSpecs, getUniqueSpecDomains, getUniqueSpecOwners, getUniqueSpecTags, groupSpecs, groupSpecsToArray };
|
|
115
|
+
//# sourceMappingURL=grouping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grouping.js","names":["items"],"sources":["../../src/analysis/grouping.ts"],"sourcesContent":["/**\n * Grouping and filtering utilities for ContractSpec workspace analysis.\n * Provides services to filter and group scan results.\n */\n\nimport type { SpecScanResult, FeatureScanResult } from '../types/analysis-types';\nimport type { Stability } from '../types/spec-types';\n\n/**\n * Filter criteria for spec scan results.\n */\nexport interface SpecFilter {\n /** Filter by tags (item must have at least one matching tag) */\n tags?: string[];\n /** Filter by owners (item must have at least one matching owner) */\n owners?: string[];\n /** Filter by stability levels */\n stability?: Stability[];\n /** Filter by spec type */\n specType?: SpecScanResult['specType'][];\n /** Filter by name pattern (glob) */\n namePattern?: string;\n}\n\n/**\n * Grouping key function type.\n */\nexport type GroupKeyFn<T> = (item: T) => string;\n\n/**\n * Grouped items result.\n */\nexport interface GroupedItems<T> {\n key: string;\n items: T[];\n}\n\n/**\n * Pre-built grouping strategies for spec scan results.\n */\nexport const SpecGroupingStrategies = {\n /** Group by first tag. */\n byTag: (item: SpecScanResult): string => item.tags?.[0] ?? 'untagged',\n\n /** Group by first owner. */\n byOwner: (item: SpecScanResult): string => item.owners?.[0] ?? 'unowned',\n\n /** Group by domain (first segment of name). */\n byDomain: (item: SpecScanResult): string => {\n const name = item.name ?? '';\n if (name.includes('.')) {\n return name.split('.')[0] ?? 'default';\n }\n return 'default';\n },\n\n /** Group by stability. */\n byStability: (item: SpecScanResult): string => item.stability ?? 'stable',\n\n /** Group by spec type. */\n bySpecType: (item: SpecScanResult): string => item.specType,\n\n /** Group by file directory. */\n byDirectory: (item: SpecScanResult): string => {\n const parts = item.filePath.split('/');\n // Return parent directory\n return parts.slice(0, -1).join('/') || '.';\n },\n};\n\n/**\n * Filter specs by criteria.\n */\nexport function filterSpecs(\n specs: SpecScanResult[],\n filter: SpecFilter\n): SpecScanResult[] {\n return specs.filter((spec) => {\n // Filter by tags\n if (filter.tags?.length) {\n const hasMatchingTag = filter.tags.some((tag) =>\n spec.tags?.includes(tag)\n );\n if (!hasMatchingTag) return false;\n }\n\n // Filter by owners\n if (filter.owners?.length) {\n const hasMatchingOwner = filter.owners.some((owner) =>\n spec.owners?.includes(owner)\n );\n if (!hasMatchingOwner) return false;\n }\n\n // Filter by stability\n if (filter.stability?.length) {\n if (!filter.stability.includes(spec.stability ?? 'stable')) {\n return false;\n }\n }\n\n // Filter by spec type\n if (filter.specType?.length) {\n if (!filter.specType.includes(spec.specType)) {\n return false;\n }\n }\n\n // Filter by name pattern\n if (filter.namePattern) {\n const name = spec.name ?? '';\n const pattern = filter.namePattern\n .replace(/\\*/g, '.*')\n .replace(/\\?/g, '.');\n const regex = new RegExp(`^${pattern}$`, 'i');\n if (!regex.test(name)) return false;\n }\n\n return true;\n });\n}\n\n/**\n * Group specs by key function.\n */\nexport function groupSpecs<T>(items: T[], keyFn: GroupKeyFn<T>): Map<string, T[]> {\n const groups = new Map<string, T[]>();\n\n for (const item of items) {\n const key = keyFn(item);\n const existing = groups.get(key);\n if (existing) {\n existing.push(item);\n } else {\n groups.set(key, [item]);\n }\n }\n\n return groups;\n}\n\n/**\n * Group specs and return as array.\n */\nexport function groupSpecsToArray<T>(\n items: T[],\n keyFn: GroupKeyFn<T>\n): GroupedItems<T>[] {\n const map = groupSpecs(items, keyFn);\n return Array.from(map.entries())\n .map(([key, items]) => ({ key, items }))\n .sort((a, b) => a.key.localeCompare(b.key));\n}\n\n/**\n * Get unique tags from spec results.\n */\nexport function getUniqueSpecTags(specs: SpecScanResult[]): string[] {\n const tags = new Set<string>();\n for (const spec of specs) {\n for (const tag of spec.tags ?? []) {\n tags.add(tag);\n }\n }\n return Array.from(tags).sort();\n}\n\n/**\n * Get unique owners from spec results.\n */\nexport function getUniqueSpecOwners(specs: SpecScanResult[]): string[] {\n const owners = new Set<string>();\n for (const spec of specs) {\n for (const owner of spec.owners ?? []) {\n owners.add(owner);\n }\n }\n return Array.from(owners).sort();\n}\n\n/**\n * Get unique domains from spec results.\n */\nexport function getUniqueSpecDomains(specs: SpecScanResult[]): string[] {\n const domains = new Set<string>();\n for (const spec of specs) {\n domains.add(SpecGroupingStrategies.byDomain(spec));\n }\n return Array.from(domains).sort();\n}\n\n/**\n * Filter features by criteria.\n */\nexport function filterFeatures(\n features: FeatureScanResult[],\n filter: SpecFilter\n): FeatureScanResult[] {\n return features.filter((feature) => {\n // Filter by tags\n if (filter.tags?.length) {\n const hasMatchingTag = filter.tags.some((tag) =>\n feature.tags?.includes(tag)\n );\n if (!hasMatchingTag) return false;\n }\n\n // Filter by owners\n if (filter.owners?.length) {\n const hasMatchingOwner = filter.owners.some((owner) =>\n feature.owners?.includes(owner)\n );\n if (!hasMatchingOwner) return false;\n }\n\n // Filter by stability\n if (filter.stability?.length) {\n if (!filter.stability.includes(feature.stability ?? 'stable')) {\n return false;\n }\n }\n\n // Filter by name pattern\n if (filter.namePattern) {\n const pattern = filter.namePattern\n .replace(/\\*/g, '.*')\n .replace(/\\?/g, '.');\n const regex = new RegExp(`^${pattern}$`, 'i');\n if (!regex.test(feature.key)) return false;\n }\n\n return true;\n });\n}\n"],"mappings":";;;;AAwCA,MAAa,yBAAyB;CAEpC,QAAQ,SAAiC,KAAK,OAAO,MAAM;CAG3D,UAAU,SAAiC,KAAK,SAAS,MAAM;CAG/D,WAAW,SAAiC;EAC1C,MAAM,OAAO,KAAK,QAAQ;AAC1B,MAAI,KAAK,SAAS,IAAI,CACpB,QAAO,KAAK,MAAM,IAAI,CAAC,MAAM;AAE/B,SAAO;;CAIT,cAAc,SAAiC,KAAK,aAAa;CAGjE,aAAa,SAAiC,KAAK;CAGnD,cAAc,SAAiC;AAG7C,SAFc,KAAK,SAAS,MAAM,IAAI,CAEzB,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,IAAI;;CAE1C;;;;AAKD,SAAgB,YACd,OACA,QACkB;AAClB,QAAO,MAAM,QAAQ,SAAS;AAE5B,MAAI,OAAO,MAAM,QAIf;OAAI,CAHmB,OAAO,KAAK,MAAM,QACvC,KAAK,MAAM,SAAS,IAAI,CACzB,CACoB,QAAO;;AAI9B,MAAI,OAAO,QAAQ,QAIjB;OAAI,CAHqB,OAAO,OAAO,MAAM,UAC3C,KAAK,QAAQ,SAAS,MAAM,CAC7B,CACsB,QAAO;;AAIhC,MAAI,OAAO,WAAW,QACpB;OAAI,CAAC,OAAO,UAAU,SAAS,KAAK,aAAa,SAAS,CACxD,QAAO;;AAKX,MAAI,OAAO,UAAU,QACnB;OAAI,CAAC,OAAO,SAAS,SAAS,KAAK,SAAS,CAC1C,QAAO;;AAKX,MAAI,OAAO,aAAa;GACtB,MAAM,OAAO,KAAK,QAAQ;GAC1B,MAAM,UAAU,OAAO,YACpB,QAAQ,OAAO,KAAK,CACpB,QAAQ,OAAO,IAAI;AAEtB,OAAI,CADU,IAAI,OAAO,IAAI,QAAQ,IAAI,IAAI,CAClC,KAAK,KAAK,CAAE,QAAO;;AAGhC,SAAO;GACP;;;;;AAMJ,SAAgB,WAAc,OAAY,OAAwC;CAChF,MAAM,yBAAS,IAAI,KAAkB;AAErC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,MAAM,MAAM,KAAK;EACvB,MAAM,WAAW,OAAO,IAAI,IAAI;AAChC,MAAI,SACF,UAAS,KAAK,KAAK;MAEnB,QAAO,IAAI,KAAK,CAAC,KAAK,CAAC;;AAI3B,QAAO;;;;;AAMT,SAAgB,kBACd,OACA,OACmB;CACnB,MAAM,MAAM,WAAW,OAAO,MAAM;AACpC,QAAO,MAAM,KAAK,IAAI,SAAS,CAAC,CAC7B,KAAK,CAAC,KAAKA,cAAY;EAAE;EAAK;EAAO,EAAE,CACvC,MAAM,GAAG,MAAM,EAAE,IAAI,cAAc,EAAE,IAAI,CAAC;;;;;AAM/C,SAAgB,kBAAkB,OAAmC;CACnE,MAAM,uBAAO,IAAI,KAAa;AAC9B,MAAK,MAAM,QAAQ,MACjB,MAAK,MAAM,OAAO,KAAK,QAAQ,EAAE,CAC/B,MAAK,IAAI,IAAI;AAGjB,QAAO,MAAM,KAAK,KAAK,CAAC,MAAM;;;;;AAMhC,SAAgB,oBAAoB,OAAmC;CACrE,MAAM,yBAAS,IAAI,KAAa;AAChC,MAAK,MAAM,QAAQ,MACjB,MAAK,MAAM,SAAS,KAAK,UAAU,EAAE,CACnC,QAAO,IAAI,MAAM;AAGrB,QAAO,MAAM,KAAK,OAAO,CAAC,MAAM;;;;;AAMlC,SAAgB,qBAAqB,OAAmC;CACtE,MAAM,0BAAU,IAAI,KAAa;AACjC,MAAK,MAAM,QAAQ,MACjB,SAAQ,IAAI,uBAAuB,SAAS,KAAK,CAAC;AAEpD,QAAO,MAAM,KAAK,QAAQ,CAAC,MAAM;;;;;AAMnC,SAAgB,eACd,UACA,QACqB;AACrB,QAAO,SAAS,QAAQ,YAAY;AAElC,MAAI,OAAO,MAAM,QAIf;OAAI,CAHmB,OAAO,KAAK,MAAM,QACvC,QAAQ,MAAM,SAAS,IAAI,CAC5B,CACoB,QAAO;;AAI9B,MAAI,OAAO,QAAQ,QAIjB;OAAI,CAHqB,OAAO,OAAO,MAAM,UAC3C,QAAQ,QAAQ,SAAS,MAAM,CAChC,CACsB,QAAO;;AAIhC,MAAI,OAAO,WAAW,QACpB;OAAI,CAAC,OAAO,UAAU,SAAS,QAAQ,aAAa,SAAS,CAC3D,QAAO;;AAKX,MAAI,OAAO,aAAa;GACtB,MAAM,UAAU,OAAO,YACpB,QAAQ,OAAO,KAAK,CACpB,QAAQ,OAAO,IAAI;AAEtB,OAAI,CADU,IAAI,OAAO,IAAI,QAAQ,IAAI,IAAI,CAClC,KAAK,QAAQ,IAAI,CAAE,QAAO;;AAGvC,SAAO;GACP"}
|
|
@@ -6,7 +6,7 @@ function validateSpecStructure(code, fileName) {
|
|
|
6
6
|
const errors = [];
|
|
7
7
|
const warnings = [];
|
|
8
8
|
if (!/export\s+(const|let)\s+\w+/.test(code)) errors.push("No exported spec found");
|
|
9
|
-
if (fileName.includes(".contracts.") || fileName.includes(".contract.")) validateOperationSpec(code, errors, warnings);
|
|
9
|
+
if (fileName.includes(".contracts.") || fileName.includes(".contract.") || fileName.includes(".operations.") || fileName.includes(".operation.")) validateOperationSpec(code, errors, warnings);
|
|
10
10
|
if (fileName.includes(".event.")) validateEventSpec(code, errors, warnings);
|
|
11
11
|
if (fileName.includes(".presentation.")) validatePresentationSpec(code, errors, warnings);
|
|
12
12
|
if (fileName.includes(".workflow.")) validateWorkflowSpec(code, errors, warnings);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec-structure.js","names":["errors: string[]","warnings: string[]"],"sources":["../../../src/analysis/validate/spec-structure.ts"],"sourcesContent":["/**\n * Spec structure validation utilities.\n * Extracted from cli-contracts/src/commands/validate/spec-checker.ts\n */\n\nimport type { ValidationResult } from '../../types/analysis-types';\n\nexport type { ValidationResult };\n\n/**\n * Validate spec structure based on source code and filename.\n */\nexport function validateSpecStructure(\n code: string,\n fileName: string\n): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Check for required exports\n const hasExport = /export\\s+(const|let)\\s+\\w+/.test(code);\n if (!hasExport) {\n errors.push('No exported spec found');\n }\n\n // Validate operation specs\n if (fileName.includes('.contracts.') || fileName.includes('.contract.')) {\n validateOperationSpec(code, errors, warnings);\n }\n\n // Validate event specs\n if (fileName.includes('.event.')) {\n validateEventSpec(code, errors, warnings);\n }\n\n // Validate presentation specs\n if (fileName.includes('.presentation.')) {\n validatePresentationSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.workflow.')) {\n validateWorkflowSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.data-view.')) {\n validateDataViewSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.migration.')) {\n validateMigrationSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.telemetry.')) {\n validateTelemetrySpec(code, errors, warnings);\n }\n\n if (fileName.includes('.experiment.')) {\n validateExperimentSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.app-config.')) {\n validateAppConfigSpec(code, errors, warnings);\n }\n\n // Common validations\n validateCommonFields(code, errors, warnings);\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/**\n * Validate operation spec\n */\nfunction validateOperationSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n // Check for defineCommand or defineQuery\n const hasDefine = /define(Command|Query)/.test(code);\n if (!hasDefine) {\n errors.push('Missing defineCommand or defineQuery call');\n }\n\n // Check for required meta fields\n if (!code.includes('meta:')) {\n errors.push('Missing meta section');\n }\n\n if (!code.includes('io:')) {\n errors.push('Missing io section');\n }\n\n if (!code.includes('policy:')) {\n errors.push('Missing policy section');\n }\n\n // Check for name\n if (!code.match(/name:\\s*['\"][^'\"]+['\"]/)) {\n errors.push('Missing or invalid name field');\n }\n\n // Check for version\n if (!code.match(/version:\\s*\\d+/)) {\n errors.push('Missing or invalid version field');\n }\n\n // Check for kind (defineCommand/defineQuery set it automatically, or explicit kind field)\n const hasDefineCommand = /defineCommand\\s*\\(/.test(code);\n const hasDefineQuery = /defineQuery\\s*\\(/.test(code);\n const hasExplicitKind = /kind:\\s*['\"](?:command|query)['\"]/.test(code);\n if (!hasDefineCommand && !hasDefineQuery && !hasExplicitKind) {\n errors.push(\n 'Missing kind: use defineCommand(), defineQuery(), or explicit kind field'\n );\n }\n\n // Warnings\n if (!code.includes('acceptance:')) {\n warnings.push('No acceptance scenarios defined');\n }\n\n if (!code.includes('examples:')) {\n warnings.push('No examples provided');\n }\n\n if (code.includes('TODO')) {\n warnings.push('Contains TODO items that need completion');\n }\n}\n\nfunction validateTelemetrySpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*TelemetrySpec\\s*=/)) {\n errors.push('Missing TelemetrySpec type annotation');\n }\n\n if (!code.match(/meta:\\s*{[\\s\\S]*name:/)) {\n errors.push('TelemetrySpec.meta is required');\n }\n\n if (!code.includes('events:')) {\n errors.push('TelemetrySpec must declare events');\n }\n\n if (!code.match(/privacy:\\s*'(public|internal|pii|sensitive)'/)) {\n warnings.push('No explicit privacy classification found');\n }\n}\n\nfunction validateExperimentSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*ExperimentSpec\\s*=/)) {\n errors.push('Missing ExperimentSpec type annotation');\n }\n if (!code.includes('controlVariant')) {\n errors.push('ExperimentSpec must declare controlVariant');\n }\n if (!code.includes('variants:')) {\n errors.push('ExperimentSpec must declare variants');\n }\n if (!code.match(/allocation:\\s*{/)) {\n warnings.push('ExperimentSpec missing allocation configuration');\n }\n}\n\nfunction validateAppConfigSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*AppBlueprintSpec\\s*=/)) {\n errors.push('Missing AppBlueprintSpec type annotation');\n }\n if (!code.includes('meta:')) {\n errors.push('AppBlueprintSpec must define meta');\n }\n if (!code.includes('appId')) {\n warnings.push('AppBlueprint meta missing appId assignment');\n }\n if (!code.includes('capabilities')) {\n warnings.push('App blueprint spec does not declare capabilities');\n }\n}\n\n/**\n * Validate event spec\n */\nfunction validateEventSpec(code: string, errors: string[], warnings: string[]) {\n if (!code.includes('defineEvent')) {\n errors.push('Missing defineEvent call');\n }\n\n if (!code.match(/name:\\s*['\"][^'\"]+['\"]/)) {\n errors.push('Missing or invalid name field');\n }\n\n if (!code.match(/version:\\s*\\d+/)) {\n errors.push('Missing or invalid version field');\n }\n\n if (!code.includes('payload:')) {\n errors.push('Missing payload field');\n }\n\n // Check for past tense naming convention\n const nameMatch = code.match(/name:\\s*['\"]([^'\"]+)['\"]/);\n if (nameMatch?.[1]) {\n const eventName = nameMatch[1].split('.').pop() ?? '';\n if (!eventName.match(/(ed|created|updated|deleted|completed)$/i)) {\n warnings.push(\n 'Event name should use past tense (e.g., \"created\", \"updated\")'\n );\n }\n }\n}\n\n/**\n * Validate presentation spec\n */\nfunction validatePresentationSpec(\n code: string,\n errors: string[],\n _warnings: string[]\n) {\n if (!code.match(/:\\s*PresentationSpec\\s*=/)) {\n errors.push('Missing PresentationSpec type annotation');\n }\n\n if (!code.includes('meta:')) {\n errors.push('Missing meta section');\n }\n\n if (!code.includes('content:')) {\n errors.push('Missing content section');\n }\n\n if (!code.match(/kind:\\s*['\"](?:web_component|markdown|data)['\"]/)) {\n errors.push('Missing or invalid kind field');\n }\n}\n\nfunction validateWorkflowSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*WorkflowSpec\\s*=/)) {\n errors.push('Missing WorkflowSpec type annotation');\n }\n\n if (!code.includes('definition:')) {\n errors.push('Missing definition section');\n }\n\n if (!code.includes('steps:')) {\n errors.push('Workflow must declare steps');\n }\n\n if (!code.includes('transitions:')) {\n warnings.push(\n 'No transitions declared; workflow will complete after first step.'\n );\n }\n\n if (!code.match(/title:\\s*['\"][^'\"]+['\"]/)) {\n warnings.push('Missing workflow title');\n }\n\n if (!code.match(/domain:\\s*['\"][^'\"]+['\"]/)) {\n warnings.push('Missing domain field');\n }\n\n if (code.includes('TODO')) {\n warnings.push('Contains TODO items that need completion');\n }\n}\n\nfunction validateMigrationSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*MigrationSpec\\s*=/)) {\n errors.push('Missing MigrationSpec type annotation');\n }\n\n if (!code.includes('plan:')) {\n errors.push('Missing plan section');\n } else {\n if (!code.includes('up:')) {\n errors.push('Migration must define at least one up step');\n }\n }\n\n if (!code.match(/name:\\s*['\"][^'\"]+['\"]/)) {\n errors.push('Missing or invalid migration name');\n }\n\n if (!code.match(/version:\\s*\\d+/)) {\n errors.push('Missing or invalid migration version');\n }\n\n if (code.includes('TODO')) {\n warnings.push('Contains TODO items that need completion');\n }\n}\n\n/**\n * Validate common fields across all spec types\n */\nfunction validateCommonFields(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n // Check for SchemaModel import\n if (\n code.includes('SchemaModel') &&\n !code.includes(\"from '@lssm/lib.schema'\")\n ) {\n errors.push('Missing import for SchemaModel from @lssm/lib.schema');\n }\n\n // Check for contracts import\n if (!code.includes(\"from '@lssm/lib.contracts'\")) {\n errors.push('Missing import from @lssm/lib.contracts');\n }\n\n // Check owners format\n const ownersMatch = code.match(/owners:\\s*\\[(.*?)\\]/s);\n if (ownersMatch?.[1]) {\n const ownersContent = ownersMatch[1];\n if (!ownersContent.includes('@')) {\n warnings.push('Owners should start with @ (e.g., \"@team\")');\n }\n }\n\n // Check for stability\n if (\n !code.match(/stability:\\s*['\"](?:experimental|beta|stable|deprecated)['\"]/)\n ) {\n warnings.push('Missing or invalid stability field');\n }\n}\n\nfunction validateDataViewSpec(\n code: string,\n errors: string[],\n _warnings: string[]\n) {\n if (!code.match(/:\\s*DataViewSpec\\s*=/)) {\n errors.push('Missing DataViewSpec type annotation');\n }\n if (!code.includes('meta:')) {\n errors.push('Missing meta section');\n }\n if (!code.includes('source:')) {\n errors.push('Missing source section');\n }\n if (!code.includes('view:')) {\n errors.push('Missing view section');\n }\n if (!code.match(/kind:\\s*['\"](list|table|detail|grid)['\"]/)) {\n errors.push('Missing or invalid view.kind (list/table/detail/grid)');\n }\n if (!code.match(/fields:\\s*\\[/)) {\n // Note: _warnings unused in this case, but kept for consistency with other validators\n errors.push('No fields defined for data view');\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"spec-structure.js","names":["errors: string[]","warnings: string[]"],"sources":["../../../src/analysis/validate/spec-structure.ts"],"sourcesContent":["/**\n * Spec structure validation utilities.\n * Extracted from cli-contracts/src/commands/validate/spec-checker.ts\n */\n\nimport type { ValidationResult } from '../../types/analysis-types';\n\nexport type { ValidationResult };\n\n/**\n * Validate spec structure based on source code and filename.\n */\nexport function validateSpecStructure(\n code: string,\n fileName: string\n): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Check for required exports\n const hasExport = /export\\s+(const|let)\\s+\\w+/.test(code);\n if (!hasExport) {\n errors.push('No exported spec found');\n }\n\n // Validate operation specs\n if (\n fileName.includes('.contracts.') ||\n fileName.includes('.contract.') ||\n fileName.includes('.operations.') ||\n fileName.includes('.operation.')\n ) {\n validateOperationSpec(code, errors, warnings);\n }\n\n // Validate event specs\n if (fileName.includes('.event.')) {\n validateEventSpec(code, errors, warnings);\n }\n\n // Validate presentation specs\n if (fileName.includes('.presentation.')) {\n validatePresentationSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.workflow.')) {\n validateWorkflowSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.data-view.')) {\n validateDataViewSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.migration.')) {\n validateMigrationSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.telemetry.')) {\n validateTelemetrySpec(code, errors, warnings);\n }\n\n if (fileName.includes('.experiment.')) {\n validateExperimentSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.app-config.')) {\n validateAppConfigSpec(code, errors, warnings);\n }\n\n // Common validations\n validateCommonFields(code, errors, warnings);\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/**\n * Validate operation spec\n */\nfunction validateOperationSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n // Check for defineCommand or defineQuery\n const hasDefine = /define(Command|Query)/.test(code);\n if (!hasDefine) {\n errors.push('Missing defineCommand or defineQuery call');\n }\n\n // Check for required meta fields\n if (!code.includes('meta:')) {\n errors.push('Missing meta section');\n }\n\n if (!code.includes('io:')) {\n errors.push('Missing io section');\n }\n\n if (!code.includes('policy:')) {\n errors.push('Missing policy section');\n }\n\n // Check for name\n if (!code.match(/name:\\s*['\"][^'\"]+['\"]/)) {\n errors.push('Missing or invalid name field');\n }\n\n // Check for version\n if (!code.match(/version:\\s*\\d+/)) {\n errors.push('Missing or invalid version field');\n }\n\n // Check for kind (defineCommand/defineQuery set it automatically, or explicit kind field)\n const hasDefineCommand = /defineCommand\\s*\\(/.test(code);\n const hasDefineQuery = /defineQuery\\s*\\(/.test(code);\n const hasExplicitKind = /kind:\\s*['\"](?:command|query)['\"]/.test(code);\n if (!hasDefineCommand && !hasDefineQuery && !hasExplicitKind) {\n errors.push(\n 'Missing kind: use defineCommand(), defineQuery(), or explicit kind field'\n );\n }\n\n // Warnings\n if (!code.includes('acceptance:')) {\n warnings.push('No acceptance scenarios defined');\n }\n\n if (!code.includes('examples:')) {\n warnings.push('No examples provided');\n }\n\n if (code.includes('TODO')) {\n warnings.push('Contains TODO items that need completion');\n }\n}\n\nfunction validateTelemetrySpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*TelemetrySpec\\s*=/)) {\n errors.push('Missing TelemetrySpec type annotation');\n }\n\n if (!code.match(/meta:\\s*{[\\s\\S]*name:/)) {\n errors.push('TelemetrySpec.meta is required');\n }\n\n if (!code.includes('events:')) {\n errors.push('TelemetrySpec must declare events');\n }\n\n if (!code.match(/privacy:\\s*'(public|internal|pii|sensitive)'/)) {\n warnings.push('No explicit privacy classification found');\n }\n}\n\nfunction validateExperimentSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*ExperimentSpec\\s*=/)) {\n errors.push('Missing ExperimentSpec type annotation');\n }\n if (!code.includes('controlVariant')) {\n errors.push('ExperimentSpec must declare controlVariant');\n }\n if (!code.includes('variants:')) {\n errors.push('ExperimentSpec must declare variants');\n }\n if (!code.match(/allocation:\\s*{/)) {\n warnings.push('ExperimentSpec missing allocation configuration');\n }\n}\n\nfunction validateAppConfigSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*AppBlueprintSpec\\s*=/)) {\n errors.push('Missing AppBlueprintSpec type annotation');\n }\n if (!code.includes('meta:')) {\n errors.push('AppBlueprintSpec must define meta');\n }\n if (!code.includes('appId')) {\n warnings.push('AppBlueprint meta missing appId assignment');\n }\n if (!code.includes('capabilities')) {\n warnings.push('App blueprint spec does not declare capabilities');\n }\n}\n\n/**\n * Validate event spec\n */\nfunction validateEventSpec(code: string, errors: string[], warnings: string[]) {\n if (!code.includes('defineEvent')) {\n errors.push('Missing defineEvent call');\n }\n\n if (!code.match(/name:\\s*['\"][^'\"]+['\"]/)) {\n errors.push('Missing or invalid name field');\n }\n\n if (!code.match(/version:\\s*\\d+/)) {\n errors.push('Missing or invalid version field');\n }\n\n if (!code.includes('payload:')) {\n errors.push('Missing payload field');\n }\n\n // Check for past tense naming convention\n const nameMatch = code.match(/name:\\s*['\"]([^'\"]+)['\"]/);\n if (nameMatch?.[1]) {\n const eventName = nameMatch[1].split('.').pop() ?? '';\n if (!eventName.match(/(ed|created|updated|deleted|completed)$/i)) {\n warnings.push(\n 'Event name should use past tense (e.g., \"created\", \"updated\")'\n );\n }\n }\n}\n\n/**\n * Validate presentation spec\n */\nfunction validatePresentationSpec(\n code: string,\n errors: string[],\n _warnings: string[]\n) {\n if (!code.match(/:\\s*PresentationSpec\\s*=/)) {\n errors.push('Missing PresentationSpec type annotation');\n }\n\n if (!code.includes('meta:')) {\n errors.push('Missing meta section');\n }\n\n if (!code.includes('content:')) {\n errors.push('Missing content section');\n }\n\n if (!code.match(/kind:\\s*['\"](?:web_component|markdown|data)['\"]/)) {\n errors.push('Missing or invalid kind field');\n }\n}\n\nfunction validateWorkflowSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*WorkflowSpec\\s*=/)) {\n errors.push('Missing WorkflowSpec type annotation');\n }\n\n if (!code.includes('definition:')) {\n errors.push('Missing definition section');\n }\n\n if (!code.includes('steps:')) {\n errors.push('Workflow must declare steps');\n }\n\n if (!code.includes('transitions:')) {\n warnings.push(\n 'No transitions declared; workflow will complete after first step.'\n );\n }\n\n if (!code.match(/title:\\s*['\"][^'\"]+['\"]/)) {\n warnings.push('Missing workflow title');\n }\n\n if (!code.match(/domain:\\s*['\"][^'\"]+['\"]/)) {\n warnings.push('Missing domain field');\n }\n\n if (code.includes('TODO')) {\n warnings.push('Contains TODO items that need completion');\n }\n}\n\nfunction validateMigrationSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*MigrationSpec\\s*=/)) {\n errors.push('Missing MigrationSpec type annotation');\n }\n\n if (!code.includes('plan:')) {\n errors.push('Missing plan section');\n } else {\n if (!code.includes('up:')) {\n errors.push('Migration must define at least one up step');\n }\n }\n\n if (!code.match(/name:\\s*['\"][^'\"]+['\"]/)) {\n errors.push('Missing or invalid migration name');\n }\n\n if (!code.match(/version:\\s*\\d+/)) {\n errors.push('Missing or invalid migration version');\n }\n\n if (code.includes('TODO')) {\n warnings.push('Contains TODO items that need completion');\n }\n}\n\n/**\n * Validate common fields across all spec types\n */\nfunction validateCommonFields(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n // Check for SchemaModel import\n if (\n code.includes('SchemaModel') &&\n !code.includes(\"from '@lssm/lib.schema'\")\n ) {\n errors.push('Missing import for SchemaModel from @lssm/lib.schema');\n }\n\n // Check for contracts import\n if (!code.includes(\"from '@lssm/lib.contracts'\")) {\n errors.push('Missing import from @lssm/lib.contracts');\n }\n\n // Check owners format\n const ownersMatch = code.match(/owners:\\s*\\[(.*?)\\]/s);\n if (ownersMatch?.[1]) {\n const ownersContent = ownersMatch[1];\n if (!ownersContent.includes('@')) {\n warnings.push('Owners should start with @ (e.g., \"@team\")');\n }\n }\n\n // Check for stability\n if (\n !code.match(/stability:\\s*['\"](?:experimental|beta|stable|deprecated)['\"]/)\n ) {\n warnings.push('Missing or invalid stability field');\n }\n}\n\nfunction validateDataViewSpec(\n code: string,\n errors: string[],\n _warnings: string[]\n) {\n if (!code.match(/:\\s*DataViewSpec\\s*=/)) {\n errors.push('Missing DataViewSpec type annotation');\n }\n if (!code.includes('meta:')) {\n errors.push('Missing meta section');\n }\n if (!code.includes('source:')) {\n errors.push('Missing source section');\n }\n if (!code.includes('view:')) {\n errors.push('Missing view section');\n }\n if (!code.match(/kind:\\s*['\"](list|table|detail|grid)['\"]/)) {\n errors.push('Missing or invalid view.kind (list/table/detail/grid)');\n }\n if (!code.match(/fields:\\s*\\[/)) {\n // Note: _warnings unused in this case, but kept for consistency with other validators\n errors.push('No fields defined for data view');\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { AnalyzedOperationKind, AnalyzedSpecType, ContractGraph, ContractNode, E
|
|
|
3
3
|
import { AIGenerationOptions, CodeGenerationContext, DEFAULT_WORKSPACE_CONFIG, GenerationResult, GenerationTarget, SpecBuildType, SpecGenerationContext, TestTarget, WorkspaceConfig } from "./types/generation-types.js";
|
|
4
4
|
import { extractEmittedEvents, extractPolicyRefs, extractTestRefs, inferSpecTypeFromFilePath, scanAllSpecsFromSource, scanSpecSource } from "./analysis/spec-scan.js";
|
|
5
5
|
import { isFeatureFile, scanFeatureSource } from "./analysis/feature-scan.js";
|
|
6
|
+
import { GroupKeyFn, GroupedItems, SpecFilter, SpecGroupingStrategies, filterFeatures, filterSpecs, getUniqueSpecDomains, getUniqueSpecOwners, getUniqueSpecTags, groupSpecs, groupSpecsToArray } from "./analysis/grouping.js";
|
|
6
7
|
import { computeSemanticDiff } from "./analysis/diff/semantic.js";
|
|
7
8
|
import { addContractNode, buildReverseEdges, createContractGraph, detectCycles, findMissingDependencies, toDot } from "./analysis/deps/graph.js";
|
|
8
9
|
import { parseImportedSpecNames } from "./analysis/deps/parse-imports.js";
|
|
@@ -23,4 +24,4 @@ import { generateComponentTemplate, generateHandlerTemplate, generateTestTemplat
|
|
|
23
24
|
import { capitalize, escapeString, toCamelCase, toKebabCase, toPascalCase } from "./templates/utils.js";
|
|
24
25
|
import { addExampleContext, buildEventSpecPrompt, buildOperationSpecPrompt, buildPresentationSpecPrompt, getSystemPrompt } from "./ai/spec-creation.js";
|
|
25
26
|
import { buildComponentPrompt, buildFormPrompt, buildHandlerPrompt, buildTestPrompt, getCodeGenSystemPrompt } from "./ai/code-generation.js";
|
|
26
|
-
export { AIGenerationOptions, AnalyzedOperationKind, AnalyzedSpecType, AppBlueprintSpecData, AppConfigFeatureFlagData, AppConfigMappingData, AppRouteConfigData, BaseSpecData, CodeGenerationContext, ContractGraph, ContractNode, DEFAULT_WORKSPACE_CONFIG, DataViewFieldData, DataViewKind, DataViewSpecData, EventSpecData, ExperimentAllocationData, ExperimentMetricData, ExperimentSpecData, ExperimentVariantData, ExperimentVariantOverrideData, ExtractedRef, FeatureScanResult, FeatureSpecData, FormSpecData, GenerationResult, GenerationTarget, IntegrationCapabilityRefData, IntegrationCapabilityRequirementData, IntegrationCategoryData, IntegrationConfigFieldData, IntegrationConfigFieldType, IntegrationHealthCheckMethod, IntegrationOwnershipModeData, IntegrationSecretFieldData, IntegrationSpecData, KnowledgeCategoryData, KnowledgeRetentionData, KnowledgeSpaceSpecData, KnowledgeTrustLevel, MigrationSpecData, MigrationStepData, MigrationStepKind, OpKind, OperationSpecData, PresentationKind, PresentationSpecData, RandomAllocationData, RefInfo, RefType, SemanticDiffItem, SemanticDiffOptions, SemanticDiffType, SpecBuildType, SpecGenerationContext, SpecScanResult, SpecType, Stability, StepType, StickyAllocationData, TargetedAllocationData, TargetingRuleData, TelemetryAnomalyRuleData, TelemetryEventData, TelemetryPrivacy, TelemetryPropertyData, TelemetryProviderData, TelemetrySpecData, TestTarget, ValidationResult, WorkflowSpecData, WorkflowStepData, WorkflowTransitionData, WorkspaceConfig, addContractNode, addExampleContext, buildComponentPrompt, buildEventSpecPrompt, buildFormPrompt, buildHandlerPrompt, buildOperationSpecPrompt, buildPresentationSpecPrompt, buildReverseEdges, buildTestPrompt, capitalize, computeSemanticDiff, createContractGraph, detectCycles, escapeString, extractEmittedEvents, extractPolicyRefs, extractTestRefs, findMissingDependencies, generateAppBlueprintSpec, generateComponentTemplate, generateDataViewSpec, generateEventSpec, generateExperimentSpec, generateHandlerTemplate, generateIntegrationSpec, generateKnowledgeSpaceSpec, generateMigrationSpec, generateOperationSpec, generatePresentationSpec, generateTelemetrySpec, generateTestTemplate, generateWorkflowRunnerTemplate, generateWorkflowSpec, getCodeGenSystemPrompt, getSystemPrompt, inferSpecTypeFromFilePath, isFeatureFile, parseImportedSpecNames, scanAllSpecsFromSource, scanFeatureSource, scanSpecSource, toCamelCase, toDot, toKebabCase, toPascalCase, validateSpecStructure };
|
|
27
|
+
export { AIGenerationOptions, AnalyzedOperationKind, AnalyzedSpecType, AppBlueprintSpecData, AppConfigFeatureFlagData, AppConfigMappingData, AppRouteConfigData, BaseSpecData, CodeGenerationContext, ContractGraph, ContractNode, DEFAULT_WORKSPACE_CONFIG, DataViewFieldData, DataViewKind, DataViewSpecData, EventSpecData, ExperimentAllocationData, ExperimentMetricData, ExperimentSpecData, ExperimentVariantData, ExperimentVariantOverrideData, ExtractedRef, FeatureScanResult, FeatureSpecData, FormSpecData, GenerationResult, GenerationTarget, GroupKeyFn, GroupedItems, IntegrationCapabilityRefData, IntegrationCapabilityRequirementData, IntegrationCategoryData, IntegrationConfigFieldData, IntegrationConfigFieldType, IntegrationHealthCheckMethod, IntegrationOwnershipModeData, IntegrationSecretFieldData, IntegrationSpecData, KnowledgeCategoryData, KnowledgeRetentionData, KnowledgeSpaceSpecData, KnowledgeTrustLevel, MigrationSpecData, MigrationStepData, MigrationStepKind, OpKind, OperationSpecData, PresentationKind, PresentationSpecData, RandomAllocationData, RefInfo, RefType, SemanticDiffItem, SemanticDiffOptions, SemanticDiffType, SpecBuildType, SpecFilter, SpecGenerationContext, SpecGroupingStrategies, SpecScanResult, SpecType, Stability, StepType, StickyAllocationData, TargetedAllocationData, TargetingRuleData, TelemetryAnomalyRuleData, TelemetryEventData, TelemetryPrivacy, TelemetryPropertyData, TelemetryProviderData, TelemetrySpecData, TestTarget, ValidationResult, WorkflowSpecData, WorkflowStepData, WorkflowTransitionData, WorkspaceConfig, addContractNode, addExampleContext, buildComponentPrompt, buildEventSpecPrompt, buildFormPrompt, buildHandlerPrompt, buildOperationSpecPrompt, buildPresentationSpecPrompt, buildReverseEdges, buildTestPrompt, capitalize, computeSemanticDiff, createContractGraph, detectCycles, escapeString, extractEmittedEvents, extractPolicyRefs, extractTestRefs, filterFeatures, filterSpecs, findMissingDependencies, generateAppBlueprintSpec, generateComponentTemplate, generateDataViewSpec, generateEventSpec, generateExperimentSpec, generateHandlerTemplate, generateIntegrationSpec, generateKnowledgeSpaceSpec, generateMigrationSpec, generateOperationSpec, generatePresentationSpec, generateTelemetrySpec, generateTestTemplate, generateWorkflowRunnerTemplate, generateWorkflowSpec, getCodeGenSystemPrompt, getSystemPrompt, getUniqueSpecDomains, getUniqueSpecOwners, getUniqueSpecTags, groupSpecs, groupSpecsToArray, inferSpecTypeFromFilePath, isFeatureFile, parseImportedSpecNames, scanAllSpecsFromSource, scanFeatureSource, scanSpecSource, toCamelCase, toDot, toKebabCase, toPascalCase, validateSpecStructure };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_WORKSPACE_CONFIG } from "./types/generation-types.js";
|
|
2
2
|
import { extractEmittedEvents, extractPolicyRefs, extractTestRefs, inferSpecTypeFromFilePath, scanAllSpecsFromSource, scanSpecSource } from "./analysis/spec-scan.js";
|
|
3
3
|
import { isFeatureFile, scanFeatureSource } from "./analysis/feature-scan.js";
|
|
4
|
+
import { SpecGroupingStrategies, filterFeatures, filterSpecs, getUniqueSpecDomains, getUniqueSpecOwners, getUniqueSpecTags, groupSpecs, groupSpecsToArray } from "./analysis/grouping.js";
|
|
4
5
|
import { computeSemanticDiff } from "./analysis/diff/semantic.js";
|
|
5
6
|
import { addContractNode, buildReverseEdges, createContractGraph, detectCycles, findMissingDependencies, toDot } from "./analysis/deps/graph.js";
|
|
6
7
|
import { parseImportedSpecNames } from "./analysis/deps/parse-imports.js";
|
|
@@ -22,4 +23,4 @@ import { generateComponentTemplate, generateHandlerTemplate, generateTestTemplat
|
|
|
22
23
|
import { addExampleContext, buildEventSpecPrompt, buildOperationSpecPrompt, buildPresentationSpecPrompt, getSystemPrompt } from "./ai/spec-creation.js";
|
|
23
24
|
import { buildComponentPrompt, buildFormPrompt, buildHandlerPrompt, buildTestPrompt, getCodeGenSystemPrompt } from "./ai/code-generation.js";
|
|
24
25
|
|
|
25
|
-
export { DEFAULT_WORKSPACE_CONFIG, addContractNode, addExampleContext, buildComponentPrompt, buildEventSpecPrompt, buildFormPrompt, buildHandlerPrompt, buildOperationSpecPrompt, buildPresentationSpecPrompt, buildReverseEdges, buildTestPrompt, capitalize, computeSemanticDiff, createContractGraph, detectCycles, escapeString, extractEmittedEvents, extractPolicyRefs, extractTestRefs, findMissingDependencies, generateAppBlueprintSpec, generateComponentTemplate, generateDataViewSpec, generateEventSpec, generateExperimentSpec, generateHandlerTemplate, generateIntegrationSpec, generateKnowledgeSpaceSpec, generateMigrationSpec, generateOperationSpec, generatePresentationSpec, generateTelemetrySpec, generateTestTemplate, generateWorkflowRunnerTemplate, generateWorkflowSpec, getCodeGenSystemPrompt, getSystemPrompt, inferSpecTypeFromFilePath, isFeatureFile, parseImportedSpecNames, scanAllSpecsFromSource, scanFeatureSource, scanSpecSource, toCamelCase, toDot, toKebabCase, toPascalCase, validateSpecStructure };
|
|
26
|
+
export { DEFAULT_WORKSPACE_CONFIG, SpecGroupingStrategies, addContractNode, addExampleContext, buildComponentPrompt, buildEventSpecPrompt, buildFormPrompt, buildHandlerPrompt, buildOperationSpecPrompt, buildPresentationSpecPrompt, buildReverseEdges, buildTestPrompt, capitalize, computeSemanticDiff, createContractGraph, detectCycles, escapeString, extractEmittedEvents, extractPolicyRefs, extractTestRefs, filterFeatures, filterSpecs, findMissingDependencies, generateAppBlueprintSpec, generateComponentTemplate, generateDataViewSpec, generateEventSpec, generateExperimentSpec, generateHandlerTemplate, generateIntegrationSpec, generateKnowledgeSpaceSpec, generateMigrationSpec, generateOperationSpec, generatePresentationSpec, generateTelemetrySpec, generateTestTemplate, generateWorkflowRunnerTemplate, generateWorkflowSpec, getCodeGenSystemPrompt, getSystemPrompt, getUniqueSpecDomains, getUniqueSpecOwners, getUniqueSpecTags, groupSpecs, groupSpecsToArray, inferSpecTypeFromFilePath, isFeatureFile, parseImportedSpecNames, scanAllSpecsFromSource, scanFeatureSource, scanSpecSource, toCamelCase, toDot, toKebabCase, toPascalCase, validateSpecStructure };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lssm/module.contractspec-workspace",
|
|
3
|
-
"version": "0.0.0-canary-
|
|
3
|
+
"version": "0.0.0-canary-20251221132705",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
"test": "bun run"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@lssm/lib.contracts": "0.0.0-canary-
|
|
27
|
-
"@lssm/lib.schema": "0.0.0-canary-
|
|
26
|
+
"@lssm/lib.contracts": "0.0.0-canary-20251221132705",
|
|
27
|
+
"@lssm/lib.schema": "0.0.0-canary-20251221132705",
|
|
28
28
|
"zod": "^4.1.13"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@lssm/tool.tsdown": "0.0.0-canary-
|
|
32
|
-
"@lssm/tool.typescript": "0.0.0-canary-
|
|
31
|
+
"@lssm/tool.tsdown": "0.0.0-canary-20251221132705",
|
|
32
|
+
"@lssm/tool.typescript": "0.0.0-canary-20251221132705",
|
|
33
33
|
"tsdown": "^0.18.1",
|
|
34
34
|
"typescript": "^5.9.3"
|
|
35
35
|
},
|