fix(javascript): keep exact empty values in graph identities

#839 displayed empty artifact-local keys and source-map original names as
`""` inside node identities, so `fetch("")` and `fetch('""')` (or
`sources: ["", "\"\""]`) produced the same node ID and merged two
distinct facts. Function nodes likewise exposed only a display label, so
`['']()` and `['""']()` were indistinguishable.

Admit the exact empty string in `artifact-local-key.key` and
`source-map-original.original_source`, keep the `""` substitution for
labels only, and record each function node's exact `name` in its
properties. Regenerate the catalog digests for the relaxed output schema.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Iwakurakaoru0822
2026-10-06 21:00:57 -07:00
parent e7cbfe04fd
commit 63012eeb60
9 changed files with 58 additions and 41 deletions
@@ -68,25 +68,19 @@ const observationInput = (
/** Node fields whose display form is normalized before validation. */
interface DisplayableNodeInput {
readonly identity: {
readonly strategy: string;
readonly key?: string;
readonly original_source?: string;
};
readonly observations: readonly { readonly label: string | null }[];
}
/**
* Static findings can carry legal empty strings, such as `fetch("")`,
* `require("")`, or a source map's `sources: [""]`. Labels, artifact-local
* keys, and original source names must be nonempty, so display the empty value
* as `""`; each observation keeps the exact value in its properties.
* `require("")`, or a source map's `sources: [""]`. Labels are nonempty display
* text, so the empty value is shown as `""`. Identities and observation
* properties keep the exact value, so distinct values never merge.
*/
const displayableNode = (
input: DisplayableNodeInput,
): DisplayableNodeInput => ({
...input,
identity: displayableIdentity(input.identity),
observations: input.observations.map((observation) => ({
...observation,
label:
@@ -95,19 +89,3 @@ const displayableNode = (
: javascriptDisplayText(observation.label),
})),
});
const displayableIdentity = (
identity: DisplayableNodeInput["identity"],
): DisplayableNodeInput["identity"] => {
if (identity.strategy === "artifact-local-key" && identity.key !== undefined)
return { ...identity, key: javascriptDisplayText(identity.key) };
if (
identity.strategy === "source-map-original" &&
identity.original_source !== undefined
)
return {
...identity,
original_source: javascriptDisplayText(identity.original_source),
};
return identity;
};