@buoy-design/scanners 0.1.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 (81) hide show
  1. package/dist/__tests__/fixtures/react-components.d.ts +5 -0
  2. package/dist/__tests__/fixtures/react-components.d.ts.map +1 -0
  3. package/dist/__tests__/fixtures/react-components.js +36 -0
  4. package/dist/__tests__/fixtures/react-components.js.map +1 -0
  5. package/dist/__tests__/setup.d.ts +2 -0
  6. package/dist/__tests__/setup.d.ts.map +1 -0
  7. package/dist/__tests__/setup.js +78 -0
  8. package/dist/__tests__/setup.js.map +1 -0
  9. package/dist/base/index.d.ts +2 -0
  10. package/dist/base/index.d.ts.map +1 -0
  11. package/dist/base/index.js +2 -0
  12. package/dist/base/index.js.map +1 -0
  13. package/dist/base/scanner.d.ts +28 -0
  14. package/dist/base/scanner.d.ts.map +1 -0
  15. package/dist/base/scanner.js +7 -0
  16. package/dist/base/scanner.js.map +1 -0
  17. package/dist/figma/client.d.ts +98 -0
  18. package/dist/figma/client.d.ts.map +1 -0
  19. package/dist/figma/client.js +54 -0
  20. package/dist/figma/client.js.map +1 -0
  21. package/dist/figma/component-scanner.d.ts +22 -0
  22. package/dist/figma/component-scanner.d.ts.map +1 -0
  23. package/dist/figma/component-scanner.js +174 -0
  24. package/dist/figma/component-scanner.js.map +1 -0
  25. package/dist/figma/index.d.ts +3 -0
  26. package/dist/figma/index.d.ts.map +1 -0
  27. package/dist/figma/index.js +3 -0
  28. package/dist/figma/index.js.map +1 -0
  29. package/dist/git/angular-scanner.d.ts +18 -0
  30. package/dist/git/angular-scanner.d.ts.map +1 -0
  31. package/dist/git/angular-scanner.js +244 -0
  32. package/dist/git/angular-scanner.js.map +1 -0
  33. package/dist/git/index.d.ts +8 -0
  34. package/dist/git/index.d.ts.map +1 -0
  35. package/dist/git/index.js +8 -0
  36. package/dist/git/index.js.map +1 -0
  37. package/dist/git/react-scanner.d.ts +29 -0
  38. package/dist/git/react-scanner.d.ts.map +1 -0
  39. package/dist/git/react-scanner.js +469 -0
  40. package/dist/git/react-scanner.js.map +1 -0
  41. package/dist/git/react-scanner.test.d.ts +2 -0
  42. package/dist/git/react-scanner.test.d.ts.map +1 -0
  43. package/dist/git/react-scanner.test.js +107 -0
  44. package/dist/git/react-scanner.test.js.map +1 -0
  45. package/dist/git/svelte-scanner.d.ts +30 -0
  46. package/dist/git/svelte-scanner.d.ts.map +1 -0
  47. package/dist/git/svelte-scanner.js +344 -0
  48. package/dist/git/svelte-scanner.js.map +1 -0
  49. package/dist/git/template-scanner.d.ts +16 -0
  50. package/dist/git/template-scanner.d.ts.map +1 -0
  51. package/dist/git/template-scanner.js +227 -0
  52. package/dist/git/template-scanner.js.map +1 -0
  53. package/dist/git/token-scanner.d.ts +43 -0
  54. package/dist/git/token-scanner.d.ts.map +1 -0
  55. package/dist/git/token-scanner.js +444 -0
  56. package/dist/git/token-scanner.js.map +1 -0
  57. package/dist/git/vue-scanner.d.ts +26 -0
  58. package/dist/git/vue-scanner.d.ts.map +1 -0
  59. package/dist/git/vue-scanner.js +296 -0
  60. package/dist/git/vue-scanner.js.map +1 -0
  61. package/dist/git/webcomponent-scanner.d.ts +22 -0
  62. package/dist/git/webcomponent-scanner.d.ts.map +1 -0
  63. package/dist/git/webcomponent-scanner.js +312 -0
  64. package/dist/git/webcomponent-scanner.js.map +1 -0
  65. package/dist/index.d.ts +7 -0
  66. package/dist/index.d.ts.map +1 -0
  67. package/dist/index.js +12 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/plugin-adapter.d.ts +11 -0
  70. package/dist/plugin-adapter.d.ts.map +1 -0
  71. package/dist/plugin-adapter.js +21 -0
  72. package/dist/plugin-adapter.js.map +1 -0
  73. package/dist/storybook/extractor.d.ts +20 -0
  74. package/dist/storybook/extractor.d.ts.map +1 -0
  75. package/dist/storybook/extractor.js +146 -0
  76. package/dist/storybook/extractor.js.map +1 -0
  77. package/dist/storybook/index.d.ts +2 -0
  78. package/dist/storybook/index.d.ts.map +1 -0
  79. package/dist/storybook/index.js +2 -0
  80. package/dist/storybook/index.js.map +1 -0
  81. package/package.json +56 -0
