@facet-coverage/core 0.1.0 → 0.3.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 (37) hide show
  1. package/README.md +296 -48
  2. package/dist/cli/commands/analyze.d.ts.map +1 -1
  3. package/dist/cli/commands/analyze.js +2 -35
  4. package/dist/cli/commands/analyze.js.map +1 -1
  5. package/dist/cli/commands/generate.d.ts +6 -2
  6. package/dist/cli/commands/generate.d.ts.map +1 -1
  7. package/dist/cli/commands/generate.js +371 -9
  8. package/dist/cli/commands/generate.js.map +1 -1
  9. package/dist/cli/commands/validate.d.ts.map +1 -1
  10. package/dist/cli/commands/validate.js +2 -34
  11. package/dist/cli/commands/validate.js.map +1 -1
  12. package/dist/cli/commands/watch.d.ts.map +1 -1
  13. package/dist/cli/commands/watch.js +2 -34
  14. package/dist/cli/commands/watch.js.map +1 -1
  15. package/dist/cli/index.js +9 -5
  16. package/dist/cli/index.js.map +1 -1
  17. package/dist/cli/utils/config.d.ts +15 -0
  18. package/dist/cli/utils/config.d.ts.map +1 -0
  19. package/dist/cli/utils/config.js +88 -0
  20. package/dist/cli/utils/config.js.map +1 -0
  21. package/dist/core/FacetParser.d.ts +18 -1
  22. package/dist/core/FacetParser.d.ts.map +1 -1
  23. package/dist/core/FacetParser.js +45 -3
  24. package/dist/core/FacetParser.js.map +1 -1
  25. package/dist/core/IDChangeDetector.d.ts +50 -0
  26. package/dist/core/IDChangeDetector.d.ts.map +1 -0
  27. package/dist/core/IDChangeDetector.js +147 -0
  28. package/dist/core/IDChangeDetector.js.map +1 -0
  29. package/dist/core/TestScanner.d.ts +10 -1
  30. package/dist/core/TestScanner.d.ts.map +1 -1
  31. package/dist/core/TestScanner.js +124 -6
  32. package/dist/core/TestScanner.js.map +1 -1
  33. package/dist/types.d.ts +7 -1
  34. package/dist/types.d.ts.map +1 -1
  35. package/dist/types.js +2 -0
  36. package/dist/types.js.map +1 -1
  37. package/package.json +1 -1
