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