resolve-everything 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License Copyright (c) 2023 Lily Skye
2
+
3
+ Permission is hereby granted, free of
4
+ charge, to any person obtaining a copy of this software and associated
5
+ documentation files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use, copy, modify, merge,
7
+ publish, distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to the
9
+ following conditions:
10
+
11
+ The above copyright notice and this permission notice
12
+ (including the next paragraph) shall be included in all copies or substantial
13
+ portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
16
+ ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
18
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # resolve-everything
2
+
3
+ `resolve-everything` is a tool which walks through the module dependency tree of a JavaScript/TypeScript project and gives you data about all the relationships.
4
+
5
+ ## Usage
6
+
7
+ ### Command-Line Interface (CLI)
8
+
9
+ ```sh
10
+ $ npx resolve-everything --entrypoint ./some-file.js
11
+ ```
12
+
13
+ which outputs JSON shaped like:
14
+
15
+ ```jsonc
16
+ {
17
+ "<full-path-to-some-file.js>": {
18
+ "id": "<full-path-to-some-file.js>",
19
+ "requests": {
20
+ // key is "require/import string that appeared in the source code"
21
+ // value is "full path to the file that refers to"
22
+ "./something": "<full-path-to-something>",
23
+ "react": "<full-path-to-react>",
24
+ "../somewhere/yeah": "<full-path-to-yeah>",
25
+ },
26
+ "dependencies": [
27
+ "<full-path-to-something>",
28
+ "<full-path-to-react>",
29
+ "<full-path-to-yeah>",
30
+ ]
31
+ },
32
+ "<full-path-to-something>": { ... },
33
+ "<full-path-to-yeah>": { ... },
34
+ ...
35
+ }
36
+ ```
37
+
38
+ #### Options:
39
+
40
+ - `--entrypoint` (path): The place to start walking the module graph. This is the only required option.
41
+
42
+ - `--skip` (RegExp|"none"): Which files not to parse and find requires/imports in. Defaults to `/node_modules/`. Specify "none" to parse everything.
43
+
44
+ - `--json` (boolean): whether to output json or human-readable data. default value varies depending on if stdout is a tty.
45
+
46
+ - `--only-entrypoint` (boolean): if true, only the imports/requires in the entrypoint file will be resolved, and no other files will be walked over.
47
+
48
+ - `--resolver` (path): module which exports a JS function that locates modules. Uses the same resolver format as [kame](https://github.com/suchipi/kame#config-hell).
49
+
50
+ - `--full-errors` (boolean): If reading, parsing, traversal, or resolution errors occur, print as much error information as possible.
51
+
52
+ ### Node API
53
+
54
+ ```ts
55
+ import { walk } from "resolve-everything";
56
+
57
+ const entrypoint = "/home/someone/some-file.js";
58
+ const { errors, modules } = walk(entrypoint /* , options */);
59
+
60
+ // modules is a Map<string, { id: string, requests: Map<string, string> }>
61
+ ```
62
+
63
+ #### Options
64
+
65
+ ```ts
66
+ export type WalkOptions = {
67
+ /**
68
+ * Which files not to parse and find requires/imports in.
69
+ *
70
+ * Defaults to `/node_modules/`.
71
+ * Specify `null` to include node_modules.
72
+ */
73
+ skip?: RegExp | null;
74
+
75
+ /**
76
+ * If true, only the imports/requires in the entrypoint file will be
77
+ * resolved, and no other files will be walked over.
78
+ */
79
+ onlyEntrypoint?: boolean;
80
+
81
+ /**
82
+ * A function which translates the string-part of an import/require into the
83
+ * absolute path to the file on disk, OR, if there is no file for that module
84
+ * (ie. it's a node builtin), a string starting with "external:".
85
+ */
86
+ resolver?: (id: string, fromFilePath: string) => string;
87
+ };
88
+ ```
89
+
90
+ See the included TypeScript types for more information.
91
+
92
+ ## License
93
+
94
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_util_1 = __importDefault(require("node:util"));
9
+ const clefairy_1 = require("clefairy");
10
+ const _1 = require(".");
11
+ (0, clefairy_1.run)({
12
+ entrypoint: clefairy_1.optionalPath,
13
+ resolver: clefairy_1.optionalPath,
14
+ fullErrors: clefairy_1.optionalBoolean,
15
+ skip: clefairy_1.optionalString,
16
+ json: clefairy_1.optionalBoolean,
17
+ onlyEntrypoint: clefairy_1.optionalBoolean,
18
+ help: clefairy_1.optionalBoolean,
19
+ h: clefairy_1.optionalBoolean,
20
+ }, async ({ entrypoint, resolver, fullErrors, skip, json, onlyEntrypoint, help, h, }) => {
21
+ if (help || h) {
22
+ const helpText = require("./help-text").default;
23
+ console.log(helpText);
24
+ return;
25
+ }
26
+ if (entrypoint == null) {
27
+ throw new Error(`You must specify an --entrypoint. Run with --help for more info.`);
28
+ }
29
+ if (!node_fs_1.default.existsSync(entrypoint)) {
30
+ throw new Error("No such file: " + entrypoint);
31
+ }
32
+ const walkOptions = {
33
+ onError: (err) => {
34
+ if (!fullErrors && /node_modules/.test(err.filename || "")) {
35
+ // Don't report resolution errors under node_modules dirs because
36
+ // they're usually not actionable.
37
+ return;
38
+ }
39
+ let message = `Failed to ${err.stage} `;
40
+ if (err.request) {
41
+ message += JSON.stringify(err.request) + " ";
42
+ }
43
+ message += `for ${JSON.stringify(err.filename)}`;
44
+ console.warn(message);
45
+ if (fullErrors) {
46
+ console.error(err.error);
47
+ }
48
+ },
49
+ };
50
+ if (skip) {
51
+ if (skip === "none") {
52
+ walkOptions.skip = null;
53
+ }
54
+ else {
55
+ const mightBeRegExpLiteral = /^\/.*\/[gimsuy]?$/.test(skip);
56
+ if (mightBeRegExpLiteral) {
57
+ try {
58
+ walkOptions.skip = eval(skip);
59
+ }
60
+ catch (err) {
61
+ walkOptions.skip = new RegExp(skip, "gu");
62
+ }
63
+ }
64
+ else {
65
+ walkOptions.skip = new RegExp(skip, "gu");
66
+ }
67
+ }
68
+ }
69
+ if (resolver) {
70
+ const exps = require(resolver);
71
+ if (typeof exps === "function") {
72
+ walkOptions.resolver = exps;
73
+ }
74
+ else if (typeof exps === "object" && exps != null) {
75
+ if (typeof exps.resolve === "function") {
76
+ walkOptions.resolver = exps.resolve;
77
+ }
78
+ else if (typeof exps.default === "function") {
79
+ walkOptions.resolver = exps.default;
80
+ }
81
+ else {
82
+ throw new Error(`Resolver at ${JSON.stringify(resolver)} didn't export a 'resolve' function.`);
83
+ }
84
+ }
85
+ else {
86
+ throw new Error(`Resolver at ${JSON.stringify(resolver)} didn't export a 'resolve' function.`);
87
+ }
88
+ }
89
+ const result = (0, _1.walk)(entrypoint, walkOptions);
90
+ let toPrint = (0, _1.serialize)(result.modules);
91
+ if (onlyEntrypoint) {
92
+ toPrint = toPrint[entrypoint];
93
+ }
94
+ if (json === undefined && !process.stdout.isTTY) {
95
+ json = true;
96
+ }
97
+ if (json) {
98
+ console.log(JSON.stringify(toPrint, null, 2));
99
+ }
100
+ else {
101
+ console.log(node_util_1.default.inspect(toPrint, { depth: 4, colors: true }));
102
+ }
103
+ });
@@ -0,0 +1,9 @@
1
+ import makeDebug from "debug";
2
+ export declare const debugLogger: {
3
+ summary: makeDebug.Debugger;
4
+ fileContent: makeDebug.Debugger;
5
+ ast: makeDebug.Debugger;
6
+ traverse: makeDebug.Debugger;
7
+ args: makeDebug.Debugger;
8
+ returns: makeDebug.Debugger;
9
+ };
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.debugLogger = void 0;
7
+ const debug_1 = __importDefault(require("debug"));
8
+ exports.debugLogger = {
9
+ summary: (0, debug_1.default)("resolve-everything:summary"),
10
+ fileContent: (0, debug_1.default)("resolve-everything:noisy:file-content"),
11
+ ast: (0, debug_1.default)("resolve-everything:noisy:ast"),
12
+ traverse: (0, debug_1.default)("resolve-everything:noisy:traverse"),
13
+ args: (0, debug_1.default)("resolve-everything:noisy:args"),
14
+ returns: (0, debug_1.default)("resolve-everything:noisy:returns"),
15
+ };
@@ -0,0 +1 @@
1
+ export declare function defaultResolver(id: string, fromFilePath: string): string;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.defaultResolver = void 0;
7
+ const node_module_1 = __importDefault(require("node:module"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const resolve_1 = __importDefault(require("resolve"));
10
+ if (!Array.isArray(node_module_1.default.builtinModules)) {
11
+ throw new Error("your node version seriously way too old bruh");
12
+ }
13
+ const allBuiltins = new Set(node_module_1.default.builtinModules);
14
+ // This is (more or less) a direct copy-paste of kame's default resolver.
15
+ // We copy-paste instead of depending on it directly, though, because kame has a LOT of deps and we just need this piece
16
+ //
17
+ // // https://github.com/suchipi/kame/blob/ae317caf325d5cbe4925fe30273159b6c04651a6/src/default-resolver.ts#L10
18
+ function defaultResolver(id, fromFilePath) {
19
+ if (id.includes(":") && !id.startsWith("file:")) {
20
+ return "external:" + id;
21
+ }
22
+ if (allBuiltins.has(id.split("/")[0])) {
23
+ return "external:" + id;
24
+ }
25
+ const result = resolve_1.default.sync(id, {
26
+ basedir: node_path_1.default.dirname(fromFilePath),
27
+ preserveSymlinks: false,
28
+ extensions: [
29
+ ".js",
30
+ ".json",
31
+ ".mjs",
32
+ ".jsx",
33
+ ".ts",
34
+ ".tsx",
35
+ ".node",
36
+ ".wasm",
37
+ ],
38
+ });
39
+ if (result.endsWith(".node") || result.endsWith(".wasm")) {
40
+ return "external:" + result;
41
+ }
42
+ return result;
43
+ }
44
+ exports.defaultResolver = defaultResolver;
@@ -0,0 +1,2 @@
1
+ declare const _default: string;
2
+ export default _default;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const kleur_1 = __importDefault(require("kleur"));
7
+ const h1 = kleur_1.default.bgBlue;
8
+ const h2 = kleur_1.default.blue().bold;
9
+ const opt = kleur_1.default.green;
10
+ const jsonSample = `{
11
+ "<full-path-to-some-file.js>": {
12
+ "id": "<full-path-to-some-file.js>",
13
+ "requests": {
14
+ // key is require/import string that appeared in the source code
15
+ // value is full path to the file that refers to
16
+ "./something": "<full-path-to-something>",
17
+ "react": "<full-path-to-react>",
18
+ "../somewhere/yeah": "<full-path-to-yeah>",
19
+ },
20
+ "dependencies": [
21
+ "<full-path-to-something>",
22
+ "<full-path-to-react>",
23
+ "<full-path-to-yeah>",
24
+ ]
25
+ },
26
+ "<full-path-to-something>": { ... },
27
+ "<full-path-to-yeah>": { ... },
28
+ ...
29
+ }`
30
+ .replaceAll(/\[\]\{\}/g, (str) => kleur_1.default.bold(str))
31
+ .replaceAll(/<[^>]+>/g, (str) => kleur_1.default.magenta(str))
32
+ .replaceAll(/"([^"]+)"/g, (str, contents) => kleur_1.default.green(`"` + kleur_1.default.bold(contents) + `"`))
33
+ .replaceAll(/\/\/.*\n/g, (str) => kleur_1.default.dim(str))
34
+ .replaceAll("...", kleur_1.default.dim("..."));
35
+ exports.default = `
36
+ ${h1("# resolve-everything")}
37
+
38
+ resolve-everything is a tool which walks through the module dependency tree of
39
+ a JavaScript/TypeScript project and gives you data about all the relationships.
40
+
41
+ ${h2("## Usage")}
42
+
43
+ $ resolve-everything --entrypoint ./some-file.js
44
+
45
+ ${h2("## Options")}
46
+
47
+ ${opt("--entrypoint")} (path):
48
+ The place to start walking the module graph.
49
+ This is the only required option.
50
+
51
+ ${opt("--skip")} (RegExp|"none"):
52
+ Which files not to parse and find requires/imports in.
53
+ Defaults to /node_modules/. Specify "none" to parse everything.
54
+
55
+ ${opt("--json")} (boolean):
56
+ Whether to output json or human-readable data.
57
+ Default value varies depending on if stdout is a tty.
58
+
59
+ ${opt("--only-entrypoint")} (boolean):
60
+ If true, only the imports/requires in the entrypoint file will be resolved,
61
+ and no other files will be walked over.
62
+
63
+ ${opt("--resolver")} (path):
64
+ Module which exports a JS function that locates modules. Uses the same
65
+ resolver format as https://github.com/suchipi/kame, namely:
66
+
67
+ export function resolve(id: string, fromFilePath: string): string;
68
+
69
+ ${opt("--full-errors")} (boolean):
70
+ If reading, parsing, traversal, or resolution errors occur, print as much
71
+ error information as possible.
72
+
73
+ ${h2("## Output")}
74
+
75
+ The program prints JSON shaped like:
76
+
77
+ ${jsonSample}
78
+
79
+ ${kleur_1.default.bold("resolve-everything")} was made with ${kleur_1.default.red("<3")} by Lily Skye. Though it likely can't resolve
80
+ *${kleur_1.default.italic("all")}* of your problems, maybe it can resolve one of them.
81
+ `.trim();
@@ -0,0 +1,6 @@
1
+ export { walk, type WalkOptions } from "./walk";
2
+ export type { ErrorReport as ReportedError, ResolverFunction } from "./types";
3
+ export { defaultResolver } from "./default-resolver";
4
+ export { Walker, type WalkerOptions } from "./walker";
5
+ export { Module } from "./module";
6
+ export { serialize, type SerializedModules as SerializeResult, } from "./serialize";
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serialize = exports.Module = exports.Walker = exports.defaultResolver = exports.walk = void 0;
4
+ var walk_1 = require("./walk");
5
+ Object.defineProperty(exports, "walk", { enumerable: true, get: function () { return walk_1.walk; } });
6
+ var default_resolver_1 = require("./default-resolver");
7
+ Object.defineProperty(exports, "defaultResolver", { enumerable: true, get: function () { return default_resolver_1.defaultResolver; } });
8
+ var walker_1 = require("./walker");
9
+ Object.defineProperty(exports, "Walker", { enumerable: true, get: function () { return walker_1.Walker; } });
10
+ var module_1 = require("./module");
11
+ Object.defineProperty(exports, "Module", { enumerable: true, get: function () { return module_1.Module; } });
12
+ var serialize_1 = require("./serialize");
13
+ Object.defineProperty(exports, "serialize", { enumerable: true, get: function () { return serialize_1.serialize; } });
@@ -0,0 +1,11 @@
1
+ import * as ee from "equivalent-exchange";
2
+ import type { ResolverFunction } from "./types";
3
+ export declare class Module {
4
+ id: string;
5
+ requests: Map<string, string>;
6
+ constructor(id: string);
7
+ read(): string | null;
8
+ parse(code: string): ee.types.File;
9
+ getRequests(ast: ee.types.File): Array<string>;
10
+ resolve(request: string, resolver: ResolverFunction): string;
11
+ }
package/dist/module.js ADDED
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.Module = void 0;
27
+ const fs = __importStar(require("node:fs"));
28
+ const ee = __importStar(require("equivalent-exchange"));
29
+ const debug_logger_1 = require("./debug-logger");
30
+ let formatAst;
31
+ if (debug_logger_1.debugLogger.ast.enabled) {
32
+ formatAst = require("pretty-print-ast");
33
+ }
34
+ else {
35
+ formatAst = () => "";
36
+ }
37
+ class Module {
38
+ constructor(id) {
39
+ this.requests = new Map();
40
+ this.id = id;
41
+ }
42
+ read() {
43
+ debug_logger_1.debugLogger.summary("Module.read", this.id);
44
+ if (!/\.[cm]?[tj]sx?$/.test(this.id)) {
45
+ debug_logger_1.debugLogger.summary("doesn't appear to be js/ts:", this.id);
46
+ debug_logger_1.debugLogger.returns("Module.read -> null");
47
+ return null;
48
+ }
49
+ const code = fs.readFileSync(this.id, "utf-8");
50
+ debug_logger_1.debugLogger.fileContent(code);
51
+ debug_logger_1.debugLogger.returns("Module.read ->", code);
52
+ return code;
53
+ }
54
+ parse(code) {
55
+ debug_logger_1.debugLogger.summary("Module.parse", this.id);
56
+ debug_logger_1.debugLogger.args("Module.parse", code);
57
+ const ast = ee.codeToAst(code, { fileName: this.id });
58
+ debug_logger_1.debugLogger.ast(formatAst(ast, { color: true }));
59
+ debug_logger_1.debugLogger.returns("Module.parse ->", ast);
60
+ return ast;
61
+ }
62
+ getRequests(ast) {
63
+ debug_logger_1.debugLogger.summary("Module.getRequests", this.id);
64
+ debug_logger_1.debugLogger.args("Module.getRequests", ast);
65
+ const requests = [];
66
+ ee.traverse(ast, {
67
+ ImportDeclaration(nodePath) {
68
+ debug_logger_1.debugLogger.traverse("found ImportDeclaration", nodePath.node);
69
+ requests.push(nodePath.node.source.value);
70
+ },
71
+ ExportAllDeclaration(nodePath) {
72
+ debug_logger_1.debugLogger.traverse("found ExportAllDeclaration", nodePath.node);
73
+ requests.push(nodePath.node.source.value);
74
+ },
75
+ ExportNamedDeclaration(nodePath) {
76
+ debug_logger_1.debugLogger.traverse("found ExportNamedDeclaration", nodePath.node);
77
+ const source = nodePath.node.source;
78
+ if (source != null) {
79
+ debug_logger_1.debugLogger.traverse("previously-mentioned ExportNamedDeclaration had a source!");
80
+ requests.push(source.value);
81
+ }
82
+ },
83
+ CallExpression(nodePath) {
84
+ const node = nodePath.node;
85
+ if (ee.hasShape(node, {
86
+ callee: {
87
+ type: "Identifier",
88
+ name: "require",
89
+ },
90
+ arguments: {
91
+ 0: {
92
+ type: "StringLiteral",
93
+ },
94
+ },
95
+ })) {
96
+ debug_logger_1.debugLogger.traverse("found require", node);
97
+ requests.push(node.arguments[0].value);
98
+ }
99
+ if (ee.hasShape(node, {
100
+ callee: {
101
+ type: "Import",
102
+ },
103
+ arguments: {
104
+ 0: {
105
+ type: "StringLiteral",
106
+ },
107
+ },
108
+ })) {
109
+ debug_logger_1.debugLogger.traverse("found dynamic import", node);
110
+ requests.push(node.arguments[0].value);
111
+ }
112
+ },
113
+ });
114
+ debug_logger_1.debugLogger.returns("Module.getRequests ->", requests);
115
+ return requests;
116
+ }
117
+ resolve(request, resolver) {
118
+ debug_logger_1.debugLogger.summary("Module.resolve", this.id, request);
119
+ debug_logger_1.debugLogger.args("Module.resolve", request, resolver);
120
+ const resolved = resolver(request, this.id);
121
+ this.requests.set(request, resolved);
122
+ debug_logger_1.debugLogger.returns("Module.resolve ->", resolved);
123
+ return resolved;
124
+ }
125
+ }
126
+ exports.Module = Module;
@@ -0,0 +1,11 @@
1
+ import type { Module } from "./module";
2
+ export type SerializedModules = {
3
+ [filename: string]: {
4
+ id: string;
5
+ requests: {
6
+ [request: string]: string;
7
+ };
8
+ dependencies: Array<string>;
9
+ };
10
+ };
11
+ export declare function serialize(modules: Map<string, Module>): SerializedModules;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serialize = void 0;
4
+ function serialize(modules) {
5
+ const result = {};
6
+ for (const [id, mod] of modules) {
7
+ result[id] = {
8
+ id,
9
+ requests: {},
10
+ dependencies: [],
11
+ };
12
+ for (const [request, resolved] of mod.requests) {
13
+ result[id].requests[request] = resolved;
14
+ result[id].dependencies.push(resolved);
15
+ }
16
+ }
17
+ return result;
18
+ }
19
+ exports.serialize = serialize;
@@ -0,0 +1,6 @@
1
+ import type { RunContext } from "first-base";
2
+ export declare const rootDir: import("path-less-traveled").PathMarker;
3
+ export declare const cliPath: string;
4
+ export declare function cleanString(str: string): string;
5
+ export declare function inspectAndClean(value: any): string;
6
+ export declare function cleanRunResult(result: RunContext["result"]): RunContext["result"];
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.cleanRunResult = exports.inspectAndClean = exports.cleanString = exports.cliPath = exports.rootDir = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const node_util_1 = __importDefault(require("node:util"));
9
+ const path_less_traveled_1 = require("path-less-traveled");
10
+ exports.rootDir = (0, path_less_traveled_1.pathMarker)(node_path_1.default.resolve(__dirname, ".."));
11
+ exports.cliPath = (0, exports.rootDir)("dist/cli.js");
12
+ function cleanString(str) {
13
+ return str.replaceAll((0, exports.rootDir)(), "<rootDir>");
14
+ }
15
+ exports.cleanString = cleanString;
16
+ function inspectAndClean(value) {
17
+ return cleanString(node_util_1.default.inspect(value, { depth: Infinity }));
18
+ }
19
+ exports.inspectAndClean = inspectAndClean;
20
+ function cleanRunResult(result) {
21
+ return {
22
+ ...result,
23
+ stdout: cleanString(result.stdout),
24
+ stderr: cleanString(result.stderr),
25
+ };
26
+ }
27
+ exports.cleanRunResult = cleanRunResult;
@@ -0,0 +1,7 @@
1
+ export type ErrorReport = {
2
+ filename?: string;
3
+ request?: string;
4
+ stage: "read" | "parse" | "getRequests" | "resolve";
5
+ error: Error;
6
+ };
7
+ export type ResolverFunction = (id: string, fromFilePath: string) => string;
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/walk.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { Module } from "./module";
2
+ import type { ErrorReport, ResolverFunction } from "./types";
3
+ export type WalkOptions = {
4
+ onError?: (error: ErrorReport) => void;
5
+ resolver?: ResolverFunction;
6
+ skip?: RegExp | null;
7
+ onlyEntrypoint?: boolean;
8
+ };
9
+ export declare function walk(entrypoint: string, options?: WalkOptions): {
10
+ errors: ErrorReport[];
11
+ modules: Map<string, Module>;
12
+ };
package/dist/walk.js ADDED
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.walk = void 0;
27
+ const path = __importStar(require("node:path"));
28
+ const walker_1 = require("./walker");
29
+ const debug_logger_1 = require("./debug-logger");
30
+ const default_resolver_1 = require("./default-resolver");
31
+ function walk(entrypoint, options) {
32
+ debug_logger_1.debugLogger.summary("walk", entrypoint);
33
+ debug_logger_1.debugLogger.args("walk", entrypoint, options);
34
+ if (!path.isAbsolute(entrypoint)) {
35
+ throw new Error(`entrypoint must be an absolute path. received: ${entrypoint}`);
36
+ }
37
+ const resolver = options?.resolver ?? default_resolver_1.defaultResolver;
38
+ const skip = typeof options?.skip === "undefined" ? /node_modules/ : options?.skip;
39
+ const onlyEntrypoint = options?.onlyEntrypoint ?? false;
40
+ const walker = new walker_1.Walker(entrypoint, {
41
+ resolver,
42
+ skip,
43
+ onlyEntrypoint,
44
+ });
45
+ if (options?.onError) {
46
+ walker.on("error", options.onError);
47
+ }
48
+ const { errors } = walker.walk();
49
+ const modules = walker.modules;
50
+ const ret = {
51
+ errors,
52
+ modules,
53
+ };
54
+ debug_logger_1.debugLogger.returns("walk ->", ret);
55
+ return ret;
56
+ }
57
+ exports.walk = walk;
@@ -0,0 +1,18 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from "node:events";
3
+ import { Module } from "./module";
4
+ import type { ErrorReport, ResolverFunction } from "./types";
5
+ export type WalkerOptions = {
6
+ resolver: ResolverFunction;
7
+ skip: RegExp | null;
8
+ onlyEntrypoint: boolean;
9
+ };
10
+ export declare class Walker extends EventEmitter {
11
+ entrypoint: string;
12
+ modules: Map<string, Module>;
13
+ private _options;
14
+ constructor(entrypoint: string, options: WalkerOptions);
15
+ walk(): {
16
+ errors: Array<ErrorReport>;
17
+ };
18
+ }
package/dist/walker.js ADDED
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.Walker = void 0;
27
+ const path = __importStar(require("node:path"));
28
+ const node_events_1 = require("node:events");
29
+ const module_1 = require("./module");
30
+ const debug_logger_1 = require("./debug-logger");
31
+ class Walker extends node_events_1.EventEmitter {
32
+ constructor(entrypoint, options) {
33
+ super();
34
+ this._options = options;
35
+ if (!path.isAbsolute(entrypoint)) {
36
+ throw Object.assign(new Error(`Entrypoint must be an absolute path. received: ${entrypoint}`), { entrypoint });
37
+ }
38
+ this.entrypoint = entrypoint;
39
+ this.modules = new Map();
40
+ }
41
+ walk() {
42
+ debug_logger_1.debugLogger.summary("Walker.walk");
43
+ const filesToProcess = [this.entrypoint];
44
+ let filename;
45
+ const errors = [];
46
+ let errorStage = "read";
47
+ let errorRequest = undefined;
48
+ const reportError = (error) => {
49
+ const report = {
50
+ filename,
51
+ stage: errorStage,
52
+ request: errorRequest,
53
+ error,
54
+ };
55
+ debug_logger_1.debugLogger.summary("error reported:", report);
56
+ this.emit("error", report);
57
+ errors.push(report);
58
+ };
59
+ while ((filename = filesToProcess.shift())) {
60
+ debug_logger_1.debugLogger.summary("Walker.walk -> processing", filename);
61
+ this.emit("processing", filename);
62
+ if (this.modules.has(filename)) {
63
+ // already processed
64
+ continue;
65
+ }
66
+ const mod = new module_1.Module(filename);
67
+ this.modules.set(filename, mod);
68
+ try {
69
+ const code = mod.read();
70
+ if (code == null) {
71
+ // not a js/ts file
72
+ continue;
73
+ }
74
+ errorStage = "parse";
75
+ const ast = mod.parse(code);
76
+ errorStage = "getRequests";
77
+ const requests = mod.getRequests(ast);
78
+ errorStage = "resolve";
79
+ errorRequest = undefined;
80
+ for (const request of requests) {
81
+ errorRequest = request;
82
+ try {
83
+ const target = mod.resolve(request, this._options.resolver);
84
+ if (target.startsWith("external:")) {
85
+ continue;
86
+ }
87
+ if (this._options.skip != null && this._options.skip.test(target)) {
88
+ continue;
89
+ }
90
+ if (!this.modules.has(target)) {
91
+ debug_logger_1.debugLogger.summary("Walker.walk -> queueing", target);
92
+ this.emit("queueing", target);
93
+ filesToProcess.push(target);
94
+ }
95
+ }
96
+ catch (error) {
97
+ reportError(error);
98
+ }
99
+ }
100
+ errorRequest = undefined;
101
+ }
102
+ catch (error) {
103
+ reportError(error);
104
+ }
105
+ if (this._options.onlyEntrypoint) {
106
+ break;
107
+ }
108
+ }
109
+ const ret = { errors };
110
+ debug_logger_1.debugLogger.returns("Walker.walk ->", ret);
111
+ return ret;
112
+ }
113
+ }
114
+ exports.Walker = Walker;
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "resolve-everything",
3
+ "version": "0.1.0",
4
+ "description": "walk your project's import/require tree and print all the relationships",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "resolve-everything": "dist/cli.js"
9
+ },
10
+ "scripts": {
11
+ "build": "rm -rf dist && bunx --bun tsc && chmod +x dist/cli.js",
12
+ "test": "vitest",
13
+ "cli": "bun src/cli.ts"
14
+ },
15
+ "keywords": [],
16
+ "author": "Lily Skye <me@suchipi.com>",
17
+ "license": "MIT",
18
+ "devDependencies": {
19
+ "@types/debug": "^4.1.10",
20
+ "@types/resolve": "^1.20.4",
21
+ "path-less-traveled": "^2.0.0",
22
+ "prettier": "^3.0.3",
23
+ "typescript": "^5.2.2",
24
+ "vitest": "^0.34.6"
25
+ },
26
+ "prettier": {},
27
+ "dependencies": {
28
+ "clefairy": "^0.4.0",
29
+ "debug": "^4.3.4",
30
+ "equivalent-exchange": "^1.10.0",
31
+ "first-base": "^1.3.0",
32
+ "kleur": "^4.1.5",
33
+ "pretty-print-ast": "^1.0.1",
34
+ "resolve": "^1.22.8"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/suchipi/resolve-everything.git"
39
+ }
40
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "include": ["./src/**/*.ts"],
3
+
4
+ "compilerOptions": {
5
+ "lib": ["es2021"],
6
+ "target": "es2020",
7
+ "module": "CommonJS",
8
+ "outDir": "./dist",
9
+ "declaration": true,
10
+ "skipLibCheck": true,
11
+
12
+ "strict": true,
13
+ "noImplicitAny": false,
14
+ "strictNullChecks": true,
15
+ "strictFunctionTypes": true,
16
+ "strictPropertyInitialization": true,
17
+ "noImplicitThis": true,
18
+ "alwaysStrict": true,
19
+ "noUnusedLocals": false,
20
+ "noUnusedParameters": false,
21
+ "noImplicitReturns": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "downlevelIteration": false,
24
+
25
+ "moduleResolution": "node",
26
+ "esModuleInterop": true
27
+ }
28
+ }