mirror of
https://github.com/morluto/rea.git
synced 2026-11-12 18:48:18 -10:00
159 lines
5.3 KiB
TypeScript
159 lines
5.3 KiB
TypeScript
import { expect, it } from "vitest";
|
|
import {
|
|
analyzeAndAdoptJavaScriptArtifactFiles,
|
|
javaScriptAnalysisOrder,
|
|
} from "./JavaScriptArtifactAnalysis.js";
|
|
import { createJavaScriptSemanticGraphProjection } from "./JavaScriptSemanticGraphBuilder.js";
|
|
import { AnalysisResourceConstraintError } from "../../domain/analysisErrorCore.js";
|
|
import { analyzeJavaScriptStaticSource } from "../../../tests/fixtures/javascriptStaticAnalysis.js";
|
|
import type { JavaScriptArtifactFile } from "../../domain/javascript/javascriptArtifactFiles.js";
|
|
import { err, ok } from "../../domain/result.js";
|
|
|
|
const source = (path: string): JavaScriptArtifactFile => ({
|
|
path,
|
|
container_sha256: "a".repeat(64),
|
|
sha256: "b".repeat(64),
|
|
bytes: 20,
|
|
inventory_artifact_id: path,
|
|
kind: "javascript",
|
|
unpacked: false,
|
|
text: { included: true, value: "export const x = 1;" },
|
|
});
|
|
|
|
const manifest = (path: string): JavaScriptArtifactFile => ({
|
|
...source(path),
|
|
kind: "package-json",
|
|
text: { included: true, value: "{}" },
|
|
});
|
|
|
|
// Lexical inventory order puts `node_modules/` before an electron-vite `out-*`
|
|
// directory, which is the shape that exhausted the result budget in #9321.
|
|
const inventory = [
|
|
source("node_modules/a/index.js"),
|
|
manifest("node_modules/a/package.json"),
|
|
source("node_modules/b/lib/yaml.js"),
|
|
source("out-global-online/main/index.js"),
|
|
source("out-global-online/preload/index.js"),
|
|
manifest("package.json"),
|
|
];
|
|
|
|
it("offers application JavaScript before dependency JavaScript", () => {
|
|
expect(javaScriptAnalysisOrder(inventory).map(({ path }) => path)).toEqual([
|
|
"node_modules/a/package.json",
|
|
"out-global-online/main/index.js",
|
|
"out-global-online/preload/index.js",
|
|
"package.json",
|
|
"node_modules/a/index.js",
|
|
"node_modules/b/lib/yaml.js",
|
|
]);
|
|
// A package merely named like a dependency directory is not one.
|
|
expect(
|
|
javaScriptAnalysisOrder([
|
|
source("node_modules.js"),
|
|
source("src/node_modules_shim.js"),
|
|
]).map(({ path }) => path),
|
|
).toEqual(["node_modules.js", "src/node_modules_shim.js"]);
|
|
});
|
|
|
|
it("spends a limited result budget on first-party sources and keeps inventory order", async () => {
|
|
const javascript = analyzeJavaScriptStaticSource("export const x = 1;");
|
|
const analyzed: string[] = [];
|
|
// Admit two sources, then report the budget as spent, as the parent does
|
|
// once its remaining result capacity is reserved for static observations.
|
|
const worker = {
|
|
analyze: async (file: JavaScriptArtifactFile) => {
|
|
analyzed.push(file.path);
|
|
const value = { javascript, module: null, projection: null };
|
|
if (analyzed.length <= 2) return ok(value);
|
|
return err({
|
|
...value,
|
|
error: new AnalysisResourceConstraintError(
|
|
"analyze_javascript_application",
|
|
"memory",
|
|
`semantic analysis of ${file.path} was not started`,
|
|
{ semantic_result_budget_bytes: 0 },
|
|
),
|
|
});
|
|
},
|
|
};
|
|
const outcome = await analyzeAndAdoptJavaScriptArtifactFiles(
|
|
{
|
|
files: inventory,
|
|
unavailable_relevant_files: [],
|
|
containers: [],
|
|
text_bytes_read: 120,
|
|
invalid_utf8_files: 0,
|
|
},
|
|
worker,
|
|
createJavaScriptSemanticGraphProjection(),
|
|
async () => {},
|
|
);
|
|
expect(analyzed).toEqual([
|
|
"out-global-online/main/index.js",
|
|
"out-global-online/preload/index.js",
|
|
"node_modules/a/index.js",
|
|
"node_modules/b/lib/yaml.js",
|
|
]);
|
|
expect(outcome.analysis.files.map(({ file }) => file.path)).toEqual(
|
|
inventory.map(({ path }) => path),
|
|
);
|
|
const failed = outcome.analysis.files
|
|
.filter(({ analysis_failure }) => analysis_failure !== undefined)
|
|
.map(({ file }) => file.path);
|
|
expect(failed).toEqual([
|
|
"node_modules/a/index.js",
|
|
"node_modules/b/lib/yaml.js",
|
|
]);
|
|
expect(outcome.interruption).toBeNull();
|
|
});
|
|
|
|
it("spends capacity in the caller's requested order for explicitly selected sources", async () => {
|
|
const files = [
|
|
source("node_modules/selected/index.js"),
|
|
source("src/main.js"),
|
|
];
|
|
const admitted: string[] = [];
|
|
const javascript = analyzeJavaScriptStaticSource("export const x = 1;");
|
|
const outcome = await analyzeAndAdoptJavaScriptArtifactFiles(
|
|
{
|
|
files,
|
|
unavailable_relevant_files: [],
|
|
containers: [],
|
|
text_bytes_read: 40,
|
|
invalid_utf8_files: 0,
|
|
source_selection: {
|
|
requested_paths: files.map((file) => file.path),
|
|
unselected_files: 0,
|
|
},
|
|
},
|
|
{
|
|
analyze: async (file) => {
|
|
const value = { javascript, module: null, projection: null };
|
|
admitted.push(file.path);
|
|
return admitted.length === 1
|
|
? ok(value)
|
|
: err({
|
|
...value,
|
|
error: new AnalysisResourceConstraintError(
|
|
"analyze_javascript_application",
|
|
"memory",
|
|
"result capacity exhausted",
|
|
{ semantic_result_budget_bytes: 0 },
|
|
),
|
|
});
|
|
},
|
|
},
|
|
createJavaScriptSemanticGraphProjection(),
|
|
async () => {},
|
|
);
|
|
expect(admitted).toEqual(files.map((file) => file.path));
|
|
expect(
|
|
outcome.analysis.files.find(({ file }) => file.path === files[0]!.path)
|
|
?.analysis_failure,
|
|
).toBeUndefined();
|
|
expect(
|
|
outcome.analysis.files.find(({ file }) => file.path === files[1]!.path)
|
|
?.analysis_failure,
|
|
).toBeDefined();
|
|
});
|