@ifc-lite/parser 5.2.0 → 6.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/columnar-entity-preparation.d.ts +3 -0
- package/dist/columnar-entity-preparation.d.ts.map +1 -1
- package/dist/columnar-entity-preparation.js +101 -11
- package/dist/columnar-entity-preparation.js.map +1 -1
- package/dist/columnar-parser-indexes.d.ts +17 -1
- package/dist/columnar-parser-indexes.d.ts.map +1 -1
- package/dist/columnar-parser-indexes.js +31 -21
- package/dist/columnar-parser-indexes.js.map +1 -1
- package/dist/columnar-parser.d.ts +10 -1
- package/dist/columnar-parser.d.ts.map +1 -1
- package/dist/columnar-parser.js +14 -2
- package/dist/columnar-parser.js.map +1 -1
- package/dist/cost-extractor.d.ts +10 -0
- package/dist/cost-extractor.d.ts.map +1 -0
- package/dist/cost-extractor.js +369 -0
- package/dist/cost-extractor.js.map +1 -0
- package/dist/cost-schedule-2x3.d.ts +31 -0
- package/dist/cost-schedule-2x3.d.ts.map +1 -0
- package/dist/cost-schedule-2x3.js +75 -0
- package/dist/cost-schedule-2x3.js.map +1 -0
- package/dist/cost-types.d.ts +105 -0
- package/dist/cost-types.d.ts.map +1 -0
- package/dist/cost-types.js +5 -0
- package/dist/cost-types.js.map +1 -0
- package/dist/data-store-transport.d.ts +1 -0
- package/dist/data-store-transport.d.ts.map +1 -1
- package/dist/data-store-transport.js +5 -29
- package/dist/data-store-transport.js.map +1 -1
- package/dist/drop-census.d.ts +136 -0
- package/dist/drop-census.d.ts.map +1 -0
- package/dist/drop-census.js +53 -0
- package/dist/drop-census.js.map +1 -0
- package/dist/entity-scanner.d.ts.map +1 -1
- package/dist/entity-scanner.js +10 -5
- package/dist/entity-scanner.js.map +1 -1
- package/dist/generated/ifc2x3/schema-registry.d.ts +50 -0
- package/dist/generated/ifc2x3/schema-registry.d.ts.map +1 -0
- package/dist/generated/ifc2x3/schema-registry.js +50052 -0
- package/dist/generated/ifc2x3/schema-registry.js.map +1 -0
- package/dist/generated/ifc4x3/schema-registry.d.ts +50 -0
- package/dist/generated/ifc4x3/schema-registry.d.ts.map +1 -0
- package/dist/generated/ifc4x3/schema-registry.js +71299 -0
- package/dist/generated/ifc4x3/schema-registry.js.map +1 -0
- package/dist/generated/schema-registry-by-version.d.ts +61 -0
- package/dist/generated/schema-registry-by-version.d.ts.map +1 -0
- package/dist/generated/schema-registry-by-version.js +86 -0
- package/dist/generated/schema-registry-by-version.js.map +1 -0
- package/dist/georef-extractor.js +5 -5
- package/dist/georef-extractor.js.map +1 -1
- package/dist/group-assignment-factor.d.ts +13 -0
- package/dist/group-assignment-factor.d.ts.map +1 -0
- package/dist/group-assignment-factor.js +30 -0
- package/dist/group-assignment-factor.js.map +1 -0
- package/dist/ifczip.d.ts +7 -1
- package/dist/ifczip.d.ts.map +1 -1
- package/dist/ifczip.js +80 -14
- package/dist/ifczip.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/on-demand-extractors.d.ts +1 -0
- package/dist/on-demand-extractors.d.ts.map +1 -1
- package/dist/on-demand-extractors.js +2 -1
- package/dist/on-demand-extractors.js.map +1 -1
- package/dist/property-value-parser.d.ts +10 -0
- package/dist/property-value-parser.d.ts.map +1 -1
- package/dist/property-value-parser.js +40 -1
- package/dist/property-value-parser.js.map +1 -1
- package/dist/scan-entities-balanced.d.ts.map +1 -1
- package/dist/scan-entities-balanced.js +11 -6
- package/dist/scan-entities-balanced.js.map +1 -1
- package/dist/scan-worker-lexing.d.ts +14 -0
- package/dist/scan-worker-lexing.d.ts.map +1 -0
- package/dist/scan-worker-lexing.js +106 -0
- package/dist/scan-worker-lexing.js.map +1 -0
- package/dist/scan-worker-source.d.ts +1 -1
- package/dist/scan-worker-source.d.ts.map +1 -1
- package/dist/scan-worker-source.js +64 -59
- package/dist/scan-worker-source.js.map +1 -1
- package/dist/schedule-extractor.d.ts +2 -80
- package/dist/schedule-extractor.d.ts.map +1 -1
- package/dist/schedule-extractor.js +100 -225
- package/dist/schedule-extractor.js.map +1 -1
- package/dist/schedule-serializer-builders.d.ts +28 -0
- package/dist/schedule-serializer-builders.d.ts.map +1 -0
- package/dist/schedule-serializer-builders.js +163 -0
- package/dist/schedule-serializer-builders.js.map +1 -0
- package/dist/schedule-serializer.d.ts +6 -0
- package/dist/schedule-serializer.d.ts.map +1 -1
- package/dist/schedule-serializer.js +26 -165
- package/dist/schedule-serializer.js.map +1 -1
- package/dist/schedule-types.d.ts +211 -0
- package/dist/schedule-types.d.ts.map +1 -0
- package/dist/schedule-types.js +221 -0
- package/dist/schedule-types.js.map +1 -0
- package/dist/spatial-hierarchy-ambiguity.d.ts +39 -0
- package/dist/spatial-hierarchy-ambiguity.d.ts.map +1 -0
- package/dist/spatial-hierarchy-ambiguity.js +25 -0
- package/dist/spatial-hierarchy-ambiguity.js.map +1 -0
- package/dist/spatial-hierarchy-attributes.d.ts +54 -0
- package/dist/spatial-hierarchy-attributes.d.ts.map +1 -0
- package/dist/spatial-hierarchy-attributes.js +145 -0
- package/dist/spatial-hierarchy-attributes.js.map +1 -0
- package/dist/spatial-hierarchy-builder.d.ts +0 -30
- package/dist/spatial-hierarchy-builder.d.ts.map +1 -1
- package/dist/spatial-hierarchy-builder.js +45 -167
- package/dist/spatial-hierarchy-builder.js.map +1 -1
- package/dist/spatial-hierarchy-canonical-parent.d.ts +52 -2
- package/dist/spatial-hierarchy-canonical-parent.d.ts.map +1 -1
- package/dist/spatial-hierarchy-canonical-parent.js +153 -4
- package/dist/spatial-hierarchy-canonical-parent.js.map +1 -1
- package/dist/step-lexing.d.ts +1 -1
- package/dist/step-lexing.d.ts.map +1 -1
- package/dist/step-lexing.js +1 -56
- package/dist/step-lexing.js.map +1 -1
- package/dist/step-record-boundary.d.ts +28 -0
- package/dist/step-record-boundary.d.ts.map +1 -0
- package/dist/step-record-boundary.js +133 -0
- package/dist/step-record-boundary.js.map +1 -0
- package/dist/step-record-boundary.vectors.d.ts +102 -0
- package/dist/step-record-boundary.vectors.d.ts.map +1 -0
- package/dist/step-record-boundary.vectors.js +131 -0
- package/dist/step-record-boundary.vectors.js.map +1 -0
- package/dist/structural-extractor.d.ts +9 -0
- package/dist/structural-extractor.d.ts.map +1 -0
- package/dist/structural-extractor.js +310 -0
- package/dist/structural-extractor.js.map +1 -0
- package/dist/structural-load-extractor.d.ts +147 -0
- package/dist/structural-load-extractor.d.ts.map +1 -0
- package/dist/structural-load-extractor.js +178 -0
- package/dist/structural-load-extractor.js.map +1 -0
- package/dist/structural-step-values.d.ts +51 -0
- package/dist/structural-step-values.d.ts.map +1 -0
- package/dist/structural-step-values.js +109 -0
- package/dist/structural-step-values.js.map +1 -0
- package/dist/structural-types.d.ts +145 -0
- package/dist/structural-types.d.ts.map +1 -0
- package/dist/structural-types.js +5 -0
- package/dist/structural-types.js.map +1 -0
- package/dist/tokenizer.d.ts +11 -5
- package/dist/tokenizer.d.ts.map +1 -1
- package/dist/tokenizer.js +78 -21
- package/dist/tokenizer.js.map +1 -1
- package/dist/wasm-init-retry.d.ts +6 -42
- package/dist/wasm-init-retry.d.ts.map +1 -1
- package/dist/wasm-init-retry.js +6 -99
- package/dist/wasm-init-retry.js.map +1 -1
- package/dist/wasm-panic-forward.d.ts +7 -63
- package/dist/wasm-panic-forward.d.ts.map +1 -1
- package/dist/wasm-panic-forward.js +7 -100
- package/dist/wasm-panic-forward.js.map +1 -1
- package/package.json +5 -4
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
*/
|
|
6
6
|
/** Exported for direct testing (run inside a mock `self`); the runtime path
|
|
7
7
|
* wraps it in a Blob worker in `scan-worker-inline.ts`. */
|
|
8
|
-
export declare const WORKER_CODE = "\n'use strict';\nself.onmessage = function(e) {\n var buf = new Uint8Array(e.data);\n var len = buf.length;\n var pos = 0;\n var line = 1;\n\n // Pre-allocate result array (estimate ~13,500 entities per MB)\n var estimatedCount = Math.max((len / 1024 / 1024) * 13500, 1000) | 0;\n // Pack results into typed arrays for fast transfer. Uint32Array for the ids:\n // that is the express-id storage contract every consumer of this scan holds\n // to (CompactEntityIndex, the entity/property/quantity tables, the wasm\n // boundary, Rust's ColumnarIndex), so the guard below refuses anything wider\n // rather than carrying it one buffer further and truncating downstream\n // (#3395). The worker runs from a Blob URL and cannot import at runtime, so\n // the bound below is interpolated from express-id.ts when this template is\n // evaluated -- one home for the number, not a copy that can drift.\n // Whether a STEP comment opens at p.\n function opensCommentAt(p) {\n return p + 1 < len && buf[p] === 0x2F && buf[p + 1] === 0x2A;\n }\n\n // Index just past the '*/' closing the comment at p, or -1 when it never\n // closes. Counts the newlines it crosses so line numbers stay in step.\n //\n // Kept behaviourally identical to skipComment/skipTrivia in step-lexing.ts,\n // which this cannot import: the worker source is a string, so this copy of\n // the rule has to live here. Comments do not nest, per ISO 10303-21.\n function skipCommentAt(p) {\n var q = p + 2;\n while (q + 1 < len) {\n if (buf[q] === 0x2A && buf[q + 1] === 0x2F) return q + 2;\n if (buf[q] === 0x0A) line++;\n q++;\n }\n return -1;\n }\n\n // Skip whitespace, comments, and any run of the two -- 10303-21 allows a\n // comment wherever whitespace is allowed, INCLUDING inside a record.\n // Returns -1 when a comment opens and never closes: everything from there on\n // is inside it, so there is nothing left to find.\n //\n // The whitespace byte set (space, tab, CR, LF, form feed, vertical tab) is\n // kept byte-for-byte in sync with isSpaceByte in step-lexing.ts and its\n // three inline twins in tokenizer.ts's scanEntitiesFast -- this file is a\n // string because a Blob worker cannot import at runtime, not a reason for\n // the rule itself to drift.\n function skipTriviaAt(p) {\n for (;;) {\n while (p < len) {\n var t = buf[p];\n if (t === 0x20 || t === 0x09 || t === 0x0D || t === 0x0C || t === 0x0B) { p++; }\n else if (t === 0x0A) { line++; p++; }\n else break;\n }\n if (!opensCommentAt(p)) return p;\n var e = skipCommentAt(p);\n if (e < 0) return -1;\n p = e;\n }\n }\n\n var ids = new Uint32Array(estimatedCount);\n var offsets = new Uint32Array(estimatedCount);\n var lengths = new Uint32Array(estimatedCount);\n var lines = new Uint32Array(estimatedCount);\n // Type names stored separately (strings)\n var types = new Array(estimatedCount);\n var count = 0;\n // Records refused by the express-id bound, reported back to the caller.\n var oversizedIds = 0;\n // 0 or 1, never a count of how many: whether this scan stopped early on an\n // unclosed string, an unclosed comment, or a declaration cut off before its\n // own '(' -- set once, by the single post-loop check at the bottom of this\n // function. Reported back to the caller. Mirrors tokenizer.ts's\n // scanEntitiesFast contract exactly, including the 0-or-1 shape.\n var malformedRecords = 0;\n // Set on the way to that post-loop check, not counted at each site:\n // 'stopped' for an unclosed string or comment that ran to end of buffer\n // with nothing left to find, 'declOpen' while a #id=TYPE( header is\n // incomplete. 'declOpen' stays armed ONLY when the reason for abandoning\n // is running out of buffer (pos >= len); a mismatch with buffer still\n // left (bad byte, oversized id) clears it, because the scan resumes\n // byte-by-byte from wherever it gave up, and a #ref token inside the\n // abandoned record's own argument list reads as a fresh, equally\n // incomplete attempt that must not report \"cut off\" just because\n // nothing later happens to clear it.\n var stopped = false;\n var declOpen = false;\n\n // Type name cache (IFC files have ~776 unique types across millions of entities)\n var typeCache = new Map();\n\n function growArrays() {\n var newSize = (count * 2) | 0;\n var newIds = new Uint32Array(newSize);\n newIds.set(ids);\n ids = newIds;\n var newOffsets = new Uint32Array(newSize);\n newOffsets.set(offsets);\n offsets = newOffsets;\n var newLengths = new Uint32Array(newSize);\n newLengths.set(lengths);\n lengths = newLengths;\n var newLines = new Uint32Array(newSize);\n newLines.set(lines);\n lines = newLines;\n types.length = newSize;\n }\n\n while (pos < len) {\n var ch = buf[pos];\n\n if (ch === 0x23) { // '#'\n var startOffset = pos;\n var startLine = line;\n pos++;\n\n // Read express ID\n var expressId = 0;\n var hasDigits = false;\n while (pos < len) {\n var c = buf[pos];\n if (c >= 0x30 && c <= 0x39) {\n expressId = expressId * 10 + (c - 0x30);\n hasDigits = true;\n pos++;\n } else {\n break;\n }\n }\n if (!hasDigits) continue;\n declOpen = true;\n\n // Whitespace AND comments: '#1 /* was #7 */ =' is a declaration. The\n // inline loop stays for the common case; skipTriviaAt runs only once a\n // comment actually opens. Mirrors tokenizer.ts's scanEntitiesFast.\n while (pos < len) {\n var c2 = buf[pos];\n if (c2 === 0x20 || c2 === 0x09 || c2 === 0x0D || c2 === 0x0C || c2 === 0x0B) { pos++; }\n else if (c2 === 0x0A) { line++; pos++; }\n else break;\n }\n if (opensCommentAt(pos)) { pos = skipTriviaAt(pos); if (pos < 0) { stopped = true; break; } }\n\n // Check for '='. A byte that is not '=' with buffer left to scan is\n // not a truncation -- clear declOpen so a reference token inside a\n // LATER abandoned record's argument list (see the oversized-id note\n // below) cannot leave it stuck armed with nothing left to clear it.\n if (pos >= len) continue;\n if (buf[pos] !== 0x3D) { declOpen = false; continue; }\n pos++;\n\n // Express-id bound, identical to StepTokenizer.scanEntitiesFast -- this\n // worker is that scan's twin and must reject the same records, and count\n // the same ones, or which scan path ran decides both whether an id\n // collides with another and what the user is told was dropped. The\n // single '>' subsumes a safe-integer check: a digit run accumulated as a\n // double is non-negative and integral, and every value past 2^32 --\n // including one past 2^53, where two distinct ids collide onto one\n // double -- fails it. Tested only after '=' has matched, because that is\n // the DECLARATION shape Rust's EntityScanner validates before refusing:\n // the 'continue' below resumes inside the refused record's argument\n // list, so an oversized '#ref' in there arrives here too and would be\n // counted as a second dropped record. Count the refusal; a record that\n // vanishes without a trace is the same defect wearing a different hat.\n if (expressId > 4294967295) { oversizedIds++; declOpen = false; continue; }\n\n // Skip whitespace and comments\n while (pos < len) {\n var c3 = buf[pos];\n if (c3 === 0x20 || c3 === 0x09 || c3 === 0x0D || c3 === 0x0C || c3 === 0x0B) { pos++; }\n else if (c3 === 0x0A) { line++; pos++; }\n else break;\n }\n if (opensCommentAt(pos)) { pos = skipTriviaAt(pos); if (pos < 0) { stopped = true; break; } }\n\n // Read type name. Must start A-Z; a bad start byte with buffer left\n // clears declOpen for the same reason as the '=' check.\n var typeStart = pos;\n if (pos >= len) continue;\n if (buf[pos] < 0x41 || buf[pos] > 0x5A) { declOpen = false; continue; }\n\n while (pos < len) {\n var c4 = buf[pos];\n if ((c4 >= 0x41 && c4 <= 0x5A) || (c4 >= 0x61 && c4 <= 0x7A) ||\n (c4 >= 0x30 && c4 <= 0x39) || c4 === 0x5F) {\n pos++;\n } else {\n break;\n }\n }\n if (pos === typeStart) continue;\n\n // Cache type name \u2014 use length + hash compound key and verify the actual\n // bytes on a hit. Length alone can't disambiguate a 32-bit hash collision\n // (e.g. \"Aa\"/\"BB\"), so without the byte compare a crafted/unlucky file\n // could have one type silently misread as another. Mirrors tokenizer.ts.\n var typeLen = pos - typeStart;\n var typeHash = typeLen;\n for (var i = typeStart; i < pos; i++) {\n typeHash = (typeHash * 31 + buf[i]) | 0;\n }\n var cacheKey = typeLen + ':' + typeHash;\n var typeName = typeCache.get(cacheKey);\n var cacheHitMatches = false;\n if (typeName !== undefined && typeName.length === typeLen) {\n cacheHitMatches = true;\n for (var v = 0; v < typeLen; v++) {\n if (typeName.charCodeAt(v) !== buf[typeStart + v]) {\n cacheHitMatches = false;\n break;\n }\n }\n }\n if (typeName === undefined || !cacheHitMatches) {\n typeName = String.fromCharCode.apply(null, buf.subarray(typeStart, pos));\n typeCache.set(cacheKey, typeName);\n }\n\n // Skip whitespace and comments\n while (pos < len) {\n var c5 = buf[pos];\n if (c5 === 0x20 || c5 === 0x09 || c5 === 0x0D || c5 === 0x0C || c5 === 0x0B) { pos++; }\n else if (c5 === 0x0A) { line++; pos++; }\n else break;\n }\n if (opensCommentAt(pos)) { pos = skipTriviaAt(pos); if (pos < 0) { stopped = true; break; } }\n\n // Check for '('. Same EOF-vs-mismatch split as '=' and the type name.\n if (pos >= len) continue;\n if (buf[pos] !== 0x28) { declOpen = false; continue; }\n declOpen = false; // Header complete: '(' found.\n\n // Skip to semicolon (handling strings)\n var inString = false;\n var foundTerminator = false;\n while (pos < len) {\n var c6 = buf[pos];\n if (c6 === 0x27) { // quote\n if (inString && pos + 1 < len && buf[pos + 1] === 0x27) {\n pos += 2;\n continue;\n }\n inString = !inString;\n } else if (c6 === 0x2F && !inString && opensCommentAt(pos)) {\n // The ';' that ends a record can be preceded by a comment holding\n // its own ';'. Take the comment whole, which also makes the quotes\n // and parens inside it text -- the other direction of the rule the\n // quote branch above gives for a '/*' inside a literal.\n var ce = skipCommentAt(pos);\n if (ce < 0) {\n // Unterminated: this record has no terminator, and neither has\n // anything after it. Drop it and stop.\n pos = len;\n break;\n }\n pos = ce;\n continue;\n } else if (c6 === 0x3B && !inString) { // semicolon\n var entityLength = pos - startOffset + 1;\n\n // Grow if needed\n if (count >= ids.length) growArrays();\n\n ids[count] = expressId;\n offsets[count] = startOffset;\n lengths[count] = entityLength;\n lines[count] = startLine;\n types[count] = typeName;\n count++;\n\n pos++;\n foundTerminator = true;\n break;\n } else if (c6 === 0x0A) {\n line++;\n }\n pos++;\n }\n\n // Ran off the end without an unquoted ';' -- usually an unescaped\n // quote left open, or the unterminated-comment break above (mirrors\n // tokenizer.ts's scanEntitiesFast). Not resynced: with no known\n // terminator, guessing a resume point risks fabricating entities from\n // misaligned bytes. Recorded in 'stopped', not incremented here -- see\n // the post-loop check below.\n if (!foundTerminator) { stopped = true; }\n } else if (ch === 0x0A) {\n line++;\n pos++;\n } else if (ch === 0x27) { // quote\n // Consume a string literal whole. HEADER records carry no '#', so this\n // loop walks them byte by byte, and a '/*' inside a description would\n // otherwise open a comment that never closes and take DATA with it.\n var sp = pos + 1;\n var closed = false;\n while (sp < len) {\n if (buf[sp] === 0x27) {\n if (sp + 1 < len && buf[sp + 1] === 0x27) { sp += 2; continue; }\n sp++;\n closed = true;\n break;\n }\n if (buf[sp] === 0x0A) { line++; }\n sp++;\n }\n pos = sp;\n // Ran off the end without a closing quote: everything from the open\n // quote to EOF was consumed looking for one, so nothing after it was\n // ever a candidate '#' -- the same \"no terminator\" shape as inside a\n // record, just outside one (a HEADER string, most often).\n if (!closed) { stopped = true; break; }\n } else if (opensCommentAt(pos)) {\n // Skip a comment region BETWEEN records. A record that is commented out\n // is still a well-formed #id = TYPE(...), so every check above accepts\n // it and only skipping the region rejects it.\n var cp = skipCommentAt(pos);\n if (cp < 0) {\n // Unterminated: everything to EOF is commented out.\n pos = len;\n stopped = true;\n break;\n }\n pos = cp;\n } else {\n pos++;\n }\n }\n\n // ONE post-loop check, not an increment at every exit site above: the scan\n // stopped early if it hit an explicit \"no terminator\" boundary ('stopped'),\n // or the last #id=TYPE( header was cut short before its own '(' was found\n // ('declOpen'). Always 0 or 1 -- the scan stops at the first one, so there\n // is nothing further to accumulate.\n if (stopped || declOpen) { malformedRecords = 1; }\n\n // Trim arrays once, reuse for both message and transfer list\n var needsTrim = ids.buffer.byteLength > count * 4;\n var trimmedIds = needsTrim ? ids.slice(0, count) : ids;\n var trimmedOffsets = needsTrim ? offsets.slice(0, count) : offsets;\n var trimmedLengths = needsTrim ? lengths.slice(0, count) : lengths;\n var trimmedLines = needsTrim ? lines.slice(0, count) : lines;\n self.postMessage({\n ids: trimmedIds.buffer,\n offsets: trimmedOffsets.buffer,\n lengths: trimmedLengths.buffer,\n lines: trimmedLines.buffer,\n types: types.slice(0, count),\n count: count,\n oversizedIds: oversizedIds,\n malformedRecords: malformedRecords,\n }, [\n trimmedIds.buffer,\n trimmedOffsets.buffer,\n trimmedLengths.buffer,\n trimmedLines.buffer,\n ]);\n};\n";
|
|
8
|
+
export declare const WORKER_CODE = "\n'use strict';\nself.onmessage = function(e) {\n var buf = new Uint8Array(e.data);\n var len = buf.length;\n var pos = 0;\n var line = 1;\n\n // Pre-allocate result array (estimate ~13,500 entities per MB)\n var estimatedCount = Math.max((len / 1024 / 1024) * 13500, 1000) | 0;\n // Pack results into typed arrays for fast transfer. Uint32Array for the ids:\n // that is the express-id storage contract every consumer of this scan holds\n // to (CompactEntityIndex, the entity/property/quantity tables, the wasm\n // boundary, Rust's ColumnarIndex), so the guard below refuses anything wider\n // rather than carrying it one buffer further and truncating downstream\n // (#3395). The worker runs from a Blob URL and cannot import at runtime, so\n // the bound below is interpolated from express-id.ts when this template is\n // evaluated -- one home for the number, not a copy that can drift.\n\n // The STEP whitespace set: space, tab, CR, LF, form feed, vertical tab.\n // The matched half is the now-exported isSpaceByte in step-lexing.ts; a\n // member going missing from one copy is what #3733 was.\n function isSpaceByteAt(p) {\n var t = buf[p];\n return t === 0x20 || t === 0x09 || t === 0x0A || t === 0x0D || t === 0x0C || t === 0x0B;\n }\n\n // Whether a STEP comment opens at p.\n function opensCommentAt(p) {\n return p + 1 < len && buf[p] === 0x2F && buf[p + 1] === 0x2A;\n }\n\n // Index just past the '*/' closing the comment at p, or -1 when it never\n // closes. Counts the newlines it crosses so line numbers stay in step.\n //\n // Kept behaviourally identical to skipComment/skipTrivia in step-lexing.ts,\n // which this cannot import: the worker source is a string, so this copy of\n // the rule has to live here. Comments do not nest, per ISO 10303-21.\n function skipCommentAt(p) {\n var q = p + 2;\n while (q + 1 < len) {\n if (buf[q] === 0x2A && buf[q + 1] === 0x2F) return q + 2;\n if (buf[q] === 0x0A) line++;\n q++;\n }\n return -1;\n }\n\n // Skip whitespace, comments, and any run of the two -- 10303-21 allows a\n // comment wherever whitespace is allowed, INCLUDING inside a record.\n // Returns -1 when a comment opens and never closes: everything from there on\n // is inside it, so there is nothing left to find.\n //\n // The whitespace byte set (space, tab, CR, LF, form feed, vertical tab) is\n // kept byte-for-byte in sync with isSpaceByte in step-lexing.ts and its\n // three inline twins in tokenizer.ts's scanEntitiesFast -- this file is a\n // string because a Blob worker cannot import at runtime, not a reason for\n // the rule itself to drift.\n function skipTriviaAt(p) {\n for (;;) {\n while (p < len) {\n var t = buf[p];\n if (t === 0x20 || t === 0x09 || t === 0x0D || t === 0x0C || t === 0x0B) { p++; }\n else if (t === 0x0A) { line++; p++; }\n else break;\n }\n if (!opensCommentAt(p)) return p;\n var e = skipCommentAt(p);\n if (e < 0) return -1;\n p = e;\n }\n }\n\n // Byte length from startOffset through the ')' balancing the '(' at p, or a\n // CLASSIFIED failure: -1 unbalanced but readable, -2 a literal or comment\n // that never closed. The RECOVERY point for a record with no ';' of its own\n // (#4179), and the exact answer for whether a ';' is the record's own.\n // Mirrors findEntityLength in step-record-boundary.ts; a literal is jumped\n // whole and a comment after it, in that order, so a paren inside either is\n // text. A top-level '=' is the NEXT declaration's, so the walk stops there\n // and answers -1 rather than balancing across a record it has not read;\n // that stop is also what keeps a file of unbalanced records linear instead\n // of quadratic (#4573; the argument is on findEntityLength). NOTE:\n // skipCommentAt advances the line counter, so a caller that re-walks the\n // record must save and restore it.\n function findEntityLengthAt(p, startOffset) {\n var d = 0;\n while (p < len) {\n var b = buf[p];\n if (b === 0x27) {\n p++;\n for (;;) {\n if (p >= len) return -2;\n if (buf[p] === 0x27) { if (buf[p + 1] === 0x27) { p += 2; continue; } p++; break; }\n p++;\n }\n } else if (opensCommentAt(p)) {\n var q = skipCommentAt(p);\n if (q < 0) return -2;\n p = q;\n } else if (b === 0x3D) { return -1; }\n else if (b === 0x28) { d++; p++; }\n else if (b === 0x29) { if (d === 0) return -1; d--; p++; if (d === 0) return p - startOffset; }\n else { p++; }\n }\n return -1;\n }\n\n\n var ids = new Uint32Array(estimatedCount);\n var offsets = new Uint32Array(estimatedCount);\n var lengths = new Uint32Array(estimatedCount);\n var lines = new Uint32Array(estimatedCount);\n // Type names stored separately (strings)\n var types = new Array(estimatedCount);\n var count = 0;\n // Records refused by the express-id bound, reported back to the caller.\n var oversizedIds = 0;\n // 0 or 1, never a count of how many: whether this scan stopped early on an\n // unclosed string, an unclosed comment, or a declaration cut off before its\n // own '(' -- set once, by the single post-loop check at the bottom of this\n // function. Reported back to the caller. Mirrors tokenizer.ts's\n // scanEntitiesFast contract exactly, including the 0-or-1 shape.\n var malformedRecords = 0;\n // Set on the way to that post-loop check, not counted at each site:\n // 'stopped' for an unclosed string or comment that ran to end of buffer\n // with nothing left to find, 'declOpen' while a #id=TYPE( header is\n // incomplete. 'declOpen' stays armed ONLY when the reason for abandoning\n // is running out of buffer (pos >= len); a mismatch with buffer still\n // left (bad byte, oversized id) clears it, because the scan resumes\n // byte-by-byte from wherever it gave up, and a #ref token inside the\n // abandoned record's own argument list reads as a fresh, equally\n // incomplete attempt that must not report \"cut off\" just because\n // nothing later happens to clear it.\n var stopped = false;\n var declOpen = false;\n\n // Type name cache (IFC files have ~776 unique types across millions of entities)\n var typeCache = new Map();\n\n function growArrays() {\n var newSize = (count * 2) | 0;\n var newIds = new Uint32Array(newSize);\n newIds.set(ids);\n ids = newIds;\n var newOffsets = new Uint32Array(newSize);\n newOffsets.set(offsets);\n offsets = newOffsets;\n var newLengths = new Uint32Array(newSize);\n newLengths.set(lengths);\n lengths = newLengths;\n var newLines = new Uint32Array(newSize);\n newLines.set(lines);\n lines = newLines;\n types.length = newSize;\n }\n\n while (pos < len) {\n var ch = buf[pos];\n\n if (ch === 0x23) { // '#'\n var startOffset = pos;\n var startLine = line;\n pos++;\n\n // Read express ID\n var expressId = 0;\n var hasDigits = false;\n while (pos < len) {\n var c = buf[pos];\n if (c >= 0x30 && c <= 0x39) {\n expressId = expressId * 10 + (c - 0x30);\n hasDigits = true;\n pos++;\n } else {\n break;\n }\n }\n if (!hasDigits) continue;\n declOpen = true;\n\n // Whitespace AND comments: '#1 /* was #7 */ =' is a declaration. The\n // inline loop stays for the common case; skipTriviaAt runs only once a\n // comment actually opens. Mirrors tokenizer.ts's scanEntitiesFast.\n while (pos < len) {\n var c2 = buf[pos];\n if (c2 === 0x20 || c2 === 0x09 || c2 === 0x0D || c2 === 0x0C || c2 === 0x0B) { pos++; }\n else if (c2 === 0x0A) { line++; pos++; }\n else break;\n }\n if (opensCommentAt(pos)) { pos = skipTriviaAt(pos); if (pos < 0) { stopped = true; break; } }\n\n // Check for '='. A byte that is not '=' with buffer left to scan is\n // not a truncation -- clear declOpen so a reference token inside a\n // LATER abandoned record's argument list (see the oversized-id note\n // below) cannot leave it stuck armed with nothing left to clear it.\n if (pos >= len) continue;\n if (buf[pos] !== 0x3D) { declOpen = false; continue; }\n pos++;\n\n // Express-id bound, identical to StepTokenizer.scanEntitiesFast -- this\n // worker is that scan's twin and must reject the same records, and count\n // the same ones, or which scan path ran decides both whether an id\n // collides with another and what the user is told was dropped. The\n // single '>' subsumes a safe-integer check: a digit run accumulated as a\n // double is non-negative and integral, and every value past 2^32 --\n // including one past 2^53, where two distinct ids collide onto one\n // double -- fails it. Tested only after '=' has matched, because that is\n // the DECLARATION shape Rust's EntityScanner validates before refusing:\n // the 'continue' below resumes inside the refused record's argument\n // list, so an oversized '#ref' in there arrives here too and would be\n // counted as a second dropped record. Count the refusal; a record that\n // vanishes without a trace is the same defect wearing a different hat.\n if (expressId > 4294967295) { oversizedIds++; declOpen = false; continue; }\n\n // Skip whitespace and comments\n while (pos < len) {\n var c3 = buf[pos];\n if (c3 === 0x20 || c3 === 0x09 || c3 === 0x0D || c3 === 0x0C || c3 === 0x0B) { pos++; }\n else if (c3 === 0x0A) { line++; pos++; }\n else break;\n }\n if (opensCommentAt(pos)) { pos = skipTriviaAt(pos); if (pos < 0) { stopped = true; break; } }\n\n // Read type name. Must start A-Z; a bad start byte with buffer left\n // clears declOpen for the same reason as the '=' check.\n var typeStart = pos;\n if (pos >= len) continue;\n if (buf[pos] < 0x41 || buf[pos] > 0x5A) { declOpen = false; continue; }\n\n while (pos < len) {\n var c4 = buf[pos];\n if ((c4 >= 0x41 && c4 <= 0x5A) || (c4 >= 0x61 && c4 <= 0x7A) ||\n (c4 >= 0x30 && c4 <= 0x39) || c4 === 0x5F) {\n pos++;\n } else {\n break;\n }\n }\n if (pos === typeStart) continue;\n\n // Cache type name \u2014 use length + hash compound key and verify the actual\n // bytes on a hit. Length alone can't disambiguate a 32-bit hash collision\n // (e.g. \"Aa\"/\"BB\"), so without the byte compare a crafted/unlucky file\n // could have one type silently misread as another. Mirrors tokenizer.ts.\n var typeLen = pos - typeStart;\n var typeHash = typeLen;\n for (var i = typeStart; i < pos; i++) {\n typeHash = (typeHash * 31 + buf[i]) | 0;\n }\n var cacheKey = typeLen + ':' + typeHash;\n var typeName = typeCache.get(cacheKey);\n var cacheHitMatches = false;\n if (typeName !== undefined && typeName.length === typeLen) {\n cacheHitMatches = true;\n for (var v = 0; v < typeLen; v++) {\n if (typeName.charCodeAt(v) !== buf[typeStart + v]) {\n cacheHitMatches = false;\n break;\n }\n }\n }\n if (typeName === undefined || !cacheHitMatches) {\n typeName = String.fromCharCode.apply(null, buf.subarray(typeStart, pos));\n typeCache.set(cacheKey, typeName);\n }\n\n // Skip whitespace and comments\n while (pos < len) {\n var c5 = buf[pos];\n if (c5 === 0x20 || c5 === 0x09 || c5 === 0x0D || c5 === 0x0C || c5 === 0x0B) { pos++; }\n else if (c5 === 0x0A) { line++; pos++; }\n else break;\n }\n if (opensCommentAt(pos)) { pos = skipTriviaAt(pos); if (pos < 0) { stopped = true; break; } }\n\n // Check for '('. Same EOF-vs-mismatch split as '=' and the type name.\n if (pos >= len) continue;\n if (buf[pos] !== 0x28) { declOpen = false; continue; }\n declOpen = false; // Header complete: '(' found.\n\n // Skip to semicolon (handling strings), bounded to THIS record's own\n // body so a record missing its ';' cannot latch onto a later one and\n // swallow what lies between (#4179): the ';' must be preceded, modulo\n // trivia, by the ')' closing the parameter list, and no '=' may come\n // before it outside a string or comment. On either failure the record is\n // DROPPED and the scan resumes at that ')' rather than abandoning the\n // file's tail. close_step_record in rust/core/src/parser/lexical.rs\n // argues both rules and the recovery; this is a hand-duplicated copy\n // because a Blob worker cannot import at runtime. Change them together.\n var parenPos = pos;\n var inString = false;\n var foundTerminator = false;\n // Memoised across the exact ';' check and the recovery below, which\n // would otherwise balance the same record twice. -3 = not computed;\n // -1 = unbalanced but readable; -2 = a literal/comment never closed.\n var recordClose = -3;\n while (pos < len) {\n var c6 = buf[pos];\n if (c6 === 0x27) { // quote\n if (inString && pos + 1 < len && buf[pos + 1] === 0x27) {\n pos += 2;\n continue;\n }\n inString = !inString;\n } else if (c6 === 0x2F && !inString && opensCommentAt(pos)) {\n // The ';' that ends a record can be preceded by a comment holding\n // its own ';'. Take the comment whole, which also makes the quotes\n // and parens inside it text -- the other direction of the rule the\n // quote branch above gives for a '/*' inside a literal.\n var ce = skipCommentAt(pos);\n if (ce < 0) break; // Unterminated: recovery below finds no ')'.\n pos = ce;\n continue;\n } else if (c6 === 0x3B && !inString) { // semicolon\n // ')' modulo whitespace settles it for every record a real file\n // holds. Anything else -- including the '/' of a trailing '*/',\n // which a backwards walk cannot see through -- goes to the cold,\n // exact balance-and-skip-trivia check.\n var w = pos;\n while (w > parenPos && isSpaceByteAt(w - 1)) w--;\n if (buf[w - 1] !== 0x29) {\n var savedBalLine = line;\n recordClose = findEntityLengthAt(parenPos, startOffset);\n line = savedBalLine;\n if (recordClose <= 0) break;\n recordClose += startOffset;\n var after = skipTriviaAt(recordClose);\n line = savedBalLine;\n if (after < 0 || after !== pos) break;\n }\n var entityLength = pos - startOffset + 1;\n\n // Grow if needed\n if (count >= ids.length) growArrays();\n\n ids[count] = expressId;\n offsets[count] = startOffset;\n lengths[count] = entityLength;\n lines[count] = startLine;\n types[count] = typeName;\n count++;\n\n pos++;\n foundTerminator = true;\n break;\n } else if (c6 === 0x3D && !inString) {\n break; // '=': the NEXT declaration already started.\n } else if (c6 === 0x0A) {\n line++;\n }\n pos++;\n }\n\n // No ';' of this record's own. EVERY such exit lands here, so the\n // recovery lives here once rather than at each break -- mirrors\n // tokenizer.ts's scanEntitiesFast. Resume at the ')' balancing this\n // record's own '(' when there is one, dropping just this record;\n // otherwise run to len, ending the scan un-resynced rather than guessing\n // a resume point from misaligned bytes. The balance walk stops at the\n // next declaration's '=' (#4573), so a refusal costs this record's\n // bytes, never a re-walk of the remainder per refusal.\n if (!foundTerminator) {\n stopped = true;\n if (recordClose === -3) {\n var savedRecLine = line;\n recordClose = findEntityLengthAt(parenPos, startOffset);\n line = savedRecLine;\n if (recordClose > 0) recordClose += startOffset;\n }\n if (recordClose > 0) {\n pos = recordClose;\n line = startLine;\n for (var q = startOffset; q < pos; q++) if (buf[q] === 0x0A) line++;\n } else if (recordClose === -1) {\n // No ')' before the next '=' (or EOF), bytes after readable:\n // re-hunt from past this record's '#'.\n pos = startOffset + 1;\n line = startLine;\n } else {\n pos = len; // Nothing to resume from (#3695).\n }\n }\n } else if (ch === 0x0A) {\n line++;\n pos++;\n } else if (ch === 0x27) { // quote\n // Consume a string literal whole. HEADER records carry no '#', so this\n // loop walks them byte by byte, and a '/*' inside a description would\n // otherwise open a comment that never closes and take DATA with it.\n var sp = pos + 1;\n var closed = false;\n while (sp < len) {\n if (buf[sp] === 0x27) {\n if (sp + 1 < len && buf[sp + 1] === 0x27) { sp += 2; continue; }\n sp++;\n closed = true;\n break;\n }\n if (buf[sp] === 0x0A) { line++; }\n sp++;\n }\n pos = sp;\n // Ran off the end without a closing quote: everything from the open\n // quote to EOF was consumed looking for one, so nothing after it was\n // ever a candidate '#' -- the same \"no terminator\" shape as inside a\n // record, just outside one (a HEADER string, most often).\n if (!closed) { stopped = true; break; }\n } else if (opensCommentAt(pos)) {\n // Skip a comment region BETWEEN records. A record that is commented out\n // is still a well-formed #id = TYPE(...), so every check above accepts\n // it and only skipping the region rejects it.\n var cp = skipCommentAt(pos);\n if (cp < 0) {\n // Unterminated: everything to EOF is commented out.\n pos = len;\n stopped = true;\n break;\n }\n pos = cp;\n } else {\n pos++;\n }\n }\n\n // ONE post-loop check, not an increment at every exit site above: the scan\n // stopped early if it hit an explicit \"no terminator\" boundary ('stopped'),\n // or the last #id=TYPE( header was cut short before its own '(' was found\n // ('declOpen'). Always 0 or 1 -- the scan stops at the first one, so there\n // is nothing further to accumulate.\n if (stopped || declOpen) { malformedRecords = 1; }\n\n // Trim arrays once, reuse for both message and transfer list\n var needsTrim = ids.buffer.byteLength > count * 4;\n var trimmedIds = needsTrim ? ids.slice(0, count) : ids;\n var trimmedOffsets = needsTrim ? offsets.slice(0, count) : offsets;\n var trimmedLengths = needsTrim ? lengths.slice(0, count) : lengths;\n var trimmedLines = needsTrim ? lines.slice(0, count) : lines;\n self.postMessage({\n ids: trimmedIds.buffer,\n offsets: trimmedOffsets.buffer,\n lengths: trimmedLengths.buffer,\n lines: trimmedLines.buffer,\n types: types.slice(0, count),\n count: count,\n oversizedIds: oversizedIds,\n malformedRecords: malformedRecords,\n }, [\n trimmedIds.buffer,\n trimmedOffsets.buffer,\n trimmedLengths.buffer,\n trimmedLines.buffer,\n ]);\n};\n";
|
|
9
9
|
//# sourceMappingURL=scan-worker-source.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan-worker-source.d.ts","sourceRoot":"","sources":["../src/scan-worker-source.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scan-worker-source.d.ts","sourceRoot":"","sources":["../src/scan-worker-source.ts"],"names":[],"mappings":"AAiBA;;;;GAIG;AACH;4DAC4D;AAC5D,eAAO,MAAM,WAAW,4lmBA6WvB,CAAC"}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* function each mirrors.
|
|
12
12
|
*/
|
|
13
13
|
import { MAX_EXPRESS_ID } from './express-id.js';
|
|
14
|
+
import { WORKER_LEXING } from './scan-worker-lexing.js';
|
|
14
15
|
/**
|
|
15
16
|
* Self-contained entity scanner code (runs inside Web Worker).
|
|
16
17
|
* This is the same algorithm as StepTokenizer.scanEntitiesFast() but
|
|
@@ -36,51 +37,7 @@ self.onmessage = function(e) {
|
|
|
36
37
|
// (#3395). The worker runs from a Blob URL and cannot import at runtime, so
|
|
37
38
|
// the bound below is interpolated from express-id.ts when this template is
|
|
38
39
|
// evaluated -- one home for the number, not a copy that can drift.
|
|
39
|
-
|
|
40
|
-
function opensCommentAt(p) {
|
|
41
|
-
return p + 1 < len && buf[p] === 0x2F && buf[p + 1] === 0x2A;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Index just past the '*/' closing the comment at p, or -1 when it never
|
|
45
|
-
// closes. Counts the newlines it crosses so line numbers stay in step.
|
|
46
|
-
//
|
|
47
|
-
// Kept behaviourally identical to skipComment/skipTrivia in step-lexing.ts,
|
|
48
|
-
// which this cannot import: the worker source is a string, so this copy of
|
|
49
|
-
// the rule has to live here. Comments do not nest, per ISO 10303-21.
|
|
50
|
-
function skipCommentAt(p) {
|
|
51
|
-
var q = p + 2;
|
|
52
|
-
while (q + 1 < len) {
|
|
53
|
-
if (buf[q] === 0x2A && buf[q + 1] === 0x2F) return q + 2;
|
|
54
|
-
if (buf[q] === 0x0A) line++;
|
|
55
|
-
q++;
|
|
56
|
-
}
|
|
57
|
-
return -1;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Skip whitespace, comments, and any run of the two -- 10303-21 allows a
|
|
61
|
-
// comment wherever whitespace is allowed, INCLUDING inside a record.
|
|
62
|
-
// Returns -1 when a comment opens and never closes: everything from there on
|
|
63
|
-
// is inside it, so there is nothing left to find.
|
|
64
|
-
//
|
|
65
|
-
// The whitespace byte set (space, tab, CR, LF, form feed, vertical tab) is
|
|
66
|
-
// kept byte-for-byte in sync with isSpaceByte in step-lexing.ts and its
|
|
67
|
-
// three inline twins in tokenizer.ts's scanEntitiesFast -- this file is a
|
|
68
|
-
// string because a Blob worker cannot import at runtime, not a reason for
|
|
69
|
-
// the rule itself to drift.
|
|
70
|
-
function skipTriviaAt(p) {
|
|
71
|
-
for (;;) {
|
|
72
|
-
while (p < len) {
|
|
73
|
-
var t = buf[p];
|
|
74
|
-
if (t === 0x20 || t === 0x09 || t === 0x0D || t === 0x0C || t === 0x0B) { p++; }
|
|
75
|
-
else if (t === 0x0A) { line++; p++; }
|
|
76
|
-
else break;
|
|
77
|
-
}
|
|
78
|
-
if (!opensCommentAt(p)) return p;
|
|
79
|
-
var e = skipCommentAt(p);
|
|
80
|
-
if (e < 0) return -1;
|
|
81
|
-
p = e;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
40
|
+
${WORKER_LEXING}
|
|
84
41
|
|
|
85
42
|
var ids = new Uint32Array(estimatedCount);
|
|
86
43
|
var offsets = new Uint32Array(estimatedCount);
|
|
@@ -254,9 +211,22 @@ self.onmessage = function(e) {
|
|
|
254
211
|
if (buf[pos] !== 0x28) { declOpen = false; continue; }
|
|
255
212
|
declOpen = false; // Header complete: '(' found.
|
|
256
213
|
|
|
257
|
-
// Skip to semicolon (handling strings)
|
|
214
|
+
// Skip to semicolon (handling strings), bounded to THIS record's own
|
|
215
|
+
// body so a record missing its ';' cannot latch onto a later one and
|
|
216
|
+
// swallow what lies between (#4179): the ';' must be preceded, modulo
|
|
217
|
+
// trivia, by the ')' closing the parameter list, and no '=' may come
|
|
218
|
+
// before it outside a string or comment. On either failure the record is
|
|
219
|
+
// DROPPED and the scan resumes at that ')' rather than abandoning the
|
|
220
|
+
// file's tail. close_step_record in rust/core/src/parser/lexical.rs
|
|
221
|
+
// argues both rules and the recovery; this is a hand-duplicated copy
|
|
222
|
+
// because a Blob worker cannot import at runtime. Change them together.
|
|
223
|
+
var parenPos = pos;
|
|
258
224
|
var inString = false;
|
|
259
225
|
var foundTerminator = false;
|
|
226
|
+
// Memoised across the exact ';' check and the recovery below, which
|
|
227
|
+
// would otherwise balance the same record twice. -3 = not computed;
|
|
228
|
+
// -1 = unbalanced but readable; -2 = a literal/comment never closed.
|
|
229
|
+
var recordClose = -3;
|
|
260
230
|
while (pos < len) {
|
|
261
231
|
var c6 = buf[pos];
|
|
262
232
|
if (c6 === 0x27) { // quote
|
|
@@ -271,15 +241,26 @@ self.onmessage = function(e) {
|
|
|
271
241
|
// and parens inside it text -- the other direction of the rule the
|
|
272
242
|
// quote branch above gives for a '/*' inside a literal.
|
|
273
243
|
var ce = skipCommentAt(pos);
|
|
274
|
-
if (ce < 0)
|
|
275
|
-
// Unterminated: this record has no terminator, and neither has
|
|
276
|
-
// anything after it. Drop it and stop.
|
|
277
|
-
pos = len;
|
|
278
|
-
break;
|
|
279
|
-
}
|
|
244
|
+
if (ce < 0) break; // Unterminated: recovery below finds no ')'.
|
|
280
245
|
pos = ce;
|
|
281
246
|
continue;
|
|
282
247
|
} else if (c6 === 0x3B && !inString) { // semicolon
|
|
248
|
+
// ')' modulo whitespace settles it for every record a real file
|
|
249
|
+
// holds. Anything else -- including the '/' of a trailing '*/',
|
|
250
|
+
// which a backwards walk cannot see through -- goes to the cold,
|
|
251
|
+
// exact balance-and-skip-trivia check.
|
|
252
|
+
var w = pos;
|
|
253
|
+
while (w > parenPos && isSpaceByteAt(w - 1)) w--;
|
|
254
|
+
if (buf[w - 1] !== 0x29) {
|
|
255
|
+
var savedBalLine = line;
|
|
256
|
+
recordClose = findEntityLengthAt(parenPos, startOffset);
|
|
257
|
+
line = savedBalLine;
|
|
258
|
+
if (recordClose <= 0) break;
|
|
259
|
+
recordClose += startOffset;
|
|
260
|
+
var after = skipTriviaAt(recordClose);
|
|
261
|
+
line = savedBalLine;
|
|
262
|
+
if (after < 0 || after !== pos) break;
|
|
263
|
+
}
|
|
283
264
|
var entityLength = pos - startOffset + 1;
|
|
284
265
|
|
|
285
266
|
// Grow if needed
|
|
@@ -295,19 +276,43 @@ self.onmessage = function(e) {
|
|
|
295
276
|
pos++;
|
|
296
277
|
foundTerminator = true;
|
|
297
278
|
break;
|
|
279
|
+
} else if (c6 === 0x3D && !inString) {
|
|
280
|
+
break; // '=': the NEXT declaration already started.
|
|
298
281
|
} else if (c6 === 0x0A) {
|
|
299
282
|
line++;
|
|
300
283
|
}
|
|
301
284
|
pos++;
|
|
302
285
|
}
|
|
303
286
|
|
|
304
|
-
//
|
|
305
|
-
//
|
|
306
|
-
// tokenizer.ts's scanEntitiesFast
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
//
|
|
310
|
-
|
|
287
|
+
// No ';' of this record's own. EVERY such exit lands here, so the
|
|
288
|
+
// recovery lives here once rather than at each break -- mirrors
|
|
289
|
+
// tokenizer.ts's scanEntitiesFast. Resume at the ')' balancing this
|
|
290
|
+
// record's own '(' when there is one, dropping just this record;
|
|
291
|
+
// otherwise run to len, ending the scan un-resynced rather than guessing
|
|
292
|
+
// a resume point from misaligned bytes. The balance walk stops at the
|
|
293
|
+
// next declaration's '=' (#4573), so a refusal costs this record's
|
|
294
|
+
// bytes, never a re-walk of the remainder per refusal.
|
|
295
|
+
if (!foundTerminator) {
|
|
296
|
+
stopped = true;
|
|
297
|
+
if (recordClose === -3) {
|
|
298
|
+
var savedRecLine = line;
|
|
299
|
+
recordClose = findEntityLengthAt(parenPos, startOffset);
|
|
300
|
+
line = savedRecLine;
|
|
301
|
+
if (recordClose > 0) recordClose += startOffset;
|
|
302
|
+
}
|
|
303
|
+
if (recordClose > 0) {
|
|
304
|
+
pos = recordClose;
|
|
305
|
+
line = startLine;
|
|
306
|
+
for (var q = startOffset; q < pos; q++) if (buf[q] === 0x0A) line++;
|
|
307
|
+
} else if (recordClose === -1) {
|
|
308
|
+
// No ')' before the next '=' (or EOF), bytes after readable:
|
|
309
|
+
// re-hunt from past this record's '#'.
|
|
310
|
+
pos = startOffset + 1;
|
|
311
|
+
line = startLine;
|
|
312
|
+
} else {
|
|
313
|
+
pos = len; // Nothing to resume from (#3695).
|
|
314
|
+
}
|
|
315
|
+
}
|
|
311
316
|
} else if (ch === 0x0A) {
|
|
312
317
|
line++;
|
|
313
318
|
pos++;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan-worker-source.js","sourceRoot":"","sources":["../src/scan-worker-source.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;GAQG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"scan-worker-source.js","sourceRoot":"","sources":["../src/scan-worker-source.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;GAQG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD;;;;GAIG;AACH;4DAC4D;AAC5D,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;EAkBzB,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA0GS,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiPrC,CAAC"}
|
|
@@ -1,86 +1,8 @@
|
|
|
1
1
|
import type { IfcDataStore } from './columnar-parser.js';
|
|
2
2
|
import { parseIso8601Duration } from './iso8601-duration.js';
|
|
3
|
+
import type { SequenceTypeEnum, TaskDurationType, ScheduleTaskTimeInfo, ScheduleTaskInfo, ScheduleSequenceInfo, WorkScheduleInfo, ScheduleExtraction } from './schedule-types.js';
|
|
3
4
|
export { parseIso8601Duration };
|
|
4
|
-
export type SequenceTypeEnum
|
|
5
|
-
export type TaskDurationType = 'WORKTIME' | 'ELAPSEDTIME' | 'NOTDEFINED';
|
|
6
|
-
export interface ScheduleTaskTimeInfo {
|
|
7
|
-
scheduleStart?: string;
|
|
8
|
-
scheduleFinish?: string;
|
|
9
|
-
scheduleDuration?: string;
|
|
10
|
-
actualStart?: string;
|
|
11
|
-
actualFinish?: string;
|
|
12
|
-
actualDuration?: string;
|
|
13
|
-
earlyStart?: string;
|
|
14
|
-
earlyFinish?: string;
|
|
15
|
-
lateStart?: string;
|
|
16
|
-
lateFinish?: string;
|
|
17
|
-
freeFloat?: string;
|
|
18
|
-
totalFloat?: string;
|
|
19
|
-
remainingTime?: string;
|
|
20
|
-
durationType?: TaskDurationType;
|
|
21
|
-
statusTime?: string;
|
|
22
|
-
isCritical?: boolean;
|
|
23
|
-
completion?: number;
|
|
24
|
-
}
|
|
25
|
-
export interface ScheduleTaskInfo {
|
|
26
|
-
expressId: number;
|
|
27
|
-
globalId: string;
|
|
28
|
-
name: string;
|
|
29
|
-
description?: string;
|
|
30
|
-
objectType?: string;
|
|
31
|
-
identification?: string;
|
|
32
|
-
longDescription?: string;
|
|
33
|
-
status?: string;
|
|
34
|
-
workMethod?: string;
|
|
35
|
-
isMilestone: boolean;
|
|
36
|
-
priority?: number;
|
|
37
|
-
predefinedType?: string;
|
|
38
|
-
taskTime?: ScheduleTaskTimeInfo;
|
|
39
|
-
/** Parent task globalId (from IfcRelNests where this task is in RelatedObjects). */
|
|
40
|
-
parentGlobalId?: string;
|
|
41
|
-
/** Child task globalIds (from IfcRelNests where this task is RelatingObject). */
|
|
42
|
-
childGlobalIds: string[];
|
|
43
|
-
/** expressIds of products assigned to this task via IfcRelAssignsToProcess. */
|
|
44
|
-
productExpressIds: number[];
|
|
45
|
-
/** globalIds of the same products (aligned with productExpressIds by index). */
|
|
46
|
-
productGlobalIds: string[];
|
|
47
|
-
/** WorkSchedule globalIds that control this task via IfcRelAssignsToControl. */
|
|
48
|
-
controllingScheduleGlobalIds: string[];
|
|
49
|
-
}
|
|
50
|
-
export interface ScheduleSequenceInfo {
|
|
51
|
-
globalId: string;
|
|
52
|
-
relatingTaskGlobalId: string;
|
|
53
|
-
relatedTaskGlobalId: string;
|
|
54
|
-
sequenceType: SequenceTypeEnum;
|
|
55
|
-
userDefinedSequenceType?: string;
|
|
56
|
-
/** Lag value expressed in seconds if it resolves to an IfcDuration; otherwise undefined. */
|
|
57
|
-
timeLagSeconds?: number;
|
|
58
|
-
/** Original lag duration string (ISO 8601 like 'P1D'), if available. */
|
|
59
|
-
timeLagDuration?: string;
|
|
60
|
-
}
|
|
61
|
-
export interface WorkScheduleInfo {
|
|
62
|
-
expressId: number;
|
|
63
|
-
globalId: string;
|
|
64
|
-
kind: 'WorkSchedule' | 'WorkPlan';
|
|
65
|
-
name: string;
|
|
66
|
-
description?: string;
|
|
67
|
-
identification?: string;
|
|
68
|
-
creationDate?: string;
|
|
69
|
-
purpose?: string;
|
|
70
|
-
duration?: string;
|
|
71
|
-
startTime?: string;
|
|
72
|
-
finishTime?: string;
|
|
73
|
-
predefinedType?: string;
|
|
74
|
-
/** Root task globalIds directly assigned via IfcRelAssignsToControl. */
|
|
75
|
-
taskGlobalIds: string[];
|
|
76
|
-
}
|
|
77
|
-
export interface ScheduleExtraction {
|
|
78
|
-
workSchedules: WorkScheduleInfo[];
|
|
79
|
-
tasks: ScheduleTaskInfo[];
|
|
80
|
-
sequences: ScheduleSequenceInfo[];
|
|
81
|
-
/** True if we encountered any scheduling entity (useful for empty-state UI). */
|
|
82
|
-
hasSchedule: boolean;
|
|
83
|
-
}
|
|
5
|
+
export type { SequenceTypeEnum, TaskDurationType, ScheduleTaskTimeInfo, ScheduleTaskInfo, ScheduleSequenceInfo, WorkScheduleInfo, ScheduleExtraction, };
|
|
84
6
|
/**
|
|
85
7
|
* Extract all scheduling data from a parsed IFC store.
|
|
86
8
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedule-extractor.d.ts","sourceRoot":"","sources":["../src/schedule-extractor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schedule-extractor.d.ts","sourceRoot":"","sources":["../src/schedule-extractor.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAoB7D,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAKhC,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,GACnB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,YAAY,GAAG,kBAAkB,CA4T/E"}
|