@@ -0,0 +1,344 @@
1
+ import { Scanner } from '../base/scanner.js';
2
+ import { createComponentId } from '@buoy-design/core';
3
+ import { glob } from 'glob';
4
+ import { readFile } from 'fs/promises';
5
+ import { relative, basename } from 'path';
6
+ export class SvelteComponentScanner extends Scanner {
7
+ async scan() {
8
+ const startTime = Date.now();
9
+ const files = await this.findComponentFiles();
10
+ const components = [];
11
+ const errors = [];
12
+ for (const file of files) {
13
+ try {
14
+ const parsed = await this.parseFile(file);
15
+ if (parsed)
16
+ components.push(parsed);
17
+ }
18
+ catch (err) {
19
+ const message = err instanceof Error ? err.message : String(err);
20
+ errors.push({
21
+ file,
22
+ message,
23
+ code: 'PARSE_ERROR',
24
+ });
25
+ }
26
+ }
27
+ const stats = {
28
+ filesScanned: files.length,
29
+ itemsFound: components.length,
30
+ duration: Date.now() - startTime,
31
+ };
32
+ return { items: components, errors, stats };
33
+ }
34
+ getSourceType() {
35
+ return 'svelte';
36
+ }
37
+ async findComponentFiles() {
38
+ const patterns = this.config.include || ['**/*.svelte'];
39
+ const ignore = this.config.exclude || [
40
+ '**/node_modules/**',
41
+ '**/*.test.*',
42
+ '**/*.spec.*',
43
+ '**/*.stories.*',
44
+ '**/dist/**',
45
+ '**/build/**',
46
+ '**/.svelte-kit/**',
47
+ ];
48
+ const allFiles = [];
49
+ for (const pattern of patterns) {
50
+ const matches = await glob(pattern, {
51
+ cwd: this.config.projectRoot,
52
+ ignore,
53
+ absolute: true,
54
+ });
55
+ allFiles.push(...matches);
56
+ }
57
+ return [...new Set(allFiles)];
58
+ }
59
+ async parseFile(filePath) {
60
+ const content = await readFile(filePath, 'utf-8');
61
+ const relativePath = relative(this.config.projectRoot, filePath);
62
+ // Extract component name from filename (e.g., MyButton.svelte -> MyButton)
63
+ const name = basename(filePath, '.svelte');
64
+ // Only process PascalCase component names
65
+ if (!/^[A-Z]/.test(name))
66
+ return null;
67
+ // Extract script content
68
+ const scriptMatch = content.match(/<script[^>]*>([\s\S]*?)<\/script>/);
69
+ const scriptContent = scriptMatch?.[1] || '';
70
+ const props = this.extractProps(scriptContent);
71
+ const dependencies = this.extractDependencies(content);
72
+ const source = {
73
+ type: 'svelte',
74
+ path: relativePath,
75
+ exportName: name,
76
+ line: 1,
77
+ };
78
+ return {
79
+ id: createComponentId(source, name),
80
+ name,
81
+ source,
82
+ props,
83
+ variants: [],
84
+ tokens: [],
85
+ dependencies,
86
+ metadata: {
87
+ deprecated: this.hasDeprecatedComment(content),
88
+ tags: [],
89
+ },
90
+ scannedAt: new Date(),
91
+ };
92
+ }
93
+ /**
94
+ * Extract matched content with proper brace balancing.
95
+ * Handles nested braces like: { cb: () => { value: string } }
96
+ */
97
+ extractBalancedBraces(content, startIndex) {
98
+ if (content[startIndex] !== '{')
99
+ return null;
100
+ let depth = 0;
101
+ let i = startIndex;
102
+ while (i < content.length) {
103
+ const char = content[i];
104
+ if (char === '{') {
105
+ depth++;
106
+ }
107
+ else if (char === '}') {
108
+ depth--;
109
+ if (depth === 0) {
110
+ // Return content between braces (excluding the braces themselves)
111
+ return content.substring(startIndex + 1, i);
112
+ }
113
+ }
114
+ i++;
115
+ }
116
+ return null; // Unbalanced braces
117
+ }
118
+ /**
119
+ * Parse Svelte 5 $props() destructuring with proper handling of nested types.
120
+ * Handles: let { cb = () => {}, data: { nested } = {} } = $props();
121
+ */
122
+ parseSvelte5Props(propsContent) {
123
+ const props = [];
124
+ let i = 0;
125
+ const charAt = (idx) => propsContent.charAt(idx);
126
+ while (i < propsContent.length) {
127
+ // Skip whitespace
128
+ while (i < propsContent.length && /\s/.test(charAt(i)))
129
+ i++;
130
+ if (i >= propsContent.length)
131
+ break;
132
+ // Match prop name
133
+ const nameMatch = propsContent.substring(i).match(/^(\w+)/);
134
+ if (!nameMatch || !nameMatch[1]) {
135
+ // Skip to next comma or end
136
+ while (i < propsContent.length && charAt(i) !== ',')
137
+ i++;
138
+ i++; // skip comma
139
+ continue;
140
+ }
141
+ const propName = nameMatch[1];
142
+ i += nameMatch[0].length;
143
+ // Skip whitespace
144
+ while (i < propsContent.length && /\s/.test(charAt(i)))
145
+ i++;
146
+ let propType = 'unknown';
147
+ let defaultValue;
148
+ // Check for type annotation (: Type) - but NOT destructuring rename
149
+ if (charAt(i) === ':') {
150
+ // Peek ahead to see if this is a type annotation or destructuring
151
+ const afterColon = propsContent.substring(i + 1).trimStart();
152
+ if (afterColon.startsWith('{')) {
153
+ // This is destructuring rename, skip this prop
154
+ i++; // skip ':'
155
+ while (i < propsContent.length && /\s/.test(charAt(i)))
156
+ i++;
157
+ // Skip the nested braces
158
+ if (charAt(i) === '{') {
159
+ const nested = this.extractBalancedBraces(propsContent, i);
160
+ if (nested !== null) {
161
+ i += nested.length + 2; // +2 for the braces
162
+ }
163
+ }
164
+ // Skip to comma
165
+ while (i < propsContent.length && charAt(i) !== ',')
166
+ i++;
167
+ if (charAt(i) === ',')
168
+ i++;
169
+ continue;
170
+ }
171
+ i++; // skip ':'
172
+ // Skip whitespace
173
+ while (i < propsContent.length && /\s/.test(charAt(i)))
174
+ i++;
175
+ // Extract type with proper nesting
176
+ let typeStr = '';
177
+ let depth = 0;
178
+ const typeDepthChars = { '{': 1, '}': -1, '(': 1, ')': -1, '<': 1, '>': -1 };
179
+ while (i < propsContent.length) {
180
+ const char = charAt(i);
181
+ const depthDelta = typeDepthChars[char];
182
+ if (depthDelta !== undefined) {
183
+ depth += depthDelta;
184
+ }
185
+ // Stop at comma or '=' only when not nested
186
+ if (depth === 0 && (char === ',' || char === '=')) {
187
+ break;
188
+ }
189
+ typeStr += char;
190
+ i++;
191
+ }
192
+ propType = typeStr.trim() || 'unknown';
193
+ }
194
+ // Skip whitespace
195
+ while (i < propsContent.length && /\s/.test(charAt(i)))
196
+ i++;
197
+ // Check for default value (= value)
198
+ if (charAt(i) === '=') {
199
+ i++; // skip '='
200
+ // Skip whitespace
201
+ while (i < propsContent.length && /\s/.test(charAt(i)))
202
+ i++;
203
+ // Extract default value with proper nesting
204
+ let valueStr = '';
205
+ let depth = 0;
206
+ const valueDepthChars = { '{': 1, '}': -1, '(': 1, ')': -1, '<': 1, '>': -1, '[': 1, ']': -1 };
207
+ while (i < propsContent.length) {
208
+ const char = charAt(i);
209
+ const depthDelta = valueDepthChars[char];
210
+ if (depthDelta !== undefined) {
211
+ depth += depthDelta;
212
+ }
213
+ // Stop at comma only when not nested
214
+ if (depth === 0 && char === ',') {
215
+ break;
216
+ }
217
+ valueStr += char;
218
+ i++;
219
+ }
220
+ defaultValue = valueStr.trim() || undefined;
221
+ }
222
+ // Skip comma
223
+ if (charAt(i) === ',')
224
+ i++;
225
+ props.push({
226
+ name: propName,
227
+ type: propType,
228
+ required: !defaultValue,
229
+ defaultValue,
230
+ });
231
+ }
232
+ return props;
233
+ }
234
+ /**
235
+ * Extract type from export let statement, handling nested types.
236
+ * Handles: export let cb: () => { value: string };
237
+ */
238
+ extractTypeFromExportLet(typeAndRest) {
239
+ let typeStr = '';
240
+ let depth = 0;
241
+ let i = 0;
242
+ const depthChars = { '{': 1, '}': -1, '(': 1, ')': -1, '<': 1, '>': -1 };
243
+ const charAt = (idx) => typeAndRest.charAt(idx);
244
+ while (i < typeAndRest.length) {
245
+ const char = charAt(i);
246
+ const depthDelta = depthChars[char];
247
+ if (depthDelta !== undefined) {
248
+ depth += depthDelta;
249
+ }
250
+ // Stop at '=' or ';' only when not nested
251
+ if (depth === 0 && (char === '=' || char === ';')) {
252
+ break;
253
+ }
254
+ typeStr += char;
255
+ i++;
256
+ }
257
+ return {
258
+ type: typeStr.trim() || 'unknown',
259
+ rest: typeAndRest.substring(i),
260
+ };
261
+ }
262
+ extractProps(scriptContent) {
263
+ const props = [];
264
+ // Svelte 4 and earlier: export let propName = defaultValue;
265
+ // Match: export let propName; or export let propName = value; or export let propName: Type;
266
+ // Need to handle nested types like: export let cb: () => { value: string };
267
+ const exportLetRegex = /export\s+let\s+(\w+)\s*([:=;])/g;
268
+ let match;
269
+ while ((match = exportLetRegex.exec(scriptContent)) !== null) {
270
+ const propName = match[1];
271
+ const nextChar = match[2];
272
+ if (!propName)
273
+ continue;
274
+ let propType = 'unknown';
275
+ let defaultValue;
276
+ if (nextChar === ':') {
277
+ // Has type annotation
278
+ const afterColon = scriptContent.substring(match.index + match[0].length - 1);
279
+ const { type, rest } = this.extractTypeFromExportLet(afterColon);
280
+ propType = type;
281
+ // Check for default value after the type
282
+ const defaultMatch = rest.match(/^\s*=\s*([^;]+);/);
283
+ if (defaultMatch && defaultMatch[1]) {
284
+ defaultValue = defaultMatch[1].trim();
285
+ }
286
+ }
287
+ else if (nextChar === '=') {
288
+ // Has default value but no type
289
+ const afterEquals = scriptContent.substring(match.index + match[0].length - 1);
290
+ const defaultMatch = afterEquals.match(/^\s*([^;]+);/);
291
+ if (defaultMatch && defaultMatch[1]) {
292
+ defaultValue = defaultMatch[1].trim();
293
+ }
294
+ }
295
+ // If nextChar is ';', no type and no default value
296
+ props.push({
297
+ name: propName,
298
+ type: propType,
299
+ required: !defaultValue,
300
+ defaultValue,
301
+ });
302
+ }
303
+ // Svelte 5 runes: let { propName = default } = $props();
304
+ // Need to handle nested types like: let { cb = () => {} } = $props();
305
+ if (scriptContent.includes('$props()')) {
306
+ // Find the $props() call and work backwards to find the matching brace
307
+ const propsCallIdx = scriptContent.indexOf('$props()');
308
+ const letBraceMatch = scriptContent.substring(0, propsCallIdx).match(/let\s*\{/);
309
+ if (letBraceMatch && letBraceMatch.index !== undefined) {
310
+ const braceStartIdx = scriptContent.indexOf('{', letBraceMatch.index);
311
+ const propsContent = this.extractBalancedBraces(scriptContent, braceStartIdx);
312
+ if (propsContent) {
313
+ const svelte5Props = this.parseSvelte5Props(propsContent);
314
+ // Only add if we haven't already found props via export let
315
+ if (props.length === 0) {
316
+ props.push(...svelte5Props);
317
+ }
318
+ }
319
+ }
320
+ }
321
+ return props;
322
+ }
323
+ extractDependencies(content) {
324
+ const deps = new Set();
325
+ // Find component imports
326
+ const importMatches = content.matchAll(/import\s+(\w+)\s+from\s+['"]\.[^'"]+\.svelte['"]/g);
327
+ for (const m of importMatches) {
328
+ if (m[1] && /^[A-Z]/.test(m[1])) {
329
+ deps.add(m[1]);
330
+ }
331
+ }
332
+ // Find component usage in template: <ComponentName
333
+ const componentUsage = content.matchAll(/<([A-Z][a-zA-Z0-9]+)/g);
334
+ for (const m of componentUsage) {
335
+ if (m[1])
336
+ deps.add(m[1]);
337
+ }
338
+ return Array.from(deps);
339
+ }
340
+ hasDeprecatedComment(content) {
341
+ return content.includes('@deprecated') || content.includes('* @deprecated');
342
+ }
343
+ }
344
+ //# sourceMappingURL=svelte-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svelte-scanner.js","sourceRoot":"","sources":["../../src/git/svelte-scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { Scanner, ScanResult, ScannerConfig } from '../base/scanner.js';
2
+ import type { Component } from '@buoy-design/core';
3
+ export interface TemplateScannerConfig extends ScannerConfig {
4
+ templateType: 'blade' | 'erb' | 'twig' | 'php' | 'html' | 'njk';
5
+ }
6
+ export declare class TemplateScanner extends Scanner<Component, TemplateScannerConfig> {
7
+ scan(): Promise<ScanResult<Component>>;
8
+ getSourceType(): string;
9
+ private findTemplateFiles;
10
+ private parseFile;
11
+ private extractComponentName;
12
+ private isLikelyComponent;
13
+ private extractDependencies;
14
+ private pathToComponentName;
15
+ }
16
+ //# sourceMappingURL=template-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-scanner.d.ts","sourceRoot":"","sources":["../../src/git/template-scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAwB,MAAM,oBAAoB,CAAC;AAC9F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAMnD,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,YAAY,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;CACjE;AAgED,qBAAa,eAAgB,SAAQ,OAAO,CAAC,SAAS,EAAE,qBAAqB,CAAC;IACtE,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IA6B5C,aAAa,IAAI,MAAM;YAIT,iBAAiB;YA2BjB,SAAS;IAuCvB,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,iBAAiB;IA0CzB,OAAO,CAAC,mBAAmB;IAwB3B,OAAO,CAAC,mBAAmB;CAc5B"}
@@ -0,0 +1,227 @@
1
+ import { Scanner } from '../base/scanner.js';
2
+ import { createComponentId } from '@buoy-design/core';
3
+ import { glob } from 'glob';
4
+ import { readFileSync } from 'fs';
5
+ import { relative, basename } from 'path';
6
+ // Map template types to file extensions and patterns
7
+ const TEMPLATE_CONFIG = {
8
+ blade: {
9
+ ext: 'blade.php',
10
+ patterns: [
11
+ /@component\(['"]([^'"]+)['"]/g, // @component('name')
12
+ /@include\(['"]([^'"]+)['"]/g, // @include('name')
13
+ /<x-([a-z0-9-:.]+)/gi, // <x-component-name>
14
+ /@livewire\(['"]([^'"]+)['"]/g, // @livewire('name')
15
+ ],
16
+ },
17
+ erb: {
18
+ ext: 'html.erb',
19
+ patterns: [
20
+ /render\s+partial:\s*['"]([^'"]+)['"]/g, // render partial: 'name'
21
+ /render\s*\(\s*['"]([^'"]+)['"]/g, // render('name') or render 'name'
22
+ /render\s+['"]([^'"]+)['"]/g, // render 'name'
23
+ ],
24
+ },
25
+ twig: {
26
+ ext: 'html.twig',
27
+ patterns: [
28
+ /\{%\s*include\s+['"]([^'"]+)['"]/g, // {% include 'name' %}
29
+ /\{%\s*embed\s+['"]([^'"]+)['"]/g, // {% embed 'name' %}
30
+ /\{%\s*extends\s+['"]([^'"]+)['"]/g, // {% extends 'name' %}
31
+ /\{\{\s*include\(['"]([^'"]+)['"]/g, // {{ include('name') }}
32
+ ],
33
+ },
34
+ php: {
35
+ ext: 'php',
36
+ patterns: [
37
+ /include\s*\(\s*['"]([^'"]+)['"]/g, // include('file.php')
38
+ /include_once\s*\(\s*['"]([^'"]+)['"]/g, // include_once('file.php')
39
+ /require\s*\(\s*['"]([^'"]+)['"]/g, // require('file.php')
40
+ /require_once\s*\(\s*['"]([^'"]+)['"]/g, // require_once('file.php')
41
+ ],
42
+ },
43
+ html: {
44
+ ext: 'html',
45
+ patterns: [
46
+ /\{\{\s*template\s+['"]([^'"]+)['"]/g, // {{ template "name" }} (Go)
47
+ /\{\{\s*partial\s+['"]([^'"]+)['"]/g, // {{ partial "name" }} (Hugo)
48
+ /\{%\s*include\s+['"]([^'"]+)['"]/g, // {% include 'name' %} (Jekyll/Liquid)
49
+ ],
50
+ },
51
+ njk: {
52
+ ext: 'njk',
53
+ patterns: [
54
+ /\{%\s*include\s+['"]([^'"]+)['"]/g, // {% include 'name' %}
55
+ /\{%\s*extends\s+['"]([^'"]+)['"]/g, // {% extends 'name' %}
56
+ /\{%\s*macro\s+(\w+)/g, // {% macro name() %}
57
+ ],
58
+ },
59
+ };
60
+ export class TemplateScanner extends Scanner {
61
+ async scan() {
62
+ const startTime = Date.now();
63
+ const files = await this.findTemplateFiles();
64
+ const components = [];
65
+ const errors = [];
66
+ for (const file of files) {
67
+ try {
68
+ const parsed = await this.parseFile(file);
69
+ if (parsed)
70
+ components.push(parsed);
71
+ }
72
+ catch (err) {
73
+ const message = err instanceof Error ? err.message : String(err);
74
+ errors.push({
75
+ file,
76
+ message,
77
+ code: 'PARSE_ERROR',
78
+ });
79
+ }
80
+ }
81
+ const stats = {
82
+ filesScanned: files.length,
83
+ itemsFound: components.length,
84
+ duration: Date.now() - startTime,
85
+ };
86
+ return { items: components, errors, stats };
87
+ }
88
+ getSourceType() {
89
+ return this.config.templateType;
90
+ }
91
+ async findTemplateFiles() {
92
+ const templateConfig = TEMPLATE_CONFIG[this.config.templateType];
93
+ const ext = templateConfig?.ext || this.config.templateType;
94
+ const patterns = this.config.include || [`**/*.${ext}`];
95
+ const ignore = this.config.exclude || [
96
+ '**/node_modules/**',
97
+ '**/vendor/**',
98
+ '**/cache/**',
99
+ '**/dist/**',
100
+ '**/build/**',
101
+ ];
102
+ const allFiles = [];
103
+ for (const pattern of patterns) {
104
+ const matches = await glob(pattern, {
105
+ cwd: this.config.projectRoot,
106
+ ignore,
107
+ absolute: true,
108
+ });
109
+ allFiles.push(...matches);
110
+ }
111
+ return [...new Set(allFiles)];
112
+ }
113
+ async parseFile(filePath) {
114
+ const content = readFileSync(filePath, 'utf-8');
115
+ const relativePath = relative(this.config.projectRoot, filePath);
116
+ // Generate component name from file path
117
+ // e.g., resources/views/components/button.blade.php -> Button
118
+ // e.g., app/views/shared/_header.html.erb -> Header
119
+ const name = this.extractComponentName(filePath);
120
+ // Skip non-component files (layouts, pages, etc.)
121
+ if (!this.isLikelyComponent(filePath, content)) {
122
+ return null;
123
+ }
124
+ const dependencies = this.extractDependencies(content);
125
+ const source = {
126
+ type: this.config.templateType,
127
+ path: relativePath,
128
+ exportName: name,
129
+ line: 1,
130
+ };
131
+ return {
132
+ id: createComponentId(source, name),
133
+ name,
134
+ source: source,
135
+ props: [], // Templates don't have typed props in the same way
136
+ variants: [],
137
+ tokens: [],
138
+ dependencies,
139
+ metadata: {
140
+ deprecated: content.includes('@deprecated') || content.includes('DEPRECATED'),
141
+ tags: [],
142
+ },
143
+ scannedAt: new Date(),
144
+ };
145
+ }
146
+ extractComponentName(filePath) {
147
+ let name = basename(filePath);
148
+ // Remove extensions
149
+ name = name.replace(/\.(blade\.php|html\.erb|html\.twig|php|html|njk)$/i, '');
150
+ // Remove partial prefix (Rails convention)
151
+ name = name.replace(/^_/, '');
152
+ // Convert to PascalCase
153
+ name = name
154
+ .split(/[-_.]/)
155
+ .map(s => s.charAt(0).toUpperCase() + s.slice(1))
156
+ .join('');
157
+ return name;
158
+ }
159
+ isLikelyComponent(filePath, _content) {
160
+ const lowerPath = filePath.toLowerCase();
161
+ const pathParts = lowerPath.split('/');
162
+ // Paths that indicate reusable components
163
+ const componentIndicators = [
164
+ 'component', 'components',
165
+ 'partial', 'partials',
166
+ 'shared',
167
+ '_includes', 'includes',
168
+ 'ui',
169
+ 'atoms', 'molecules', 'organisms',
170
+ 'widgets', 'blocks', 'elements',
171
+ ];
172
+ // Check for component indicators in path
173
+ if (componentIndicators.some(ci => pathParts.some(p => p.includes(ci)))) {
174
+ return true;
175
+ }
176
+ // Check for partial prefix (Rails convention: _partial.html.erb)
177
+ if (basename(filePath).startsWith('_')) {
178
+ return true;
179
+ }
180
+ // Paths that indicate pages/layouts (not reusable components)
181
+ const pageIndicators = [
182
+ 'layout', 'layouts',
183
+ 'page', 'pages',
184
+ 'views', // ASP.NET/Rails views folder
185
+ 'areas', // ASP.NET areas
186
+ 'email', 'mail', 'emails',
187
+ ];
188
+ if (pageIndicators.some(pi => pathParts.some(p => p === pi))) {
189
+ return false;
190
+ }
191
+ // Default: don't include without explicit component indicators
192
+ return false;
193
+ }
194
+ extractDependencies(content) {
195
+ const deps = new Set();
196
+ const templateConfig = TEMPLATE_CONFIG[this.config.templateType];
197
+ if (!templateConfig)
198
+ return [];
199
+ for (const pattern of templateConfig.patterns) {
200
+ // Reset regex lastIndex for each use
201
+ pattern.lastIndex = 0;
202
+ let match;
203
+ while ((match = pattern.exec(content)) !== null) {
204
+ if (match[1]) {
205
+ // Extract the dependency name and convert to PascalCase
206
+ const depPath = match[1];
207
+ const depName = this.pathToComponentName(depPath);
208
+ deps.add(depName);
209
+ }
210
+ }
211
+ }
212
+ return Array.from(deps);
213
+ }
214
+ pathToComponentName(path) {
215
+ // Get the last part of the path
216
+ const parts = path.split(/[\/\.]/);
217
+ let name = parts[parts.length - 1] || parts[parts.length - 2] || path;
218
+ // Remove partial prefix
219
+ name = name.replace(/^_/, '');
220
+ // Convert to PascalCase
221
+ return name
222
+ .split(/[-_]/)
223
+ .map(s => s.charAt(0).toUpperCase() + s.slice(1))
224
+ .join('');
225
+ }
226
+ }
227
+ //# sourceMappingURL=template-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-scanner.js","sourceRoot":"","sources":["../../src/git/template-scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { Scanner, ScanResult, ScannerConfig } from '../base/scanner.js';
2
+ import type { DesignToken } from '@buoy-design/core';
3
+ export interface TokenScannerConfig extends ScannerConfig {
4
+ files?: string[];
5
+ cssVariablePrefix?: string;
6
+ }
7
+ export declare class TokenScanner extends Scanner<DesignToken, TokenScannerConfig> {
8
+ scan(): Promise<ScanResult<DesignToken>>;
9
+ getSourceType(): string;
10
+ private findTokenFiles;
11
+ private parseJsonTokenFile;
12
+ private isTokenValue;
13
+ private createTokenFromJson;
14
+ private parseCssVariables;
15
+ /**
16
+ * Strip CSS comments from content, preserving line structure
17
+ * for accurate line number calculation
18
+ */
19
+ private stripCssComments;
20
+ /**
21
+ * Extract CSS custom properties handling:
22
+ * - Multi-line values (gradients, box-shadows)
23
+ * - Values containing semicolons in url() or content strings
24
+ */
25
+ private extractCssVariables;
26
+ /**
27
+ * Extract SCSS variables handling multi-line values and strings
28
+ */
29
+ private extractScssVariables;
30
+ /**
31
+ * Extract a CSS value starting at the given position, handling:
32
+ * - Nested parentheses (for url(), calc(), etc.)
33
+ * - Quoted strings (which may contain semicolons)
34
+ * - Multi-line values
35
+ * Returns null if no valid value found
36
+ */
37
+ private extractCssValue;
38
+ private inferCategory;
39
+ private normalizeCategory;
40
+ private parseTokenValue;
41
+ private normalizeColor;
42
+ }
43
+ //# sourceMappingURL=token-scanner.d.ts.map