@buoy-design/scanners 0.1.0 → 0.1.1
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/LICENSE +21 -0
- package/dist/base/scanner.d.ts +36 -0
- package/dist/base/scanner.d.ts.map +1 -1
- package/dist/base/scanner.js +112 -0
- package/dist/base/scanner.js.map +1 -1
- package/dist/figma/client.d.ts +46 -5
- package/dist/figma/client.d.ts.map +1 -1
- package/dist/figma/client.js +109 -6
- package/dist/figma/client.js.map +1 -1
- package/dist/figma/index.d.ts +2 -2
- package/dist/figma/index.d.ts.map +1 -1
- package/dist/figma/index.js +2 -2
- package/dist/figma/index.js.map +1 -1
- package/dist/git/angular-scanner.d.ts +2 -2
- package/dist/git/angular-scanner.d.ts.map +1 -1
- package/dist/git/angular-scanner.js +53 -43
- package/dist/git/angular-scanner.js.map +1 -1
- package/dist/git/react-scanner.d.ts +4 -3
- package/dist/git/react-scanner.d.ts.map +1 -1
- package/dist/git/react-scanner.js +89 -120
- package/dist/git/react-scanner.js.map +1 -1
- package/dist/git/svelte-scanner.d.ts +2 -2
- package/dist/git/svelte-scanner.d.ts.map +1 -1
- package/dist/git/svelte-scanner.js +90 -59
- package/dist/git/svelte-scanner.js.map +1 -1
- package/dist/git/token-scanner.d.ts +2 -2
- package/dist/git/token-scanner.d.ts.map +1 -1
- package/dist/git/token-scanner.js +135 -116
- package/dist/git/token-scanner.js.map +1 -1
- package/dist/git/vue-scanner.d.ts +2 -2
- package/dist/git/vue-scanner.d.ts.map +1 -1
- package/dist/git/vue-scanner.js +64 -46
- package/dist/git/vue-scanner.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/tailwind/arbitrary-detector.d.ts +26 -0
- package/dist/tailwind/arbitrary-detector.d.ts.map +1 -0
- package/dist/tailwind/arbitrary-detector.js +190 -0
- package/dist/tailwind/arbitrary-detector.js.map +1 -0
- package/dist/tailwind/config-parser.d.ts +29 -0
- package/dist/tailwind/config-parser.d.ts.map +1 -0
- package/dist/tailwind/config-parser.js +221 -0
- package/dist/tailwind/config-parser.js.map +1 -0
- package/dist/tailwind/index.d.ts +4 -0
- package/dist/tailwind/index.d.ts.map +1 -0
- package/dist/tailwind/index.js +4 -0
- package/dist/tailwind/index.js.map +1 -0
- package/dist/tailwind/scanner.d.ts +26 -0
- package/dist/tailwind/scanner.d.ts.map +1 -0
- package/dist/tailwind/scanner.js +49 -0
- package/dist/tailwind/scanner.js.map +1 -0
- package/package.json +23 -13
|
@@ -1,26 +1,32 @@
|
|
|
1
|
-
import { Scanner } from
|
|
2
|
-
import { createComponentId } from
|
|
3
|
-
import * as ts from
|
|
4
|
-
import { glob } from
|
|
5
|
-
import { readFileSync } from
|
|
6
|
-
import { relative } from
|
|
1
|
+
import { Scanner, parallelProcess, extractResults, } from "../base/scanner.js";
|
|
2
|
+
import { createComponentId } from "@buoy-design/core";
|
|
3
|
+
import * as ts from "typescript";
|
|
4
|
+
import { glob } from "glob";
|
|
5
|
+
import { readFileSync } from "fs";
|
|
6
|
+
import { relative } from "path";
|
|
7
7
|
export class AngularComponentScanner extends Scanner {
|
|
8
8
|
async scan() {
|
|
9
9
|
const startTime = Date.now();
|
|
10
10
|
const files = await this.findComponentFiles();
|
|
11
11
|
const components = [];
|
|
12
12
|
const errors = [];
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
// Process files in parallel
|
|
14
|
+
const results = await parallelProcess(files, async (file) => ({ file, components: await this.parseFile(file) }), this.concurrency);
|
|
15
|
+
const { successes } = extractResults(results);
|
|
16
|
+
for (const success of successes) {
|
|
17
|
+
components.push(...success.components);
|
|
18
|
+
}
|
|
19
|
+
// Map failures to errors
|
|
20
|
+
for (let i = 0; i < results.length; i++) {
|
|
21
|
+
const result = results[i];
|
|
22
|
+
if (result.status === "rejected") {
|
|
23
|
+
const message = result.reason instanceof Error
|
|
24
|
+
? result.reason.message
|
|
25
|
+
: String(result.reason);
|
|
20
26
|
errors.push({
|
|
21
|
-
file,
|
|
27
|
+
file: files[i],
|
|
22
28
|
message,
|
|
23
|
-
code:
|
|
29
|
+
code: "PARSE_ERROR",
|
|
24
30
|
});
|
|
25
31
|
}
|
|
26
32
|
}
|
|
@@ -32,16 +38,16 @@ export class AngularComponentScanner extends Scanner {
|
|
|
32
38
|
return { items: components, errors, stats };
|
|
33
39
|
}
|
|
34
40
|
getSourceType() {
|
|
35
|
-
return
|
|
41
|
+
return "angular";
|
|
36
42
|
}
|
|
37
43
|
async findComponentFiles() {
|
|
38
|
-
const patterns = this.config.include || [
|
|
44
|
+
const patterns = this.config.include || ["**/*.component.ts"];
|
|
39
45
|
const ignore = this.config.exclude || [
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
"**/node_modules/**",
|
|
47
|
+
"**/*.spec.ts",
|
|
48
|
+
"**/*.test.ts",
|
|
49
|
+
"**/dist/**",
|
|
50
|
+
"**/build/**",
|
|
45
51
|
];
|
|
46
52
|
const allFiles = [];
|
|
47
53
|
for (const pattern of patterns) {
|
|
@@ -55,7 +61,7 @@ export class AngularComponentScanner extends Scanner {
|
|
|
55
61
|
return [...new Set(allFiles)];
|
|
56
62
|
}
|
|
57
63
|
async parseFile(filePath) {
|
|
58
|
-
const content = readFileSync(filePath,
|
|
64
|
+
const content = readFileSync(filePath, "utf-8");
|
|
59
65
|
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
60
66
|
const components = [];
|
|
61
67
|
const relativePath = relative(this.config.projectRoot, filePath);
|
|
@@ -78,10 +84,10 @@ export class AngularComponentScanner extends Scanner {
|
|
|
78
84
|
const modifiers = ts.getDecorators(node);
|
|
79
85
|
if (!modifiers)
|
|
80
86
|
return undefined;
|
|
81
|
-
return modifiers.find(decorator => {
|
|
87
|
+
return modifiers.find((decorator) => {
|
|
82
88
|
if (ts.isCallExpression(decorator.expression)) {
|
|
83
89
|
const expr = decorator.expression.expression;
|
|
84
|
-
return ts.isIdentifier(expr) && expr.text ===
|
|
90
|
+
return ts.isIdentifier(expr) && expr.text === "Component";
|
|
85
91
|
}
|
|
86
92
|
return false;
|
|
87
93
|
});
|
|
@@ -91,12 +97,13 @@ export class AngularComponentScanner extends Scanner {
|
|
|
91
97
|
return null;
|
|
92
98
|
const name = node.name.getText(sourceFile);
|
|
93
99
|
const selector = this.extractSelector(decorator, sourceFile);
|
|
94
|
-
const line = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line +
|
|
100
|
+
const line = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line +
|
|
101
|
+
1;
|
|
95
102
|
const source = {
|
|
96
|
-
type:
|
|
103
|
+
type: "angular",
|
|
97
104
|
path: relativePath,
|
|
98
105
|
exportName: name,
|
|
99
|
-
selector: selector || name.replace(
|
|
106
|
+
selector: selector || name.replace("Component", "").toLowerCase(),
|
|
100
107
|
line,
|
|
101
108
|
};
|
|
102
109
|
const props = this.extractInputs(node, sourceFile);
|
|
@@ -127,7 +134,8 @@ export class AngularComponentScanner extends Scanner {
|
|
|
127
134
|
return null;
|
|
128
135
|
for (const prop of config.properties) {
|
|
129
136
|
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
|
130
|
-
if (prop.name.text ===
|
|
137
|
+
if (prop.name.text === "selector" &&
|
|
138
|
+
ts.isStringLiteral(prop.initializer)) {
|
|
131
139
|
return prop.initializer.text;
|
|
132
140
|
}
|
|
133
141
|
}
|
|
@@ -144,19 +152,21 @@ export class AngularComponentScanner extends Scanner {
|
|
|
144
152
|
const decorators = ts.getDecorators(member);
|
|
145
153
|
if (!decorators)
|
|
146
154
|
continue;
|
|
147
|
-
const hasInput = decorators.some(d => {
|
|
155
|
+
const hasInput = decorators.some((d) => {
|
|
148
156
|
if (ts.isCallExpression(d.expression)) {
|
|
149
157
|
const expr = d.expression.expression;
|
|
150
|
-
return ts.isIdentifier(expr) && expr.text ===
|
|
158
|
+
return ts.isIdentifier(expr) && expr.text === "Input";
|
|
151
159
|
}
|
|
152
160
|
if (ts.isIdentifier(d.expression)) {
|
|
153
|
-
return d.expression.text ===
|
|
161
|
+
return d.expression.text === "Input";
|
|
154
162
|
}
|
|
155
163
|
return false;
|
|
156
164
|
});
|
|
157
165
|
if (hasInput) {
|
|
158
166
|
const propName = member.name.getText(sourceFile);
|
|
159
|
-
const propType = member.type
|
|
167
|
+
const propType = member.type
|
|
168
|
+
? member.type.getText(sourceFile)
|
|
169
|
+
: "unknown";
|
|
160
170
|
const hasDefault = !!member.initializer;
|
|
161
171
|
inputs.push({
|
|
162
172
|
name: propName,
|
|
@@ -174,11 +184,11 @@ export class AngularComponentScanner extends Scanner {
|
|
|
174
184
|
continue;
|
|
175
185
|
if (member.initializer && ts.isCallExpression(member.initializer)) {
|
|
176
186
|
const callExpr = member.initializer.expression;
|
|
177
|
-
if (ts.isIdentifier(callExpr) && callExpr.text ===
|
|
187
|
+
if (ts.isIdentifier(callExpr) && callExpr.text === "input") {
|
|
178
188
|
const propName = member.name.getText(sourceFile);
|
|
179
189
|
inputs.push({
|
|
180
190
|
name: propName,
|
|
181
|
-
type:
|
|
191
|
+
type: "Signal",
|
|
182
192
|
required: false,
|
|
183
193
|
});
|
|
184
194
|
}
|
|
@@ -196,13 +206,13 @@ export class AngularComponentScanner extends Scanner {
|
|
|
196
206
|
const decorators = ts.getDecorators(member);
|
|
197
207
|
if (!decorators)
|
|
198
208
|
continue;
|
|
199
|
-
const hasOutput = decorators.some(d => {
|
|
209
|
+
const hasOutput = decorators.some((d) => {
|
|
200
210
|
if (ts.isCallExpression(d.expression)) {
|
|
201
211
|
const expr = d.expression.expression;
|
|
202
|
-
return ts.isIdentifier(expr) && expr.text ===
|
|
212
|
+
return ts.isIdentifier(expr) && expr.text === "Output";
|
|
203
213
|
}
|
|
204
214
|
if (ts.isIdentifier(d.expression)) {
|
|
205
|
-
return d.expression.text ===
|
|
215
|
+
return d.expression.text === "Output";
|
|
206
216
|
}
|
|
207
217
|
return false;
|
|
208
218
|
});
|
|
@@ -210,9 +220,9 @@ export class AngularComponentScanner extends Scanner {
|
|
|
210
220
|
const propName = member.name.getText(sourceFile);
|
|
211
221
|
outputs.push({
|
|
212
222
|
name: propName,
|
|
213
|
-
type:
|
|
223
|
+
type: "EventEmitter",
|
|
214
224
|
required: false,
|
|
215
|
-
description:
|
|
225
|
+
description: "Output event",
|
|
216
226
|
});
|
|
217
227
|
}
|
|
218
228
|
}
|
|
@@ -224,11 +234,11 @@ export class AngularComponentScanner extends Scanner {
|
|
|
224
234
|
continue;
|
|
225
235
|
if (member.initializer && ts.isCallExpression(member.initializer)) {
|
|
226
236
|
const callExpr = member.initializer.expression;
|
|
227
|
-
if (ts.isIdentifier(callExpr) && callExpr.text ===
|
|
237
|
+
if (ts.isIdentifier(callExpr) && callExpr.text === "output") {
|
|
228
238
|
const propName = member.name.getText(sourceFile);
|
|
229
239
|
outputs.push({
|
|
230
240
|
name: propName,
|
|
231
|
-
type:
|
|
241
|
+
type: "OutputSignal",
|
|
232
242
|
required: false,
|
|
233
243
|
});
|
|
234
244
|
}
|
|
@@ -238,7 +248,7 @@ export class AngularComponentScanner extends Scanner {
|
|
|
238
248
|
}
|
|
239
249
|
hasDeprecatedDecorator(node) {
|
|
240
250
|
const jsDocs = ts.getJSDocTags(node);
|
|
241
|
-
return jsDocs.some(tag => tag.tagName.text ===
|
|
251
|
+
return jsDocs.some((tag) => tag.tagName.text === "deprecated");
|
|
242
252
|
}
|
|
243
253
|
}
|
|
244
254
|
//# sourceMappingURL=angular-scanner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-scanner.js","sourceRoot":"","sources":["../../src/git/angular-scanner.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"angular-scanner.js","sourceRoot":"","sources":["../../src/git/angular-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { Scanner, ScanResult, ScannerConfig } from
|
|
2
|
-
import type { Component } from
|
|
1
|
+
import { Scanner, ScanResult, ScannerConfig } from "../base/scanner.js";
|
|
2
|
+
import type { Component } from "@buoy-design/core";
|
|
3
3
|
export interface ReactScannerConfig extends ScannerConfig {
|
|
4
4
|
designSystemPackage?: string;
|
|
5
5
|
componentPatterns?: string[];
|
|
6
6
|
}
|
|
7
7
|
export declare class ReactComponentScanner extends Scanner<Component, ReactScannerConfig> {
|
|
8
|
+
/** Default file patterns for React components */
|
|
9
|
+
private static readonly DEFAULT_PATTERNS;
|
|
8
10
|
scan(): Promise<ScanResult<Component>>;
|
|
9
11
|
getSourceType(): string;
|
|
10
|
-
private findComponentFiles;
|
|
11
12
|
private parseFile;
|
|
12
13
|
private isReactComponent;
|
|
13
14
|
private isReactComponentExpression;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-scanner.d.ts","sourceRoot":"","sources":["../../src/git/react-scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"react-scanner.d.ts","sourceRoot":"","sources":["../../src/git/react-scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EACV,SAAS,EAIV,MAAM,mBAAmB,CAAC;AAyD3B,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,qBAAa,qBAAsB,SAAQ,OAAO,CAChD,SAAS,EACT,kBAAkB,CACnB;IACC,iDAAiD;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAA4B;IAE9D,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IAO5C,aAAa,IAAI,MAAM;YAIT,SAAS;IAiDvB,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,0BAA0B;IAyBlC,OAAO,CAAC,UAAU;IAwBlB,OAAO,CAAC,wBAAwB;IAwChC,OAAO,CAAC,wBAAwB;IAiDhC,OAAO,CAAC,YAAY;IAmDpB,OAAO,CAAC,mBAAmB;IAsB3B,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,sBAAsB;IA4E9B,OAAO,CAAC,wBAAwB;IAyChC,OAAO,CAAC,oBAAoB;IAmB5B,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,gBAAgB;IA2BxB,OAAO,CAAC,gBAAgB;IAoBxB,OAAO,CAAC,kBAAkB;CAkB3B"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { Scanner } from
|
|
2
|
-
import { createComponentId } from
|
|
3
|
-
import * as ts from
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { relative } from 'path';
|
|
1
|
+
import { Scanner } from "../base/scanner.js";
|
|
2
|
+
import { createComponentId } from "@buoy-design/core";
|
|
3
|
+
import * as ts from "typescript";
|
|
4
|
+
import { readFile } from "fs/promises";
|
|
5
|
+
import { relative } from "path";
|
|
7
6
|
// Patterns for detecting hardcoded values
|
|
8
7
|
const COLOR_PATTERNS = [
|
|
9
8
|
/^#[0-9a-fA-F]{3,8}$/, // Hex colors
|
|
@@ -20,92 +19,49 @@ const FONT_SIZE_PATTERNS = [
|
|
|
20
19
|
];
|
|
21
20
|
// Style properties that commonly contain design tokens
|
|
22
21
|
const STYLE_PROPERTIES = {
|
|
23
|
-
color:
|
|
24
|
-
backgroundColor:
|
|
25
|
-
background:
|
|
26
|
-
borderColor:
|
|
27
|
-
fill:
|
|
28
|
-
stroke:
|
|
29
|
-
padding:
|
|
30
|
-
paddingTop:
|
|
31
|
-
paddingRight:
|
|
32
|
-
paddingBottom:
|
|
33
|
-
paddingLeft:
|
|
34
|
-
margin:
|
|
35
|
-
marginTop:
|
|
36
|
-
marginRight:
|
|
37
|
-
marginBottom:
|
|
38
|
-
marginLeft:
|
|
39
|
-
gap:
|
|
40
|
-
width:
|
|
41
|
-
height:
|
|
42
|
-
top:
|
|
43
|
-
right:
|
|
44
|
-
bottom:
|
|
45
|
-
left:
|
|
46
|
-
fontSize:
|
|
47
|
-
fontFamily:
|
|
48
|
-
boxShadow:
|
|
49
|
-
textShadow:
|
|
50
|
-
border:
|
|
51
|
-
borderWidth:
|
|
52
|
-
borderRadius:
|
|
22
|
+
color: "color",
|
|
23
|
+
backgroundColor: "color",
|
|
24
|
+
background: "color",
|
|
25
|
+
borderColor: "color",
|
|
26
|
+
fill: "color",
|
|
27
|
+
stroke: "color",
|
|
28
|
+
padding: "spacing",
|
|
29
|
+
paddingTop: "spacing",
|
|
30
|
+
paddingRight: "spacing",
|
|
31
|
+
paddingBottom: "spacing",
|
|
32
|
+
paddingLeft: "spacing",
|
|
33
|
+
margin: "spacing",
|
|
34
|
+
marginTop: "spacing",
|
|
35
|
+
marginRight: "spacing",
|
|
36
|
+
marginBottom: "spacing",
|
|
37
|
+
marginLeft: "spacing",
|
|
38
|
+
gap: "spacing",
|
|
39
|
+
width: "spacing",
|
|
40
|
+
height: "spacing",
|
|
41
|
+
top: "spacing",
|
|
42
|
+
right: "spacing",
|
|
43
|
+
bottom: "spacing",
|
|
44
|
+
left: "spacing",
|
|
45
|
+
fontSize: "fontSize",
|
|
46
|
+
fontFamily: "fontFamily",
|
|
47
|
+
boxShadow: "shadow",
|
|
48
|
+
textShadow: "shadow",
|
|
49
|
+
border: "border",
|
|
50
|
+
borderWidth: "border",
|
|
51
|
+
borderRadius: "border",
|
|
53
52
|
};
|
|
54
53
|
export class ReactComponentScanner extends Scanner {
|
|
54
|
+
/** Default file patterns for React components */
|
|
55
|
+
static DEFAULT_PATTERNS = ["**/*.tsx", "**/*.jsx"];
|
|
55
56
|
async scan() {
|
|
56
|
-
|
|
57
|
-
const files = await this.findComponentFiles();
|
|
58
|
-
const components = [];
|
|
59
|
-
const errors = [];
|
|
60
|
-
for (const file of files) {
|
|
61
|
-
try {
|
|
62
|
-
const parsed = await this.parseFile(file);
|
|
63
|
-
components.push(...parsed);
|
|
64
|
-
}
|
|
65
|
-
catch (err) {
|
|
66
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
67
|
-
errors.push({
|
|
68
|
-
file,
|
|
69
|
-
message,
|
|
70
|
-
code: 'PARSE_ERROR',
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const stats = {
|
|
75
|
-
filesScanned: files.length,
|
|
76
|
-
itemsFound: components.length,
|
|
77
|
-
duration: Date.now() - startTime,
|
|
78
|
-
};
|
|
79
|
-
return { items: components, errors, stats };
|
|
57
|
+
return this.runScan((file) => this.parseFile(file), ReactComponentScanner.DEFAULT_PATTERNS);
|
|
80
58
|
}
|
|
81
59
|
getSourceType() {
|
|
82
|
-
return
|
|
83
|
-
}
|
|
84
|
-
async findComponentFiles() {
|
|
85
|
-
const patterns = this.config.include || ['**/*.tsx', '**/*.jsx'];
|
|
86
|
-
const ignore = this.config.exclude || [
|
|
87
|
-
'**/node_modules/**',
|
|
88
|
-
'**/*.test.*',
|
|
89
|
-
'**/*.spec.*',
|
|
90
|
-
'**/*.stories.*',
|
|
91
|
-
'**/dist/**',
|
|
92
|
-
'**/build/**',
|
|
93
|
-
];
|
|
94
|
-
const allFiles = [];
|
|
95
|
-
for (const pattern of patterns) {
|
|
96
|
-
const matches = await glob(pattern, {
|
|
97
|
-
cwd: this.config.projectRoot,
|
|
98
|
-
ignore,
|
|
99
|
-
absolute: true,
|
|
100
|
-
});
|
|
101
|
-
allFiles.push(...matches);
|
|
102
|
-
}
|
|
103
|
-
// Deduplicate
|
|
104
|
-
return [...new Set(allFiles)];
|
|
60
|
+
return "react";
|
|
105
61
|
}
|
|
106
62
|
async parseFile(filePath) {
|
|
107
|
-
const content = await readFile(filePath,
|
|
108
|
-
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith(
|
|
63
|
+
const content = await readFile(filePath, "utf-8");
|
|
64
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.JSX);
|
|
109
65
|
const components = [];
|
|
110
66
|
const relativePath = relative(this.config.projectRoot, filePath);
|
|
111
67
|
const visit = (node) => {
|
|
@@ -152,10 +108,10 @@ export class ReactComponentScanner extends Scanner {
|
|
|
152
108
|
// React.forwardRef or React.memo
|
|
153
109
|
if (ts.isCallExpression(node)) {
|
|
154
110
|
const callText = node.expression.getText(sourceFile);
|
|
155
|
-
if (callText.includes(
|
|
156
|
-
callText.includes(
|
|
157
|
-
callText.includes(
|
|
158
|
-
callText.includes(
|
|
111
|
+
if (callText.includes("forwardRef") ||
|
|
112
|
+
callText.includes("memo") ||
|
|
113
|
+
callText.includes("React.forwardRef") ||
|
|
114
|
+
callText.includes("React.memo")) {
|
|
159
115
|
return true;
|
|
160
116
|
}
|
|
161
117
|
}
|
|
@@ -164,7 +120,9 @@ export class ReactComponentScanner extends Scanner {
|
|
|
164
120
|
returnsJsx(node) {
|
|
165
121
|
let hasJsx = false;
|
|
166
122
|
const checkNode = (n) => {
|
|
167
|
-
if (ts.isJsxElement(n) ||
|
|
123
|
+
if (ts.isJsxElement(n) ||
|
|
124
|
+
ts.isJsxSelfClosingElement(n) ||
|
|
125
|
+
ts.isJsxFragment(n)) {
|
|
168
126
|
hasJsx = true;
|
|
169
127
|
return;
|
|
170
128
|
}
|
|
@@ -180,9 +138,10 @@ export class ReactComponentScanner extends Scanner {
|
|
|
180
138
|
return null;
|
|
181
139
|
const name = node.name.getText(sourceFile);
|
|
182
140
|
const props = this.extractProps(node.parameters, sourceFile);
|
|
183
|
-
const line = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line +
|
|
141
|
+
const line = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line +
|
|
142
|
+
1;
|
|
184
143
|
const source = {
|
|
185
|
-
type:
|
|
144
|
+
type: "react",
|
|
186
145
|
path: relativePath,
|
|
187
146
|
exportName: name,
|
|
188
147
|
line,
|
|
@@ -211,9 +170,10 @@ export class ReactComponentScanner extends Scanner {
|
|
|
211
170
|
// Check for uppercase first letter
|
|
212
171
|
if (!/^[A-Z]/.test(name))
|
|
213
172
|
return null;
|
|
214
|
-
const line = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line +
|
|
173
|
+
const line = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line +
|
|
174
|
+
1;
|
|
215
175
|
const source = {
|
|
216
|
-
type:
|
|
176
|
+
type: "react",
|
|
217
177
|
path: relativePath,
|
|
218
178
|
exportName: name,
|
|
219
179
|
line,
|
|
@@ -252,7 +212,7 @@ export class ReactComponentScanner extends Scanner {
|
|
|
252
212
|
if (ts.isPropertySignature(member) && member.name) {
|
|
253
213
|
props.push({
|
|
254
214
|
name: member.name.getText(sourceFile),
|
|
255
|
-
type: member.type ? member.type.getText(sourceFile) :
|
|
215
|
+
type: member.type ? member.type.getText(sourceFile) : "unknown",
|
|
256
216
|
required: !member.questionToken,
|
|
257
217
|
});
|
|
258
218
|
}
|
|
@@ -261,7 +221,7 @@ export class ReactComponentScanner extends Scanner {
|
|
|
261
221
|
else if (typeNode && ts.isTypeReferenceNode(typeNode)) {
|
|
262
222
|
// Reference to an interface/type - we just note the type name
|
|
263
223
|
props.push({
|
|
264
|
-
name:
|
|
224
|
+
name: "props",
|
|
265
225
|
type: typeNode.getText(sourceFile),
|
|
266
226
|
required: true,
|
|
267
227
|
});
|
|
@@ -272,7 +232,7 @@ export class ReactComponentScanner extends Scanner {
|
|
|
272
232
|
if (ts.isBindingElement(element) && ts.isIdentifier(element.name)) {
|
|
273
233
|
props.push({
|
|
274
234
|
name: element.name.getText(sourceFile),
|
|
275
|
-
type:
|
|
235
|
+
type: "unknown",
|
|
276
236
|
required: !element.initializer,
|
|
277
237
|
defaultValue: element.initializer
|
|
278
238
|
? element.initializer.getText(sourceFile)
|
|
@@ -301,14 +261,14 @@ export class ReactComponentScanner extends Scanner {
|
|
|
301
261
|
}
|
|
302
262
|
hasDeprecatedTag(node, sourceFile) {
|
|
303
263
|
const jsDocs = ts.getJSDocTags(node);
|
|
304
|
-
return jsDocs.some(tag => tag.tagName.getText(sourceFile) ===
|
|
264
|
+
return jsDocs.some((tag) => tag.tagName.getText(sourceFile) === "deprecated");
|
|
305
265
|
}
|
|
306
266
|
extractTags(node, sourceFile) {
|
|
307
267
|
const tags = [];
|
|
308
268
|
const jsDocs = ts.getJSDocTags(node);
|
|
309
269
|
for (const tag of jsDocs) {
|
|
310
270
|
const tagName = tag.tagName.getText(sourceFile);
|
|
311
|
-
if (tagName !==
|
|
271
|
+
if (tagName !== "param" && tagName !== "returns" && tagName !== "type") {
|
|
312
272
|
tags.push(tagName);
|
|
313
273
|
}
|
|
314
274
|
}
|
|
@@ -321,17 +281,18 @@ export class ReactComponentScanner extends Scanner {
|
|
|
321
281
|
if (ts.isJsxAttribute(n)) {
|
|
322
282
|
const attrName = n.name.getText(sourceFile);
|
|
323
283
|
// style={{ color: '#fff', padding: '8px' }}
|
|
324
|
-
if (attrName ===
|
|
284
|
+
if (attrName === "style" && n.initializer) {
|
|
325
285
|
const styleValues = this.extractStyleObjectValues(n.initializer, sourceFile);
|
|
326
286
|
hardcoded.push(...styleValues);
|
|
327
287
|
}
|
|
328
288
|
// Direct color/size props like color="#fff" or size={16}
|
|
329
|
-
if ([
|
|
289
|
+
if (["color", "bg", "backgroundColor", "fill", "stroke"].includes(attrName)) {
|
|
330
290
|
const value = this.getJsxAttributeValue(n, sourceFile);
|
|
331
291
|
if (value && this.isHardcodedColor(value)) {
|
|
332
|
-
const line = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile))
|
|
292
|
+
const line = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile))
|
|
293
|
+
.line + 1;
|
|
333
294
|
hardcoded.push({
|
|
334
|
-
type:
|
|
295
|
+
type: "color",
|
|
335
296
|
value,
|
|
336
297
|
property: attrName,
|
|
337
298
|
location: `line ${line}`,
|
|
@@ -339,12 +300,13 @@ export class ReactComponentScanner extends Scanner {
|
|
|
339
300
|
}
|
|
340
301
|
}
|
|
341
302
|
// Size props
|
|
342
|
-
if ([
|
|
303
|
+
if (["size", "width", "height", "padding", "margin", "gap"].includes(attrName)) {
|
|
343
304
|
const value = this.getJsxAttributeValue(n, sourceFile);
|
|
344
305
|
if (value && this.isHardcodedSpacing(value)) {
|
|
345
|
-
const line = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile))
|
|
306
|
+
const line = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile))
|
|
307
|
+
.line + 1;
|
|
346
308
|
hardcoded.push({
|
|
347
|
-
type:
|
|
309
|
+
type: "spacing",
|
|
348
310
|
value,
|
|
349
311
|
property: attrName,
|
|
350
312
|
location: `line ${line}`,
|
|
@@ -357,7 +319,7 @@ export class ReactComponentScanner extends Scanner {
|
|
|
357
319
|
visit(node);
|
|
358
320
|
// Deduplicate by value+property
|
|
359
321
|
const seen = new Set();
|
|
360
|
-
return hardcoded.filter(h => {
|
|
322
|
+
return hardcoded.filter((h) => {
|
|
361
323
|
const key = `${h.property}:${h.value}`;
|
|
362
324
|
if (seen.has(key))
|
|
363
325
|
return false;
|
|
@@ -419,7 +381,7 @@ export class ReactComponentScanner extends Scanner {
|
|
|
419
381
|
if (ts.isTemplateExpression(node)) {
|
|
420
382
|
// Only if it's a simple template
|
|
421
383
|
const text = node.getText(sourceFile);
|
|
422
|
-
if (!text.includes(
|
|
384
|
+
if (!text.includes("${")) {
|
|
423
385
|
return text.slice(1, -1); // Remove backticks
|
|
424
386
|
}
|
|
425
387
|
}
|
|
@@ -427,43 +389,50 @@ export class ReactComponentScanner extends Scanner {
|
|
|
427
389
|
}
|
|
428
390
|
isHardcodedValue(value, type) {
|
|
429
391
|
// Skip CSS variables and token references
|
|
430
|
-
if (value.includes(
|
|
392
|
+
if (value.includes("var(--") ||
|
|
393
|
+
value.includes("theme.") ||
|
|
394
|
+
value.includes("tokens.")) {
|
|
431
395
|
return false;
|
|
432
396
|
}
|
|
433
397
|
switch (type) {
|
|
434
|
-
case
|
|
398
|
+
case "color":
|
|
435
399
|
return this.isHardcodedColor(value);
|
|
436
|
-
case
|
|
437
|
-
case
|
|
400
|
+
case "spacing":
|
|
401
|
+
case "fontSize":
|
|
438
402
|
return this.isHardcodedSpacing(value);
|
|
439
|
-
case
|
|
403
|
+
case "fontFamily":
|
|
440
404
|
// Font families are often hardcoded, only flag if it's a system font
|
|
441
|
-
return !value.includes(
|
|
405
|
+
return !value.includes("var(--") && !value.includes("inherit");
|
|
442
406
|
default:
|
|
443
407
|
return false;
|
|
444
408
|
}
|
|
445
409
|
}
|
|
446
410
|
isHardcodedColor(value) {
|
|
447
411
|
// Skip CSS variables and token references
|
|
448
|
-
if (value.includes(
|
|
412
|
+
if (value.includes("var(--") ||
|
|
413
|
+
value.includes("theme.") ||
|
|
414
|
+
value.includes("tokens.")) {
|
|
449
415
|
return false;
|
|
450
416
|
}
|
|
451
417
|
// Skip named colors that might be intentional (inherit, transparent, currentColor)
|
|
452
|
-
if ([
|
|
418
|
+
if (["inherit", "transparent", "currentColor", "initial", "unset"].includes(value)) {
|
|
453
419
|
return false;
|
|
454
420
|
}
|
|
455
|
-
return COLOR_PATTERNS.some(p => p.test(value));
|
|
421
|
+
return COLOR_PATTERNS.some((p) => p.test(value));
|
|
456
422
|
}
|
|
457
423
|
isHardcodedSpacing(value) {
|
|
458
424
|
// Skip CSS variables and token references
|
|
459
|
-
if (value.includes(
|
|
425
|
+
if (value.includes("var(--") ||
|
|
426
|
+
value.includes("theme.") ||
|
|
427
|
+
value.includes("tokens.")) {
|
|
460
428
|
return false;
|
|
461
429
|
}
|
|
462
430
|
// Skip common non-token values
|
|
463
|
-
if ([
|
|
431
|
+
if (["auto", "inherit", "0", "100%", "50%"].includes(value)) {
|
|
464
432
|
return false;
|
|
465
433
|
}
|
|
466
|
-
return SPACING_PATTERNS.some(p => p.test(value)) ||
|
|
434
|
+
return (SPACING_PATTERNS.some((p) => p.test(value)) ||
|
|
435
|
+
FONT_SIZE_PATTERNS.some((p) => p.test(value)));
|
|
467
436
|
}
|
|
468
437
|
}
|
|
469
438
|
//# sourceMappingURL=react-scanner.js.map
|