mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
perf(javascript): index structured observations by path
Build package, JSON-module and source-map indexes once instead of rescanning every observation list per file. Preserve first-observation lookup semantics when paths repeat and share each JSON lookup with the file projection. Validation: duplicate-observation consumer regression and reconstruction suites. Flameox captured before/after CPU profiles on 3,000 JSON files; the complete CLI output stayed byte-identical. Exploratory samples do not establish an end-to-end timing improvement.
This commit is contained in:
@@ -115,9 +115,18 @@ export const addJavaScriptArtifactContainers = (
|
||||
export const addJavaScriptArtifactFiles = (
|
||||
context: JavaScriptArtifactGraphContext,
|
||||
): void => {
|
||||
const packagesByPath = indexFirstByPath(context.analysis.packages);
|
||||
const jsonModulesByPath = indexFirstByPath(context.analysis.json_modules);
|
||||
const sourceMapsByPath = indexFirstByPath(context.analysis.source_maps);
|
||||
for (const analyzed of context.analysis.files) {
|
||||
const { file } = analyzed;
|
||||
const target = createFileTarget(context, file, analyzed.javascript);
|
||||
const jsonValue = jsonModulesByPath.get(file.path);
|
||||
const target = createFileTarget(
|
||||
context,
|
||||
file,
|
||||
analyzed.javascript,
|
||||
jsonValue,
|
||||
);
|
||||
context.fileNodes.set(file.path, target);
|
||||
if (file.kind === "javascript") context.assetNodes.set(file.path, target);
|
||||
const entry = createAsarEntry(context, file);
|
||||
@@ -163,9 +172,7 @@ export const addJavaScriptArtifactFiles = (
|
||||
? "JavaScript syntax could not be parsed."
|
||||
: `JavaScript text was unavailable: ${file.text.reason}.`,
|
||||
});
|
||||
const packageValue = context.analysis.packages.find(
|
||||
({ path }) => path === file.path,
|
||||
);
|
||||
const packageValue = packagesByPath.get(file.path);
|
||||
if (packageValue !== undefined && packageValue.status !== "included")
|
||||
addUnavailableStaticParseScope(context, {
|
||||
file,
|
||||
@@ -173,9 +180,6 @@ export const addJavaScriptArtifactFiles = (
|
||||
operation: "parse-package-json",
|
||||
limitation: packageValue.limitation,
|
||||
});
|
||||
const jsonValue = context.analysis.json_modules.find(
|
||||
({ path }) => path === file.path,
|
||||
);
|
||||
if (jsonValue !== undefined && jsonValue.status !== "included")
|
||||
addUnavailableStaticParseScope(context, {
|
||||
file,
|
||||
@@ -183,9 +187,7 @@ export const addJavaScriptArtifactFiles = (
|
||||
operation: "parse-json-module",
|
||||
limitation: jsonValue.limitation,
|
||||
});
|
||||
const sourceMap = context.analysis.source_maps.find(
|
||||
({ path }) => path === file.path,
|
||||
);
|
||||
const sourceMap = sourceMapsByPath.get(file.path);
|
||||
if (sourceMap !== undefined && sourceMap.status === "invalid")
|
||||
addUnavailableStaticParseScope(context, {
|
||||
file,
|
||||
@@ -270,11 +272,9 @@ const createFileTarget = (
|
||||
context: JavaScriptArtifactGraphContext,
|
||||
file: JavaScriptArtifactFile,
|
||||
javascript: JavaScriptModuleArtifactAnalysis["files"][number]["javascript"],
|
||||
json: JavaScriptModuleArtifactAnalysis["json_modules"][number] | undefined,
|
||||
): ApplicationNode => {
|
||||
const kind = artifactFileNodeKind(file.kind);
|
||||
const json = context.analysis.json_modules.find(
|
||||
({ path }) => path === file.path,
|
||||
);
|
||||
return context.accumulator.addNode({
|
||||
kind,
|
||||
identity: {
|
||||
@@ -309,6 +309,16 @@ const createFileTarget = (
|
||||
});
|
||||
};
|
||||
|
||||
const indexFirstByPath = <Value extends { readonly path: string }>(
|
||||
values: readonly Value[],
|
||||
): ReadonlyMap<string, Value> => {
|
||||
const index = new Map<string, Value>();
|
||||
for (const value of values) {
|
||||
if (!index.has(value.path)) index.set(value.path, value);
|
||||
}
|
||||
return index;
|
||||
};
|
||||
|
||||
const createAsarEntry = (
|
||||
context: JavaScriptArtifactGraphContext,
|
||||
file: JavaScriptArtifactFile,
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { expect, it } from "vitest";
|
||||
|
||||
import { scanCanonicalArtifactInventory } from "../../fixtures/artifactInventory.js";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
import { readJavaScriptArtifactFiles } from "../../support/javascriptApplicationScope.js";
|
||||
import { analyzeJavaScriptArtifactFiles } from "../../../src/application/javascript/JavaScriptArtifactAnalysis.js";
|
||||
import { buildJavaScriptArtifactGraph } from "../../../src/application/javascript/JavaScriptArtifactGraphBuilder.js";
|
||||
import { createJavaScriptArtifactReader } from "../../../src/artifacts/javascript/JavaScriptArtifactReader.js";
|
||||
import type {
|
||||
JavaScriptJsonModuleObservation,
|
||||
JavaScriptPackageObservation,
|
||||
JavaScriptSourceMapObservation,
|
||||
} from "../../../src/application/javascript/JavaScriptArtifactAnalysisTypes.js";
|
||||
|
||||
it("uses the first structured observation when paths repeat", async () => {
|
||||
const root = await createTestTempDirectory("rea-artifact-graph-index-");
|
||||
await Promise.all([
|
||||
writeFile(join(root, "package.json"), JSON.stringify({ name: "fixture" })),
|
||||
writeFile(join(root, "data.json"), JSON.stringify({ actual: true })),
|
||||
writeFile(join(root, "app.js"), "//# sourceMappingURL=app.js.map"),
|
||||
writeFile(
|
||||
join(root, "app.js.map"),
|
||||
JSON.stringify({
|
||||
version: 3,
|
||||
sources: ["app.ts"],
|
||||
names: [],
|
||||
mappings: "",
|
||||
}),
|
||||
),
|
||||
]);
|
||||
const snapshot = await scanCanonicalArtifactInventory(root, {});
|
||||
const reader = createJavaScriptArtifactReader(root, "directory");
|
||||
try {
|
||||
const files = await readJavaScriptArtifactFiles(reader, snapshot);
|
||||
const analysis = analyzeJavaScriptArtifactFiles(files);
|
||||
const packageObservation = analysis.packages.find(
|
||||
({ path }) => path === "package.json",
|
||||
);
|
||||
const jsonObservation = analysis.json_modules.find(
|
||||
({ path }) => path === "data.json",
|
||||
);
|
||||
const sourceMapObservation = analysis.source_maps.find(
|
||||
({ path }) => path === "app.js.map",
|
||||
);
|
||||
expect(packageObservation).toBeDefined();
|
||||
expect(jsonObservation).toBeDefined();
|
||||
expect(sourceMapObservation).toBeDefined();
|
||||
if (
|
||||
packageObservation === undefined ||
|
||||
jsonObservation === undefined ||
|
||||
sourceMapObservation === undefined
|
||||
)
|
||||
throw new TypeError("Expected structured artifact observations");
|
||||
|
||||
const graph = buildJavaScriptArtifactGraph(snapshot, files, {
|
||||
...analysis,
|
||||
packages: [
|
||||
packageObservation,
|
||||
{
|
||||
...packageObservation,
|
||||
status: "invalid",
|
||||
name: null,
|
||||
version: null,
|
||||
main: null,
|
||||
renderer: null,
|
||||
limitation: "later duplicate",
|
||||
} satisfies JavaScriptPackageObservation,
|
||||
],
|
||||
json_modules: [
|
||||
jsonObservation,
|
||||
{
|
||||
...jsonObservation,
|
||||
status: "invalid",
|
||||
top_level_keys: [],
|
||||
omitted_top_level_keys: 0,
|
||||
limitation: "later duplicate",
|
||||
} satisfies JavaScriptJsonModuleObservation,
|
||||
],
|
||||
source_maps: [
|
||||
sourceMapObservation,
|
||||
{
|
||||
...sourceMapObservation,
|
||||
status: "invalid",
|
||||
sources: [],
|
||||
limitation: "later duplicate",
|
||||
} satisfies JavaScriptSourceMapObservation,
|
||||
],
|
||||
});
|
||||
|
||||
const dataFile = graph.nodes.find(({ observations }) =>
|
||||
observations.some(({ properties }) => properties.path === "data.json"),
|
||||
);
|
||||
expect(dataFile?.observations[0]?.properties).toMatchObject({
|
||||
json_parse_status: "included",
|
||||
json_top_level_keys: ["actual"],
|
||||
omitted_json_top_level_keys: 0,
|
||||
});
|
||||
const unavailablePaths = graph.nodes
|
||||
.filter(({ kind }) => kind === "unknown")
|
||||
.flatMap(({ observations }) =>
|
||||
observations.map(({ properties }) => ({
|
||||
path: properties.path,
|
||||
operation: properties.operation,
|
||||
})),
|
||||
);
|
||||
expect(unavailablePaths).not.toContainEqual({
|
||||
path: "package.json",
|
||||
operation: "parse-package-json",
|
||||
});
|
||||
expect(unavailablePaths).not.toContainEqual({
|
||||
path: "data.json",
|
||||
operation: "parse-json-module",
|
||||
});
|
||||
expect(unavailablePaths).not.toContainEqual({
|
||||
path: "app.js.map",
|
||||
operation: "parse-local-source-map",
|
||||
});
|
||||
} finally {
|
||||
await reader.close();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user