@pedroab0/skills 1.1.0 → 1.2.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.
@@ -1,163 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const assert = require('assert');
4
- const fs = require('fs');
5
- const path = require('path');
6
- const os = require('os');
7
- const { execSync } = require('child_process');
8
- const {
9
- decodeTextBuffer,
10
- resolveSpecPath,
11
- inspectSpec,
12
- formatTerminalReport,
13
- formatMarkdownReport,
14
- } = require('./inspect_spec.js');
15
-
16
- console.log('--- Running Spec Inspector Unit Tests ---');
17
-
18
- // Mock Node AST tree
19
- const mockSpec = {
20
- name: 'Product Card',
21
- type: 'FRAME',
22
- bounds: { width: 360, height: 480 },
23
- layoutMode: 'VERTICAL',
24
- itemSpacing: 16,
25
- itemSpacingToken: 'spacing/md',
26
- padding: { top: 24, right: 24, bottom: 24, left: 24 },
27
- paddingToken: 'spacing/lg',
28
- cornerRadius: 12,
29
- cornerRadiusToken: 'radii/lg',
30
- fills: [{ type: 'SOLID', color: '#FFFFFF', token: 'color/surface' }],
31
- children: [
32
- {
33
- name: 'Badge Instance',
34
- type: 'INSTANCE',
35
- component: { name: 'Badge' },
36
- props: { variant: 'success', label: 'In Stock' },
37
- },
38
- {
39
- name: 'Title',
40
- type: 'TEXT',
41
- characters: 'Wireless Noise-Canceling Headphones',
42
- style: {
43
- fontFamily: 'Inter',
44
- fontSize: 20,
45
- fontWeight: 700,
46
- },
47
- fills: [{ type: 'SOLID', color: '#111827', token: 'color/text-primary' }],
48
- },
49
- {
50
- name: 'Description',
51
- type: 'TEXT',
52
- characters: 'Premium audio experience with active noise cancellation.',
53
- style: {
54
- fontFamily: 'Inter',
55
- fontSize: 14,
56
- fontWeight: 400,
57
- },
58
- },
59
- {
60
- name: 'Action Button',
61
- type: 'INSTANCE',
62
- component: { name: 'Button' },
63
- props: { variant: 'primary', size: 'md', hasIcon: true },
64
- },
65
- {
66
- name: 'Secondary Button',
67
- type: 'INSTANCE',
68
- component: { name: 'Button' },
69
- props: { variant: 'outline', size: 'md' },
70
- },
71
- ],
72
- };
73
-
74
- // 1. inspectSpec: dimensions and layout
75
- const report = inspectSpec(mockSpec, '/mock/.specs/card.json');
76
- assert.strictEqual(report.rootLayout.name, 'Product Card');
77
- assert.strictEqual(report.rootLayout.width, 360);
78
- assert.strictEqual(report.rootLayout.height, 480);
79
- assert.strictEqual(report.rootLayout.layoutMode, 'VERTICAL');
80
- assert.strictEqual(report.rootLayout.itemSpacing, 16);
81
- assert.strictEqual(report.rootLayout.itemSpacingToken, 'spacing/md');
82
- assert.strictEqual(report.rootLayout.paddingToken, 'spacing/lg');
83
- console.log(' ✓ inspectSpec: correctly extracts root dimensions and auto-layout metrics');
84
-
85
- // 2. inspectSpec: tokens
86
- assert.ok(report.tokens.colors.has('color/surface'), 'Includes surface color token');
87
- assert.ok(report.tokens.colors.has('color/text-primary'), 'Includes text color token');
88
- assert.ok(report.tokens.spacing.has('spacing/md'), 'Includes spacing/md token');
89
- assert.ok(report.tokens.radii.has('radii/lg'), 'Includes radii/lg token');
90
- console.log(' ✓ inspectSpec: aggregates design tokens across colors, spacing, and radii');
91
-
92
- // 3. inspectSpec: component instances & gaps
93
- assert.strictEqual(report.instances.size, 2, 'Detects 2 distinct components');
94
- assert.strictEqual(report.instances.get('Button').length, 2, 'Detects 2 Button instances');
95
- assert.strictEqual(report.instances.get('Badge').length, 1, 'Detects 1 Badge instance');
96
- assert.strictEqual(report.instances.get('Button')[0].variant, 'primary');
97
- assert.strictEqual(report.instances.get('Button')[1].variant, 'outline');
98
- console.log(' ✓ inspectSpec: aggregates component instances and variant prop shapes');
99
-
100
- // 4. inspectSpec: typography
101
- assert.strictEqual(report.typography.totalTextLayers, 2);
102
- assert.ok(report.typography.fontFamilies.has('Inter'));
103
- assert.ok(report.typography.fontSizes.has(20));
104
- assert.ok(report.typography.fontSizes.has(14));
105
- assert.ok(report.typography.fontWeights.has(700));
106
- console.log(' ✓ inspectSpec: extracts font families, sizes, weights, and text samples');
107
-
108
- // 5. formatTerminalReport & formatMarkdownReport
109
- const terminalText = formatTerminalReport(report);
110
- assert.ok(terminalText.includes('Product Card'));
111
- assert.ok(terminalText.includes('Vertical Flex (Column)'));
112
- assert.ok(terminalText.includes('<Button />'));
113
- assert.ok(terminalText.includes('<Badge />'));
114
- assert.ok(terminalText.includes('Component Gaps & Codebase Checklist'));
115
- console.log(' ✓ formatTerminalReport: formats clean box-drawing terminal report');
116
-
117
- const markdownText = formatMarkdownReport(report);
118
- assert.ok(markdownText.includes('### 📐 Figma Spec Summary: `card.json`'));
119
- assert.ok(markdownText.includes('`<Button />`'));
120
- assert.ok(markdownText.includes('`spacing/md`'));
121
- console.log(' ✓ formatMarkdownReport: formats Markdown table and component checklist');
122
-
123
- // 6. resolveSpecPath: resolution from disk
124
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'spec-test-'));
125
- try {
126
- const specsSubdir = path.join(tmpDir, '.specs');
127
- fs.mkdirSync(specsSubdir, { recursive: true });
128
- const testFile = path.join(specsSubdir, 'product.json');
129
- fs.writeFileSync(testFile, JSON.stringify(mockSpec), 'utf8');
130
-
131
- // Direct path
132
- assert.strictEqual(resolveSpecPath(testFile), testFile);
133
-
134
- // Shorthand in cwd
135
- const origCwd = process.cwd();
136
- try {
137
- process.chdir(tmpDir);
138
- const expected = fs.realpathSync(path.resolve(specsSubdir, 'product.json'));
139
- assert.strictEqual(fs.realpathSync(resolveSpecPath('product')), expected);
140
- assert.strictEqual(fs.realpathSync(resolveSpecPath('.specs/product')), expected);
141
- assert.strictEqual(fs.realpathSync(resolveSpecPath('.specs/product.json')), expected);
142
- console.log(' ✓ resolveSpecPath: resolves direct files, shorthand names, and .specs/ subdirectories');
143
- } finally {
144
- process.chdir(origCwd);
145
- }
146
-
147
- // 7. decodeTextBuffer & CLI UTF-8 BOM / UTF-16LE BOM resilience (Windows PowerShell 5.1 & Notepad)
148
- const utf8BomFile = path.join(specsSubdir, 'utf8bom.json');
149
- fs.writeFileSync(utf8BomFile, '\uFEFF' + JSON.stringify(mockSpec), 'utf8');
150
- const utf16BomFile = path.join(specsSubdir, 'utf16le.json');
151
- const utf16Buf = Buffer.concat([Buffer.from([0xff, 0xfe]), Buffer.from(JSON.stringify(mockSpec), 'utf16le')]);
152
- fs.writeFileSync(utf16BomFile, utf16Buf);
153
-
154
- assert.strictEqual(JSON.parse(decodeTextBuffer(fs.readFileSync(utf8BomFile))).name, 'Product Card');
155
- assert.strictEqual(JSON.parse(decodeTextBuffer(fs.readFileSync(utf16BomFile))).name, 'Product Card');
156
- const cliOut = execSync(`node "${path.join(__dirname, 'inspect_spec.js')}" "${utf16BomFile}" --markdown`, { encoding: 'utf8' });
157
- assert.ok(cliOut.includes('Product Card'));
158
- console.log(' ✓ decodeTextBuffer & CLI: parses UTF-8 BOM and UTF-16LE BOM specs cleanly');
159
- } finally {
160
- fs.rmSync(tmpDir, { recursive: true, force: true });
161
- }
162
-
163
- console.log('\nResults: 7/7 Spec Inspector tests passed.\n');