@empline/preflight 1.1.20 → 1.1.22

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.
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * JSX Structure Duplication Detection Preflight
4
+ *
5
+ * Detects duplicate JSX structures across files that should be extracted
6
+ * into shared components. Unlike component-consolidation-opportunities which
7
+ * uses predefined patterns, this check discovers arbitrary duplicate structures.
8
+ *
9
+ * How it works:
10
+ * 1. Parses JSX from files and extracts structural blocks
11
+ * 2. Creates normalized fingerprints (ignoring variable names, values)
12
+ * 3. Groups similar structures across files
13
+ * 4. Reports structures that appear 3+ times as consolidation candidates
14
+ *
15
+ * Usage:
16
+ * pnpm preflight:jsx-duplication
17
+ * npx tsx src/checks/architecture/jsx-structure-duplication.ts --verbose
18
+ */
19
+ export declare const id = "architecture/jsx-structure-duplication";
20
+ export declare const name = "JSX Structure Duplication Detection";
21
+ export declare const category = "architecture";
22
+ export declare const blocking = false;
23
+ export declare const description = "Detects duplicate JSX structures that should be extracted into shared components";
24
+ export declare const tags: string[];
25
+ export declare function run(): Promise<void>;
26
+ //# sourceMappingURL=jsx-structure-duplication.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsx-structure-duplication.d.ts","sourceRoot":"","sources":["../../../src/checks/architecture/jsx-structure-duplication.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG;AAWH,eAAO,MAAM,EAAE,2CAA2C,CAAC;AAC3D,eAAO,MAAM,IAAI,wCAAwC,CAAC;AAC1D,eAAO,MAAM,QAAQ,iBAAiB,CAAC;AACvC,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,WAAW,qFAC4D,CAAC;AACrF,eAAO,MAAM,IAAI,UAA6E,CAAC;AAgR/F,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAsDzC"}
@@ -0,0 +1,343 @@
1
+ #!/usr/bin/env tsx
2
+ "use strict";
3
+ /**
4
+ * JSX Structure Duplication Detection Preflight
5
+ *
6
+ * Detects duplicate JSX structures across files that should be extracted
7
+ * into shared components. Unlike component-consolidation-opportunities which
8
+ * uses predefined patterns, this check discovers arbitrary duplicate structures.
9
+ *
10
+ * How it works:
11
+ * 1. Parses JSX from files and extracts structural blocks
12
+ * 2. Creates normalized fingerprints (ignoring variable names, values)
13
+ * 3. Groups similar structures across files
14
+ * 4. Reports structures that appear 3+ times as consolidation candidates
15
+ *
16
+ * Usage:
17
+ * pnpm preflight:jsx-duplication
18
+ * npx tsx src/checks/architecture/jsx-structure-duplication.ts --verbose
19
+ */
20
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ var desc = Object.getOwnPropertyDescriptor(m, k);
23
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
24
+ desc = { enumerable: true, get: function() { return m[k]; } };
25
+ }
26
+ Object.defineProperty(o, k2, desc);
27
+ }) : (function(o, m, k, k2) {
28
+ if (k2 === undefined) k2 = k;
29
+ o[k2] = m[k];
30
+ }));
31
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
32
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
33
+ }) : function(o, v) {
34
+ o["default"] = v;
35
+ });
36
+ var __importStar = (this && this.__importStar) || (function () {
37
+ var ownKeys = function(o) {
38
+ ownKeys = Object.getOwnPropertyNames || function (o) {
39
+ var ar = [];
40
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
41
+ return ar;
42
+ };
43
+ return ownKeys(o);
44
+ };
45
+ return function (mod) {
46
+ if (mod && mod.__esModule) return mod;
47
+ var result = {};
48
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
49
+ __setModuleDefault(result, mod);
50
+ return result;
51
+ };
52
+ })();
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ exports.tags = exports.description = exports.blocking = exports.category = exports.name = exports.id = void 0;
55
+ exports.run = run;
56
+ const fs = __importStar(require("fs"));
57
+ const crypto = __importStar(require("crypto"));
58
+ const glob_1 = require("glob");
59
+ const console_chars_1 = require("../../utils/console-chars");
60
+ const universal_progress_reporter_1 = require("../system/universal-progress-reporter");
61
+ const glob_patterns_1 = require("../../shared/glob-patterns");
62
+ // Check metadata
63
+ exports.id = "architecture/jsx-structure-duplication";
64
+ exports.name = "JSX Structure Duplication Detection";
65
+ exports.category = "architecture";
66
+ exports.blocking = false;
67
+ exports.description = "Detects duplicate JSX structures that should be extracted into shared components";
68
+ exports.tags = ["architecture", "duplication", "shared-components", "jsx", "refactoring"];
69
+ // Configuration
70
+ const CONFIG = {
71
+ // Minimum occurrences to report as duplicate
72
+ minOccurrences: 3,
73
+ // Minimum lines for a JSX block to be considered
74
+ minBlockLines: 5,
75
+ // Maximum lines for a JSX block (too large = probably not a reusable component)
76
+ maxBlockLines: 50,
77
+ // Directories to scan
78
+ includeDirs: ["app", "components"],
79
+ // File patterns to exclude
80
+ excludePatterns: [
81
+ ...glob_patterns_1.CORE_EXCLUDES,
82
+ "**/components/shared/**", // Already shared
83
+ "**/components/ui/**", // Primitive components
84
+ "**/*.test.tsx",
85
+ "**/*.spec.tsx",
86
+ "**/*.stories.tsx",
87
+ ],
88
+ };
89
+ // JSX Block Detection
90
+ /**
91
+ * Extract JSX blocks from file content.
92
+ * Looks for multi-line JSX structures wrapped in parentheses or fragments.
93
+ */
94
+ function extractJSXBlocks(content, filePath) {
95
+ const blocks = [];
96
+ const lines = content.split("\n");
97
+ // Pattern to detect start of JSX blocks:
98
+ // - Opening tag with attributes spanning multiple lines
99
+ // - Fragment openings
100
+ // - Conditional JSX: {condition && (<JSX>...)}
101
+ // - Ternary JSX: {condition ? (<JSX>...) : ...}
102
+ const jsxStartPatterns = [
103
+ // Conditional rendering with opening paren
104
+ /\{[^}]*&&\s*\(\s*$/,
105
+ /\{[^}]*\?\s*\(\s*$/,
106
+ // Return statement with JSX
107
+ /return\s*\(\s*$/,
108
+ // Variable assignment with JSX
109
+ /=\s*\(\s*$/,
110
+ // Opening Card/Box/Stack/div with className
111
+ /<(?:Card|Box|Stack|div|Paper|Container)[^>]*className[^>]*>\s*$/,
112
+ ];
113
+ let blockStart = null;
114
+ let depth = 0;
115
+ let currentBlock = [];
116
+ for (let i = 0; i < lines.length; i++) {
117
+ const line = lines[i];
118
+ const trimmed = line.trim();
119
+ // Check if this starts a new JSX block
120
+ if (blockStart === null) {
121
+ for (const pattern of jsxStartPatterns) {
122
+ if (pattern.test(line)) {
123
+ blockStart = i;
124
+ depth = 1;
125
+ currentBlock = [line];
126
+ break;
127
+ }
128
+ }
129
+ continue;
130
+ }
131
+ // We're inside a block, track depth
132
+ currentBlock.push(line);
133
+ // Count opening/closing parens and tags
134
+ const openParens = (line.match(/\(/g) || []).length;
135
+ const closeParens = (line.match(/\)/g) || []).length;
136
+ depth += openParens - closeParens;
137
+ // Also track JSX tag depth for self-contained components
138
+ const openTags = (line.match(/<[A-Z][^/>]*(?<!\/)\s*>/g) || []).length;
139
+ const closeTags = (line.match(/<\/[A-Z][^>]*>/g) || []).length;
140
+ const selfClosing = (line.match(/<[A-Z][^>]*\/>/g) || []).length;
141
+ // Check if block is complete
142
+ if (depth <= 0 || (trimmed.startsWith("</") && closeTags > openTags)) {
143
+ const blockLines = currentBlock.length;
144
+ if (blockLines >= CONFIG.minBlockLines && blockLines <= CONFIG.maxBlockLines) {
145
+ const raw = currentBlock.join("\n");
146
+ const normalized = normalizeJSX(raw);
147
+ const fingerprint = hashString(normalized);
148
+ blocks.push({
149
+ file: filePath,
150
+ startLine: blockStart + 1, // 1-indexed
151
+ endLine: i + 1,
152
+ raw,
153
+ normalized,
154
+ fingerprint,
155
+ context: currentBlock[0].trim().substring(0, 60),
156
+ });
157
+ }
158
+ blockStart = null;
159
+ depth = 0;
160
+ currentBlock = [];
161
+ }
162
+ }
163
+ return blocks;
164
+ }
165
+ /**
166
+ * Normalize JSX for comparison by removing variable specifics
167
+ * while preserving structure.
168
+ */
169
+ function normalizeJSX(jsx) {
170
+ return (jsx
171
+ // Remove all whitespace
172
+ .replace(/\s+/g, " ")
173
+ // Normalize string values
174
+ .replace(/"[^"]*"/g, '"STRING"')
175
+ .replace(/'[^']*'/g, '"STRING"')
176
+ // Normalize variable names in expressions
177
+ .replace(/\{[a-z_][a-zA-Z0-9_]*\}/gi, "{VAR}")
178
+ // Normalize function calls
179
+ .replace(/\{[a-z_][a-zA-Z0-9_]*\([^)]*\)\}/gi, "{FUNC()}")
180
+ // Normalize property access
181
+ .replace(/\{[a-z_][a-zA-Z0-9_]*\.[a-zA-Z0-9_.]+\}/gi, "{VAR.PROP}")
182
+ // Normalize numbers
183
+ .replace(/\{[0-9]+\}/g, "{NUM}")
184
+ // Normalize conditional expressions but keep structure
185
+ .replace(/\{[^}]+\s*\?\s*/g, "{COND ? ")
186
+ .replace(/\s*:\s*[^}]+\}/g, " : ALT}")
187
+ // Normalize onClick/onChange handlers
188
+ .replace(/on[A-Z][a-zA-Z]*=\{[^}]+\}/g, "onEVENT={HANDLER}")
189
+ // Normalize className values but keep the attribute
190
+ .replace(/className="[^"]+"/g, 'className="CLASSES"')
191
+ // Normalize key props
192
+ .replace(/key=\{[^}]+\}/g, "key={KEY}")
193
+ // Trim
194
+ .trim());
195
+ }
196
+ /**
197
+ * Create a hash of the normalized JSX for grouping
198
+ */
199
+ function hashString(str) {
200
+ return crypto.createHash("md5").update(str).digest("hex").substring(0, 12);
201
+ }
202
+ /**
203
+ * Extract a suggested component name from the JSX structure
204
+ */
205
+ function suggestComponentName(blocks) {
206
+ // Look for common patterns in the JSX
207
+ const sample = blocks[0].raw;
208
+ // Check for common UI patterns
209
+ if (/Resume.*Import/i.test(sample))
210
+ return "ResumeImportPrompt";
211
+ if (/Empty.*State/i.test(sample))
212
+ return "EmptyStateCard";
213
+ if (/Loading.*Spinner/i.test(sample))
214
+ return "LoadingIndicator";
215
+ if (/Confirm.*Dialog/i.test(sample))
216
+ return "ConfirmationCard";
217
+ if (/Error.*Message/i.test(sample))
218
+ return "ErrorDisplay";
219
+ if (/Success.*Message/i.test(sample))
220
+ return "SuccessDisplay";
221
+ if (/Filter.*Bar/i.test(sample))
222
+ return "FilterBar";
223
+ if (/Search.*Input/i.test(sample))
224
+ return "SearchBar";
225
+ if (/Stat.*Card/i.test(sample))
226
+ return "StatCard";
227
+ if (/Progress.*Bar/i.test(sample))
228
+ return "ProgressIndicator";
229
+ // Check for the root component type
230
+ const rootMatch = sample.match(/<([A-Z][a-zA-Z]+)/);
231
+ if (rootMatch) {
232
+ return `Shared${rootMatch[1]}`;
233
+ }
234
+ return "SharedComponent";
235
+ }
236
+ /**
237
+ * Generate a preview of the structure for display
238
+ */
239
+ function generateStructurePreview(block) {
240
+ const lines = block.raw.split("\n").slice(0, 8);
241
+ return lines.map((l) => " " + l.trim()).join("\n") + (block.raw.split("\n").length > 8 ? "\n ..." : "");
242
+ }
243
+ // Main Detection Logic
244
+ async function detectDuplicates() {
245
+ const allBlocks = [];
246
+ // Gather all files
247
+ const files = [];
248
+ for (const dir of CONFIG.includeDirs) {
249
+ const matches = await (0, glob_1.glob)(`${dir}/**/*.tsx`, {
250
+ ignore: CONFIG.excludePatterns,
251
+ cwd: process.cwd(),
252
+ });
253
+ files.push(...matches);
254
+ }
255
+ console.log(`${console_chars_1.emoji.folder} Scanning ${files.length} files for JSX structures...`);
256
+ // Extract blocks from each file
257
+ for (const file of files) {
258
+ try {
259
+ const content = fs.readFileSync(file, "utf-8");
260
+ const blocks = extractJSXBlocks(content, file);
261
+ allBlocks.push(...blocks);
262
+ }
263
+ catch {
264
+ // Skip unreadable files
265
+ }
266
+ }
267
+ console.log(`${console_chars_1.emoji.search} Found ${allBlocks.length} JSX blocks to analyze`);
268
+ // Group by fingerprint
269
+ const groups = new Map();
270
+ for (const block of allBlocks) {
271
+ if (!groups.has(block.fingerprint)) {
272
+ groups.set(block.fingerprint, []);
273
+ }
274
+ groups.get(block.fingerprint).push(block);
275
+ }
276
+ // Filter to duplicates (3+ occurrences in different files)
277
+ const duplicates = [];
278
+ for (const [fingerprint, blocks] of groups) {
279
+ // Get unique files
280
+ const uniqueFiles = new Set(blocks.map((b) => b.file));
281
+ if (uniqueFiles.size >= CONFIG.minOccurrences) {
282
+ duplicates.push({
283
+ fingerprint,
284
+ blocks: blocks.slice(0, 5), // Limit to 5 examples
285
+ suggestedName: suggestComponentName(blocks),
286
+ structurePreview: generateStructurePreview(blocks[0]),
287
+ });
288
+ }
289
+ }
290
+ // Sort by number of occurrences (most duplicated first)
291
+ duplicates.sort((a, b) => b.blocks.length - a.blocks.length);
292
+ return duplicates;
293
+ }
294
+ // Main Runner
295
+ async function run() {
296
+ const reporter = (0, universal_progress_reporter_1.createUniversalProgressReporter)(exports.name);
297
+ const startTime = Date.now();
298
+ const args = process.argv.slice(2);
299
+ const verbose = args.includes("--verbose") || args.includes("-v");
300
+ console.log(`\n${console_chars_1.emoji.search} JSX Structure Duplication Detection`);
301
+ console.log((0, console_chars_1.createDivider)(70, "heavy"));
302
+ console.log(`${console_chars_1.emoji.info} Looking for duplicate JSX structures that should be shared components\n`);
303
+ const duplicates = await detectDuplicates();
304
+ console.log((0, console_chars_1.createDivider)(70, "light"));
305
+ if (duplicates.length === 0) {
306
+ console.log(`\n${console_chars_1.emoji.success} No duplicate JSX structures detected`);
307
+ console.log(` Your codebase has good component reuse!\n`);
308
+ process.exit(0);
309
+ }
310
+ console.log(`\n${console_chars_1.emoji.warning} Found ${duplicates.length} duplicate JSX structure(s)\n`);
311
+ console.log(`These patterns appear in 3+ files and should be extracted to shared components:\n`);
312
+ for (const group of duplicates) {
313
+ const fileCount = new Set(group.blocks.map((b) => b.file)).size;
314
+ console.log(`${console_chars_1.emoji.components} ${group.suggestedName} (found in ${fileCount} files)`);
315
+ console.log(` Fingerprint: ${group.fingerprint}`);
316
+ console.log(` Suggested location: components/shared/${group.suggestedName}.tsx\n`);
317
+ if (verbose) {
318
+ console.log(` Structure preview:`);
319
+ console.log(group.structurePreview);
320
+ console.log();
321
+ }
322
+ console.log(` Found in:`);
323
+ for (const block of group.blocks) {
324
+ console.log(` - ${block.file}:${block.startLine}-${block.endLine}`);
325
+ }
326
+ console.log();
327
+ }
328
+ console.log((0, console_chars_1.createDivider)(70, "heavy"));
329
+ console.log(`\n${console_chars_1.emoji.hint} Recommendations:`);
330
+ console.log(` 1. Create shared components for the patterns above`);
331
+ console.log(` 2. Use props to handle variations between usages`);
332
+ console.log(` 3. Export from components/shared/index.ts`);
333
+ console.log(` 4. Update all files to use the new shared component\n`);
334
+ const elapsed = Date.now() - startTime;
335
+ console.log(`${console_chars_1.emoji.clock} Completed in ${(elapsed / 1000).toFixed(1)}s`);
336
+ console.log(`${console_chars_1.emoji.info} This check is non-blocking (advisory only)\n`);
337
+ process.exit(0);
338
+ }
339
+ // Allow direct execution
340
+ if (require.main === module) {
341
+ run().catch(console.error);
342
+ }
343
+ //# sourceMappingURL=jsx-structure-duplication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsx-structure-duplication.js","sourceRoot":"","sources":["../../../src/checks/architecture/jsx-structure-duplication.ts"],"names":[],"mappings":";;AACA;;;;;;;;;;;;;;;;GAgBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiSH,kBAsDC;AArVD,uCAAyB;AAEzB,+CAAiC;AACjC,+BAA4B;AAC5B,6DAAiE;AACjE,uFAAwF;AACxF,8DAA2D;AAE3D,iBAAiB;AACJ,QAAA,EAAE,GAAG,wCAAwC,CAAC;AAC9C,QAAA,IAAI,GAAG,qCAAqC,CAAC;AAC7C,QAAA,QAAQ,GAAG,cAAc,CAAC;AAC1B,QAAA,QAAQ,GAAG,KAAK,CAAC;AACjB,QAAA,WAAW,GACtB,kFAAkF,CAAC;AACxE,QAAA,IAAI,GAAG,CAAC,cAAc,EAAE,aAAa,EAAE,mBAAmB,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;AAqB/F,gBAAgB;AAEhB,MAAM,MAAM,GAAG;IACb,6CAA6C;IAC7C,cAAc,EAAE,CAAC;IACjB,iDAAiD;IACjD,aAAa,EAAE,CAAC;IAChB,gFAAgF;IAChF,aAAa,EAAE,EAAE;IACjB,sBAAsB;IACtB,WAAW,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC;IAClC,2BAA2B;IAC3B,eAAe,EAAE;QACf,GAAG,6BAAa;QAChB,yBAAyB,EAAE,iBAAiB;QAC5C,qBAAqB,EAAE,uBAAuB;QAC9C,eAAe;QACf,eAAe;QACf,kBAAkB;KACnB;CACF,CAAC;AAEF,sBAAsB;AAEtB;;;GAGG;AACH,SAAS,gBAAgB,CAAC,OAAe,EAAE,QAAgB;IACzD,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,yCAAyC;IACzC,wDAAwD;IACxD,sBAAsB;IACtB,+CAA+C;IAC/C,gDAAgD;IAChD,MAAM,gBAAgB,GAAG;QACvB,2CAA2C;QAC3C,oBAAoB;QACpB,oBAAoB;QACpB,4BAA4B;QAC5B,iBAAiB;QACjB,+BAA+B;QAC/B,YAAY;QACZ,4CAA4C;QAC5C,iEAAiE;KAClE,CAAC;IAEF,IAAI,UAAU,GAAkB,IAAI,CAAC;IACrC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,YAAY,GAAa,EAAE,CAAC;IAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAE5B,uCAAuC;QACvC,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;gBACvC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvB,UAAU,GAAG,CAAC,CAAC;oBACf,KAAK,GAAG,CAAC,CAAC;oBACV,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC;oBACtB,MAAM;gBACR,CAAC;YACH,CAAC;YACD,SAAS;QACX,CAAC;QAED,oCAAoC;QACpC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAExB,wCAAwC;QACxC,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACpD,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACrD,KAAK,IAAI,UAAU,GAAG,WAAW,CAAC;QAElC,yDAAyD;QACzD,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACvE,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QAC/D,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QAEjE,6BAA6B;QAC7B,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,SAAS,GAAG,QAAQ,CAAC,EAAE,CAAC;YACrE,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC;YAEvC,IAAI,UAAU,IAAI,MAAM,CAAC,aAAa,IAAI,UAAU,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;gBAC7E,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACpC,MAAM,UAAU,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;gBACrC,MAAM,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;gBAE3C,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,QAAQ;oBACd,SAAS,EAAE,UAAU,GAAG,CAAC,EAAE,YAAY;oBACvC,OAAO,EAAE,CAAC,GAAG,CAAC;oBACd,GAAG;oBACH,UAAU;oBACV,WAAW;oBACX,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC;iBACjD,CAAC,CAAC;YACL,CAAC;YAED,UAAU,GAAG,IAAI,CAAC;YAClB,KAAK,GAAG,CAAC,CAAC;YACV,YAAY,GAAG,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO,CACL,GAAG;QACD,wBAAwB;SACvB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;QACrB,0BAA0B;SACzB,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC;SAC/B,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC;QAChC,0CAA0C;SACzC,OAAO,CAAC,2BAA2B,EAAE,OAAO,CAAC;QAC9C,2BAA2B;SAC1B,OAAO,CAAC,oCAAoC,EAAE,UAAU,CAAC;QAC1D,4BAA4B;SAC3B,OAAO,CAAC,2CAA2C,EAAE,YAAY,CAAC;QACnE,oBAAoB;SACnB,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC;QAChC,uDAAuD;SACtD,OAAO,CAAC,kBAAkB,EAAE,UAAU,CAAC;SACvC,OAAO,CAAC,iBAAiB,EAAE,SAAS,CAAC;QACtC,sCAAsC;SACrC,OAAO,CAAC,6BAA6B,EAAE,mBAAmB,CAAC;QAC5D,oDAAoD;SACnD,OAAO,CAAC,oBAAoB,EAAE,qBAAqB,CAAC;QACrD,sBAAsB;SACrB,OAAO,CAAC,gBAAgB,EAAE,WAAW,CAAC;QACvC,OAAO;SACN,IAAI,EAAE,CACV,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC7E,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAAC,MAAkB;IAC9C,sCAAsC;IACtC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAE7B,+BAA+B;IAC/B,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,oBAAoB,CAAC;IAChE,IAAI,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,gBAAgB,CAAC;IAC1D,IAAI,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,kBAAkB,CAAC;IAChE,IAAI,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,kBAAkB,CAAC;IAC/D,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,cAAc,CAAC;IAC1D,IAAI,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,gBAAgB,CAAC;IAC9D,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,WAAW,CAAC;IACpD,IAAI,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,WAAW,CAAC;IACtD,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,UAAU,CAAC;IAClD,IAAI,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,mBAAmB,CAAC;IAE9D,oCAAoC;IACpC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACpD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,SAAS,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IACjC,CAAC;IAED,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAAC,KAAe;IAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC5G,CAAC;AAED,uBAAuB;AAEvB,KAAK,UAAU,gBAAgB;IAC7B,MAAM,SAAS,GAAe,EAAE,CAAC;IAEjC,mBAAmB;IACnB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,MAAM,IAAA,WAAI,EAAC,GAAG,GAAG,WAAW,EAAE;YAC5C,MAAM,EAAE,MAAM,CAAC,eAAe;YAC9B,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;SACnB,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,GAAG,qBAAK,CAAC,MAAM,aAAa,KAAK,CAAC,MAAM,8BAA8B,CAAC,CAAC;IAEpF,gCAAgC;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC/C,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAC/C,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,GAAG,qBAAK,CAAC,MAAM,UAAU,SAAS,CAAC,MAAM,wBAAwB,CAAC,CAAC;IAE/E,uBAAuB;IACvB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC7C,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACpC,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;IAED,2DAA2D;IAC3D,MAAM,UAAU,GAAqB,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QAC3C,mBAAmB;QACnB,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACvD,IAAI,WAAW,CAAC,IAAI,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;YAC9C,UAAU,CAAC,IAAI,CAAC;gBACd,WAAW;gBACX,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,sBAAsB;gBAClD,aAAa,EAAE,oBAAoB,CAAC,MAAM,CAAC;gBAC3C,gBAAgB,EAAE,wBAAwB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;aACtD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,wDAAwD;IACxD,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAE7D,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,cAAc;AAEP,KAAK,UAAU,GAAG;IACvB,MAAM,QAAQ,GAAG,IAAA,6DAA+B,EAAC,YAAI,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAElE,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,MAAM,sCAAsC,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,IAAA,6BAAa,EAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,GAAG,qBAAK,CAAC,IAAI,0EAA0E,CAAC,CAAC;IAErG,MAAM,UAAU,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAE5C,OAAO,CAAC,GAAG,CAAC,IAAA,6BAAa,EAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IAExC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,OAAO,uCAAuC,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,OAAO,UAAU,UAAU,CAAC,MAAM,+BAA+B,CAAC,CAAC;IAC1F,OAAO,CAAC,GAAG,CAAC,mFAAmF,CAAC,CAAC;IAEjG,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,GAAG,qBAAK,CAAC,UAAU,IAAI,KAAK,CAAC,aAAa,cAAc,SAAS,SAAS,CAAC,CAAC;QACxF,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,4CAA4C,KAAK,CAAC,aAAa,QAAQ,CAAC,CAAC;QAErF,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;YACpC,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC5B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,IAAA,6BAAa,EAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,IAAI,mBAAmB,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IAEvE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,GAAG,qBAAK,CAAC,KAAK,iBAAiB,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,GAAG,qBAAK,CAAC,IAAI,+CAA+C,CAAC,CAAC;IAE1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,yBAAyB;AACzB,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empline/preflight",
3
- "version": "1.1.20",
3
+ "version": "1.1.22",
4
4
  "description": "Distributable preflight validation system with app-specific plugin support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -19,13 +19,15 @@
