@sdk-usage/core 0.0.0-next-a13a5b4 → 0.0.0-next-193dba9
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/package.json +5 -5
- package/dist/index.cjs +0 -286
- package/dist/index.d.ts +0 -96
- package/dist/index.mjs +0 -282
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdk-usage/core",
|
|
3
|
-
"version": "0.0.0-next-
|
|
3
|
+
"version": "0.0.0-next-193dba9",
|
|
4
4
|
"description": "sdk-usage core functionalities",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"analyze",
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@open-vanilla/visitor": "^1.0.0",
|
|
44
|
-
"@swc/core": "^1.
|
|
44
|
+
"@swc/core": "^1.15.33",
|
|
45
45
|
"fdir": "^6.5.0",
|
|
46
|
-
"picomatch": "^4.0.
|
|
46
|
+
"picomatch": "^4.0.4"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@types/node": "
|
|
50
|
-
"quickbundle": "
|
|
49
|
+
"@types/node": "24.12.4",
|
|
50
|
+
"quickbundle": "3.0.0"
|
|
51
51
|
},
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"access": "public",
|
package/dist/index.cjs
DELETED
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var node_fs = require('node:fs');
|
|
4
|
-
var node_path = require('node:path');
|
|
5
|
-
var fdir = require('fdir');
|
|
6
|
-
var node_module = require('node:module');
|
|
7
|
-
var node_child_process = require('node:child_process');
|
|
8
|
-
var core = require('@swc/core');
|
|
9
|
-
var visitor = require('@open-vanilla/visitor');
|
|
10
|
-
|
|
11
|
-
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
12
|
-
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
13
|
-
const resolvePackageJson = (fromPath)=>{
|
|
14
|
-
const filepath = node_path.join(fromPath, "./package.json");
|
|
15
|
-
if (node_fs.existsSync(filepath)) {
|
|
16
|
-
return filepath;
|
|
17
|
-
}
|
|
18
|
-
return resolvePackageJson(node_path.join(fromPath, "../"));
|
|
19
|
-
};
|
|
20
|
-
/**
|
|
21
|
-
* Execute an external command.
|
|
22
|
-
* @param command - The command to execute.
|
|
23
|
-
* @param options - Options including current working directory configuration.
|
|
24
|
-
* @param options.cwd - Configure the current working directory.
|
|
25
|
-
* @returns The output (either the command output or error).
|
|
26
|
-
* @example
|
|
27
|
-
* exec("ls");
|
|
28
|
-
*/ const exec = async (command, options = {})=>{
|
|
29
|
-
return new Promise((resolve, reject)=>{
|
|
30
|
-
let stdout = "";
|
|
31
|
-
let stderr = "";
|
|
32
|
-
const [bin, ...arguments_] = command.split(" ");
|
|
33
|
-
// eslint-disable-next-line sonarjs/os-command
|
|
34
|
-
const childProcess = node_child_process.spawn(bin, arguments_, {
|
|
35
|
-
cwd: options.cwd,
|
|
36
|
-
shell: true,
|
|
37
|
-
stdio: "pipe"
|
|
38
|
-
});
|
|
39
|
-
childProcess.stdout.on("data", (chunk)=>{
|
|
40
|
-
stdout += chunk;
|
|
41
|
-
});
|
|
42
|
-
childProcess.stderr.on("data", (chunk)=>{
|
|
43
|
-
stderr += chunk;
|
|
44
|
-
});
|
|
45
|
-
childProcess.on("close", (exitCode)=>{
|
|
46
|
-
if (exitCode !== 0) {
|
|
47
|
-
const output = `${stderr}${stdout}`;
|
|
48
|
-
reject(new Error(output.trim()));
|
|
49
|
-
} else {
|
|
50
|
-
resolve(stdout.trim());
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const scan = async (path, options = {})=>{
|
|
57
|
-
const excludedFolders = options.excludeFolders ?? DEFAULT_EXCLUDED_FOLDERS;
|
|
58
|
-
const includedFiles = options.includeFiles ?? DEFAULT_INCLUDED_FILES;
|
|
59
|
-
const projectPaths = new fdir.fdir().withBasePath().glob("**/package.json").exclude((directoryName)=>excludedFolders.includes(directoryName)).crawl(path).sync();
|
|
60
|
-
const projects = [];
|
|
61
|
-
for (const projectPath of projectPaths){
|
|
62
|
-
const metadata = require$1(projectPath);
|
|
63
|
-
const folder = node_path.dirname(projectPath);
|
|
64
|
-
let link;
|
|
65
|
-
try {
|
|
66
|
-
link = await exec("git config --get remote.origin.url", {
|
|
67
|
-
cwd: folder
|
|
68
|
-
});
|
|
69
|
-
} catch {
|
|
70
|
-
link = "";
|
|
71
|
-
}
|
|
72
|
-
projects.push({
|
|
73
|
-
folder,
|
|
74
|
-
link,
|
|
75
|
-
metadata
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
return projects.map((project)=>{
|
|
79
|
-
const files = new fdir.fdir().withBasePath().glob(...includedFiles).exclude((directoryName)=>excludedFolders.includes(directoryName)).crawl(project.folder).sync();
|
|
80
|
-
return {
|
|
81
|
-
...project,
|
|
82
|
-
files
|
|
83
|
-
};
|
|
84
|
-
});
|
|
85
|
-
};
|
|
86
|
-
const DEFAULT_EXCLUDED_FOLDERS = [
|
|
87
|
-
".git",
|
|
88
|
-
"node_modules",
|
|
89
|
-
"dist",
|
|
90
|
-
"out"
|
|
91
|
-
];
|
|
92
|
-
const DEFAULT_INCLUDED_FILES = [
|
|
93
|
-
"**/*/!(test|*.test|stories|*.stories).?(m){j,t}s?(x)"
|
|
94
|
-
];
|
|
95
|
-
|
|
96
|
-
const parse = async (code, { onAdd, plugins })=>{
|
|
97
|
-
const context = {
|
|
98
|
-
imports: new Map()
|
|
99
|
-
};
|
|
100
|
-
let ast;
|
|
101
|
-
try {
|
|
102
|
-
ast = await core.parse(code, {
|
|
103
|
-
syntax: "typescript",
|
|
104
|
-
tsx: true
|
|
105
|
-
});
|
|
106
|
-
} catch {
|
|
107
|
-
ast = undefined;
|
|
108
|
-
// TODO: log error with file path
|
|
109
|
-
}
|
|
110
|
-
if (ast === undefined) return;
|
|
111
|
-
const visitor$1 = {
|
|
112
|
-
ImportDeclaration (node) {
|
|
113
|
-
const module = node.source.value;
|
|
114
|
-
node.specifiers.forEach((specifier)=>{
|
|
115
|
-
const specifierValue = specifier.local.value;
|
|
116
|
-
context.imports.set(specifierValue, {
|
|
117
|
-
name: // @ts-expect-error `imported` field is not exposed by `ImportSpecifier` node (issue in `@swc/core` type definition).
|
|
118
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
119
|
-
specifier.imported?.value ?? specifierValue,
|
|
120
|
-
alias: specifierValue,
|
|
121
|
-
module
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
for (const plugin of plugins){
|
|
127
|
-
const pluginOutput = plugin(context, {
|
|
128
|
-
getJSXAttributeValue
|
|
129
|
-
});
|
|
130
|
-
const nodeKeys = Object.keys(pluginOutput);
|
|
131
|
-
for (const nodeKey of nodeKeys){
|
|
132
|
-
const currentVisitorFunction = visitor$1[nodeKey];
|
|
133
|
-
visitor$1[nodeKey] = (node)=>{
|
|
134
|
-
if (typeof currentVisitorFunction === "function") {
|
|
135
|
-
currentVisitorFunction(node);
|
|
136
|
-
}
|
|
137
|
-
const output = pluginOutput[nodeKey]?.(node);
|
|
138
|
-
if (output) {
|
|
139
|
-
onAdd(output);
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
visitor.visit(ast, visitor$1);
|
|
145
|
-
};
|
|
146
|
-
const getJSXAttributeValue = (node)=>{
|
|
147
|
-
if (!node) {
|
|
148
|
-
return true;
|
|
149
|
-
}
|
|
150
|
-
switch(node.type){
|
|
151
|
-
case "NullLiteral":
|
|
152
|
-
{
|
|
153
|
-
return null;
|
|
154
|
-
}
|
|
155
|
-
case "StringLiteral":
|
|
156
|
-
case "NumericLiteral":
|
|
157
|
-
case "BigIntLiteral":
|
|
158
|
-
case "BooleanLiteral":
|
|
159
|
-
case "JSXText":
|
|
160
|
-
{
|
|
161
|
-
return node.value;
|
|
162
|
-
}
|
|
163
|
-
case "JSXExpressionContainer":
|
|
164
|
-
{
|
|
165
|
-
return getJSXAttributeValue(node.expression);
|
|
166
|
-
}
|
|
167
|
-
case "JSXElement":
|
|
168
|
-
case "JSXFragment":
|
|
169
|
-
case "RegExpLiteral":
|
|
170
|
-
default:
|
|
171
|
-
{
|
|
172
|
-
return createUnknownToken(node.type);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
/**
|
|
177
|
-
* Helper to unify the way unknown AST token are managed.
|
|
178
|
-
* @param token - AST token value.
|
|
179
|
-
* @returns Formatted AST token.
|
|
180
|
-
* @example
|
|
181
|
-
* createUnknownToken("VariableDeclaration");
|
|
182
|
-
*/ const createUnknownToken = (token)=>`#${token}`;
|
|
183
|
-
|
|
184
|
-
const createLocation = ({ code, file, link, module, offset, path })=>{
|
|
185
|
-
const linesTillOffset = code.slice(0, Math.max(0, offset)).split(/\n/);
|
|
186
|
-
const line = linesTillOffset.length;
|
|
187
|
-
const column = linesTillOffset[line - 1].length;
|
|
188
|
-
return {
|
|
189
|
-
column,
|
|
190
|
-
file: `./${node_path.relative(path, file)}`,
|
|
191
|
-
line,
|
|
192
|
-
link,
|
|
193
|
-
module
|
|
194
|
-
};
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Aggregate factory that creates an item.
|
|
199
|
-
* @param input - Factory variables.
|
|
200
|
-
* @param input.name - Name.
|
|
201
|
-
* @param input.type - Component type.
|
|
202
|
-
* @param input.module - Source module.
|
|
203
|
-
* @param input.version - Module version.
|
|
204
|
-
* @param input.location - Location.
|
|
205
|
-
* @param input.input - Parameter list and metadata describing the way it's passed.
|
|
206
|
-
* @returns Created item.
|
|
207
|
-
* @example
|
|
208
|
-
* createItem({ ... });
|
|
209
|
-
*/ const createItem = ({ name, input, location, module, type, version })=>{
|
|
210
|
-
const item = {
|
|
211
|
-
name,
|
|
212
|
-
type,
|
|
213
|
-
module,
|
|
214
|
-
version,
|
|
215
|
-
createdAt: new Date().toISOString(),
|
|
216
|
-
location: createLocation(location),
|
|
217
|
-
input: {
|
|
218
|
-
metadata: {
|
|
219
|
-
withSpreading: input?.metadata.withSpreading ?? false
|
|
220
|
-
},
|
|
221
|
-
data: input?.data ?? {}
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
return item;
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
const createInstance = (path, options)=>{
|
|
228
|
-
return {
|
|
229
|
-
async getItems () {
|
|
230
|
-
const projects = await scan(path);
|
|
231
|
-
const items = [];
|
|
232
|
-
for (const project of projects){
|
|
233
|
-
const module = project.metadata.name;
|
|
234
|
-
const dependencies = {
|
|
235
|
-
...project.metadata.devDependencies,
|
|
236
|
-
...project.metadata.optionalDependencies,
|
|
237
|
-
...project.metadata.dependencies
|
|
238
|
-
};
|
|
239
|
-
const link = project.link;
|
|
240
|
-
for (const file of project.files){
|
|
241
|
-
const code = node_fs.readFileSync(file, "utf8");
|
|
242
|
-
await parse(code, {
|
|
243
|
-
onAdd (item) {
|
|
244
|
-
if (options.includeModules && options.includeModules.length > 0 && !options.includeModules.includes(item.module)) {
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
let version = dependencies[item.module] ?? "";
|
|
248
|
-
if (options.resolveInstalledVersions) {
|
|
249
|
-
try {
|
|
250
|
-
version = require$1(resolvePackageJson(require$1.resolve(item.module, {
|
|
251
|
-
paths: [
|
|
252
|
-
file
|
|
253
|
-
]
|
|
254
|
-
}))).version;
|
|
255
|
-
} catch {
|
|
256
|
-
// @TODO: No operation (later warnings can be added).
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
items.push(createItem({
|
|
260
|
-
...item,
|
|
261
|
-
location: {
|
|
262
|
-
code,
|
|
263
|
-
file,
|
|
264
|
-
link,
|
|
265
|
-
module,
|
|
266
|
-
offset: item.offset,
|
|
267
|
-
path
|
|
268
|
-
},
|
|
269
|
-
version
|
|
270
|
-
}));
|
|
271
|
-
},
|
|
272
|
-
plugins: options.plugins ?? []
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
return items;
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
const createPlugin = (input)=>{
|
|
282
|
-
return input;
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
exports.createInstance = createInstance;
|
|
286
|
-
exports.createPlugin = createPlugin;
|
package/dist/index.d.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { ImportDeclaration, JSXAttrValue, JSXOpeningElement, TsType } from '@swc/core';
|
|
2
|
-
|
|
3
|
-
type Primitive = bigint | boolean | number | string | null | undefined;
|
|
4
|
-
type Nodes = {
|
|
5
|
-
ImportDeclaration: ImportDeclaration;
|
|
6
|
-
JSXAttrValue: JSXAttrValue;
|
|
7
|
-
JSXOpeningElement: JSXOpeningElement;
|
|
8
|
-
TsType: TsType;
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Import entity to model an import statement.
|
|
12
|
-
*/
|
|
13
|
-
type Import = {
|
|
14
|
-
name: string;
|
|
15
|
-
alias: string;
|
|
16
|
-
module: string;
|
|
17
|
-
};
|
|
18
|
-
/**
|
|
19
|
-
* Package entity to model `package.json` metadata.
|
|
20
|
-
*/
|
|
21
|
-
type Package = {
|
|
22
|
-
name: string;
|
|
23
|
-
description: string;
|
|
24
|
-
dependencies?: Record<string, string>;
|
|
25
|
-
devDependencies?: Record<string, string>;
|
|
26
|
-
optionalDependencies?: Record<string, string>;
|
|
27
|
-
peerDependencies?: Record<string, string>;
|
|
28
|
-
version: string;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
type ScanOptions = {
|
|
32
|
-
/**
|
|
33
|
-
* A list of folders to ignore.
|
|
34
|
-
*/
|
|
35
|
-
excludeFolders?: string[];
|
|
36
|
-
/**
|
|
37
|
-
* A list of files to include (following glob matcher).
|
|
38
|
-
*/
|
|
39
|
-
includeFiles?: string[];
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
type Location = {
|
|
43
|
-
column: number;
|
|
44
|
-
file: string;
|
|
45
|
-
line: number;
|
|
46
|
-
link: string;
|
|
47
|
-
module: string;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
type Item = {
|
|
51
|
-
name: string;
|
|
52
|
-
createdAt: string;
|
|
53
|
-
input: {
|
|
54
|
-
data: Record<string, unknown>;
|
|
55
|
-
metadata: {
|
|
56
|
-
withSpreading: boolean;
|
|
57
|
-
};
|
|
58
|
-
};
|
|
59
|
-
location: Location;
|
|
60
|
-
module: Package["name"];
|
|
61
|
-
type: string;
|
|
62
|
-
version: Package["version"];
|
|
63
|
-
};
|
|
64
|
-
type ItemDTO = Partial<Pick<Item, "input">> & Pick<Item, "module" | "name" | "type"> & {
|
|
65
|
-
offset: number;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
declare const createPlugin: (input: Plugin) => Plugin;
|
|
69
|
-
type Plugin = (context: {
|
|
70
|
-
imports: Map<Import["alias"], Import>;
|
|
71
|
-
}, helpers: {
|
|
72
|
-
getJSXAttributeValue: (node: Nodes["JSXAttrValue"] | undefined) => Primitive;
|
|
73
|
-
}) => {
|
|
74
|
-
[Key in keyof Nodes]?: (node: Nodes[Key]) => ItemDTO | undefined;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
type Options = Partial<Pick<ScanOptions, "excludeFolders" | "includeFiles"> & {
|
|
78
|
-
/**
|
|
79
|
-
* Only analyze components imported from the specificied module list.
|
|
80
|
-
*/
|
|
81
|
-
includeModules: string[];
|
|
82
|
-
/**
|
|
83
|
-
* A list of plugins to enable.
|
|
84
|
-
*/
|
|
85
|
-
plugins: Plugin[];
|
|
86
|
-
/**
|
|
87
|
-
* Attempt to resolve installed versions of modules. If false or not possible, the specified version from the package.json will be used.
|
|
88
|
-
* @default false
|
|
89
|
-
*/
|
|
90
|
-
resolveInstalledVersions: boolean;
|
|
91
|
-
}>;
|
|
92
|
-
declare const createInstance: (path: string, options: Options) => {
|
|
93
|
-
getItems(): Promise<Item[]>;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
export { createInstance, createPlugin };
|
package/dist/index.mjs
DELETED
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { join, dirname, relative } from 'node:path';
|
|
3
|
-
import { fdir } from 'fdir';
|
|
4
|
-
import { createRequire } from 'node:module';
|
|
5
|
-
import { spawn } from 'node:child_process';
|
|
6
|
-
import { parse as parse$1 } from '@swc/core';
|
|
7
|
-
import { visit } from '@open-vanilla/visitor';
|
|
8
|
-
|
|
9
|
-
const require = createRequire(import.meta.url);
|
|
10
|
-
const resolvePackageJson = (fromPath)=>{
|
|
11
|
-
const filepath = join(fromPath, "./package.json");
|
|
12
|
-
if (existsSync(filepath)) {
|
|
13
|
-
return filepath;
|
|
14
|
-
}
|
|
15
|
-
return resolvePackageJson(join(fromPath, "../"));
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Execute an external command.
|
|
19
|
-
* @param command - The command to execute.
|
|
20
|
-
* @param options - Options including current working directory configuration.
|
|
21
|
-
* @param options.cwd - Configure the current working directory.
|
|
22
|
-
* @returns The output (either the command output or error).
|
|
23
|
-
* @example
|
|
24
|
-
* exec("ls");
|
|
25
|
-
*/ const exec = async (command, options = {})=>{
|
|
26
|
-
return new Promise((resolve, reject)=>{
|
|
27
|
-
let stdout = "";
|
|
28
|
-
let stderr = "";
|
|
29
|
-
const [bin, ...arguments_] = command.split(" ");
|
|
30
|
-
// eslint-disable-next-line sonarjs/os-command
|
|
31
|
-
const childProcess = spawn(bin, arguments_, {
|
|
32
|
-
cwd: options.cwd,
|
|
33
|
-
shell: true,
|
|
34
|
-
stdio: "pipe"
|
|
35
|
-
});
|
|
36
|
-
childProcess.stdout.on("data", (chunk)=>{
|
|
37
|
-
stdout += chunk;
|
|
38
|
-
});
|
|
39
|
-
childProcess.stderr.on("data", (chunk)=>{
|
|
40
|
-
stderr += chunk;
|
|
41
|
-
});
|
|
42
|
-
childProcess.on("close", (exitCode)=>{
|
|
43
|
-
if (exitCode !== 0) {
|
|
44
|
-
const output = `${stderr}${stdout}`;
|
|
45
|
-
reject(new Error(output.trim()));
|
|
46
|
-
} else {
|
|
47
|
-
resolve(stdout.trim());
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const scan = async (path, options = {})=>{
|
|
54
|
-
const excludedFolders = options.excludeFolders ?? DEFAULT_EXCLUDED_FOLDERS;
|
|
55
|
-
const includedFiles = options.includeFiles ?? DEFAULT_INCLUDED_FILES;
|
|
56
|
-
const projectPaths = new fdir().withBasePath().glob("**/package.json").exclude((directoryName)=>excludedFolders.includes(directoryName)).crawl(path).sync();
|
|
57
|
-
const projects = [];
|
|
58
|
-
for (const projectPath of projectPaths){
|
|
59
|
-
const metadata = require(projectPath);
|
|
60
|
-
const folder = dirname(projectPath);
|
|
61
|
-
let link;
|
|
62
|
-
try {
|
|
63
|
-
link = await exec("git config --get remote.origin.url", {
|
|
64
|
-
cwd: folder
|
|
65
|
-
});
|
|
66
|
-
} catch {
|
|
67
|
-
link = "";
|
|
68
|
-
}
|
|
69
|
-
projects.push({
|
|
70
|
-
folder,
|
|
71
|
-
link,
|
|
72
|
-
metadata
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
return projects.map((project)=>{
|
|
76
|
-
const files = new fdir().withBasePath().glob(...includedFiles).exclude((directoryName)=>excludedFolders.includes(directoryName)).crawl(project.folder).sync();
|
|
77
|
-
return {
|
|
78
|
-
...project,
|
|
79
|
-
files
|
|
80
|
-
};
|
|
81
|
-
});
|
|
82
|
-
};
|
|
83
|
-
const DEFAULT_EXCLUDED_FOLDERS = [
|
|
84
|
-
".git",
|
|
85
|
-
"node_modules",
|
|
86
|
-
"dist",
|
|
87
|
-
"out"
|
|
88
|
-
];
|
|
89
|
-
const DEFAULT_INCLUDED_FILES = [
|
|
90
|
-
"**/*/!(test|*.test|stories|*.stories).?(m){j,t}s?(x)"
|
|
91
|
-
];
|
|
92
|
-
|
|
93
|
-
const parse = async (code, { onAdd, plugins })=>{
|
|
94
|
-
const context = {
|
|
95
|
-
imports: new Map()
|
|
96
|
-
};
|
|
97
|
-
let ast;
|
|
98
|
-
try {
|
|
99
|
-
ast = await parse$1(code, {
|
|
100
|
-
syntax: "typescript",
|
|
101
|
-
tsx: true
|
|
102
|
-
});
|
|
103
|
-
} catch {
|
|
104
|
-
ast = undefined;
|
|
105
|
-
// TODO: log error with file path
|
|
106
|
-
}
|
|
107
|
-
if (ast === undefined) return;
|
|
108
|
-
const visitor = {
|
|
109
|
-
ImportDeclaration (node) {
|
|
110
|
-
const module = node.source.value;
|
|
111
|
-
node.specifiers.forEach((specifier)=>{
|
|
112
|
-
const specifierValue = specifier.local.value;
|
|
113
|
-
context.imports.set(specifierValue, {
|
|
114
|
-
name: // @ts-expect-error `imported` field is not exposed by `ImportSpecifier` node (issue in `@swc/core` type definition).
|
|
115
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
116
|
-
specifier.imported?.value ?? specifierValue,
|
|
117
|
-
alias: specifierValue,
|
|
118
|
-
module
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
for (const plugin of plugins){
|
|
124
|
-
const pluginOutput = plugin(context, {
|
|
125
|
-
getJSXAttributeValue
|
|
126
|
-
});
|
|
127
|
-
const nodeKeys = Object.keys(pluginOutput);
|
|
128
|
-
for (const nodeKey of nodeKeys){
|
|
129
|
-
const currentVisitorFunction = visitor[nodeKey];
|
|
130
|
-
visitor[nodeKey] = (node)=>{
|
|
131
|
-
if (typeof currentVisitorFunction === "function") {
|
|
132
|
-
currentVisitorFunction(node);
|
|
133
|
-
}
|
|
134
|
-
const output = pluginOutput[nodeKey]?.(node);
|
|
135
|
-
if (output) {
|
|
136
|
-
onAdd(output);
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
visit(ast, visitor);
|
|
142
|
-
};
|
|
143
|
-
const getJSXAttributeValue = (node)=>{
|
|
144
|
-
if (!node) {
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
switch(node.type){
|
|
148
|
-
case "NullLiteral":
|
|
149
|
-
{
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
case "StringLiteral":
|
|
153
|
-
case "NumericLiteral":
|
|
154
|
-
case "BigIntLiteral":
|
|
155
|
-
case "BooleanLiteral":
|
|
156
|
-
case "JSXText":
|
|
157
|
-
{
|
|
158
|
-
return node.value;
|
|
159
|
-
}
|
|
160
|
-
case "JSXExpressionContainer":
|
|
161
|
-
{
|
|
162
|
-
return getJSXAttributeValue(node.expression);
|
|
163
|
-
}
|
|
164
|
-
case "JSXElement":
|
|
165
|
-
case "JSXFragment":
|
|
166
|
-
case "RegExpLiteral":
|
|
167
|
-
default:
|
|
168
|
-
{
|
|
169
|
-
return createUnknownToken(node.type);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
/**
|
|
174
|
-
* Helper to unify the way unknown AST token are managed.
|
|
175
|
-
* @param token - AST token value.
|
|
176
|
-
* @returns Formatted AST token.
|
|
177
|
-
* @example
|
|
178
|
-
* createUnknownToken("VariableDeclaration");
|
|
179
|
-
*/ const createUnknownToken = (token)=>`#${token}`;
|
|
180
|
-
|
|
181
|
-
const createLocation = ({ code, file, link, module, offset, path })=>{
|
|
182
|
-
const linesTillOffset = code.slice(0, Math.max(0, offset)).split(/\n/);
|
|
183
|
-
const line = linesTillOffset.length;
|
|
184
|
-
const column = linesTillOffset[line - 1].length;
|
|
185
|
-
return {
|
|
186
|
-
column,
|
|
187
|
-
file: `./${relative(path, file)}`,
|
|
188
|
-
line,
|
|
189
|
-
link,
|
|
190
|
-
module
|
|
191
|
-
};
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Aggregate factory that creates an item.
|
|
196
|
-
* @param input - Factory variables.
|
|
197
|
-
* @param input.name - Name.
|
|
198
|
-
* @param input.type - Component type.
|
|
199
|
-
* @param input.module - Source module.
|
|
200
|
-
* @param input.version - Module version.
|
|
201
|
-
* @param input.location - Location.
|
|
202
|
-
* @param input.input - Parameter list and metadata describing the way it's passed.
|
|
203
|
-
* @returns Created item.
|
|
204
|
-
* @example
|
|
205
|
-
* createItem({ ... });
|
|
206
|
-
*/ const createItem = ({ name, input, location, module, type, version })=>{
|
|
207
|
-
const item = {
|
|
208
|
-
name,
|
|
209
|
-
type,
|
|
210
|
-
module,
|
|
211
|
-
version,
|
|
212
|
-
createdAt: new Date().toISOString(),
|
|
213
|
-
location: createLocation(location),
|
|
214
|
-
input: {
|
|
215
|
-
metadata: {
|
|
216
|
-
withSpreading: input?.metadata.withSpreading ?? false
|
|
217
|
-
},
|
|
218
|
-
data: input?.data ?? {}
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
return item;
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
const createInstance = (path, options)=>{
|
|
225
|
-
return {
|
|
226
|
-
async getItems () {
|
|
227
|
-
const projects = await scan(path);
|
|
228
|
-
const items = [];
|
|
229
|
-
for (const project of projects){
|
|
230
|
-
const module = project.metadata.name;
|
|
231
|
-
const dependencies = {
|
|
232
|
-
...project.metadata.devDependencies,
|
|
233
|
-
...project.metadata.optionalDependencies,
|
|
234
|
-
...project.metadata.dependencies
|
|
235
|
-
};
|
|
236
|
-
const link = project.link;
|
|
237
|
-
for (const file of project.files){
|
|
238
|
-
const code = readFileSync(file, "utf8");
|
|
239
|
-
await parse(code, {
|
|
240
|
-
onAdd (item) {
|
|
241
|
-
if (options.includeModules && options.includeModules.length > 0 && !options.includeModules.includes(item.module)) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
let version = dependencies[item.module] ?? "";
|
|
245
|
-
if (options.resolveInstalledVersions) {
|
|
246
|
-
try {
|
|
247
|
-
version = require(resolvePackageJson(require.resolve(item.module, {
|
|
248
|
-
paths: [
|
|
249
|
-
file
|
|
250
|
-
]
|
|
251
|
-
}))).version;
|
|
252
|
-
} catch {
|
|
253
|
-
// @TODO: No operation (later warnings can be added).
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
items.push(createItem({
|
|
257
|
-
...item,
|
|
258
|
-
location: {
|
|
259
|
-
code,
|
|
260
|
-
file,
|
|
261
|
-
link,
|
|
262
|
-
module,
|
|
263
|
-
offset: item.offset,
|
|
264
|
-
path
|
|
265
|
-
},
|
|
266
|
-
version
|
|
267
|
-
}));
|
|
268
|
-
},
|
|
269
|
-
plugins: options.plugins ?? []
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
return items;
|
|
274
|
-
}
|
|
275
|
-
};
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
const createPlugin = (input)=>{
|
|
279
|
-
return input;
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
export { createInstance, createPlugin };
|