comment-variables 0.1.0 → 0.3.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.
- package/comments.config.js +88 -9
- package/library/_commons/constants/bases.js +77 -0
- package/library/_commons/constants/rules.js +9 -0
- package/library/_commons/rules/compress.js +78 -0
- package/library/_commons/rules/resolve.js +77 -0
- package/library/_commons/schemas/config.js +67 -0
- package/library/_commons/utilities/find-all-imports.js +120 -0
- package/library/_commons/utilities/flatten-config-data.js +107 -0
- package/library/_commons/utilities/flows.js +110 -0
- package/library/_commons/utilities/helpers.js +17 -0
- package/library/_commons/utilities/resolve-config.js +67 -0
- package/library/index.js +127 -0
- package/package.json +13 -8
- package/comments.config.ts +0 -24
- package/find-all-imports.js +0 -102
- package/import.js +0 -5
- package/import2.js +0 -1
- package/index.js +0 -384
- package/run-with-config.js +0 -138
- package/test-file.js +0 -7
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { ESLint } from "eslint";
|
|
2
|
+
import markdown from "@eslint/markdown";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
commentVariablesPluginName,
|
|
6
|
+
resolveRuleName,
|
|
7
|
+
compressRuleName,
|
|
8
|
+
allJSTSFileGlobs,
|
|
9
|
+
allMDFileGlobs,
|
|
10
|
+
allMDVirtualJSTSFileGlobs,
|
|
11
|
+
typeScriptAndJSXCompatible,
|
|
12
|
+
} from "../constants/bases.js";
|
|
13
|
+
import { ruleNames_makeRules } from "../constants/rules.js";
|
|
14
|
+
|
|
15
|
+
/* coreCommentsFlow */
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The core flow at the heart of resolving and compressing comments.
|
|
19
|
+
* @param {typeof resolveRuleName | typeof compressRuleName} ruleName The name of the rule currently used. (Either `"resolve"` or `"compress"`.)
|
|
20
|
+
* @param {string[]} ignores The array of paths and globs for the flow's ESLint instance to ignore.
|
|
21
|
+
* @param {{[key: string]: string}} flattenedConfigData Either the flattened config data or the reversed flattened config data, since they share the same structure.
|
|
22
|
+
*/
|
|
23
|
+
const coreCommentsFlow = async (ruleName, ignores, flattenedConfigData) => {
|
|
24
|
+
const eslint = new ESLint({
|
|
25
|
+
fix: true,
|
|
26
|
+
errorOnUnmatchedPattern: false,
|
|
27
|
+
overrideConfigFile: true,
|
|
28
|
+
overrideConfig: [
|
|
29
|
+
{
|
|
30
|
+
files: allJSTSFileGlobs,
|
|
31
|
+
ignores,
|
|
32
|
+
languageOptions: typeScriptAndJSXCompatible,
|
|
33
|
+
plugins: {
|
|
34
|
+
[commentVariablesPluginName]: {
|
|
35
|
+
rules: {
|
|
36
|
+
[ruleName]: ruleNames_makeRules[ruleName](flattenedConfigData),
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
rules: {
|
|
41
|
+
[`${commentVariablesPluginName}/${ruleName}`]: "warn",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
files: allMDFileGlobs,
|
|
46
|
+
ignores,
|
|
47
|
+
plugins: { markdown },
|
|
48
|
+
processor: "markdown/markdown",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
files: allMDVirtualJSTSFileGlobs,
|
|
52
|
+
ignores,
|
|
53
|
+
languageOptions: typeScriptAndJSXCompatible,
|
|
54
|
+
rules: {
|
|
55
|
+
[`${commentVariablesPluginName}/${ruleName}`]: "warn",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const results = await eslint.lintFiles([
|
|
62
|
+
...allJSTSFileGlobs,
|
|
63
|
+
...allMDFileGlobs,
|
|
64
|
+
]);
|
|
65
|
+
await ESLint.outputFixes(results);
|
|
66
|
+
|
|
67
|
+
console.log({ results });
|
|
68
|
+
|
|
69
|
+
const resolvedOrCompressed =
|
|
70
|
+
ruleName === resolveRuleName
|
|
71
|
+
? "Resolved"
|
|
72
|
+
: ruleName === compressRuleName
|
|
73
|
+
? "Compressed"
|
|
74
|
+
: "Unknown rule name'd";
|
|
75
|
+
|
|
76
|
+
const total = results.reduce((sum, r) => {
|
|
77
|
+
const add = r.output ? 1 : 0;
|
|
78
|
+
return sum + add;
|
|
79
|
+
}, 0);
|
|
80
|
+
|
|
81
|
+
console.log(
|
|
82
|
+
`✅ ${resolvedOrCompressed} comments on ${total} file${
|
|
83
|
+
total === 1 ? "" : "s"
|
|
84
|
+
}.`
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/* resolveCommentsFlow */
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The flow that resolves $COMMENT#* placeholders intro actual comments.
|
|
92
|
+
* @param {string[]} ignores The array of paths and globs for the flow's ESLint instance to ignore.
|
|
93
|
+
* @param {{[key: string]: string}} flattenedConfigData The flattened config data, with $COMMENT#* placeholders as keys and actual comments as values.
|
|
94
|
+
* @returns
|
|
95
|
+
*/
|
|
96
|
+
export const resolveCommentsFlow = async (ignores, flattenedConfigData) =>
|
|
97
|
+
coreCommentsFlow(resolveRuleName, ignores, flattenedConfigData);
|
|
98
|
+
|
|
99
|
+
/* compressCommentsFlow */
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* The flow that compresses actual comments into $COMMENT#* placeholders.
|
|
103
|
+
* @param {string[]} ignores The array of paths and globs for the flow's ESLint instance to ignore.
|
|
104
|
+
* @param {{[key: string]: string}} reversedFlattenedConfigData The reversed flattened config data, with actual comments as keys and $COMMENT#* placeholders as values.
|
|
105
|
+
* @returns
|
|
106
|
+
*/
|
|
107
|
+
export const compressCommentsFlow = async (
|
|
108
|
+
ignores,
|
|
109
|
+
reversedFlattenedConfigData
|
|
110
|
+
) => coreCommentsFlow(compressRuleName, ignores, reversedFlattenedConfigData);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* exitDueToFailure */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Terminates the whole process with a 'failure' code (1).
|
|
5
|
+
* @returns {never} Never. (Somehow typing needs to be explicit for unreachable code inference.)
|
|
6
|
+
*/
|
|
7
|
+
export const exitDueToFailure = () => process.exit(1);
|
|
8
|
+
|
|
9
|
+
/* escapeRegex */
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Escapes all regex characters with a `"\"` in a string to prepare it for use in a regex.
|
|
13
|
+
* @param {string} string The string.
|
|
14
|
+
* @returns The string with regex characters escaped.
|
|
15
|
+
*/
|
|
16
|
+
export const escapeRegex = (string) =>
|
|
17
|
+
string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { pathToFileURL } from "url";
|
|
3
|
+
|
|
4
|
+
import { flattenConfigData } from "./flatten-config-data.js";
|
|
5
|
+
|
|
6
|
+
import { ConfigDataSchema, ConfigIgnoresSchema } from "../schemas/config.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Verifies, validates and resolves the config path to retrieve the config's data and ignores.
|
|
10
|
+
* @param {string} configPath The path of the config, either from `comments.config.js` or from a config passed via the `--config` flag.
|
|
11
|
+
* @returns The flattened config data, the reverse flattened config data, the verified config path and the raw passed ignores.
|
|
12
|
+
*/
|
|
13
|
+
export async function resolveConfig(configPath) {
|
|
14
|
+
// Step 1: Checks if config file exists
|
|
15
|
+
|
|
16
|
+
if (!existsSync(configPath)) {
|
|
17
|
+
console.warn("No config file found. Exiting gracefully.");
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Step 2: Imports the config dynamically
|
|
22
|
+
|
|
23
|
+
const configModule = await import(pathToFileURL(configPath));
|
|
24
|
+
const config = configModule.default;
|
|
25
|
+
|
|
26
|
+
// Step 3: Validates config object
|
|
27
|
+
|
|
28
|
+
// validates config
|
|
29
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
30
|
+
console.warn(
|
|
31
|
+
"Invalid config format. The config should be an object. Exiting."
|
|
32
|
+
);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// validates config.data
|
|
37
|
+
const configDataResult = ConfigDataSchema.safeParse(config.data);
|
|
38
|
+
|
|
39
|
+
if (!configDataResult.success) {
|
|
40
|
+
console.warn("Config data could not pass validation from zod.");
|
|
41
|
+
configDataResult.error.errors.map((e) => console.log(e.message));
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// validates config.ignores
|
|
46
|
+
const configIgnoresSchemaResult = ConfigIgnoresSchema.safeParse(
|
|
47
|
+
config.ignores
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (!configIgnoresSchemaResult.success) {
|
|
51
|
+
console.warn("Config ignores could not pass validation from zod.");
|
|
52
|
+
configIgnoresSchemaResult.error.errors.map((e) => console.log(e.message));
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// sends back:
|
|
57
|
+
// - the flattened config data,
|
|
58
|
+
// - the reverse flattened config data,
|
|
59
|
+
// - the verified config path
|
|
60
|
+
// - and the raw passed ignores
|
|
61
|
+
console.log("Running with config:", config);
|
|
62
|
+
return {
|
|
63
|
+
...flattenConfigData(configDataResult.data), // finalized
|
|
64
|
+
configPath, // finalized
|
|
65
|
+
passedIgnores: configIgnoresSchemaResult.data, // addressed with --lint-config-imports and --my-ignores-only to be finalized
|
|
66
|
+
};
|
|
67
|
+
}
|
package/library/index.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The shebang (#!) is necessary to communicate with Unix-based systems, like Linux and macOS. On Windows, it is ignored, but npm tooling bridges the gap by generating wrappers that make the CLI work anyway.
|
|
3
|
+
|
|
4
|
+
import path from "path";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
cwd,
|
|
8
|
+
hasPackageJson,
|
|
9
|
+
hasGitFolder,
|
|
10
|
+
defaultConfigFileName,
|
|
11
|
+
configFlag,
|
|
12
|
+
lintConfigImportsFlag,
|
|
13
|
+
myIgnoresOnlyFlag,
|
|
14
|
+
knownIgnores,
|
|
15
|
+
} from "./_commons/constants/bases.js";
|
|
16
|
+
|
|
17
|
+
import { exitDueToFailure } from "./_commons/utilities/helpers.js";
|
|
18
|
+
import { resolveConfig } from "./_commons/utilities/resolve-config.js";
|
|
19
|
+
import { findAllImports } from "./_commons/utilities/find-all-imports.js";
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
resolveCommentsFlow,
|
|
23
|
+
compressCommentsFlow,
|
|
24
|
+
} from "./_commons/utilities/flows.js";
|
|
25
|
+
|
|
26
|
+
// ENSURES THE CLI TOOL ONLY RUN IN FOLDERS THAT POSSESS A package.json FILE AND A .git FOLDER.
|
|
27
|
+
|
|
28
|
+
if (!hasPackageJson) {
|
|
29
|
+
console.error(
|
|
30
|
+
"ERROR. No package.json file found in this directory. Aborting to prevent accidental changes."
|
|
31
|
+
);
|
|
32
|
+
exitDueToFailure();
|
|
33
|
+
}
|
|
34
|
+
if (!hasGitFolder) {
|
|
35
|
+
console.error(
|
|
36
|
+
"ERROR. No git folder found in this directory. Aborting to prevent irreversible changes."
|
|
37
|
+
);
|
|
38
|
+
exitDueToFailure();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// GATHERS COMMANDS.
|
|
42
|
+
|
|
43
|
+
const commands = process.argv;
|
|
44
|
+
|
|
45
|
+
// OBTAINS THE VALIDATED FLATTENED CONFIG, REVERSE FLATTENED CONFIG, AND CONFIG PATH.
|
|
46
|
+
|
|
47
|
+
// extracts the position of the --config flag
|
|
48
|
+
const configFlagIndex = commands.indexOf(configFlag);
|
|
49
|
+
// determines if there's a valid config flag input
|
|
50
|
+
const hasConfigFlag = configFlagIndex >= 2;
|
|
51
|
+
// determines if there's an actual config path passed to the config flag
|
|
52
|
+
const passedConfig = commands[configFlagIndex + 1];
|
|
53
|
+
// gets the absolute passed config path if the --config flag is set
|
|
54
|
+
const passedConfigPath =
|
|
55
|
+
hasConfigFlag && passedConfig ? path.join(cwd, passedConfig) : null;
|
|
56
|
+
// defaults to comments.config.js if no --config flag is set
|
|
57
|
+
const rawConfigPath = passedConfigPath ?? path.join(cwd, defaultConfigFileName);
|
|
58
|
+
|
|
59
|
+
const results = await resolveConfig(rawConfigPath);
|
|
60
|
+
if (!results) {
|
|
61
|
+
exitDueToFailure();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const {
|
|
65
|
+
flattenedConfigData,
|
|
66
|
+
reversedFlattenedConfigData,
|
|
67
|
+
configPath,
|
|
68
|
+
passedIgnores,
|
|
69
|
+
} = results;
|
|
70
|
+
|
|
71
|
+
console.log("Flattened config is:", flattenedConfigData);
|
|
72
|
+
console.log("Reversed flattened config is:", reversedFlattenedConfigData);
|
|
73
|
+
console.log("Config path is:", configPath);
|
|
74
|
+
console.log("Passed ignores are:", passedIgnores);
|
|
75
|
+
|
|
76
|
+
// ADDRESSES THE --lint-config-imports FLAG, GIVEN THAT THE FILES IMPORTED BY THE CONFIG ARE IGNORED BY DEFAULT.
|
|
77
|
+
|
|
78
|
+
const lintConfigImports = commands.indexOf(lintConfigImportsFlag) >= 2;
|
|
79
|
+
const rawConfigPathIgnores = lintConfigImports
|
|
80
|
+
? [configPath]
|
|
81
|
+
: [...(findAllImports(configPath) ?? [])];
|
|
82
|
+
|
|
83
|
+
// the ignore paths must be relative
|
|
84
|
+
const configPathIgnores = rawConfigPathIgnores.map((e) =>
|
|
85
|
+
path.relative(cwd, e)
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
console.log(
|
|
89
|
+
lintConfigImports ? "Config path ignore is:" : "Config path ignores are:",
|
|
90
|
+
configPathIgnores
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// ADDRESSES THE --my-ignores-only FLAG, GIVEN THAT KNOWN IGNORES ARE IGNORED BY DEFAULT
|
|
94
|
+
|
|
95
|
+
const myIgnoresOnly = commands.indexOf(myIgnoresOnlyFlag) >= 2;
|
|
96
|
+
const rawIgnores = [...configPathIgnores, ...passedIgnores];
|
|
97
|
+
const ignores = myIgnoresOnly ? rawIgnores : [...rawIgnores, ...knownIgnores];
|
|
98
|
+
|
|
99
|
+
console.log("Ignores are:", ignores);
|
|
100
|
+
|
|
101
|
+
// ADDRESSES THE CORE COMMANDS "resolve" AND "compress".
|
|
102
|
+
|
|
103
|
+
const coreCommand = commands[2];
|
|
104
|
+
|
|
105
|
+
switch (coreCommand) {
|
|
106
|
+
case "resolve":
|
|
107
|
+
await resolveCommentsFlow(ignores, flattenedConfigData);
|
|
108
|
+
break;
|
|
109
|
+
case "compress":
|
|
110
|
+
await compressCommentsFlow(ignores, reversedFlattenedConfigData);
|
|
111
|
+
break;
|
|
112
|
+
case undefined: // falls through the default
|
|
113
|
+
default:
|
|
114
|
+
if (coreCommand && !coreCommand.startsWith("--"))
|
|
115
|
+
console.error(
|
|
116
|
+
`ERROR. Core command not recognized. Choose between "resolve" and "compress".`
|
|
117
|
+
);
|
|
118
|
+
else
|
|
119
|
+
console.log(
|
|
120
|
+
`If these settings are correct with you, feel free to initiate the command "resolve" to resolve comments, or "compress" to compress them back to their $COMMENT#* forms.${
|
|
121
|
+
passedConfigPath || lintConfigImports || myIgnoresOnly
|
|
122
|
+
? " (And DON'T FORGET YOUR FLAGS!)"
|
|
123
|
+
: ""
|
|
124
|
+
}`
|
|
125
|
+
);
|
|
126
|
+
break;
|
|
127
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "comment-variables",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "A CLI tool for configuring, managing and maintaining JavaScript comments as JavaScript variables.",
|
|
5
5
|
"bin": {
|
|
6
|
-
"jscomments": "./index.js",
|
|
7
|
-
"comment-variables": "./index.js"
|
|
6
|
+
"jscomments": "./library/index.js",
|
|
7
|
+
"comment-variables": "./library/index.js"
|
|
8
8
|
},
|
|
9
|
-
"main": "index.js",
|
|
9
|
+
"main": "library/index.js",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "git+https://github.com/LutherTS/jscomments.git"
|
|
@@ -14,14 +14,19 @@
|
|
|
14
14
|
"scripts": {
|
|
15
15
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
16
16
|
},
|
|
17
|
-
"keywords": [
|
|
18
|
-
|
|
17
|
+
"keywords": [
|
|
18
|
+
"cli",
|
|
19
|
+
"javascript",
|
|
20
|
+
"comments",
|
|
21
|
+
"variables"
|
|
22
|
+
],
|
|
23
|
+
"author": "Luther Tchofo Safo <luther@tchofo-safo-portfolio.me>",
|
|
19
24
|
"license": "MIT",
|
|
20
25
|
"type": "module",
|
|
21
26
|
"dependencies": {
|
|
22
27
|
"@eslint/markdown": "^6.5.0",
|
|
23
28
|
"eslint": "^9.29.0",
|
|
24
|
-
"get-sourcecode-from-file-path": "^1.0.
|
|
29
|
+
"get-sourcecode-from-file-path": "^1.0.1",
|
|
25
30
|
"resolve-importing-path": "^1.0.2",
|
|
26
31
|
"tsconfig-paths": "^4.2.0",
|
|
27
32
|
"typescript-eslint": "^8.34.1",
|
package/comments.config.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { test } from "./import.js";
|
|
2
|
-
|
|
3
|
-
const config = {
|
|
4
|
-
levelOne: {
|
|
5
|
-
levelTwo: {
|
|
6
|
-
levelThree: "Level three.",
|
|
7
|
-
// levelthree: "Also level three.", // errors
|
|
8
|
-
// alsoLevelThree: "Level three.", // errors
|
|
9
|
-
levelThreeBis: "Level three bis.",
|
|
10
|
-
levelThreeTer: "Level three ter.",
|
|
11
|
-
levelThreeAlso: "Also level three here.",
|
|
12
|
-
levelThreeToo: "This too is level three.",
|
|
13
|
-
// test: "LEVELONE#LEVELTWO#LEVELTHREE", // errors
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export default config;
|
|
19
|
-
|
|
20
|
-
// This too is level three.
|
|
21
|
-
|
|
22
|
-
/* Notes
|
|
23
|
-
I'll need to install TypeScript to test this.
|
|
24
|
-
*/
|
package/find-all-imports.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
|
|
4
|
-
import { resolveImportingPath } from "resolve-importing-path";
|
|
5
|
-
import { getSourceCodeFromFilePath } from "get-sourcecode-from-file-path";
|
|
6
|
-
|
|
7
|
-
/* findAllImports */
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Helper to process and recursively resolve a single import path.
|
|
11
|
-
* Returns false if resolution fails at any level.
|
|
12
|
-
*/
|
|
13
|
-
const processImport = (
|
|
14
|
-
importPath,
|
|
15
|
-
currentDir,
|
|
16
|
-
cwd,
|
|
17
|
-
visited,
|
|
18
|
-
depth,
|
|
19
|
-
maxDepth
|
|
20
|
-
) => {
|
|
21
|
-
const resolvedPath = resolveImportingPath(currentDir, importPath, cwd);
|
|
22
|
-
if (!resolvedPath) return true; // Skips unresolved paths (not an error).
|
|
23
|
-
|
|
24
|
-
const result = findAllImports(
|
|
25
|
-
resolvedPath,
|
|
26
|
-
cwd,
|
|
27
|
-
visited,
|
|
28
|
-
depth + 1,
|
|
29
|
-
maxDepth
|
|
30
|
-
);
|
|
31
|
-
return result !== null; // Returns false if child failed.
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export const findAllImports = (
|
|
35
|
-
filePath,
|
|
36
|
-
cwd = process.cwd(),
|
|
37
|
-
visited = new Set(),
|
|
38
|
-
depth = 0,
|
|
39
|
-
maxDepth = 100
|
|
40
|
-
) => {
|
|
41
|
-
// Early failure checks (with logging).
|
|
42
|
-
if (depth > maxDepth) {
|
|
43
|
-
console.error(`ERROR. Max depth ${maxDepth} reached at ${filePath}.`);
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
if (!fs.existsSync(filePath)) {
|
|
47
|
-
console.error(`ERROR. File not found at ${filePath}.`);
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
if (visited.has(filePath)) return visited;
|
|
51
|
-
|
|
52
|
-
// Parses AST.
|
|
53
|
-
visited.add(filePath);
|
|
54
|
-
const sourceCode = getSourceCodeFromFilePath(filePath);
|
|
55
|
-
if (!sourceCode?.ast) {
|
|
56
|
-
console.error(`ERROR. Failed to parse AST for ${filePath}.`);
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Processes all imports.
|
|
61
|
-
const currentDir = path.dirname(filePath);
|
|
62
|
-
for (const node of sourceCode.ast.body) {
|
|
63
|
-
// ES Modules (import x from 'y')
|
|
64
|
-
if (node.type === "ImportDeclaration") {
|
|
65
|
-
if (
|
|
66
|
-
!processImport(
|
|
67
|
-
node.source.value,
|
|
68
|
-
currentDir,
|
|
69
|
-
cwd,
|
|
70
|
-
visited,
|
|
71
|
-
depth,
|
|
72
|
-
maxDepth
|
|
73
|
-
)
|
|
74
|
-
) {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// CommonJS (require('x'))
|
|
80
|
-
if (
|
|
81
|
-
node.type === "ExpressionStatement" &&
|
|
82
|
-
node.expression.type === "CallExpression" &&
|
|
83
|
-
node.expression.callee.name === "require" &&
|
|
84
|
-
node.expression.arguments[0]?.type === "Literal"
|
|
85
|
-
) {
|
|
86
|
-
if (
|
|
87
|
-
!processImport(
|
|
88
|
-
node.expression.arguments[0].value,
|
|
89
|
-
currentDir,
|
|
90
|
-
cwd,
|
|
91
|
-
visited,
|
|
92
|
-
depth,
|
|
93
|
-
maxDepth
|
|
94
|
-
)
|
|
95
|
-
) {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return visited; // success
|
|
102
|
-
};
|
package/import.js
DELETED
package/import2.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const test2 = "test2";
|