19
19
  },
20
20
  "scripts": {
21
21
  "build": "tsc",
22
- "prebuild": "npm run check:hygiene",
22
+ "prebuild": "npm run check:hygiene && npm run check:metadata && npm run check:broken",
23
23
  "dev": "tsc --watch",
24
24
  "preflight": "tsx src/bin/preflight.ts",
25
- "check:all": "tsx src/checks/**/*.ts",
26
- "check:security": "tsx src/checks/security/*.ts",
27
- "check:business": "tsx src/checks/business/*.ts",
25
+ "check:system": "tsx src/bin/preflight.ts --category system",
26
+ "check:security": "tsx src/bin/preflight.ts --category security",
27
+ "check:business": "tsx src/bin/preflight.ts --category business",
28
28
  "check:hygiene": "tsx scripts/maintenance/module-boundary-validator.ts",
29
+ "check:metadata": "tsx src/checks/system/preflight-metadata-validator.ts",
30
+ "check:broken": "tsx src/checks/system/broken-preflight-detection.ts",
29
31
  "check:hygiene:all": "tsx scripts/maintenance/module-boundary-validator.ts && tsx scripts/maintenance/workflow-composition-validator.ts && tsx scripts/maintenance/canonical-import-enforcer.ts",
30
32
  "lint": "eslint src/",
31
33
  "test": "vitest",