bluera-knowledge 0.9.31 → 0.9.34
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/.claude/commands/code-review.md +15 -0
- package/.claude/hooks/post-edit-check.sh +5 -3
- package/.claude/skills/atomic-commits/SKILL.md +3 -1
- package/.claude/skills/code-review-repo/skill.md +62 -0
- package/.husky/pre-commit +3 -2
- package/.prettierrc +9 -0
- package/.versionrc.json +1 -1
- package/CHANGELOG.md +35 -0
- package/CLAUDE.md +6 -0
- package/README.md +25 -13
- package/bun.lock +277 -33
- package/dist/{chunk-L2YVNC63.js → chunk-6FHWC36B.js} +9 -1
- package/dist/chunk-6FHWC36B.js.map +1 -0
- package/dist/{chunk-2SJHNRXD.js → chunk-DC7CGSGT.js} +288 -241
- package/dist/chunk-DC7CGSGT.js.map +1 -0
- package/dist/{chunk-RWSXP3PQ.js → chunk-WFNPNAAP.js} +3194 -3024
- package/dist/chunk-WFNPNAAP.js.map +1 -0
- package/dist/{chunk-OGEY66FZ.js → chunk-Z2KKVH45.js} +548 -482
- package/dist/chunk-Z2KKVH45.js.map +1 -0
- package/dist/index.js +871 -754
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +3 -3
- package/dist/watch.service-BJV3TI3F.js +7 -0
- package/dist/workers/background-worker-cli.js +46 -45
- package/dist/workers/background-worker-cli.js.map +1 -1
- package/eslint.config.js +43 -1
- package/package.json +18 -11
- package/plugin.json +8 -0
- package/python/requirements.txt +1 -1
- package/src/analysis/ast-parser.test.ts +12 -11
- package/src/analysis/ast-parser.ts +28 -22
- package/src/analysis/code-graph.test.ts +52 -62
- package/src/analysis/code-graph.ts +9 -13
- package/src/analysis/dependency-usage-analyzer.test.ts +91 -271
- package/src/analysis/dependency-usage-analyzer.ts +52 -24
- package/src/analysis/go-ast-parser.test.ts +22 -22
- package/src/analysis/go-ast-parser.ts +18 -25
- package/src/analysis/parser-factory.test.ts +9 -9
- package/src/analysis/parser-factory.ts +3 -3
- package/src/analysis/python-ast-parser.test.ts +27 -27
- package/src/analysis/python-ast-parser.ts +2 -2
- package/src/analysis/repo-url-resolver.test.ts +82 -82
- package/src/analysis/rust-ast-parser.test.ts +19 -19
- package/src/analysis/rust-ast-parser.ts +17 -27
- package/src/analysis/tree-sitter-parser.test.ts +3 -3
- package/src/analysis/tree-sitter-parser.ts +10 -16
- package/src/cli/commands/crawl.test.ts +40 -24
- package/src/cli/commands/crawl.ts +186 -161
- package/src/cli/commands/index-cmd.test.ts +90 -90
- package/src/cli/commands/index-cmd.ts +52 -36
- package/src/cli/commands/mcp.test.ts +6 -6
- package/src/cli/commands/mcp.ts +2 -2
- package/src/cli/commands/plugin-api.test.ts +16 -18
- package/src/cli/commands/plugin-api.ts +9 -6
- package/src/cli/commands/search.test.ts +16 -7
- package/src/cli/commands/search.ts +124 -87
- package/src/cli/commands/serve.test.ts +67 -25
- package/src/cli/commands/serve.ts +18 -3
- package/src/cli/commands/setup.test.ts +176 -101
- package/src/cli/commands/setup.ts +140 -117
- package/src/cli/commands/store.test.ts +82 -53
- package/src/cli/commands/store.ts +56 -37
- package/src/cli/program.ts +2 -2
- package/src/crawl/article-converter.test.ts +4 -1
- package/src/crawl/article-converter.ts +46 -31
- package/src/crawl/bridge.test.ts +240 -132
- package/src/crawl/bridge.ts +87 -30
- package/src/crawl/claude-client.test.ts +124 -56
- package/src/crawl/claude-client.ts +7 -15
- package/src/crawl/intelligent-crawler.test.ts +65 -22
- package/src/crawl/intelligent-crawler.ts +86 -53
- package/src/crawl/markdown-utils.ts +1 -4
- package/src/db/embeddings.ts +4 -6
- package/src/db/lance.test.ts +63 -4
- package/src/db/lance.ts +31 -12
- package/src/index.ts +26 -17
- package/src/logging/index.ts +1 -5
- package/src/logging/logger.ts +3 -5
- package/src/logging/payload.test.ts +1 -1
- package/src/logging/payload.ts +3 -5
- package/src/mcp/commands/index.ts +2 -2
- package/src/mcp/commands/job.commands.ts +12 -18
- package/src/mcp/commands/meta.commands.ts +13 -13
- package/src/mcp/commands/registry.ts +5 -8
- package/src/mcp/commands/store.commands.ts +19 -19
- package/src/mcp/handlers/execute.handler.test.ts +10 -10
- package/src/mcp/handlers/execute.handler.ts +4 -5
- package/src/mcp/handlers/index.ts +10 -14
- package/src/mcp/handlers/job.handler.test.ts +10 -10
- package/src/mcp/handlers/job.handler.ts +22 -25
- package/src/mcp/handlers/search.handler.test.ts +36 -65
- package/src/mcp/handlers/search.handler.ts +135 -104
- package/src/mcp/handlers/store.handler.test.ts +41 -52
- package/src/mcp/handlers/store.handler.ts +108 -88
- package/src/mcp/schemas/index.test.ts +73 -68
- package/src/mcp/schemas/index.ts +18 -12
- package/src/mcp/server.test.ts +1 -1
- package/src/mcp/server.ts +59 -46
- package/src/plugin/commands.test.ts +230 -95
- package/src/plugin/commands.ts +24 -25
- package/src/plugin/dependency-analyzer.test.ts +52 -52
- package/src/plugin/dependency-analyzer.ts +85 -22
- package/src/plugin/git-clone.test.ts +24 -13
- package/src/plugin/git-clone.ts +3 -7
- package/src/server/app.test.ts +109 -109
- package/src/server/app.ts +32 -23
- package/src/server/index.test.ts +64 -66
- package/src/services/chunking.service.test.ts +32 -32
- package/src/services/chunking.service.ts +16 -9
- package/src/services/code-graph.service.test.ts +30 -36
- package/src/services/code-graph.service.ts +24 -10
- package/src/services/code-unit.service.test.ts +55 -11
- package/src/services/code-unit.service.ts +85 -11
- package/src/services/config.service.test.ts +37 -18
- package/src/services/config.service.ts +30 -7
- package/src/services/index.service.test.ts +49 -18
- package/src/services/index.service.ts +98 -48
- package/src/services/index.ts +8 -10
- package/src/services/job.service.test.ts +22 -22
- package/src/services/job.service.ts +18 -18
- package/src/services/project-root.service.test.ts +1 -3
- package/src/services/search.service.test.ts +248 -120
- package/src/services/search.service.ts +286 -156
- package/src/services/services.test.ts +36 -0
- package/src/services/snippet.service.test.ts +14 -6
- package/src/services/snippet.service.ts +7 -5
- package/src/services/store.service.test.ts +68 -29
- package/src/services/store.service.ts +41 -12
- package/src/services/watch.service.test.ts +34 -14
- package/src/services/watch.service.ts +11 -1
- package/src/types/brands.test.ts +3 -1
- package/src/types/index.ts +2 -13
- package/src/types/search.ts +10 -8
- package/src/utils/type-guards.test.ts +20 -15
- package/src/utils/type-guards.ts +1 -1
- package/src/workers/background-worker-cli.ts +2 -2
- package/src/workers/background-worker.test.ts +54 -40
- package/src/workers/background-worker.ts +76 -60
- package/src/workers/spawn-worker.test.ts +22 -10
- package/src/workers/spawn-worker.ts +6 -6
- package/tests/analysis/ast-parser.test.ts +3 -3
- package/tests/analysis/code-graph.test.ts +5 -5
- package/tests/fixtures/code-snippets/api/error-handling.ts +4 -15
- package/tests/fixtures/code-snippets/api/rest-controller.ts +3 -9
- package/tests/fixtures/code-snippets/auth/jwt-auth.ts +5 -21
- package/tests/fixtures/code-snippets/auth/oauth-flow.ts +4 -4
- package/tests/fixtures/code-snippets/database/repository-pattern.ts +11 -3
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/handler.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-pages/handler.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/serve-static.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/client/client.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/client/types.ts +22 -20
- package/tests/fixtures/corpus/oss-repos/hono/src/context.ts +13 -10
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/accepts/accepts.ts +10 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/adapter/index.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/css/index.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/factory/index.ts +16 -16
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/ssg.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/hono-base.ts +3 -3
- package/tests/fixtures/corpus/oss-repos/hono/src/hono.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/css.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/intrinsic-element/components.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/render.ts +7 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/hooks/index.ts +3 -3
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-element/components.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/utils.ts +6 -6
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jsx-renderer/index.ts +3 -3
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/serve-static/index.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/preset/quick.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/preset/tiny.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/router/pattern-router/router.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/node.ts +4 -4
- package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/router.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/node.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/types.ts +166 -169
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/body.ts +8 -8
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/color.ts +3 -3
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/cookie.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/encode.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/types.ts +30 -33
- package/tests/fixtures/corpus/oss-repos/hono/src/validator/validator.ts +2 -2
- package/tests/fixtures/test-server.ts +3 -2
- package/tests/helpers/performance-metrics.ts +8 -25
- package/tests/helpers/search-relevance.ts +14 -69
- package/tests/integration/cli-consistency.test.ts +5 -4
- package/tests/integration/e2e-workflow.test.ts +2 -0
- package/tests/integration/python-bridge.test.ts +13 -3
- package/tests/mcp/server.test.ts +1 -1
- package/tests/services/code-unit.service.test.ts +48 -0
- package/tests/services/job.service.test.ts +124 -0
- package/tests/services/search.progressive-context.test.ts +2 -2
- package/.claude-plugin/plugin.json +0 -13
- package/BUGS-FOUND.md +0 -71
- package/dist/chunk-2SJHNRXD.js.map +0 -1
- package/dist/chunk-L2YVNC63.js.map +0 -1
- package/dist/chunk-OGEY66FZ.js.map +0 -1
- package/dist/chunk-RWSXP3PQ.js.map +0 -1
- package/dist/watch.service-YAIKKDCF.js +0 -7
- package/skills/atomic-commits/SKILL.md +0 -77
- /package/dist/{watch.service-YAIKKDCF.js.map → watch.service-BJV3TI3F.js.map} +0 -0
|
@@ -21,16 +21,10 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
21
21
|
describe('Package name extraction', () => {
|
|
22
22
|
it('extracts regular package name', async () => {
|
|
23
23
|
const packageJson = {
|
|
24
|
-
dependencies: {
|
|
24
|
+
dependencies: { lodash: '^4.0.0' },
|
|
25
25
|
};
|
|
26
|
-
await writeFile(
|
|
27
|
-
|
|
28
|
-
JSON.stringify(packageJson)
|
|
29
|
-
);
|
|
30
|
-
await writeFile(
|
|
31
|
-
join(tempDir, 'index.ts'),
|
|
32
|
-
'import { map } from "lodash";'
|
|
33
|
-
);
|
|
26
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
27
|
+
await writeFile(join(tempDir, 'index.ts'), 'import { map } from "lodash";');
|
|
34
28
|
|
|
35
29
|
const result = await analyzer.analyze(tempDir);
|
|
36
30
|
|
|
@@ -43,16 +37,10 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
43
37
|
|
|
44
38
|
it('extracts scoped package name', async () => {
|
|
45
39
|
const packageJson = {
|
|
46
|
-
dependencies: { '@org/package': '^1.0.0' }
|
|
40
|
+
dependencies: { '@org/package': '^1.0.0' },
|
|
47
41
|
};
|
|
48
|
-
await writeFile(
|
|
49
|
-
|
|
50
|
-
JSON.stringify(packageJson)
|
|
51
|
-
);
|
|
52
|
-
await writeFile(
|
|
53
|
-
join(tempDir, 'index.ts'),
|
|
54
|
-
'import { foo } from "@org/package";'
|
|
55
|
-
);
|
|
42
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
43
|
+
await writeFile(join(tempDir, 'index.ts'), 'import { foo } from "@org/package";');
|
|
56
44
|
|
|
57
45
|
const result = await analyzer.analyze(tempDir);
|
|
58
46
|
|
|
@@ -64,16 +52,10 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
64
52
|
|
|
65
53
|
it('extracts package from deep import path', async () => {
|
|
66
54
|
const packageJson = {
|
|
67
|
-
dependencies: {
|
|
55
|
+
dependencies: { lodash: '^4.0.0' },
|
|
68
56
|
};
|
|
69
|
-
await writeFile(
|
|
70
|
-
|
|
71
|
-
JSON.stringify(packageJson)
|
|
72
|
-
);
|
|
73
|
-
await writeFile(
|
|
74
|
-
join(tempDir, 'index.ts'),
|
|
75
|
-
'import map from "lodash/map";'
|
|
76
|
-
);
|
|
57
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
58
|
+
await writeFile(join(tempDir, 'index.ts'), 'import map from "lodash/map";');
|
|
77
59
|
|
|
78
60
|
const result = await analyzer.analyze(tempDir);
|
|
79
61
|
|
|
@@ -85,14 +67,8 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
85
67
|
|
|
86
68
|
it('ignores relative imports', async () => {
|
|
87
69
|
const packageJson = { dependencies: {} };
|
|
88
|
-
await writeFile(
|
|
89
|
-
|
|
90
|
-
JSON.stringify(packageJson)
|
|
91
|
-
);
|
|
92
|
-
await writeFile(
|
|
93
|
-
join(tempDir, 'index.ts'),
|
|
94
|
-
'import { helper } from "./utils";'
|
|
95
|
-
);
|
|
70
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
71
|
+
await writeFile(join(tempDir, 'index.ts'), 'import { helper } from "./utils";');
|
|
96
72
|
|
|
97
73
|
const result = await analyzer.analyze(tempDir);
|
|
98
74
|
|
|
@@ -104,14 +80,8 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
104
80
|
|
|
105
81
|
it('ignores node built-ins', async () => {
|
|
106
82
|
const packageJson = { dependencies: {} };
|
|
107
|
-
await writeFile(
|
|
108
|
-
|
|
109
|
-
JSON.stringify(packageJson)
|
|
110
|
-
);
|
|
111
|
-
await writeFile(
|
|
112
|
-
join(tempDir, 'index.ts'),
|
|
113
|
-
'import { readFile } from "node:fs/promises";'
|
|
114
|
-
);
|
|
83
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
84
|
+
await writeFile(join(tempDir, 'index.ts'), 'import { readFile } from "node:fs/promises";');
|
|
115
85
|
|
|
116
86
|
const result = await analyzer.analyze(tempDir);
|
|
117
87
|
|
|
@@ -123,14 +93,8 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
123
93
|
|
|
124
94
|
it('ignores absolute paths', async () => {
|
|
125
95
|
const packageJson = { dependencies: {} };
|
|
126
|
-
await writeFile(
|
|
127
|
-
|
|
128
|
-
JSON.stringify(packageJson)
|
|
129
|
-
);
|
|
130
|
-
await writeFile(
|
|
131
|
-
join(tempDir, 'index.ts'),
|
|
132
|
-
'import { util } from "/absolute/path";'
|
|
133
|
-
);
|
|
96
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
97
|
+
await writeFile(join(tempDir, 'index.ts'), 'import { util } from "/absolute/path";');
|
|
134
98
|
|
|
135
99
|
const result = await analyzer.analyze(tempDir);
|
|
136
100
|
|
|
@@ -145,14 +109,11 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
145
109
|
it('reads dependencies from package.json', async () => {
|
|
146
110
|
const packageJson = {
|
|
147
111
|
dependencies: {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
112
|
+
react: '^18.0.0',
|
|
113
|
+
lodash: '^4.0.0',
|
|
114
|
+
},
|
|
151
115
|
};
|
|
152
|
-
await writeFile(
|
|
153
|
-
join(tempDir, 'package.json'),
|
|
154
|
-
JSON.stringify(packageJson)
|
|
155
|
-
);
|
|
116
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
156
117
|
await writeFile(
|
|
157
118
|
join(tempDir, 'index.ts'),
|
|
158
119
|
'import React from "react"; import _ from "lodash";'
|
|
@@ -169,17 +130,11 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
169
130
|
it('identifies dev dependencies', async () => {
|
|
170
131
|
const packageJson = {
|
|
171
132
|
devDependencies: {
|
|
172
|
-
|
|
173
|
-
}
|
|
133
|
+
vitest: '^1.0.0',
|
|
134
|
+
},
|
|
174
135
|
};
|
|
175
|
-
await writeFile(
|
|
176
|
-
|
|
177
|
-
JSON.stringify(packageJson)
|
|
178
|
-
);
|
|
179
|
-
await writeFile(
|
|
180
|
-
join(tempDir, 'test.ts'),
|
|
181
|
-
'import { describe } from "vitest";'
|
|
182
|
-
);
|
|
136
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
137
|
+
await writeFile(join(tempDir, 'test.ts'), 'import { describe } from "vitest";');
|
|
183
138
|
|
|
184
139
|
const result = await analyzer.analyze(tempDir);
|
|
185
140
|
|
|
@@ -191,10 +146,7 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
191
146
|
|
|
192
147
|
it('handles project with no dependencies', async () => {
|
|
193
148
|
const packageJson = {};
|
|
194
|
-
await writeFile(
|
|
195
|
-
join(tempDir, 'package.json'),
|
|
196
|
-
JSON.stringify(packageJson)
|
|
197
|
-
);
|
|
149
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
198
150
|
|
|
199
151
|
const result = await analyzer.analyze(tempDir);
|
|
200
152
|
|
|
@@ -215,14 +167,8 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
215
167
|
});
|
|
216
168
|
|
|
217
169
|
it('reads Python dependencies from requirements.txt', async () => {
|
|
218
|
-
await writeFile(
|
|
219
|
-
|
|
220
|
-
'requests==2.28.0\nnumpy>=1.20.0'
|
|
221
|
-
);
|
|
222
|
-
await writeFile(
|
|
223
|
-
join(tempDir, 'script.py'),
|
|
224
|
-
'import requests\nimport numpy'
|
|
225
|
-
);
|
|
170
|
+
await writeFile(join(tempDir, 'requirements.txt'), 'requests==2.28.0\nnumpy>=1.20.0');
|
|
171
|
+
await writeFile(join(tempDir, 'script.py'), 'import requests\nimport numpy');
|
|
226
172
|
|
|
227
173
|
const result = await analyzer.analyze(tempDir);
|
|
228
174
|
|
|
@@ -233,10 +179,7 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
233
179
|
});
|
|
234
180
|
|
|
235
181
|
it('handles malformed package.json gracefully', async () => {
|
|
236
|
-
await writeFile(
|
|
237
|
-
join(tempDir, 'package.json'),
|
|
238
|
-
'{ invalid json'
|
|
239
|
-
);
|
|
182
|
+
await writeFile(join(tempDir, 'package.json'), '{ invalid json');
|
|
240
183
|
|
|
241
184
|
const result = await analyzer.analyze(tempDir);
|
|
242
185
|
|
|
@@ -250,16 +193,10 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
250
193
|
describe('File scanning', () => {
|
|
251
194
|
it('scans JavaScript files', async () => {
|
|
252
195
|
const packageJson = {
|
|
253
|
-
dependencies: {
|
|
196
|
+
dependencies: { package: '^1.0.0' },
|
|
254
197
|
};
|
|
255
|
-
await writeFile(
|
|
256
|
-
|
|
257
|
-
JSON.stringify(packageJson)
|
|
258
|
-
);
|
|
259
|
-
await writeFile(
|
|
260
|
-
join(tempDir, 'index.js'),
|
|
261
|
-
'import { foo } from "package";'
|
|
262
|
-
);
|
|
198
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
199
|
+
await writeFile(join(tempDir, 'index.js'), 'import { foo } from "package";');
|
|
263
200
|
|
|
264
201
|
const result = await analyzer.analyze(tempDir);
|
|
265
202
|
|
|
@@ -271,16 +208,10 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
271
208
|
|
|
272
209
|
it('scans TypeScript files', async () => {
|
|
273
210
|
const packageJson = {
|
|
274
|
-
dependencies: {
|
|
211
|
+
dependencies: { package: '^1.0.0' },
|
|
275
212
|
};
|
|
276
|
-
await writeFile(
|
|
277
|
-
|
|
278
|
-
JSON.stringify(packageJson)
|
|
279
|
-
);
|
|
280
|
-
await writeFile(
|
|
281
|
-
join(tempDir, 'index.ts'),
|
|
282
|
-
'import { foo } from "package";'
|
|
283
|
-
);
|
|
213
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
214
|
+
await writeFile(join(tempDir, 'index.ts'), 'import { foo } from "package";');
|
|
284
215
|
|
|
285
216
|
const result = await analyzer.analyze(tempDir);
|
|
286
217
|
|
|
@@ -292,18 +223,12 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
292
223
|
|
|
293
224
|
it('scans nested directories', async () => {
|
|
294
225
|
const packageJson = {
|
|
295
|
-
dependencies: {
|
|
226
|
+
dependencies: { pkg: '^1.0.0' },
|
|
296
227
|
};
|
|
297
|
-
await writeFile(
|
|
298
|
-
join(tempDir, 'package.json'),
|
|
299
|
-
JSON.stringify(packageJson)
|
|
300
|
-
);
|
|
228
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
301
229
|
|
|
302
230
|
await mkdir(join(tempDir, 'src'), { recursive: true });
|
|
303
|
-
await writeFile(
|
|
304
|
-
join(tempDir, 'src/app.ts'),
|
|
305
|
-
'import { x } from "pkg";'
|
|
306
|
-
);
|
|
231
|
+
await writeFile(join(tempDir, 'src/app.ts'), 'import { x } from "pkg";');
|
|
307
232
|
|
|
308
233
|
const result = await analyzer.analyze(tempDir);
|
|
309
234
|
|
|
@@ -315,18 +240,12 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
315
240
|
|
|
316
241
|
it('ignores node_modules directory', async () => {
|
|
317
242
|
const packageJson = {
|
|
318
|
-
dependencies: {
|
|
243
|
+
dependencies: { pkg: '^1.0.0' },
|
|
319
244
|
};
|
|
320
|
-
await writeFile(
|
|
321
|
-
join(tempDir, 'package.json'),
|
|
322
|
-
JSON.stringify(packageJson)
|
|
323
|
-
);
|
|
245
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
324
246
|
|
|
325
247
|
await mkdir(join(tempDir, 'node_modules'), { recursive: true });
|
|
326
|
-
await writeFile(
|
|
327
|
-
join(tempDir, 'node_modules/file.js'),
|
|
328
|
-
'import { x } from "pkg";'
|
|
329
|
-
);
|
|
248
|
+
await writeFile(join(tempDir, 'node_modules/file.js'), 'import { x } from "pkg";');
|
|
330
249
|
|
|
331
250
|
const result = await analyzer.analyze(tempDir);
|
|
332
251
|
|
|
@@ -339,12 +258,9 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
339
258
|
|
|
340
259
|
it('ignores dist and build directories', async () => {
|
|
341
260
|
const packageJson = {
|
|
342
|
-
dependencies: {
|
|
261
|
+
dependencies: { pkg: '^1.0.0' },
|
|
343
262
|
};
|
|
344
|
-
await writeFile(
|
|
345
|
-
join(tempDir, 'package.json'),
|
|
346
|
-
JSON.stringify(packageJson)
|
|
347
|
-
);
|
|
263
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
348
264
|
|
|
349
265
|
await mkdir(join(tempDir, 'dist'), { recursive: true });
|
|
350
266
|
await mkdir(join(tempDir, 'build'), { recursive: true });
|
|
@@ -362,16 +278,10 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
362
278
|
|
|
363
279
|
it('handles unreadable files gracefully', async () => {
|
|
364
280
|
const packageJson = {
|
|
365
|
-
dependencies: {
|
|
281
|
+
dependencies: { pkg: '^1.0.0' },
|
|
366
282
|
};
|
|
367
|
-
await writeFile(
|
|
368
|
-
|
|
369
|
-
JSON.stringify(packageJson)
|
|
370
|
-
);
|
|
371
|
-
await writeFile(
|
|
372
|
-
join(tempDir, 'good.ts'),
|
|
373
|
-
'import { x } from "pkg";'
|
|
374
|
-
);
|
|
283
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
284
|
+
await writeFile(join(tempDir, 'good.ts'), 'import { x } from "pkg";');
|
|
375
285
|
|
|
376
286
|
const result = await analyzer.analyze(tempDir);
|
|
377
287
|
|
|
@@ -385,12 +295,9 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
385
295
|
describe('Usage counting', () => {
|
|
386
296
|
it('counts import occurrences', async () => {
|
|
387
297
|
const packageJson = {
|
|
388
|
-
dependencies: {
|
|
298
|
+
dependencies: { lodash: '^4.0.0' },
|
|
389
299
|
};
|
|
390
|
-
await writeFile(
|
|
391
|
-
join(tempDir, 'package.json'),
|
|
392
|
-
JSON.stringify(packageJson)
|
|
393
|
-
);
|
|
300
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
394
301
|
await writeFile(
|
|
395
302
|
join(tempDir, 'file1.ts'),
|
|
396
303
|
'import { map } from "lodash";\nimport { filter } from "lodash";'
|
|
@@ -407,20 +314,11 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
407
314
|
|
|
408
315
|
it('counts files using a package', async () => {
|
|
409
316
|
const packageJson = {
|
|
410
|
-
dependencies: {
|
|
317
|
+
dependencies: { pkg: '^1.0.0' },
|
|
411
318
|
};
|
|
412
|
-
await writeFile(
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
);
|
|
416
|
-
await writeFile(
|
|
417
|
-
join(tempDir, 'file1.ts'),
|
|
418
|
-
'import { x } from "pkg";'
|
|
419
|
-
);
|
|
420
|
-
await writeFile(
|
|
421
|
-
join(tempDir, 'file2.ts'),
|
|
422
|
-
'import { y } from "pkg";'
|
|
423
|
-
);
|
|
319
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
320
|
+
await writeFile(join(tempDir, 'file1.ts'), 'import { x } from "pkg";');
|
|
321
|
+
await writeFile(join(tempDir, 'file2.ts'), 'import { y } from "pkg";');
|
|
424
322
|
|
|
425
323
|
const result = await analyzer.analyze(tempDir);
|
|
426
324
|
|
|
@@ -433,16 +331,10 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
433
331
|
|
|
434
332
|
it('tracks which files use each package', async () => {
|
|
435
333
|
const packageJson = {
|
|
436
|
-
dependencies: {
|
|
334
|
+
dependencies: { pkg: '^1.0.0' },
|
|
437
335
|
};
|
|
438
|
-
await writeFile(
|
|
439
|
-
|
|
440
|
-
JSON.stringify(packageJson)
|
|
441
|
-
);
|
|
442
|
-
await writeFile(
|
|
443
|
-
join(tempDir, 'app.ts'),
|
|
444
|
-
'import { x } from "pkg";'
|
|
445
|
-
);
|
|
336
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
337
|
+
await writeFile(join(tempDir, 'app.ts'), 'import { x } from "pkg";');
|
|
446
338
|
|
|
447
339
|
const result = await analyzer.analyze(tempDir);
|
|
448
340
|
|
|
@@ -455,14 +347,11 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
455
347
|
it('sorts results by import count', async () => {
|
|
456
348
|
const packageJson = {
|
|
457
349
|
dependencies: {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
}
|
|
350
|
+
pkg1: '^1.0.0',
|
|
351
|
+
pkg2: '^1.0.0',
|
|
352
|
+
},
|
|
461
353
|
};
|
|
462
|
-
await writeFile(
|
|
463
|
-
join(tempDir, 'package.json'),
|
|
464
|
-
JSON.stringify(packageJson)
|
|
465
|
-
);
|
|
354
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
466
355
|
await writeFile(
|
|
467
356
|
join(tempDir, 'file.ts'),
|
|
468
357
|
'import { a } from "pkg1";\nimport { b } from "pkg1";\nimport { c } from "pkg2";'
|
|
@@ -481,19 +370,13 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
481
370
|
describe('Progress reporting', () => {
|
|
482
371
|
it('calls progress callback during analysis', async () => {
|
|
483
372
|
const packageJson = {
|
|
484
|
-
dependencies: {
|
|
373
|
+
dependencies: { pkg: '^1.0.0' },
|
|
485
374
|
};
|
|
486
|
-
await writeFile(
|
|
487
|
-
join(tempDir, 'package.json'),
|
|
488
|
-
JSON.stringify(packageJson)
|
|
489
|
-
);
|
|
375
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
490
376
|
|
|
491
377
|
// Create multiple files to trigger progress (fires every 10 files)
|
|
492
378
|
for (let i = 0; i < 25; i++) {
|
|
493
|
-
await writeFile(
|
|
494
|
-
join(tempDir, `file${i}.ts`),
|
|
495
|
-
'import { x } from "pkg";'
|
|
496
|
-
);
|
|
379
|
+
await writeFile(join(tempDir, `file${i}.ts`), 'import { x } from "pkg";');
|
|
497
380
|
}
|
|
498
381
|
|
|
499
382
|
const progressCalls: Array<{ current: number; total: number; message: string }> = [];
|
|
@@ -512,75 +395,51 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
512
395
|
describe('Import detection methods', () => {
|
|
513
396
|
it('uses ESM imports as primary detection method', async () => {
|
|
514
397
|
const packageJson = {
|
|
515
|
-
dependencies: {
|
|
398
|
+
dependencies: { pkg: '^1.0.0' },
|
|
516
399
|
};
|
|
517
|
-
await writeFile(
|
|
518
|
-
|
|
519
|
-
JSON.stringify(packageJson)
|
|
520
|
-
);
|
|
521
|
-
await writeFile(
|
|
522
|
-
join(tempDir, 'file.js'),
|
|
523
|
-
'import { foo } from "pkg";'
|
|
524
|
-
);
|
|
400
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
401
|
+
await writeFile(join(tempDir, 'file.js'), 'import { foo } from "pkg";');
|
|
525
402
|
|
|
526
403
|
const result = await analyzer.analyze(tempDir);
|
|
527
404
|
|
|
528
405
|
expect(result.success).toBe(true);
|
|
529
406
|
if (result.success) {
|
|
530
|
-
const pkgUsage = result.data.usages.find(u => u.packageName === 'pkg');
|
|
407
|
+
const pkgUsage = result.data.usages.find((u) => u.packageName === 'pkg');
|
|
531
408
|
expect(pkgUsage).toBeDefined();
|
|
532
409
|
expect(pkgUsage?.packageName).toBe('pkg');
|
|
533
410
|
}
|
|
534
411
|
});
|
|
535
412
|
|
|
536
413
|
it('detects Python import statements', async () => {
|
|
537
|
-
await writeFile(
|
|
538
|
-
|
|
539
|
-
'requests==2.28.0'
|
|
540
|
-
);
|
|
541
|
-
await writeFile(
|
|
542
|
-
join(tempDir, 'script.py'),
|
|
543
|
-
'import requests'
|
|
544
|
-
);
|
|
414
|
+
await writeFile(join(tempDir, 'requirements.txt'), 'requests==2.28.0');
|
|
415
|
+
await writeFile(join(tempDir, 'script.py'), 'import requests');
|
|
545
416
|
|
|
546
417
|
const result = await analyzer.analyze(tempDir);
|
|
547
418
|
|
|
548
419
|
expect(result.success).toBe(true);
|
|
549
420
|
if (result.success) {
|
|
550
|
-
expect(result.data.usages.some(u => u.packageName === 'requests')).toBe(true);
|
|
421
|
+
expect(result.data.usages.some((u) => u.packageName === 'requests')).toBe(true);
|
|
551
422
|
}
|
|
552
423
|
});
|
|
553
424
|
|
|
554
425
|
it('detects Python from...import statements', async () => {
|
|
555
|
-
await writeFile(
|
|
556
|
-
|
|
557
|
-
'numpy>=1.20.0'
|
|
558
|
-
);
|
|
559
|
-
await writeFile(
|
|
560
|
-
join(tempDir, 'script.py'),
|
|
561
|
-
'from numpy import array'
|
|
562
|
-
);
|
|
426
|
+
await writeFile(join(tempDir, 'requirements.txt'), 'numpy>=1.20.0');
|
|
427
|
+
await writeFile(join(tempDir, 'script.py'), 'from numpy import array');
|
|
563
428
|
|
|
564
429
|
const result = await analyzer.analyze(tempDir);
|
|
565
430
|
|
|
566
431
|
expect(result.success).toBe(true);
|
|
567
432
|
if (result.success) {
|
|
568
|
-
expect(result.data.usages.some(u => u.packageName === 'numpy')).toBe(true);
|
|
433
|
+
expect(result.data.usages.some((u) => u.packageName === 'numpy')).toBe(true);
|
|
569
434
|
}
|
|
570
435
|
});
|
|
571
436
|
|
|
572
437
|
it('handles malformed code gracefully', async () => {
|
|
573
438
|
const packageJson = {
|
|
574
|
-
dependencies: {
|
|
439
|
+
dependencies: { pkg: '^1.0.0' },
|
|
575
440
|
};
|
|
576
|
-
await writeFile(
|
|
577
|
-
|
|
578
|
-
JSON.stringify(packageJson)
|
|
579
|
-
);
|
|
580
|
-
await writeFile(
|
|
581
|
-
join(tempDir, 'broken.ts'),
|
|
582
|
-
'import { incomplete from "pkg"'
|
|
583
|
-
);
|
|
441
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
442
|
+
await writeFile(join(tempDir, 'broken.ts'), 'import { incomplete from "pkg"');
|
|
584
443
|
|
|
585
444
|
const result = await analyzer.analyze(tempDir);
|
|
586
445
|
|
|
@@ -594,10 +453,7 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
594
453
|
describe('Analysis metadata', () => {
|
|
595
454
|
it('includes analysis time', async () => {
|
|
596
455
|
const packageJson = { dependencies: {} };
|
|
597
|
-
await writeFile(
|
|
598
|
-
join(tempDir, 'package.json'),
|
|
599
|
-
JSON.stringify(packageJson)
|
|
600
|
-
);
|
|
456
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
601
457
|
|
|
602
458
|
const result = await analyzer.analyze(tempDir);
|
|
603
459
|
|
|
@@ -609,16 +465,10 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
609
465
|
|
|
610
466
|
it('counts skipped files', async () => {
|
|
611
467
|
const packageJson = {
|
|
612
|
-
dependencies: {
|
|
468
|
+
dependencies: { pkg: '^1.0.0' },
|
|
613
469
|
};
|
|
614
|
-
await writeFile(
|
|
615
|
-
|
|
616
|
-
JSON.stringify(packageJson)
|
|
617
|
-
);
|
|
618
|
-
await writeFile(
|
|
619
|
-
join(tempDir, 'good.ts'),
|
|
620
|
-
'import { x } from "pkg";'
|
|
621
|
-
);
|
|
470
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
471
|
+
await writeFile(join(tempDir, 'good.ts'), 'import { x } from "pkg";');
|
|
622
472
|
|
|
623
473
|
const result = await analyzer.analyze(tempDir);
|
|
624
474
|
|
|
@@ -632,16 +482,10 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
632
482
|
describe('Language detection', () => {
|
|
633
483
|
it('sets language to javascript for package.json dependencies', async () => {
|
|
634
484
|
const packageJson = {
|
|
635
|
-
dependencies: {
|
|
485
|
+
dependencies: { lodash: '^4.0.0' },
|
|
636
486
|
};
|
|
637
|
-
await writeFile(
|
|
638
|
-
|
|
639
|
-
JSON.stringify(packageJson)
|
|
640
|
-
);
|
|
641
|
-
await writeFile(
|
|
642
|
-
join(tempDir, 'index.ts'),
|
|
643
|
-
'import { map } from "lodash";'
|
|
644
|
-
);
|
|
487
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
488
|
+
await writeFile(join(tempDir, 'index.ts'), 'import { map } from "lodash";');
|
|
645
489
|
|
|
646
490
|
const result = await analyzer.analyze(tempDir);
|
|
647
491
|
|
|
@@ -652,14 +496,8 @@ describe('DependencyUsageAnalyzer', () => {
|
|
|
652
496
|
});
|
|
653
497
|
|
|
654
498
|
it('sets language to python for requirements.txt dependencies', async () => {
|
|
655
|
-
await writeFile(
|
|
656
|
-
|
|
657
|
-
'requests==2.28.0'
|
|
658
|
-
);
|
|
659
|
-
await writeFile(
|
|
660
|
-
join(tempDir, 'script.py'),
|
|
661
|
-
'import requests'
|
|
662
|
-
);
|
|
499
|
+
await writeFile(join(tempDir, 'requirements.txt'), 'requests==2.28.0');
|
|
500
|
+
await writeFile(join(tempDir, 'script.py'), 'import requests');
|
|
663
501
|
|
|
664
502
|
const result = await analyzer.analyze(tempDir);
|
|
665
503
|
|
|
@@ -704,10 +542,7 @@ serde = "1.0"
|
|
|
704
542
|
tokio = { version = "1.0" }
|
|
705
543
|
`
|
|
706
544
|
);
|
|
707
|
-
await writeFile(
|
|
708
|
-
join(tempDir, 'main.rs'),
|
|
709
|
-
'use serde::Serialize;'
|
|
710
|
-
);
|
|
545
|
+
await writeFile(join(tempDir, 'main.rs'), 'use serde::Serialize;');
|
|
711
546
|
|
|
712
547
|
const result = await analyzer.analyze(tempDir);
|
|
713
548
|
|
|
@@ -729,10 +564,7 @@ require (
|
|
|
729
564
|
)
|
|
730
565
|
`
|
|
731
566
|
);
|
|
732
|
-
await writeFile(
|
|
733
|
-
join(tempDir, 'main.go'),
|
|
734
|
-
'import "github.com/gorilla/mux"'
|
|
735
|
-
);
|
|
567
|
+
await writeFile(join(tempDir, 'main.go'), 'import "github.com/gorilla/mux"');
|
|
736
568
|
|
|
737
569
|
const result = await analyzer.analyze(tempDir);
|
|
738
570
|
|
|
@@ -763,33 +595,21 @@ require (
|
|
|
763
595
|
it('handles mixed language projects', async () => {
|
|
764
596
|
// JavaScript
|
|
765
597
|
const packageJson = {
|
|
766
|
-
dependencies: {
|
|
598
|
+
dependencies: { express: '^4.0.0' },
|
|
767
599
|
};
|
|
768
|
-
await writeFile(
|
|
769
|
-
|
|
770
|
-
JSON.stringify(packageJson)
|
|
771
|
-
);
|
|
772
|
-
await writeFile(
|
|
773
|
-
join(tempDir, 'server.js'),
|
|
774
|
-
'import express from "express";'
|
|
775
|
-
);
|
|
600
|
+
await writeFile(join(tempDir, 'package.json'), JSON.stringify(packageJson));
|
|
601
|
+
await writeFile(join(tempDir, 'server.js'), 'import express from "express";');
|
|
776
602
|
|
|
777
603
|
// Python
|
|
778
|
-
await writeFile(
|
|
779
|
-
|
|
780
|
-
'flask==2.0.0'
|
|
781
|
-
);
|
|
782
|
-
await writeFile(
|
|
783
|
-
join(tempDir, 'app.py'),
|
|
784
|
-
'import flask'
|
|
785
|
-
);
|
|
604
|
+
await writeFile(join(tempDir, 'requirements.txt'), 'flask==2.0.0');
|
|
605
|
+
await writeFile(join(tempDir, 'app.py'), 'import flask');
|
|
786
606
|
|
|
787
607
|
const result = await analyzer.analyze(tempDir);
|
|
788
608
|
|
|
789
609
|
expect(result.success).toBe(true);
|
|
790
610
|
if (result.success) {
|
|
791
|
-
const jsUsage = result.data.usages.find(u => u.packageName === 'express');
|
|
792
|
-
const pyUsage = result.data.usages.find(u => u.packageName === 'flask');
|
|
611
|
+
const jsUsage = result.data.usages.find((u) => u.packageName === 'express');
|
|
612
|
+
const pyUsage = result.data.usages.find((u) => u.packageName === 'flask');
|
|
793
613
|
|
|
794
614
|
expect(jsUsage?.language).toBe('javascript');
|
|
795
615
|
expect(pyUsage?.language).toBe('python');
|