@@ -0,0 +1,15 @@
1
+ import type { FacetConfig } from '../../types.js';
2
+ /**
3
+ * Load configuration from file or use defaults.
4
+ * Supports .js, .mjs, and .json config formats.
5
+ *
6
+ * @param configPath - Optional explicit path to config file
7
+ * @param cwd - Current working directory
8
+ * @returns Merged configuration with defaults
9
+ */
10
+ export declare function loadConfig(configPath: string | undefined, cwd: string): Promise<FacetConfig>;
11
+ /**
12
+ * Get the resolved config file path if one exists.
13
+ */
14
+ export declare function findConfigFile(cwd: string): string | null;
15
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAYlD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,WAAW,CAAC,CA0BtB;AA6BD;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQzD"}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadConfig = loadConfig;
4
+ exports.findConfigFile = findConfigFile;
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ const types_js_1 = require("../../types.js");
8
+ /**
9
+ * Configuration file names to search for (in order of priority)
10
+ */
11
+ const CONFIG_FILE_NAMES = [
12
+ 'facet.config.js',
13
+ 'facet.config.mjs',
14
+ 'facet.config.json',
15
+ ];
16
+ /**
17
+ * Load configuration from file or use defaults.
18
+ * Supports .js, .mjs, and .json config formats.
19
+ *
20
+ * @param configPath - Optional explicit path to config file
21
+ * @param cwd - Current working directory
22
+ * @returns Merged configuration with defaults
23
+ */
24
+ async function loadConfig(configPath, cwd) {
25
+ const configFiles = [
26
+ configPath,
27
+ ...CONFIG_FILE_NAMES,
28
+ ].filter(Boolean);
29
+ for (const file of configFiles) {
30
+ const fullPath = (0, path_1.resolve)(cwd, file);
31
+ if ((0, fs_1.existsSync)(fullPath)) {
32
+ if (file.endsWith('.json')) {
33
+ const content = (0, fs_1.readFileSync)(fullPath, 'utf-8');
34
+ return mergeConfig(JSON.parse(content));
35
+ }
36
+ else {
37
+ // Dynamic import for JS/MJS config
38
+ try {
39
+ const imported = await import(fullPath);
40
+ return mergeConfig(imported.default || imported);
41
+ }
42
+ catch (error) {
43
+ console.warn(`Warning: Could not load config from ${file}`);
44
+ }
45
+ }
46
+ }
47
+ }
48
+ return types_js_1.defaultConfig;
49
+ }
50
+ /**
51
+ * Deep merge user config with defaults.
52
+ * Ensures nested objects like validation, output, and thresholds are properly merged.
53
+ */
54
+ function mergeConfig(userConfig) {
55
+ return {
56
+ ...types_js_1.defaultConfig,
57
+ ...userConfig,
58
+ validation: {
59
+ ...types_js_1.defaultConfig.validation,
60
+ ...userConfig.validation,
61
+ },
62
+ output: {
63
+ ...types_js_1.defaultConfig.output,
64
+ ...userConfig.output,
65
+ },
66
+ thresholds: {
67
+ ...types_js_1.defaultConfig.thresholds,
68
+ ...userConfig.thresholds,
69
+ byType: {
70
+ ...types_js_1.defaultConfig.thresholds.byType,
71
+ ...userConfig.thresholds?.byType,
72
+ },
73
+ },
74
+ };
75
+ }
76
+ /**
77
+ * Get the resolved config file path if one exists.
78
+ */
79
+ function findConfigFile(cwd) {
80
+ for (const file of CONFIG_FILE_NAMES) {
81
+ const fullPath = (0, path_1.resolve)(cwd, file);
82
+ if ((0, fs_1.existsSync)(fullPath)) {
83
+ return fullPath;
84
+ }
85
+ }
86
+ return null;
87
+ }
88
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/cli/utils/config.ts"],"names":[],"mappings":";;AAsBA,gCA6BC;AAgCD,wCAQC;AA3FD,2BAA8C;AAC9C,+BAA+B;AAE/B,6CAA+C;AAE/C;;GAEG;AACH,MAAM,iBAAiB,GAAG;IACxB,iBAAiB;IACjB,kBAAkB;IAClB,mBAAmB;CACpB,CAAC;AAEF;;;;;;;GAOG;AACI,KAAK,UAAU,UAAU,CAC9B,UAA8B,EAC9B,GAAW;IAEX,MAAM,WAAW,GAAG;QAClB,UAAU;QACV,GAAG,iBAAiB;KACrB,CAAC,MAAM,CAAC,OAAO,CAAa,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,IAAA,cAAO,EAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAEpC,IAAI,IAAA,eAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3B,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAChD,OAAO,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YAC1C,CAAC;iBAAM,CAAC;gBACN,mCAAmC;gBACnC,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;oBACxC,OAAO,WAAW,CAAC,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,CAAC;gBACnD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,IAAI,CAAC,uCAAuC,IAAI,EAAE,CAAC,CAAC;gBAC9D,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,wBAAa,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAAC,UAAgC;IACnD,OAAO;QACL,GAAG,wBAAa;QAChB,GAAG,UAAU;QACb,UAAU,EAAE;YACV,GAAG,wBAAa,CAAC,UAAU;YAC3B,GAAG,UAAU,CAAC,UAAU;SACzB;QACD,MAAM,EAAE;YACN,GAAG,wBAAa,CAAC,MAAM;YACvB,GAAG,UAAU,CAAC,MAAM;SACrB;QACD,UAAU,EAAE;YACV,GAAG,wBAAa,CAAC,UAAU;YAC3B,GAAG,UAAU,CAAC,UAAU;YACxB,MAAM,EAAE;gBACN,GAAG,wBAAa,CAAC,UAAU,CAAC,MAAM;gBAClC,GAAG,UAAU,CAAC,UAAU,EAAE,MAAM;aACjC;SACF;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,GAAW;IACxC,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAA,cAAO,EAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACpC,IAAI,IAAA,eAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,QAAQ,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -28,12 +28,29 @@ export declare class FacetParser {
28
28
  */
29
29
  getSectionSlugs(filePath: string): string[];
30
30
  /**
31
- * Extract the filename without extension as a prefix
31
+ * Check if a file uses the .facet.md naming convention
32
+ */
33
+ static isFacetMdFile(filePath: string): boolean;
34
+ /**
35
+ * Extract the filename without extension as a prefix.
36
+ * Handles both naming conventions:
37
+ * - business.facet.md -> "business"
38
+ * - business.md -> "business"
32
39
  */
33
40
  static getFilePrefix(filePath: string): string;
34
41
  /**
35
42
  * Generate facet ID from file and section
36
43
  */
37
44
  static generateFacetId(filePath: string, sectionSlug: string): string;
45
+ /**
46
+ * Generate hierarchical facet ID that includes the path from root.
47
+ * Used for nested feature structures.
48
+ *
49
+ * @param rootDir - The root features directory
50
+ * @param facetFile - The facet markdown file path
51
+ * @param sectionSlug - The section slug
52
+ * @returns ID like "checkout/payments/pci:section-slug" or "business:section-slug"
53
+ */
54
+ static generateHierarchicalFacetId(rootDir: string, facetFile: string, sectionSlug: string): string;
38
55
  }
