From bfb133f544287e9f94b48fdba92c1b95be9dd127 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 16 Sep 2026 12:00:42 -0400 Subject: [PATCH 1/2] Summarize a dictionary or a MAT-file from a scan the caller already has MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `summarizeSlddScan` and `summarizeMatScan`, the exact analogue of `summarizeParsedModel` for the other two file kinds: a `FileSummaries` holding the one file, built from a `scanSldd`/`scanMat` result instead of from bytes. A caller that has already scanned a data file could not get its summary without scanning it again. data-explorer-vscode's cheap tier is that caller — it wants both the raw `refs` a scan carries and the summary out of one read — and the second scan measured 46% of that tier's per-dictionary CPU: 14.6 ms of 31.5 ms on a 20,000-entry dictionary, spent deriving a `names` list it was already holding. `summarizeFiles`'s sldd and mat branches now route through the new functions, as its model branch already routes through `summarizeParsedModel`. It still scans the bytes itself — it takes bytes, not scans — and only stops open-coding the summary, so the two ways to reach one summary share an implementation rather than agreeing. Which weakens the obvious test, and the new sweep says so: an equality between the two paths over every committed `.sldd` and `.mat` cannot fail on the shared code, so every swept file is ALSO compared against a summary derived from the full readers `readSlddContent` and `parseMat`. Verified by mutation — without that second assertion, dropping `filter(Boolean)` from the summary left the whole sweep green. The constructed cases cover what no fixture has: references in both spellings and mixed case, unnamed entries around a named one, the basename key rule, a dictionary whose fast path refuses and whose full read recovers, a truncated MAT, and the two files no reader can read at all. --- dist/datamodel/usage/UsageIndex.d.ts | 46 +++ dist/datamodel/usage/UsageIndex.d.ts.map | 2 +- dist/datamodel/usage/UsageIndex.js | 145 ++++--- dist/datamodel/usage/UsageIndex.js.map | 2 +- dist/index.d.ts | 2 +- dist/index.d.ts.map | 2 +- dist/index.js | 8 +- dist/index.js.map | 2 +- src/datamodel/usage/UsageIndex.ts | 151 +++++--- src/index.ts | 8 + test/usageScanSummary.test.ts | 469 +++++++++++++++++++++++ 11 files changed, 741 insertions(+), 96 deletions(-) create mode 100644 test/usageScanSummary.test.ts diff --git a/dist/datamodel/usage/UsageIndex.d.ts b/dist/datamodel/usage/UsageIndex.d.ts index 5b29db9..08b9a36 100644 --- a/dist/datamodel/usage/UsageIndex.d.ts +++ b/dist/datamodel/usage/UsageIndex.d.ts @@ -1,4 +1,6 @@ import type { MaskScope } from '../maskScope.js'; +import type { SlddScanResult } from '../parser/SlddScan.js'; +import type { MatScanResult } from '../parser/MatScan.js'; import type { ParsedSlx } from '../parser/SlxParser.js'; import type { NodeUsage } from '../../core/DataModel.js'; /** @@ -155,6 +157,50 @@ export declare function summarizeFiles(files: UsageFile[]): FileSummaries; * swallowing a throw would hand back an empty answer for a model that HAD been parsed. */ export declare function summarizeParsedModel(parsed: ParsedSlx, srcId: string, filename: string): FileSummaries; +/** + * The dictionary branch of `summarizeFiles`, over a scan the caller has ALREADY run. + * + * Same trade as `summarizeParsedModel`, on the file kind a workspace holds most of. A host + * that scans a dictionary for its own purposes — data-explorer-vscode's cheap tier wants + * both the raw `refs` the scan carries and this summary out of one read — got the summary + * only by handing the bytes to `summarizeFiles`, which scanned them a second time. That + * second scan measured 46% of the tier's per-dictionary CPU: 14.6 ms of 31.5 ms on a + * 20,000-entry dictionary, spent deriving a `names` list the caller was already holding. + * + * The answer is a whole `FileSummaries` carrying just this dictionary, keyed by + * `refBasename(filename)` exactly as `summarizeFiles` keys it, so it is what + * `summarizeFiles([{ srcId, filename, bytes }])` returns for a `.sldd` and + * `mergeFileSummaries` folds it in beside the models and MAT-files. usageScanSummary.test.ts + * pins that equality over every committed dictionary — and, because `summarizeFiles` routes + * through here and so cannot disagree by construction, pins the summary itself against the + * FULL reader as well. Two ways to reach one summary is the shape a drift takes; two ways + * that share an implementation only move the risk into the implementation. + * + * `filename` is still required and is still not `srcId`: the map KEY comes off the + * basename, case-folded, because the lookups against it are references authored inside a + * model (see fileKinds.refBasename), and a srcId may be a path or a URI. + * + * WHAT THE CALLER MUST NOT DO: hand in a scan of bytes other than the ones `srcId` names. + * Nothing here can detect it — a scan is two string arrays — and the result is an index + * that credits one file's entries to another, which reads as a confidently wrong Usage + * cell rather than as an error. + * + * No per-file `try`, unlike `summarizeFiles`: there is no file here to be unreadable. A + * caller holding a scan has already been told the bytes were readable, and swallowing a + * throw would hand back an empty answer for a dictionary that HAD been read. + */ +export declare function summarizeSlddScan(scan: SlddScanResult, srcId: string, filename: string): FileSummaries; +/** + * The MAT half of `summarizeSlddScan`, for a caller that already ran `scanMat` — the same + * saved read, on the file kind a model resolves last. + * + * `slddRefs` is empty and not a field this could fill: a MAT-file inherits nothing, which + * is what `DataSummary.slddRefs` says of it. + * + * The same caution applies — a scan of bytes `srcId` does not name cannot be detected here + * — and so does the reason there is no `try`: see `summarizeSlddScan`. + */ +export declare function summarizeMatScan(scan: MatScanResult, srcId: string, filename: string): FileSummaries; /** * Where the name `name` resolves for a block of `model` sitting at `systemPath`, or null * if it does not. diff --git a/dist/datamodel/usage/UsageIndex.d.ts.map b/dist/datamodel/usage/UsageIndex.d.ts.map index f777eb7..c5c454c 100644 --- a/dist/datamodel/usage/UsageIndex.d.ts.map +++ b/dist/datamodel/usage/UsageIndex.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"UsageIndex.d.ts","sourceRoot":"","sources":["../../../src/datamodel/usage/UsageIndex.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"UsageIndex.d.ts","sourceRoot":"","sources":["../../../src/datamodel/usage/UsageIndex.ts"],"names":[],"mappings":"AA2CA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,GAAG,KAAK,CAAC;AAE/D;;;;;;;;;GASG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,4FAA4F;AAC5F,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,uFAAuF;IACvF,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,+CAA+C;IAC/C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;;OAIG;IACH,KAAK,EAAE,SAAS,EAAE,CAAC;IAInB,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;KACpB,EAAE,CAAC;CACL;AAED,mGAAmG;AACnG,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,EAAE,CAAC;IAGvB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACrC;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAAC;IACnD;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAAC;IAC9D,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;CAC1C;AA4CD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,aAAa,CAyChE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAEtG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAkBtG;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAiBpG;AAID;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,EACpC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,EACnC,UAAU,GAAE,MAAW,GACtB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,IAAI,CAqCnE;AAQD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,aAAa,CAcjF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,UAAU,CAE9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,aAAa,GAAG,UAAU,CA8FjF"} \ No newline at end of file diff --git a/dist/datamodel/usage/UsageIndex.js b/dist/datamodel/usage/UsageIndex.js index 4ea7503..83a9068 100644 --- a/dist/datamodel/usage/UsageIndex.js +++ b/dist/datamodel/usage/UsageIndex.js @@ -85,48 +85,6 @@ function modelSummary(parsed, srcId, filename) { })), }; } -/** - * A usage summary reads ONE string per entry, so it goes through `scanSldd` rather than - * `readSlddContent`: 3288 ms to 116 ms on the larger customer dictionary, and 63 MB of - * retained heap to 2 MB, because the entry tree it used to build was discarded a line - * later. `scanSldd` falls back to the full parse on any dictionary it cannot prove itself - * equivalent on, so this is a substitution and not a second reader. - * - * Nothing is lost by not passing a `warnings` array: this never passed one either. A - * usage index is built over a whole folder and drops unreadable files silently by design - * (see `summarizeFiles`), so there was no channel for a per-part warning to reach. - */ -function slddSummary(srcId, bytes) { - const { names, refs } = scanSldd(bytes); - return { - srcId, - // `filter(Boolean)` because `scanSldd` reports `''` for an entry with no readable - // name, to keep positions aligned for callers that index by position. A Set keyed on - // names has no use for that placeholder, and the previous code dropped it too. - names: new Set(names.filter(Boolean)), - slddRefs: refs.map(refBasename), - }; -} -/** - * The MAT half of the same substitution `slddSummary` makes, for the same reason: this - * reads one string per variable and `parseMat` was decoding every element of every matrix - * to supply them — 1271 ms over the corpus's `.mat` files against 4.4 ms here. - * - * `scanMat` falls back to the full parse on any file it cannot prove itself equivalent - * on, so this is a substitution and not a second reader. It discards `parseMat`'s - * warnings, which this never collected either: a usage index is built over a folder and - * drops unreadable files silently by design (see `summarizeFiles`). - */ -function matSummary(srcId, bytes) { - return { - srcId, - // `filter(Boolean)` because `scanMat` reports '' for a variable with no name, to keep - // positions aligned for callers that index by position. A Set keyed on names has no - // use for that placeholder, and the previous code dropped it too. - names: new Set(scanMat(bytes).names.filter(Boolean)), - slddRefs: [], - }; -} /** * Parse each file into the summary its kind calls for, dispatching on the FILENAME through * the shared kind tests. @@ -149,10 +107,30 @@ export function summarizeFiles(files) { models.push(...summarizeParsedModel(parseModel(file.bytes, file.filename), file.srcId, file.filename).models); } else if (isMatFile(file.filename)) { - matByName.set(refBasename(file.filename), matSummary(file.srcId, file.bytes)); + // `scanMat` and not `parseMat`, for the same reason the dictionary branch below + // scans: a summary reads one string per variable and the full parse was decoding + // every element of every matrix to supply it — 1271 ms over the corpus's `.mat` + // files against 4.4 ms. It falls back to `parseMat` on any file it cannot prove + // itself equivalent on, so this is a substitution and not a second reader, and it + // discards the warnings `parseMat` would collect, which this never collected + // either: unreadable files are dropped silently here by design. + // + // Then through `summarizeMatScan`, as the model branch goes through + // `summarizeParsedModel`. The part it returns is keyed the way this map is keyed, + // so folding its one entry in is a copy rather than a second keying rule. + for (const [name, summary] of summarizeMatScan(scanMat(file.bytes), file.srcId, file.filename).matByName) { + matByName.set(name, summary); + } } else if (isSlddFile(file.filename)) { - slddByName.set(refBasename(file.filename), slddSummary(file.srcId, file.bytes)); + // `scanSldd` and not `readSlddContent`: 3288 ms to 116 ms on the larger customer + // dictionary, and 63 MB of retained heap to 2 MB, because the entry tree the full + // read builds was discarded a line later. Same substitution discipline as above — + // it falls back to the full parse on anything it cannot prove itself equivalent + // on — and no `warnings` array for the same reason. + for (const [name, summary] of summarizeSlddScan(scanSldd(file.bytes), file.srcId, file.filename).slddByName) { + slddByName.set(name, summary); + } } } catch { @@ -186,6 +164,85 @@ export function summarizeFiles(files) { export function summarizeParsedModel(parsed, srcId, filename) { return { models: [modelSummary(parsed, srcId, filename)], slddByName: new Map(), matByName: new Map() }; } +/** + * The dictionary branch of `summarizeFiles`, over a scan the caller has ALREADY run. + * + * Same trade as `summarizeParsedModel`, on the file kind a workspace holds most of. A host + * that scans a dictionary for its own purposes — data-explorer-vscode's cheap tier wants + * both the raw `refs` the scan carries and this summary out of one read — got the summary + * only by handing the bytes to `summarizeFiles`, which scanned them a second time. That + * second scan measured 46% of the tier's per-dictionary CPU: 14.6 ms of 31.5 ms on a + * 20,000-entry dictionary, spent deriving a `names` list the caller was already holding. + * + * The answer is a whole `FileSummaries` carrying just this dictionary, keyed by + * `refBasename(filename)` exactly as `summarizeFiles` keys it, so it is what + * `summarizeFiles([{ srcId, filename, bytes }])` returns for a `.sldd` and + * `mergeFileSummaries` folds it in beside the models and MAT-files. usageScanSummary.test.ts + * pins that equality over every committed dictionary — and, because `summarizeFiles` routes + * through here and so cannot disagree by construction, pins the summary itself against the + * FULL reader as well. Two ways to reach one summary is the shape a drift takes; two ways + * that share an implementation only move the risk into the implementation. + * + * `filename` is still required and is still not `srcId`: the map KEY comes off the + * basename, case-folded, because the lookups against it are references authored inside a + * model (see fileKinds.refBasename), and a srcId may be a path or a URI. + * + * WHAT THE CALLER MUST NOT DO: hand in a scan of bytes other than the ones `srcId` names. + * Nothing here can detect it — a scan is two string arrays — and the result is an index + * that credits one file's entries to another, which reads as a confidently wrong Usage + * cell rather than as an error. + * + * No per-file `try`, unlike `summarizeFiles`: there is no file here to be unreadable. A + * caller holding a scan has already been told the bytes were readable, and swallowing a + * throw would hand back an empty answer for a dictionary that HAD been read. + */ +export function summarizeSlddScan(scan, srcId, filename) { + return { + models: [], + slddByName: new Map([ + [ + refBasename(filename), + { + srcId, + // `filter(Boolean)` because `scanSldd` reports `''` for an entry with no readable + // name, to keep positions aligned for callers that index by position. A Set keyed + // on names has no use for that placeholder. + names: new Set(scan.names.filter(Boolean)), + slddRefs: scan.refs.map(refBasename), + }, + ], + ]), + matByName: new Map(), + }; +} +/** + * The MAT half of `summarizeSlddScan`, for a caller that already ran `scanMat` — the same + * saved read, on the file kind a model resolves last. + * + * `slddRefs` is empty and not a field this could fill: a MAT-file inherits nothing, which + * is what `DataSummary.slddRefs` says of it. + * + * The same caution applies — a scan of bytes `srcId` does not name cannot be detected here + * — and so does the reason there is no `try`: see `summarizeSlddScan`. + */ +export function summarizeMatScan(scan, srcId, filename) { + return { + models: [], + slddByName: new Map(), + matByName: new Map([ + [ + refBasename(filename), + { + srcId, + // `filter(Boolean)` because `scanMat` reports '' for a variable with no name, to + // keep positions aligned for callers that index by position. + names: new Set(scan.names.filter(Boolean)), + slddRefs: [], + }, + ], + ]), + }; +} // --- Resolving --------------------------------------------------------------- /** * Where the name `name` resolves for a block of `model` sitting at `systemPath`, or null diff --git a/dist/datamodel/usage/UsageIndex.js.map b/dist/datamodel/usage/UsageIndex.js.map index 459980a..044c49f 100644 --- a/dist/datamodel/usage/UsageIndex.js.map +++ b/dist/datamodel/usage/UsageIndex.js.map @@ -1 +1 @@ -{"version":3,"file":"UsageIndex.js","sourceRoot":"","sources":["../../../src/datamodel/usage/UsageIndex.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"UsageIndex.js","sourceRoot":"","sources":["../../../src/datamodel/usage/UsageIndex.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts index 3fe2bca..1fa89fd 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -40,7 +40,7 @@ export { scanModelStructure, type ModelStructure } from './datamodel/parser/Mode export { DATA_PART, DATA_PART_XML, DATA_PART_KEY, TEXT_PARTS, TEXT_CONTENT } from './datamodel/parser/SlddParts.js'; export { SC_PART, SC_PART_XML, SC_TYPE_TO_CLASSIFICATION, applyScEdits, catalogFromDefinitions, classificationOf, scRenameEdits, scanScJsonText, scanScXml, } from './datamodel/parser/ScCatalog.js'; export type { ScDefinition, ScNameSite, ScTextEdit, SystemComposerCatalog } from './datamodel/parser/ScCatalog.js'; -export { buildUsageIndex, buildUsageIndexFromSummaries, mergeFileSummaries, summarizeFiles, summarizeParsedModel, resolveName, } from './datamodel/usage/UsageIndex.js'; +export { buildUsageIndex, buildUsageIndexFromSummaries, mergeFileSummaries, summarizeFiles, summarizeParsedModel, summarizeSlddScan, summarizeMatScan, resolveName, } from './datamodel/usage/UsageIndex.js'; export type { UsageIndex, UsageFile, FileSummaries, ModelSummary, DataSummary, ParamOrigin, OriginKind, } from './datamodel/usage/UsageIndex.js'; export { maskDefining } from './datamodel/maskScope.js'; export type { MaskScope } from './datamodel/maskScope.js'; diff --git a/dist/index.d.ts.map b/dist/index.d.ts.map index 5b4aaea..c1e7a5b 100644 --- a/dist/index.d.ts.map +++ b/dist/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,uCAAuC,CAAC;AAG/C,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC3D,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,QAAQ,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,WAAW,MAAM,uBAAuB,CAAC;AAGrD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGzE,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAI5D,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAO1D,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAO1F,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAY3D,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AACtG,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAQjE,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACzF,YAAY,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAQ/F,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AACtG,OAAO,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAG3D,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAUtH,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClF,YAAY,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAK9E,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAGzF,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAkBrE,OAAO,EACL,KAAK,EACL,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,EACb,WAAW,EACX,UAAU,EACV,SAAS,EACT,aAAa,GACd,MAAM,0BAA0B,CAAC;AAUlC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAS1H,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAU/E,OAAO,EAAE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAU5E,OAAO,EAAE,kBAAkB,EAAE,KAAK,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAWnG,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAWpH,OAAO,EACL,OAAO,EACP,WAAW,EACX,yBAAyB,EACzB,YAAY,EACZ,sBAAsB,EACtB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,SAAS,GACV,MAAM,iCAAiC,CAAC;AACzC,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAgBnH,OAAO,EACL,eAAe,EACf,4BAA4B,EAC5B,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,WAAW,GACZ,MAAM,iCAAiC,CAAC;AACzC,YAAY,EACV,UAAU,EACV,SAAS,EACT,aAAa,EACb,YAAY,EACZ,WAAW,EACX,WAAW,EACX,UAAU,GACX,MAAM,iCAAiC,CAAC;AAKzC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAG1D,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG/E,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,wCAAwC,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAKrE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAWzE,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAmBrD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC1H,YAAY,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AACvF,YAAY,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAczE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAe7D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAqBvE,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AAGzE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js index 66af5bf..2934fcd 100644 --- a/dist/index.js +++ b/dist/index.js @@ -144,7 +144,13 @@ export { SC_PART, SC_PART_XML, SC_TYPE_TO_CLASSIFICATION, applyScEdits, catalogF // `summarizeParsedModel` splits the summarising half the same way for the file a host has // OPEN: it already parsed those bytes for the model's own rows, and `summarizeFiles` would // parse them a second time to say which blocks use what. Same summary, one parse. -export { buildUsageIndex, buildUsageIndexFromSummaries, mergeFileSummaries, summarizeFiles, summarizeParsedModel, resolveName, } from './datamodel/usage/UsageIndex.js'; +// `summarizeSlddScan` and `summarizeMatScan` are that split for the other two kinds, over a +// `scanSldd`/`scanMat` result rather than a parse — a host that scans a dictionary for its +// own indexes reads the same bytes twice otherwise, and the second scan measured 46% of one +// such tier's per-dictionary CPU (14.6 ms of 31.5 ms on a 20,000-entry dictionary). All +// three return a `FileSummaries` keyed as `summarizeFiles` keys it, so they fold together +// through `mergeFileSummaries` whichever way each file was summarised. +export { buildUsageIndex, buildUsageIndexFromSummaries, mergeFileSummaries, summarizeFiles, summarizeParsedModel, summarizeSlddScan, summarizeMatScan, resolveName, } from './datamodel/usage/UsageIndex.js'; // The innermost of those scopes, and the only one that is not a file: a masked subsystem's // own parameters. On the barrel because `ParamOrigin.maskBlock` hands one out — a host // rendering a mask-resolved parameter needs the block's path to name the source of the diff --git a/dist/index.js.map b/dist/index.js.map index 09f7450..71f2746 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/datamodel/usage/UsageIndex.ts b/src/datamodel/usage/UsageIndex.ts index 5de7849..242e350 100644 --- a/src/datamodel/usage/UsageIndex.ts +++ b/src/datamodel/usage/UsageIndex.ts @@ -44,8 +44,10 @@ import { maskDefining } from '../maskScope.js'; import type { MaskScope } from '../maskScope.js'; import { basenameOf, isMatFile, isModelFile, isSlddFile, modelNameOf, refBasename } from '../fileKinds.js'; import { scanSldd } from '../parser/SlddScan.js'; +import type { SlddScanResult } from '../parser/SlddScan.js'; import { parseModel } from '../parser/ModelParser.js'; import { scanMat } from '../parser/MatScan.js'; +import type { MatScanResult } from '../parser/MatScan.js'; import type { ParsedSlx } from '../parser/SlxParser.js'; import type { NodeUsage } from '../../core/DataModel.js'; @@ -224,50 +226,6 @@ function modelSummary(parsed: ParsedSlx, srcId: string, filename: string): Model }; } -/** - * A usage summary reads ONE string per entry, so it goes through `scanSldd` rather than - * `readSlddContent`: 3288 ms to 116 ms on the larger customer dictionary, and 63 MB of - * retained heap to 2 MB, because the entry tree it used to build was discarded a line - * later. `scanSldd` falls back to the full parse on any dictionary it cannot prove itself - * equivalent on, so this is a substitution and not a second reader. - * - * Nothing is lost by not passing a `warnings` array: this never passed one either. A - * usage index is built over a whole folder and drops unreadable files silently by design - * (see `summarizeFiles`), so there was no channel for a per-part warning to reach. - */ -function slddSummary(srcId: string, bytes: ArrayBuffer): DataSummary { - const { names, refs } = scanSldd(bytes); - return { - srcId, - // `filter(Boolean)` because `scanSldd` reports `''` for an entry with no readable - // name, to keep positions aligned for callers that index by position. A Set keyed on - // names has no use for that placeholder, and the previous code dropped it too. - names: new Set(names.filter(Boolean)), - slddRefs: refs.map(refBasename), - }; -} - -/** - * The MAT half of the same substitution `slddSummary` makes, for the same reason: this - * reads one string per variable and `parseMat` was decoding every element of every matrix - * to supply them — 1271 ms over the corpus's `.mat` files against 4.4 ms here. - * - * `scanMat` falls back to the full parse on any file it cannot prove itself equivalent - * on, so this is a substitution and not a second reader. It discards `parseMat`'s - * warnings, which this never collected either: a usage index is built over a folder and - * drops unreadable files silently by design (see `summarizeFiles`). - */ -function matSummary(srcId: string, bytes: ArrayBuffer): DataSummary { - return { - srcId, - // `filter(Boolean)` because `scanMat` reports '' for a variable with no name, to keep - // positions aligned for callers that index by position. A Set keyed on names has no - // use for that placeholder, and the previous code dropped it too. - names: new Set(scanMat(bytes).names.filter(Boolean)), - slddRefs: [], - }; -} - /** * Parse each file into the summary its kind calls for, dispatching on the FILENAME through * the shared kind tests. @@ -289,9 +247,29 @@ export function summarizeFiles(files: UsageFile[]): FileSummaries { // already holds are then the same summary by construction, not by agreement. models.push(...summarizeParsedModel(parseModel(file.bytes, file.filename), file.srcId, file.filename).models); } else if (isMatFile(file.filename)) { - matByName.set(refBasename(file.filename), matSummary(file.srcId, file.bytes)); + // `scanMat` and not `parseMat`, for the same reason the dictionary branch below + // scans: a summary reads one string per variable and the full parse was decoding + // every element of every matrix to supply it — 1271 ms over the corpus's `.mat` + // files against 4.4 ms. It falls back to `parseMat` on any file it cannot prove + // itself equivalent on, so this is a substitution and not a second reader, and it + // discards the warnings `parseMat` would collect, which this never collected + // either: unreadable files are dropped silently here by design. + // + // Then through `summarizeMatScan`, as the model branch goes through + // `summarizeParsedModel`. The part it returns is keyed the way this map is keyed, + // so folding its one entry in is a copy rather than a second keying rule. + for (const [name, summary] of summarizeMatScan(scanMat(file.bytes), file.srcId, file.filename).matByName) { + matByName.set(name, summary); + } } else if (isSlddFile(file.filename)) { - slddByName.set(refBasename(file.filename), slddSummary(file.srcId, file.bytes)); + // `scanSldd` and not `readSlddContent`: 3288 ms to 116 ms on the larger customer + // dictionary, and 63 MB of retained heap to 2 MB, because the entry tree the full + // read builds was discarded a line later. Same substitution discipline as above — + // it falls back to the full parse on anything it cannot prove itself equivalent + // on — and no `warnings` array for the same reason. + for (const [name, summary] of summarizeSlddScan(scanSldd(file.bytes), file.srcId, file.filename).slddByName) { + slddByName.set(name, summary); + } } } catch { /* unreadable file contributes nothing */ @@ -326,6 +304,87 @@ export function summarizeParsedModel(parsed: ParsedSlx, srcId: string, filename: return { models: [modelSummary(parsed, srcId, filename)], slddByName: new Map(), matByName: new Map() }; } +/** + * The dictionary branch of `summarizeFiles`, over a scan the caller has ALREADY run. + * + * Same trade as `summarizeParsedModel`, on the file kind a workspace holds most of. A host + * that scans a dictionary for its own purposes — data-explorer-vscode's cheap tier wants + * both the raw `refs` the scan carries and this summary out of one read — got the summary + * only by handing the bytes to `summarizeFiles`, which scanned them a second time. That + * second scan measured 46% of the tier's per-dictionary CPU: 14.6 ms of 31.5 ms on a + * 20,000-entry dictionary, spent deriving a `names` list the caller was already holding. + * + * The answer is a whole `FileSummaries` carrying just this dictionary, keyed by + * `refBasename(filename)` exactly as `summarizeFiles` keys it, so it is what + * `summarizeFiles([{ srcId, filename, bytes }])` returns for a `.sldd` and + * `mergeFileSummaries` folds it in beside the models and MAT-files. usageScanSummary.test.ts + * pins that equality over every committed dictionary — and, because `summarizeFiles` routes + * through here and so cannot disagree by construction, pins the summary itself against the + * FULL reader as well. Two ways to reach one summary is the shape a drift takes; two ways + * that share an implementation only move the risk into the implementation. + * + * `filename` is still required and is still not `srcId`: the map KEY comes off the + * basename, case-folded, because the lookups against it are references authored inside a + * model (see fileKinds.refBasename), and a srcId may be a path or a URI. + * + * WHAT THE CALLER MUST NOT DO: hand in a scan of bytes other than the ones `srcId` names. + * Nothing here can detect it — a scan is two string arrays — and the result is an index + * that credits one file's entries to another, which reads as a confidently wrong Usage + * cell rather than as an error. + * + * No per-file `try`, unlike `summarizeFiles`: there is no file here to be unreadable. A + * caller holding a scan has already been told the bytes were readable, and swallowing a + * throw would hand back an empty answer for a dictionary that HAD been read. + */ +export function summarizeSlddScan(scan: SlddScanResult, srcId: string, filename: string): FileSummaries { + return { + models: [], + slddByName: new Map([ + [ + refBasename(filename), + { + srcId, + // `filter(Boolean)` because `scanSldd` reports `''` for an entry with no readable + // name, to keep positions aligned for callers that index by position. A Set keyed + // on names has no use for that placeholder. + names: new Set(scan.names.filter(Boolean)), + slddRefs: scan.refs.map(refBasename), + }, + ], + ]), + matByName: new Map(), + }; +} + +/** + * The MAT half of `summarizeSlddScan`, for a caller that already ran `scanMat` — the same + * saved read, on the file kind a model resolves last. + * + * `slddRefs` is empty and not a field this could fill: a MAT-file inherits nothing, which + * is what `DataSummary.slddRefs` says of it. + * + * The same caution applies — a scan of bytes `srcId` does not name cannot be detected here + * — and so does the reason there is no `try`: see `summarizeSlddScan`. + */ +export function summarizeMatScan(scan: MatScanResult, srcId: string, filename: string): FileSummaries { + return { + models: [], + slddByName: new Map(), + matByName: new Map([ + [ + refBasename(filename), + { + srcId, + // `filter(Boolean)` because `scanMat` reports '' for a variable with no name, to + // keep positions aligned for callers that index by position. + names: new Set(scan.names.filter(Boolean)), + slddRefs: [], + }, + ], + ]), + }; +} + // --- Resolving --------------------------------------------------------------- /** diff --git a/src/index.ts b/src/index.ts index a4c182f..2b6bc28 100644 --- a/src/index.ts +++ b/src/index.ts @@ -219,12 +219,20 @@ export type { ScDefinition, ScNameSite, ScTextEdit, SystemComposerCatalog } from // `summarizeParsedModel` splits the summarising half the same way for the file a host has // OPEN: it already parsed those bytes for the model's own rows, and `summarizeFiles` would // parse them a second time to say which blocks use what. Same summary, one parse. +// `summarizeSlddScan` and `summarizeMatScan` are that split for the other two kinds, over a +// `scanSldd`/`scanMat` result rather than a parse — a host that scans a dictionary for its +// own indexes reads the same bytes twice otherwise, and the second scan measured 46% of one +// such tier's per-dictionary CPU (14.6 ms of 31.5 ms on a 20,000-entry dictionary). All +// three return a `FileSummaries` keyed as `summarizeFiles` keys it, so they fold together +// through `mergeFileSummaries` whichever way each file was summarised. export { buildUsageIndex, buildUsageIndexFromSummaries, mergeFileSummaries, summarizeFiles, summarizeParsedModel, + summarizeSlddScan, + summarizeMatScan, resolveName, } from './datamodel/usage/UsageIndex.js'; export type { diff --git a/test/usageScanSummary.test.ts b/test/usageScanSummary.test.ts new file mode 100644 index 0000000..0b3d2a9 --- /dev/null +++ b/test/usageScanSummary.test.ts @@ -0,0 +1,469 @@ +// Copyright 2026 The MathWorks, Inc. +// +// Summarising a dictionary or a MAT-file from a SCAN the caller already ran, and the one +// thing that has to be true of it: it is the same summary `summarizeFiles` builds from the +// bytes. +// +// `summarizeSlddScan` and `summarizeMatScan` exist because a host reads these files for its +// own indexes and then handed the bytes to `summarizeFiles`, which scanned them a second +// time — 46% of one such tier's per-dictionary CPU. Which makes two ways to summarise one +// file, and the tests that matter are the ones BETWEEN them. Not "does the new path answer +// plausibly": a summariser reachable two ways that reads a different field on one of them +// answers plausibly on both and is still wrong, and only a comparison catches it. +// +// So the shape here is an EQUALITY SWEEP: for every committed `.sldd` and `.mat` this suite +// can reach, plus the constructed shapes no fixture has, +// +// summarizeFiles([{ srcId, filename, bytes }]) == summarize*Scan(scan(bytes), srcId, filename) +// +// compared whole — the `names` Sets, the map KEYS, and `slddRefs` in order. The fixtures are +// globbed rather than listed, so a dictionary added for some unrelated reason is covered by +// this the day it lands, and the globs are guarded by a count so an empty one cannot make +// every case disappear silently. +// +// AND A SECOND ASSERTION BESIDE IT, because the first one alone is now weaker than it looks: +// `summarizeFiles` was refactored to route THROUGH these functions, so the two sides share +// the code that builds the summary and a wrong rule inside it would agree with itself. So +// every swept file is also compared against a summary derived from the FULL readers — +// `readSlddContent` and `parseMat`, the parsers the scanners substitute for. Verified by +// mutation: without that, dropping `filter(Boolean)` from the summary left the whole sweep +// green. See `expectMatchesFullReader`. +// +// The refusal cases are the ones worth reading. Both scanners fall back to the full reader +// for bytes they have not been proven equivalent on, so the summary of a file that took the +// fallback must ALSO match, and a case that merely happened to take the fast path would prove +// nothing about that. For the dictionary the refusal is asserted directly, through +// `scanDataSourceXml`, so it cannot quietly stop being one; for the MAT it is not assertable +// from here and the case says so where it sits. +import { describe, it, expect } from 'vitest'; +import { readFileSync, readdirSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { strToU8, unzipSync, zipSync } from 'fflate'; +import { scanDataSourceXml } from '../src/datamodel/parser/SlddScan.js'; +import { + buildUsageIndex, + buildUsageIndexFromSummaries, + isJsonTextBytes, + mergeFileSummaries, + normalizeRefNames, + parseMat, + parseModel, + readSlddContent, + scanMat, + scanSldd, + slddChunkContent, + summarizeFiles, + summarizeMatScan, + summarizeParsedModel, + summarizeSlddScan, +} from '../src/index.js'; +import type { UsageFile } from '../src/index.js'; + +const FIXTURES = fileURLToPath(new URL('./fixtures/', import.meta.url)); +const MCOS = fileURLToPath(new URL('./fixtures/mcos/', import.meta.url)); + +function bytesOf(path: string): ArrayBuffer { + const b = readFileSync(path); + return b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength) as ArrayBuffer; +} + +const fixtureBytes = (rel: string): ArrayBuffer => bytesOf(fileURLToPath(new URL(`./fixtures/${rel}`, import.meta.url))); +const artifact = (rel: string): ArrayBuffer => + bytesOf(fileURLToPath(new URL(`./parity/artifacts/${rel}`, import.meta.url))); + +// A distinct srcId, never equal to the filename: the two are separate arguments and the +// summary carries them differently — the srcId verbatim, the map key off the basename +// case-folded — so a case where they coincided would let either stand in for the other. +const file = (name: string, bytes: ArrayBuffer, srcId = `src:${name}`): UsageFile => ({ + srcId, + filename: name, + bytes, +}); + +// ---- the two assertions ------------------------------------------------------------- + +/** + * THE CONTRACT, for a dictionary: summarising the bytes and summarising a scan of those + * bytes produce the same `FileSummaries`, compared whole. + * + * `toEqual` is what makes this worth writing — it walks into the `Map` and the `Set`, so a + * wrong KEY (the basename rule) fails here just as a wrong name does, and `slddRefs` is an + * array so its ORDER is compared too. That order is contract: `resolveName` walks it and + * takes the first hit. + */ +function expectSlddPathsAgree(f: UsageFile): void { + expect(summarizeSlddScan(scanSldd(f.bytes), f.srcId, f.filename)).toEqual(summarizeFiles([f])); +} + +function expectMatPathsAgree(f: UsageFile): void { + expect(summarizeMatScan(scanMat(f.bytes), f.srcId, f.filename)).toEqual(summarizeFiles([f])); +} + +/** + * AND THE ORACLE, without which the equality above is by construction rather than by test. + * + * `summarizeFiles` now routes THROUGH these functions — that is the point of the refactor, + * one implementation and not two — so the two sides of the equality share the code that + * builds the summary and could only differ in which bytes were scanned and how the key was + * spelled. A wrong `names` rule would agree with itself perfectly. Verified by mutation: + * dropping `filter(Boolean)` and `refBasename` from the summary left the whole sweep green. + * + * So the sweep also compares against a summary derived from the FULL readers — the parsers + * the scanners substitute for — with the two rules spelled out here rather than imported: + * the `''` placeholder a scan keeps for position is not a name, and a reference is matched + * by basename case-folded. That is an independent derivation, and it is what makes the + * sweep able to fail. + */ +function expectMatchesFullReader(f: UsageFile, kind: 'sldd' | 'mat'): void { + const key = f.filename.toLowerCase(); // every swept file is named by its bare basename + if (kind === 'mat') { + expect(summarizeMatScan(scanMat(f.bytes), f.srcId, f.filename).matByName.get(key)).toEqual({ + srcId: f.srcId, + names: new Set(parseMat(f.bytes).variables.map((v) => v.name).filter((n) => n !== '')), + slddRefs: [], + }); + return; + } + const content = slddChunkContent(readSlddContent(f.bytes, [])); + const entries = (content?.entries ?? []) as { name?: unknown }[]; + expect(summarizeSlddScan(scanSldd(f.bytes), f.srcId, f.filename).slddByName.get(key)).toEqual({ + srcId: f.srcId, + names: new Set(entries.map((e) => (typeof e?.name === 'string' ? e.name : '')).filter((n) => n !== '')), + slddRefs: (content ? normalizeRefNames(content['Dictionary References']) : []).map((r) => + (r.split(/[\\/]/).pop() || r).toLowerCase(), + ), + }); +} + +// ---- fixture-wide sweep, dictionaries ------------------------------------------------- + +const slddFixtures = readdirSync(FIXTURES).filter((n) => n.endsWith('.sldd')).sort(); + +// The parity artifacts are the same two dictionaries MATLAB wrote in BOTH spellings, and +// they are the largest committed ones — so they are the sweep's realistic input, where the +// hand-built cases below are its sharp one. +const slddArtifacts = ['binary/cases.sldd', 'binary/params.sldd', 'text/cases.sldd', 'text/params.sldd']; + +describe('summarizeSlddScan — the same summary summarizeFiles builds, on every committed dictionary', () => { + it('found the fixtures, in both spellings', () => { + // Guards the glob twice over: an empty list would make every case below disappear + // while the suite reported success, and a list of only one spelling would leave the + // zip-or-JSON fork — the one place the two readers differ most — untested. + expect(slddFixtures.length).toBeGreaterThan(15); + const zipped = slddFixtures.map((n) => !isJsonTextBytes(new Uint8Array(fixtureBytes(n)))); + expect(zipped.filter(Boolean).length).toBeGreaterThan(0); + expect(zipped.filter((z) => !z).length).toBeGreaterThan(0); + }); + + it.each(slddFixtures)('agrees on fixtures/%s', (name) => { + const f = file(name, fixtureBytes(name)); + expectSlddPathsAgree(f); + expectMatchesFullReader(f, 'sldd'); + }); + + it.each(slddArtifacts)('agrees on artifacts/%s', (rel) => { + const f = file(rel.split('/')[1], artifact(rel), `src:${rel}`); + expectSlddPathsAgree(f); + expectMatchesFullReader(f, 'sldd'); + }); + + it('is not comparing empty summaries', () => { + // The sweep is worthless if every dictionary summarises to nothing, so the two + // artifacts are pinned as carrying real names — in both spellings, since a reader that + // returned nothing for one of them would agree with itself perfectly. + for (const rel of ['binary/cases.sldd', 'text/cases.sldd']) { + const names = summarizeSlddScan(scanSldd(artifact(rel)), 'src', 'cases.sldd').slddByName.get('cases.sldd')?.names; + expect(names?.size, rel).toBeGreaterThan(3); + } + }); +}); + +// ---- constructed dictionaries --------------------------------------------------------- + +/** A textual `.sldd` defining `names` and referencing `refs`, as usageIndex.test.ts builds one. */ +function slddBytes(names: string[], refs: unknown[] = []): ArrayBuffer { + const u8 = strToU8( + JSON.stringify({ + __MW_TEXT_PARTS__: { + '__MW_TEXT_PART__/data/chunk0': { + __MW_TEXT_content: { + entries: names.map((name) => ({ name, class: 'Simulink.Parameter' })), + 'Dictionary References': refs, + AllowAccessBWS: false, + }, + }, + }, + }), + ); + return u8.buffer.slice(u8.byteOffset, u8.byteOffset + u8.byteLength) as ArrayBuffer; +} + +const CHUNK_PART = 'data/chunk0.xml'; +const chunkXmlText = (body: string): string => + '\n' + + `\n${body}\n`; + +/** + * A real compressed `.sldd`, unzipped, its data part replaced, rezipped — the technique + * usageIndex.test.ts and parseWarnings.test.ts use, so the bytes under test differ from a + * file MATLAB wrote in exactly the one way the case is about and the entries come back + * through the real binary reader. + */ +function binarySlddWithChunk(body: string): ArrayBuffer { + const entries = unzipSync(new Uint8Array(fixtureBytes('compressed.sldd'))); + expect(Object.keys(entries)).toContain(CHUNK_PART); // the fixture really holds it + entries[CHUNK_PART] = strToU8(chunkXmlText(body)); + const zipped = zipSync(entries); + return zipped.buffer.slice(zipped.byteOffset, zipped.byteOffset + zipped.byteLength) as ArrayBuffer; +} + +const xmlEntry = (name: string): string => `

${name}

`; +const xmlRef = (name: string): string => + `

${name}

`; + +describe('summarizeSlddScan — the shapes no committed fixture has', () => { + // Every one of these is a shape the two paths could disagree on and no fixture exercises: + // references at all (no committed dictionary has one), an entry with no name, and the + // degenerate empty document. + const CASES: [what: string, load: () => UsageFile][] = [ + [ + // Both spellings of a reference and a mixed-case one, because the summary's `slddRefs` + // is `refs.map(refBasename)` — the fold that makes `Sub.SLDD` resolve — and an empty + // reference that `normalizeRefNames` drops, which is where the two paths could differ + // by one position. + 'a textual dictionary with references, in both spellings and mixed case', + () => file('top.sldd', slddBytes(['Kp', 'Ki'], ['LEAF.SLDD', { file: 'other/Mid.sldd' }, ''])), + ], + [ + // Entries the scanner reports as `''`, which both paths must drop from the Set while + // the scan keeps them in position. A case with the unnamed entry FIRST, so a path that + // dropped it late would shift the rest. + 'a compressed dictionary with unnamed entries around a named one', + () => + file( + 'holes.sldd', + binarySlddWithChunk( + `

1

` + + xmlEntry('aParam') + + `

`, + ), + ), + ], + [ + 'a compressed dictionary with entries and references in one document', + () => file('both.sldd', binarySlddWithChunk(xmlEntry('A') + xmlRef('one.sldd') + xmlEntry('B') + xmlRef('two.sldd'))), + ], + ['a dictionary defining nothing at all', () => file('empty.sldd', slddBytes([]))], + [ + // A JSON file short of the shape a dictionary has — a partial write really produces + // this, and both paths owe the empty summary rather than a throw on either. + 'valid JSON that is not a dictionary', + () => file('notadict.sldd', (() => { + const u8 = strToU8(JSON.stringify({ nothing: true })); + return u8.buffer.slice(u8.byteOffset, u8.byteOffset + u8.byteLength) as ArrayBuffer; + })()), + ], + ]; + + for (const [what, load] of CASES) { + it(`agrees on ${what}`, () => { + expectSlddPathsAgree(load()); + }); + } + + it('really is comparing summaries with the awkward parts in them', () => { + // The equalities above would hold vacuously if the scanner returned nothing for these, + // so the two fields they were chosen for are pinned by value: references folded and in + // order, and the unnamed entries absent from a Set that still holds the named one. + const refs = CASES[0][1](); + expect(summarizeSlddScan(scanSldd(refs.bytes), refs.srcId, refs.filename).slddByName.get('top.sldd')).toEqual({ + srcId: 'src:top.sldd', + names: new Set(['Kp', 'Ki']), + slddRefs: ['leaf.sldd', 'mid.sldd'], + }); + + const holes = CASES[1][1](); + const summary = summarizeSlddScan(scanSldd(holes.bytes), holes.srcId, holes.filename).slddByName.get('holes.sldd'); + expect(scanSldd(holes.bytes).names).toEqual(['', 'aParam', '']); // the scan keeps the positions + expect(summary?.names).toEqual(new Set(['aParam'])); // the summary does not + }); + + it('agrees for a dictionary the fast path REFUSES and the full reader recovers', () => { + // The case the fallback exists for, and the reason it is asserted rather than assumed: + // `scanSldd` hands a document it has not been proven equivalent on to + // `readSlddContent`, so what `summarizeSlddScan` is given for such a file is the full + // reader's answer — and it still has to be the summary `summarizeFiles` builds. An + // entity in a name is the documented refusal (fast-xml-parser decodes `&`, reading + // the bytes plainly would not). + const body = xmlEntry('A&B') + xmlEntry('plain'); + expect(() => scanDataSourceXml(strToU8(chunkXmlText(body)))).toThrow(/entity/i); + const refused = file('entity.sldd', binarySlddWithChunk(body)); + // The recovery really happened — the decoded name, not the raw bytes. + expect(scanSldd(refused.bytes).names).toEqual(['A&B', 'plain']); + expectSlddPathsAgree(refused); + }); + + it('keys on the basename case-folded, and carries the srcId verbatim', () => { + // The key rule is the one thing a caller cannot pass in, so it is pinned directly: a + // reference authored as `Params.SLDD` inside a model has to find a file stored under a + // directory path, and the srcId — the host's own identifier, a URI as often as a path — + // has to come back out untouched. + const summaries = summarizeSlddScan(scanSldd(slddBytes(['Kp'])), 'vscode://x/Params.SLDD?v=2', '/work/dicts/Params.SLDD'); + expect([...summaries.slddByName.keys()]).toEqual(['params.sldd']); + expect(summaries.slddByName.get('params.sldd')?.srcId).toBe('vscode://x/Params.SLDD?v=2'); + // And the same file through `summarizeFiles`, so the key rule is not two rules. + expect(summaries).toEqual( + summarizeFiles([ + { srcId: 'vscode://x/Params.SLDD?v=2', filename: '/work/dicts/Params.SLDD', bytes: slddBytes(['Kp']) }, + ]), + ); + }); + + it('holds nothing but the one dictionary', () => { + // The other two halves of the `FileSummaries` are empty, which is what lets a caller + // fold this in beside a model it parsed and a MAT it scanned. + const only = summarizeSlddScan(scanSldd(slddBytes(['Kp'])), 'src', 'a.sldd'); + expect(only.models).toEqual([]); + expect(only.matByName.size).toBe(0); + expect(only.slddByName.size).toBe(1); + }); +}); + +// ---- fixture-wide sweep, MAT-files ---------------------------------------------------- + +const matFixtures = [ + ...readdirSync(FIXTURES).filter((n) => n.endsWith('.mat')).map((n) => n), + ...readdirSync(MCOS).filter((n) => n.endsWith('.mat')).map((n) => `mcos/${n}`), +].sort(); + +describe('summarizeMatScan — the same summary summarizeFiles builds, on every committed MAT-file', () => { + it('found the fixtures at all', () => { + // `strings_v73.mat` is in this list on purpose and is the one file here neither reader + // can read: it is HDF5, both paths refuse it, and the case for that is at the bottom. + expect(matFixtures.length).toBeGreaterThan(10); + }); + + it.each(matFixtures.filter((n) => !n.endsWith('_v73.mat')))('agrees on fixtures/%s', (rel) => { + const f = file(rel.split('/').pop()!, fixtureBytes(rel), `src:${rel}`); + expectMatPathsAgree(f); + expectMatchesFullReader(f, 'mat'); + }); + + it('agrees on artifacts/mat/cases.mat', () => { + const f = file('cases.mat', artifact('mat/cases.mat')); + expectMatPathsAgree(f); + expectMatchesFullReader(f, 'mat'); + }); + + it('is not comparing empty summaries', () => { + // `strings.mat` holds eleven named variables and the unnamed MCOS element — so this + // pins both that the sweep has substance and that the placeholder is dropped. + const names = summarizeMatScan(scanMat(fixtureBytes('strings.mat')), 'src', 'strings.mat').matByName.get('strings.mat')?.names; + expect(names?.size).toBe(11); + expect(names?.has('')).toBe(false); + expect(scanMat(fixtureBytes('strings.mat')).names).toContain(''); // which the scan itself keeps + }); + + it('agrees for a truncated file, where the answer is the repaired read', () => { + // The MAT half of the recovery case: a file cut inside its last record. `parseMat` + // clamps every declared length against the buffer and hands back the names it could + // reach; `scanMat` will not reproduce a repair, so what comes out for these bytes is + // that clamped answer — six names on the intact file, five here — and the summary of it + // must still be the summary either path builds. + // + // That the fast path REFUSED rather than agreeing by luck is not assertable from here: + // the fallback returns `parseMat`'s answer, so the two are indistinguishable in the + // result. matScan.test.ts asserts it directly, by counting inflations through the + // native-inflate seam. What this case owes is the equality, on bytes that took that + // path. + const whole = fixtureBytes('sparse_cases.mat'); + const cut = new Uint8Array(whole).subarray(0, whole.byteLength - 24).slice().buffer as ArrayBuffer; + expect(scanMat(whole).names).toHaveLength(6); + expect(parseMat(cut).variables.map((v) => v.name)).toEqual(scanMat(cut).names); + expect(scanMat(cut).names).toHaveLength(5); // a comparison with something in it + expectMatPathsAgree(file('sparse_cases.mat', cut)); + }); + + it('holds nothing but the one MAT-file, and inherits nothing', () => { + const only = summarizeMatScan(scanMat(fixtureBytes('mcos/Numeric.mat')), 'src', 'Numeric.mat'); + expect(only.models).toEqual([]); + expect(only.slddByName.size).toBe(0); + // A MAT-file references no dictionary — the field exists because `DataSummary` is one + // shape for both kinds, and for this kind it is always empty. + expect(only.matByName.get('numeric.mat')?.slddRefs).toEqual([]); + }); +}); + +// ---- the two paths that cannot be compared, and why ----------------------------------- + +describe('bytes no reader can read', () => { + it.each([ + ['a dictionary that is neither a zip nor JSON', 'junk.sldd', () => scanSldd(strToU8('not a zip').buffer as ArrayBuffer)], + ['a MAT-file MATLAB wrote as HDF5', 'strings_v73.mat', () => scanMat(fixtureBytes('strings_v73.mat'))], + ])('has no summary to compare for %s, because there is no scan', (_what, name, scan) => { + // The one place the paths cannot be equal, and the same asymmetry `summarizeParsedModel` + // has: `summarizeFiles` drops an unreadable file silently (its per-file catch), while + // these functions are never reached for one — the caller's own scan threw first and it + // has nothing to hand over. So the summary they do not produce is the summary + // `summarizeFiles` does not produce either. + expect(scan).toThrow(); + const bytes = name === 'junk.sldd' ? (strToU8('not a zip').buffer as ArrayBuffer) : fixtureBytes(name); + expect(summarizeFiles([file(name, bytes)])).toEqual({ + models: [], + slddByName: new Map(), + matByName: new Map(), + }); + }); +}); + +// ---- composition ---------------------------------------------------------------------- + +describe('a whole workspace summarised from what the caller already holds', () => { + // A real model MATLAB wrote, so the parse is not a construction of this file's: mdlcases.mdl + // links `mdlparams.sldd`, defines `inner`, `span` and `tau` in its own workspace, and its + // blocks read `Kp`, `Ki`, `inner`, `[tau 1]` and `span`. Which makes `Kp` resolve in the + // linked dictionary and `Ki` only through the reference that dictionary carries — so the + // chain the SCAN's own `refs` supplied is load-bearing in the answers below. + const model = file('mdlcases.mdl', artifact('mdl/mdlcases.mdl')); + const top = file('mdlparams.sldd', slddBytes(['Kp'], ['leaf.sldd'])); + const leaf = file('leaf.sldd', slddBytes(['Ki'])); + const mat = file('extra.mat', fixtureBytes('mcos/Numeric.mat')); + const parts = () => [ + summarizeParsedModel(parseModel(model.bytes, model.filename), model.srcId, model.filename), + summarizeSlddScan(scanSldd(top.bytes), top.srcId, top.filename), + summarizeSlddScan(scanSldd(leaf.bytes), leaf.srcId, leaf.filename), + summarizeMatScan(scanMat(mat.bytes), mat.srcId, mat.filename), + ]; + + it('folds into the summaries summarizeFiles builds over the same four files', () => { + // The reason all three of these return a `FileSummaries` rather than a bare summary: the + // model is the file the host parsed for its own rows, the dictionaries and the MAT are + // files it scanned for its own indexes, and the parts fold together — models in file + // order, maps keyed alike — into what one pass over the four files produces. + expect(mergeFileSummaries(parts())).toEqual(summarizeFiles([model, top, leaf, mat])); + }); + + it('answers what buildUsageIndex answers from the bytes', () => { + const composed = buildUsageIndexFromSummaries(mergeFileSummaries(parts())); + const whole = buildUsageIndex([model, top, leaf, mat]); + + // Not a vacuous comparison: one name resolves in the linked dictionary and one down its + // reference, and both directions of the index have entries to compare. + expect(whole.usagesOf(top.srcId, 'Kp')).toHaveLength(1); + expect(whole.usagesOf(leaf.srcId, 'Ki')).toHaveLength(1); + expect(whole.paramsOf(model.srcId, '1')).not.toEqual([]); + + expect(composed.models).toEqual(whole.models); + for (const [srcId, name] of [ + [top.srcId, 'Kp'], + [leaf.srcId, 'Ki'], + [model.srcId, 'tau'], + [mat.srcId, 'Numeric'], + ] as const) { + expect(composed.usagesOf(srcId, name)).toEqual(whole.usagesOf(srcId, name)); + } + for (const sid of ['1', '2', '3', '6', '8']) { + expect(composed.paramsOf(model.srcId, sid)).toEqual(whole.paramsOf(model.srcId, sid)); + } + }); +}); From 21af5b895724509706d302e8df46a43f1092442e Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 16 Sep 2026 14:00:11 -0400 Subject: [PATCH 2/2] Bump to 1.21.0 for the scan-based summaries --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9ce0614..ce6540d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-explorer-core", - "version": "1.20.0", + "version": "1.21.0", "description": "Parser, data model, and node schema for Simulink data-dictionary, model, MAT-file, and project files. Presentation-independent; embeddable in-process.", "license": "BSD-3-Clause", "type": "module",