fix(javascript): analyze sources containing empty string literals

A single legal empty literal such as `fetch('')`, `require('')`,
`bus.on('', f)`, `localStorage.getItem('')`, or `ipcMain.handle('', f)`
made the whole application analysis fail with `unreadable_output`: the
literal became an application-graph observation label, an artifact-local
identity key, or a semantic node label, all of which must be nonempty.

Normalize display at the two graph construction seams instead of at each
producer: `JavaScriptArtifactGraphAccumulator.addNode` and
`constructSemanticGraphNode` show the empty value as `""` via a shared
`javascriptDisplayText` helper. Observation and node properties keep the
exact empty value. This replaces the per-site `semanticNameLabel` calls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Iwakurakaoru0822
2026-10-06 20:43:08 -07:00
parent ad1f6b508f
commit 11fc3b9815
7 changed files with 119 additions and 21 deletions
@@ -1,5 +1,6 @@
import type { JavaScriptApplicationGraph } from "../domain/javascriptApplicationGraph.js";
import type { JsonValue } from "../domain/jsonValue.js";
import { javascriptDisplayText } from "../domain/javascriptAstValues.js";
import {
createJavaScriptSemanticGraphNode,
createJavaScriptSemanticGraphRelation,
@@ -18,14 +19,6 @@ import {
unavailableSemanticRootEvidence,
} from "./JavaScriptSemanticGraphEvidence.js";
/**
* Display an exact JavaScript key or name as a nonempty graph label. The legal
* empty key is shown as `""`; callers keep the exact value where the node
* carries it.
*/
export const semanticNameLabel = (name: string): string =>
name === "" ? '""' : name;
/** Mutable local projection state hidden from graph callers. */
export interface SemanticGraphProjectionState {
readonly nodes: Map<string, JavaScriptSemanticGraphNode>;
@@ -85,7 +78,7 @@ export const constructSemanticGraphNode = (
},
function_node_id: input.functionNodeId,
application_node_ids: matchingApplicationNodeIds(file, input, state),
label: input.label,
label: input.label === null ? null : javascriptDisplayText(input.label),
properties: input.properties ?? {},
evidence: observedSemanticEvidence(file, input.location),
});