39
56
  //# sourceMappingURL=FacetParser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FacetParser.d.ts","sourceRoot":"","sources":["../../src/core/FacetParser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEnE;;GAEG;AACH,qBAAa,WAAW;IACtB;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAUrC;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc;IAS3C;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAW,GAAG,cAAc;IAgDpE;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAI9E;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO;IAS7D;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;IAK3C;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAK9C;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM;CAItE"}
1
+ {"version":3,"file":"FacetParser.d.ts","sourceRoot":"","sources":["../../src/core/FacetParser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEnE;;GAEG;AACH,qBAAa,WAAW;IACtB;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAUrC;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc;IAS3C;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAW,GAAG,cAAc;IAoDpE;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAI9E;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO;IAS7D;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;IAK3C;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAI/C;;;;;OAKG;IACH,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAQ9C;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM;IAKrE;;;;;;;;OAQG;IACH,MAAM,CAAC,2BAA2B,CAChC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,MAAM;CAoBV"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FacetParser = void 0;
4
4
  const fs_1 = require("fs");
5
+ const path_1 = require("path");
5
6
  /**
6
7
  * Parses markdown files and extracts sections
7
8
  */
@@ -35,14 +36,17 @@ class FacetParser {
35
36
  const lines = content.split('\n');
36
37
  const sections = [];
37
38
  // First pass: find all headings
39
+ // Supports explicit anchor syntax: ## Heading {#custom-id}
38
40
  const headings = [];
39
41
  for (let i = 0; i < lines.length; i++) {
40
42
  const line = lines[i];
41
- const match = line.match(/^(#{1,6})\s+(.+)$/);
43
+ // Match heading with optional {#anchor-id} at the end
44
+ const match = line.match(/^(#{1,6})\s+(.+?)(?:\s*\{#([a-z0-9-]+)\})?\s*$/);
42
45
  if (match) {
43
46
  headings.push({
44
47
  level: match[1].length,
45
48
  title: match[2].trim(),
49
+ explicitId: match[3] || undefined,
46
50
  line: i + 1, // 1-indexed
47
51
  });
48
52
  }
@@ -58,11 +62,12 @@ class FacetParser {
58
62
  const sectionContent = contentLines.join('\n').trim();
59
63
  sections.push({
60
64
  title: heading.title,
61
- slug: FacetParser.slugify(heading.title),
65
+ slug: heading.explicitId || FacetParser.slugify(heading.title),
62
66
  level: heading.level,
63
67
  startLine,
64
68
  endLine,
65
69
  content: sectionContent,
70
+ explicitId: heading.explicitId,
66
71
  });
67
72
  }
68
73
  return {
@@ -96,10 +101,22 @@ class FacetParser {
96
101
  return parsed.sections.map(s => s.slug);
97
102
  }
98
103
  /**
99
- * Extract the filename without extension as a prefix
104
+ * Check if a file uses the .facet.md naming convention
105
+ */
106
+ static isFacetMdFile(filePath) {
107
+ return filePath.toLowerCase().endsWith('.facet.md');
108
+ }
109
+ /**
110
+ * Extract the filename without extension as a prefix.
111
+ * Handles both naming conventions:
112
+ * - business.facet.md -> "business"
113
+ * - business.md -> "business"
100
114
  */
101
115
  static getFilePrefix(filePath) {
102
116
  const basename = filePath.split('/').pop() || '';
117
+ if (FacetParser.isFacetMdFile(filePath)) {
118
+ return basename.replace(/\.facet\.md$/i, '').toLowerCase();
119
+ }
103
120
  return basename.replace(/\.md$/i, '').toLowerCase();
104
121
  }
105
122
  /**
@@ -109,6 +126,31 @@ class FacetParser {
109
126
  const prefix = FacetParser.getFilePrefix(filePath);
110
127
  return `${prefix}:${sectionSlug}`;
111
128
  }
129
+ /**
130
+ * Generate hierarchical facet ID that includes the path from root.
131
+ * Used for nested feature structures.
132
+ *
133
+ * @param rootDir - The root features directory
134
+ * @param facetFile - The facet markdown file path
135
+ * @param sectionSlug - The section slug
136
+ * @returns ID like "checkout/payments/pci:section-slug" or "business:section-slug"
137
+ */
138
+ static generateHierarchicalFacetId(rootDir, facetFile, sectionSlug) {
139
+ // Get the directory containing the facet file
140
+ const facetDir = (0, path_1.dirname)(facetFile);
141
+ // Calculate relative path from root
142
+ let relativePath = (0, path_1.relative)(rootDir, facetDir);
143
+ // Remove 'facets' directory from the path if present
144
+ relativePath = relativePath
145
+ .split('/')
146
+ .filter((p) => p !== 'facets' && p !== '.')
147
+ .join('/');
148
+ const prefix = FacetParser.getFilePrefix(facetFile);
149
+ if (relativePath) {
150
+ return `${relativePath}/${prefix}:${sectionSlug}`;
151
+ }
152
+ return `${prefix}:${sectionSlug}`;
153
+ }
112
154
  }
113
155
  exports.FacetParser = FacetParser;
114
156
  //# sourceMappingURL=FacetParser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FacetParser.js","sourceRoot":"","sources":["../../src/core/FacetParser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FacetParser.js","sourceRoot":"","sources":["../../src/core/FacetParser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import type { Facet, TestLink } from '../types.js';
2
+ import type { TestScanner } from './TestScanner.js';
3
+ /**
4
+ * Represents a single ID change
5
+ */
6
+ export interface IDChange {
7
+ /** Type of change */
8
+ type: 'added' | 'removed' | 'renamed';
9
+ /** Old facet ID (for removed/renamed) */
10
+ oldId?: string;
11
+ /** New facet ID (for added/renamed) */
12
+ newId?: string;
13
+ /** Source file */
14
+ file: string;
15
+ /** Section slug */
16
+ section: string;
17
+ /** Facet title */
18
+ title: string;
19
+ }
20
+ /**
21
+ * Report of all ID changes detected
22
+ */
23
+ export interface IDChangeReport {
24
+ /** Whether any changes were detected */
25
+ hasChanges: boolean;
26
+ /** Newly added facet IDs */
27
+ added: IDChange[];
28
+ /** Removed facet IDs */
29
+ removed: IDChange[];
30
+ /** Renamed facet IDs (heading changed but same source location) */
31
+ renamed: IDChange[];
32
+ }
33
+ /**
34
+ * Detects changes in facet IDs between generate runs
35
+ */
36
+ export declare class IDChangeDetector {
37
+ /**
38
+ * Compare new facets with existing structure.json and detect changes
39
+ */
40
+ static detectChanges(existingPath: string, newFacets: Facet[]): IDChangeReport;
41
+ /**
42
+ * Find tests that reference changed/removed facet IDs
43
+ */
44
+ static findAffectedTests(changes: IDChangeReport, scanner: TestScanner, cwd: string): Promise<Map<string, TestLink[]>>;
45
+ /**
46
+ * Format a change report for console output
47
+ */
48
+ static formatReport(report: IDChangeReport): string[];
49
+ }
50
+ //# sourceMappingURL=IDChangeDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IDChangeDetector.d.ts","sourceRoot":"","sources":["../../src/core/IDChangeDetector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAkB,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,qBAAqB;IACrB,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IACtC,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wCAAwC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,4BAA4B;IAC5B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,wBAAwB;IACxB,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,mEAAmE;IACnE,OAAO,EAAE,QAAQ,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,cAAc;IA8F9E;;OAEG;WACU,iBAAiB,CAC5B,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAmBnC;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,EAAE;CAgCtD"}
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IDChangeDetector = void 0;
4
+ const fs_1 = require("fs");
5
+ /**
6
+ * Detects changes in facet IDs between generate runs
7
+ */
8
+ class IDChangeDetector {
9
+ /**
10
+ * Compare new facets with existing structure.json and detect changes
11
+ */
12
+ static detectChanges(existingPath, newFacets) {
13
+ const report = {
14
+ hasChanges: false,
15
+ added: [],
16
+ removed: [],
17
+ renamed: [],
18
+ };
19
+ // If no existing file, all facets are new (but don't report as changes for first-time generation)
20
+ if (!(0, fs_1.existsSync)(existingPath)) {
21
+ return report;
22
+ }
23
+ let existing;
24
+ try {
25
+ existing = JSON.parse((0, fs_1.readFileSync)(existingPath, 'utf-8'));
26
+ }
27
+ catch {
28
+ // If we can't read/parse existing file, treat as first-time generation
29
+ return report;
30
+ }
31
+ // Build maps for comparison
32
+ // Key by ID for direct ID comparison
33
+ const existingById = new Map();
34
+ // Key by source location (file#section) to detect renames
35
+ const existingBySource = new Map();
36
+ for (const facet of existing.facets) {
37
+ existingById.set(facet.id, facet);
38
+ const sourceKey = `${facet.source.file}#${facet.source.section}`;
39
+ existingBySource.set(sourceKey, facet);
40
+ }
41
+ const newById = new Map();
42
+ const newBySource = new Map();
43
+ for (const facet of newFacets) {
44
+ newById.set(facet.id, facet);
45
+ const sourceKey = `${facet.source.file}#${facet.source.section}`;
46
+ newBySource.set(sourceKey, facet);
47
+ }
48
+ // Detect removed and renamed facets
49
+ for (const [id, facet] of existingById) {
50
+ if (!newById.has(id)) {
51
+ // ID no longer exists - check if it was renamed
52
+ const sourceKey = `${facet.source.file}#${facet.source.section}`;
53
+ const newFacet = newBySource.get(sourceKey);
54
+ if (newFacet && newFacet.id !== id) {
55
+ // Same source location but different ID = renamed (heading changed)
56
+ report.renamed.push({
57
+ type: 'renamed',
58
+ oldId: id,
59
+ newId: newFacet.id,
60
+ file: facet.source.file,
61
+ section: facet.source.section,
62
+ title: newFacet.title || '',
63
+ });
64
+ }
65
+ else if (!newFacet) {
66
+ // Source location also gone = removed
67
+ report.removed.push({
68
+ type: 'removed',
69
+ oldId: id,
70
+ file: facet.source.file,
71
+ section: facet.source.section,
72
+ title: facet.title || '',
73
+ });
74
+ }
75
+ }
76
+ }
77
+ // Detect added facets (excluding those that were renames)
78
+ const renamedNewIds = new Set(report.renamed.map(r => r.newId));
79
+ for (const [id, facet] of newById) {
80
+ if (!existingById.has(id) && !renamedNewIds.has(id)) {
81
+ report.added.push({
82
+ type: 'added',
83
+ newId: id,
84
+ file: facet.source.file,
85
+ section: facet.source.section,
86
+ title: facet.title || '',
87
+ });
88
+ }
89
+ }
90
+ report.hasChanges =
91
+ report.added.length > 0 ||
92
+ report.removed.length > 0 ||
93
+ report.renamed.length > 0;
94
+ return report;
95
+ }
96
+ /**
97
+ * Find tests that reference changed/removed facet IDs
98
+ */
99
+ static async findAffectedTests(changes, scanner, cwd) {
100
+ const affected = new Map();
101
+ // Only check removed and renamed (old) IDs
102
+ const changedIds = [
103
+ ...changes.removed.map(c => c.oldId),
104
+ ...changes.renamed.map(c => c.oldId),
105
+ ];
106
+ for (const id of changedIds) {
107
+ const tests = await scanner.getTestsForFacet(id, cwd);
108
+ if (tests.length > 0) {
109
+ affected.set(id, tests);
110
+ }
111
+ }
112
+ return affected;
113
+ }
114
+ /**
115
+ * Format a change report for console output
116
+ */
117
+ static formatReport(report) {
118
+ const lines = [];
119
+ if (report.renamed.length > 0) {
120
+ lines.push('\n Renamed (tests may break):');
121
+ for (const change of report.renamed) {
122
+ lines.push(` ${change.oldId} → ${change.newId}`);
123
+ if (change.title) {
124
+ lines.push(` Title: "${change.title}"`);
125
+ }
126
+ // Extract the section part after the colon for the hint
127
+ const oldSection = change.oldId?.split(':')[1] || change.section;
128
+ lines.push(` 💡 To keep old ID: Add {#${oldSection}} to heading`);
129
+ }
130
+ }
131
+ if (report.removed.length > 0) {
132
+ lines.push('\n Removed:');
133
+ for (const change of report.removed) {
134
+ lines.push(` - ${change.oldId}`);
135
+ }
136
+ }
137
+ if (report.added.length > 0) {
138
+ lines.push('\n Added:');
139
+ for (const change of report.added) {
140
+ lines.push(` + ${change.newId}`);
141
+ }
142
+ }
143
+ return lines;
144
+ }
145
+ }
146
+ exports.IDChangeDetector = IDChangeDetector;
147
+ //# sourceMappingURL=IDChangeDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IDChangeDetector.js","sourceRoot":"","sources":["../../src/core/IDChangeDetector.ts"],"names":[],"mappings":";;;AAAA,2BAA8C;AAoC9C;;GAEG;AACH,MAAa,gBAAgB;IAC3B;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,YAAoB,EAAE,SAAkB;QAC3D,MAAM,MAAM,GAAmB;YAC7B,UAAU,EAAE,KAAK;YACjB,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,EAAE;SACZ,CAAC;QAEF,kGAAkG;QAClG,IAAI,CAAC,IAAA,eAAU,EAAC,YAAY,CAAC,EAAE,CAAC;YAC9B,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,IAAI,QAAwB,CAAC;QAC7B,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,iBAAY,EAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;YACvE,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,4BAA4B;QAC5B,qCAAqC;QACrC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAiB,CAAC;QAC9C,0DAA0D;QAC1D,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAiB,CAAC;QAElD,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YACpC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAClC,MAAM,SAAS,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACjE,gBAAgB,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,GAAG,EAAiB,CAAC;QACzC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAiB,CAAC;QAE7C,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC7B,MAAM,SAAS,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACjE,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC;QAED,oCAAoC;QACpC,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,YAAY,EAAE,CAAC;YACvC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBACrB,gDAAgD;gBAChD,MAAM,SAAS,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjE,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAE5C,IAAI,QAAQ,IAAI,QAAQ,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;oBACnC,oEAAoE;oBACpE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;wBAClB,IAAI,EAAE,SAAS;wBACf,KAAK,EAAE,EAAE;wBACT,KAAK,EAAE,QAAQ,CAAC,EAAE;wBAClB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI;wBACvB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;wBAC7B,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,EAAE;qBAC5B,CAAC,CAAC;gBACL,CAAC;qBAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACrB,sCAAsC;oBACtC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;wBAClB,IAAI,EAAE,SAAS;wBACf,KAAK,EAAE,EAAE;wBACT,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI;wBACvB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;wBAC7B,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE;qBACzB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,0DAA0D;QAC1D,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QAChE,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;YAClC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBACpD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;oBAChB,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,EAAE;oBACT,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI;oBACvB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;oBAC7B,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE;iBACzB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,MAAM,CAAC,UAAU;YACf,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;gBACvB,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;gBACzB,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAE5B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAC5B,OAAuB,EACvB,OAAoB,EACpB,GAAW;QAEX,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAsB,CAAC;QAE/C,2CAA2C;QAC3C,MAAM,UAAU,GAAG;YACjB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAM,CAAC;YACrC,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAM,CAAC;SACtC,CAAC;QAEF,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YACtD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,MAAsB;QACxC,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;YAC/C,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpC,KAAK,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,KAAK,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;gBACtD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;oBACjB,KAAK,CAAC,IAAI,CAAC,mBAAmB,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;gBACjD,CAAC;gBACD,wDAAwD;gBACxD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC;gBACjE,KAAK,CAAC,IAAI,CAAC,oCAAoC,UAAU,cAAc,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC7B,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpC,KAAK,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAC3B,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBAClC,KAAK,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AA/JD,4CA+JC"}
@@ -5,6 +5,14 @@ import type { TestLink, FacetConfig } from '../types.js';
5
5
  export declare class TestScanner {
6
6
  private config;
7
7
  constructor(config?: Partial<FacetConfig>);
8
+ /**
9
+ * Convert a Facets constant name to a facet ID.
10
+ * Handles hierarchical IDs like:
11
+ * - FEATURES_CORE_PRODUCT_STRUCTURE_READING -> features/core/product:structure-reading
12
+ * - FEATURES_CLI_DX_CLI_ERGONOMICS -> features/cli/dx:cli-ergonomics
13
+ * - PRODUCT_STRUCTURE_READING -> product:structure-reading (legacy)
14
+ */
15
+ private convertConstantToFacetId;
8
16
  /**
9
17
  * Find all test files matching configured patterns
10
18
  */
@@ -15,7 +23,8 @@ export declare class TestScanner {
15
23
  scanFile(filePath: string, cwd?: string): TestLink[];
16
24
  /**
17
25
  * Scan test content for facet annotations
18
- * Supports both Playwright-style annotations and comment-based annotations:
26
+ * Supports multiple annotation styles:
27
+ * - Function call: facet('id1', 'id2') or facet(Facets.ID) inside test body
19
28
  * - Playwright: test('name', { annotation: facet('id1', 'id2') }, ...)
20
29
  * - Comment: // @facet id1, id2 \n test('name', ...)
21
30
  */
@@ -1 +1 @@
1
- {"version":3,"file":"TestScanner.d.ts","sourceRoot":"","sources":["../../src/core/TestScanner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGzD;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAc;gBAEhB,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM;IAI7C;;OAEG;IACG,aAAa,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBnE;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,QAAQ,EAAE;IASnE;;;;;OAKG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,QAAQ,EAAE;IAwHvF;;OAEG;IACG,YAAY,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAgBpE;;OAEG;IACG,wBAAwB,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAajF;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;CAI1F"}
1
+ {"version":3,"file":"TestScanner.d.ts","sourceRoot":"","sources":["../../src/core/TestScanner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGzD;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAc;gBAEhB,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM;IAI7C;;;;;;OAMG;IACH,OAAO,CAAC,wBAAwB;IA8ChC;;OAEG;IACG,aAAa,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBnE;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,QAAQ,EAAE;IASnE;;;;;;OAMG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,QAAQ,EAAE;IA0MvF;;OAEG;IACG,YAAY,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAgBpE;;OAEG;IACG,wBAAwB,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAajF;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;CAI1F"}