dsh-ptc-plus 0.3.2 → 0.4.2

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.
Files changed (206) hide show
  1. package/README.en.md +63 -80
  2. package/README.md +63 -80
  3. package/assets/ptc-plus-bindings-en.png +0 -0
  4. package/assets/ptc-plus-bindings-zh.png +0 -0
  5. package/assets/ptc-plus-repair-en.png +0 -0
  6. package/assets/ptc-plus-repair-zh.png +0 -0
  7. package/assets/ptc-plus-repl-workspace-en.png +0 -0
  8. package/assets/ptc-plus-repl-workspace-zh.png +0 -0
  9. package/assets/ptc-plus-settings-en.png +0 -0
  10. package/assets/ptc-plus-settings-zh.png +0 -0
  11. package/client.js +30827 -742
  12. package/compiler-amaro.cjs +5 -0
  13. package/compiler-amaro.cjs.map +6 -0
  14. package/compiler-asset-124f80c1bba92ff5fe79cfec6e8ad518f476de4a42514cae3919538887f510e8.txt +1 -0
  15. package/compiler-assets.json +3 -0
  16. package/compiler-core.cjs +556 -0
  17. package/compiler-core.cjs.map +6 -0
  18. package/compiler-platform.cjs +2 -0
  19. package/compiler-platform.cjs.map +6 -0
  20. package/compiler-typescript.cjs +388 -0
  21. package/compiler-typescript.cjs.map +6 -0
  22. package/docs/README.md +7 -0
  23. package/docs/adr/0004-declare-program-bindings-at-the-host.md +1 -1
  24. package/docs/adr/0006-rewrite-module-syntax-with-an-ast.md +5 -3
  25. package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +1 -1
  26. package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -0
  27. package/docs/adr/0010-session-log-derived-recovery-tips.md +59 -5
  28. package/docs/adr/0011-isolate-the-local-recovery-tip-provider.md +1 -1
  29. package/docs/adr/0012-preserve-mixed-destructuring-initialization.md +3 -1
  30. package/docs/adr/0013-isolate-repl-redeclaration-convenience.md +3 -1
  31. package/docs/adr/0014-persist-cell-rewrite-policy.md +6 -2
  32. package/docs/adr/0015-preserve-source-positions-through-rewrites.md +1 -1
  33. package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
  34. package/docs/adr/0017-track-the-latest-dsh-public-surface.md +49 -0
  35. package/docs/adr/0018-use-versioned-fixture-for-ab-benchmark.md +3 -3
  36. package/docs/adr/0019-plugin-settings-and-kill-switch.md +5 -3
  37. package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
  38. package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +12 -0
  39. package/docs/adr/0023-global-user-bindings.md +104 -0
  40. package/docs/adr/0024-repl-console-observation.md +33 -0
  41. package/docs/adr/0025-use-versioned-logical-binding-identities.md +119 -0
  42. package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +21 -0
  43. package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +37 -0
  44. package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +103 -0
  45. package/docs/adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md +27 -0
  46. package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +27 -0
  47. package/docs/architecture.md +77 -21
  48. package/docs/binding-review-placement-design.md +200 -0
  49. package/docs/capability-projection.md +1 -1
  50. package/docs/client-ui.md +95 -19
  51. package/docs/durability-design.md +28 -10
  52. package/docs/evaluation.md +78 -6
  53. package/docs/installation.md +41 -6
  54. package/docs/publishing.md +5 -3
  55. package/docs/runtime-reference.md +76 -25
  56. package/docs/semantic-validation.md +29 -0
  57. package/docs/stateful-binding-updates-proposal.md +759 -0
  58. package/docs/user-bindings.en.md +66 -0
  59. package/docs/user-bindings.md +66 -0
  60. package/docs/value-wire.md +3 -3
  61. package/docs/verification-optimization-work.md +41 -0
  62. package/docs/verification.md +71 -0
  63. package/index.js +369 -92
  64. package/internal/ast-traversal.js +5 -2
  65. package/internal/async-local-storage-intrinsics.js +38 -0
  66. package/internal/binding-declaration-contract.js +8 -0
  67. package/internal/binding-descriptors.js +1 -0
  68. package/internal/binding-pattern-traversal.js +25 -0
  69. package/internal/binding-pattern.js +26 -29
  70. package/internal/binding-source-analysis.js +708 -0
  71. package/internal/binding-update-policy.js +72 -0
  72. package/internal/bounded-worker-round.js +56 -0
  73. package/internal/callable-definition-environment.js +42 -0
  74. package/internal/callable-source-catalog.js +129 -0
  75. package/internal/callable-source-encoding.js +47 -0
  76. package/internal/callable-source-facts.js +459 -0
  77. package/internal/callable-source-format.js +2 -0
  78. package/internal/callable-source-lowering.js +123 -0
  79. package/internal/cell-analysis-contract.js +25 -0
  80. package/internal/cell-analysis.js +253 -290
  81. package/internal/cell-completion.js +15 -0
  82. package/internal/cell-error.js +7 -0
  83. package/internal/cell-parser.js +66 -0
  84. package/internal/cell-rewriter.js +3 -677
  85. package/internal/commonjs-export-evidence.js +63 -0
  86. package/internal/commonjs-source-evidence.js +72 -0
  87. package/internal/compiler-amaro.cjs +2 -0
  88. package/internal/compiler-compression.js +12 -0
  89. package/internal/compiler-data.js +58 -0
  90. package/internal/compiler-descriptors.js +54 -0
  91. package/internal/compiler-dynamic-cache.js +48 -0
  92. package/internal/compiler-entry.js +35 -0
  93. package/internal/compiler-generated-names.js +17 -0
  94. package/internal/compiler-intrinsics.js +50 -0
  95. package/internal/compiler-module-links.js +37 -0
  96. package/internal/compiler-operations.js +61 -0
  97. package/internal/compiler-platform-factory.js +84 -0
  98. package/internal/compiler-platform.js +136 -0
  99. package/internal/compiler-record-roles.js +53 -0
  100. package/internal/compiler-region-output.js +259 -0
  101. package/internal/compiler-resource-lowering.js +103 -0
  102. package/internal/compiler-scope-facts.js +115 -0
  103. package/internal/compiler-service.js +109 -0
  104. package/internal/compiler-source-cache.js +32 -0
  105. package/internal/compiler-source-pieces.js +93 -0
  106. package/internal/compiler-source-regions.js +132 -0
  107. package/internal/compiler-storage-source.js +54 -0
  108. package/internal/compiler-text.js +15 -0
  109. package/internal/compiler-typescript.cjs +2 -0
  110. package/internal/config-spec.js +83 -27
  111. package/internal/cordis-tools-owner.js +130 -21
  112. package/internal/diagnostic.js +27 -1
  113. package/internal/direct-surface-owner.js +76 -23
  114. package/internal/dynamic-binding-evidence.js +16 -0
  115. package/internal/dynamic-environment-compiler.js +779 -0
  116. package/internal/dynamic-environment-integration.js +91 -0
  117. package/internal/dynamic-environment-runtime.js +383 -0
  118. package/internal/dynamic-native-calls.js +153 -0
  119. package/internal/dynamic-native-runtime.js +262 -0
  120. package/internal/dynamic-scope-analysis.js +90 -0
  121. package/internal/edit-transport-owner.js +27 -2
  122. package/internal/execution-seam-compat.js +193 -0
  123. package/internal/failure-reporting.js +136 -28
  124. package/internal/host-rpc.js +66 -0
  125. package/internal/isolated-worker.js +555 -0
  126. package/internal/kernel-child.js +139 -0
  127. package/internal/kernel-worker.js +1179 -233
  128. package/internal/language-semantics.js +14 -0
  129. package/internal/legacy-binding-catalog.js +48 -0
  130. package/internal/legacy-cell-analysis.js +600 -0
  131. package/internal/legacy-cell-parser.js +50 -0
  132. package/internal/legacy-cell-rewriter.js +631 -0
  133. package/internal/legacy-repl-convenience.js +291 -0
  134. package/internal/managed-module-operations.js +170 -0
  135. package/internal/module-compilation.js +322 -0
  136. package/internal/module-runtime-platform.js +19 -0
  137. package/internal/module-transform-contract.js +42 -0
  138. package/internal/native-await-declarations.js +68 -0
  139. package/internal/native-root-compilation.js +54 -0
  140. package/internal/native-root-dynamic.js +67 -0
  141. package/internal/record-utils.js +24 -15
  142. package/internal/recovery-tips.js +27 -15
  143. package/internal/rejected-cell-editor.js +13 -8
  144. package/internal/repl-convenience.js +2 -289
  145. package/internal/repl-memory-projection.js +81 -12
  146. package/internal/repl-observation-interest.js +70 -0
  147. package/internal/repl-rewrite-contract.js +6 -0
  148. package/internal/repl-scope-normalizer.js +2091 -0
  149. package/internal/repl-value-observer.js +117 -0
  150. package/internal/rpc-contract.js +52 -0
  151. package/internal/runtime-bridge-owner.js +172 -28
  152. package/internal/runtime-config.js +48 -52
  153. package/internal/runtime-contexts.js +82 -10
  154. package/internal/runtime-intrinsics.js +101 -0
  155. package/internal/runtime-messages.js +111 -0
  156. package/internal/session-cell-executor.js +402 -87
  157. package/internal/session-journal-recovery.js +684 -0
  158. package/internal/session-journal-schema.js +123 -0
  159. package/internal/session-journal.js +199 -654
  160. package/internal/session-log-view.js +42 -9
  161. package/internal/session-runtime.js +257 -95
  162. package/internal/session-state.js +247 -71
  163. package/internal/source-position-map.js +230 -71
  164. package/internal/stateful-module-compiler.js +154 -0
  165. package/internal/stateful-module-runtime.js +303 -0
  166. package/internal/stateful-root-compiler.js +600 -0
  167. package/internal/stateful-root-runtime.js +340 -0
  168. package/internal/typert-codec-compat.js +28 -0
  169. package/internal/typescript-transform.js +31 -0
  170. package/internal/user-binding-authoring.js +70 -0
  171. package/internal/user-binding-console-worker.js +244 -0
  172. package/internal/user-binding-console.js +148 -0
  173. package/internal/user-binding-draft-projection.js +335 -0
  174. package/internal/user-binding-model-context.js +31 -0
  175. package/internal/user-binding-runner.js +56 -0
  176. package/internal/user-bindings-owner.js +1065 -0
  177. package/internal/user-bindings-store.js +293 -0
  178. package/internal/user-bindings.js +361 -0
  179. package/internal/value-wire-schema.js +28 -0
  180. package/internal/value-wire.js +130 -91
  181. package/internal/worker-client.js +57 -67
  182. package/internal/worker-cwd-virtualization.js +80 -53
  183. package/internal/worker-environment.js +65 -0
  184. package/internal/worker-output-relay.js +29 -0
  185. package/internal/worker-repl-realm.js +134 -0
  186. package/internal/worker-shutdown.js +14 -0
  187. package/package.json +76 -7
  188. package/src/client-activity.js +95 -53
  189. package/src/client-authoring-view.js +580 -0
  190. package/src/client-binding-review.js +230 -0
  191. package/src/client-bindings-data.js +29 -0
  192. package/src/client-catalog.js +127 -0
  193. package/src/client-code-editor.js +84 -0
  194. package/src/client-console.js +112 -0
  195. package/src/client-copy.js +370 -0
  196. package/src/client-feature-gates.js +62 -0
  197. package/src/client-host-compat.js +150 -0
  198. package/src/client-indicator-view.js +267 -0
  199. package/src/client-repl-view.js +292 -0
  200. package/src/client-rpc.js +20 -0
  201. package/src/client-settings-view.js +221 -0
  202. package/src/client-styles.js +106 -0
  203. package/src/client-tool-view.js +108 -0
  204. package/src/client-transport.js +159 -0
  205. package/src/client-workbench.js +521 -0
  206. package/src/client.js +233 -615
@@ -0,0 +1,72 @@
1
+ import { LIVE_MODULE_SEMANTICS } from './repl-rewrite-contract.js'
2
+ import { LEGACY_LANGUAGE_SEMANTICS, STATEFUL_LANGUAGE_SEMANTICS,
3
+ PROTECTED_LANGUAGE_SEMANTICS, normalizeLanguageSemantics } from './language-semantics.js'
4
+ import { moduleTransformForLanguage, normalizeModuleTransform } from './module-transform-contract.js'
5
+
6
+ /**
7
+ * Translate the public compatibility settings into the execution policy used
8
+ * by the compiler and journal. Keeping this mapping in one owner prevents
9
+ * individual lowering paths from combining legacy switches differently.
10
+ */
11
+ export function executionPolicies(config, replayRecord = undefined) {
12
+ if (config.bindingUpdates !== undefined && !['stateful', 'protected'].includes(config.bindingUpdates)) {
13
+ throw new TypeError('ptc-plus: bindingUpdates must be stateful or protected')
14
+ }
15
+ if (replayRecord !== undefined) {
16
+ const bindingPolicy = Object.freeze({ ...replayRecord.bindingPolicy })
17
+ const rewritesEnabled = Object.freeze({ ...replayRecord.rewritePolicy })
18
+ const moduleSemantics = Object.freeze({ ...replayRecord.moduleSemantics })
19
+ const languageSemantics = normalizeLanguageSemantics(replayRecord.languageSemantics ?? LEGACY_LANGUAGE_SEMANTICS)
20
+ return Object.freeze({
21
+ languageSemantics,
22
+ moduleTransform: normalizeModuleTransform(replayRecord.moduleTransform, languageSemantics),
23
+ bindingPolicy,
24
+ rewritesEnabled,
25
+ moduleSemantics,
26
+ })
27
+ }
28
+ if (config.bindingUpdates === 'stateful' && config.legacyBindingSettings !== true) {
29
+ return Object.freeze({
30
+ languageSemantics: STATEFUL_LANGUAGE_SEMANTICS,
31
+ moduleTransform: moduleTransformForLanguage(STATEFUL_LANGUAGE_SEMANTICS),
32
+ bindingPolicy: Object.freeze({ variableRedeclarations: true, functionClassRedeclarations: true }),
33
+ rewritesEnabled: Object.freeze({ autoRewriteImports: true, autoStripExports: true, autoSplitRedeclarations: true }),
34
+ moduleSemantics: LIVE_MODULE_SEMANTICS,
35
+ })
36
+ }
37
+ if (config.bindingUpdates === 'protected' && config.legacyBindingSettings !== true) {
38
+ return Object.freeze({
39
+ languageSemantics: PROTECTED_LANGUAGE_SEMANTICS,
40
+ moduleTransform: moduleTransformForLanguage(PROTECTED_LANGUAGE_SEMANTICS),
41
+ bindingPolicy: Object.freeze({ variableRedeclarations: false, functionClassRedeclarations: false }),
42
+ // Module syntax is part of the language in protected mode too. The
43
+ // policy protects existing names; it does not remove valid syntax.
44
+ rewritesEnabled: Object.freeze({ autoRewriteImports: true, autoStripExports: true, autoSplitRedeclarations: true }),
45
+ moduleSemantics: LIVE_MODULE_SEMANTICS,
46
+ })
47
+ }
48
+ return Object.freeze({
49
+ languageSemantics: LEGACY_LANGUAGE_SEMANTICS,
50
+ moduleTransform: moduleTransformForLanguage(LEGACY_LANGUAGE_SEMANTICS),
51
+ bindingPolicy: Object.freeze({
52
+ variableRedeclarations: config.looseTopLevelRedeclarations === true,
53
+ functionClassRedeclarations: config.looseTopLevelFunctionClassRedeclarations === true,
54
+ }),
55
+ rewritesEnabled: Object.freeze({
56
+ autoRewriteImports: config.autoRewriteImports === true,
57
+ autoStripExports: config.autoStripExports === true,
58
+ autoSplitRedeclarations: config.autoSplitRedeclarations === true,
59
+ }),
60
+ moduleSemantics: LIVE_MODULE_SEMANTICS,
61
+ })
62
+ }
63
+
64
+ /** Stable prose inputs for the model-visible REPL guidance. */
65
+ export function guidancePolicies(config) {
66
+ const policies = executionPolicies(config)
67
+ return Object.freeze({
68
+ ...policies,
69
+ durableReplay: config.durableReplay === true,
70
+ cordisToolsEnabled: config.cordisToolsEnabled === true,
71
+ })
72
+ }
@@ -0,0 +1,56 @@
1
+ /** How a bounded worker round ended without a result. */
2
+ export const ROUND_TIMEOUT = 'timeout'
3
+ export const ROUND_CANCELLED = 'cancelled'
4
+ export const ROUND_OUTPUT_LIMIT = 'output-limit'
5
+
6
+ /**
7
+ * Own one bounded worker round: captured output bytes, the wall-clock deadline,
8
+ * cancellation and a single settlement. Worker creation, retention and
9
+ * termination stay with the caller, which is told exactly once how the round
10
+ * ended through `settle({ ok: true, result })` or `settle({ ok: false, reason })`.
11
+ */
12
+ export function createBoundedWorkerRound({ maxOutputBytes, maxWallMs, signal, settle }) {
13
+ const logs = []
14
+ let capturedBytes = 0
15
+ let ended = false
16
+ const end = (outcome) => {
17
+ if (ended) return false
18
+ ended = true
19
+ clearTimeout(timer)
20
+ signal?.removeEventListener('abort', abort)
21
+ settle(outcome)
22
+ return true
23
+ }
24
+ const fail = reason => end({ ok: false, reason })
25
+ const abort = () => { fail(ROUND_CANCELLED) }
26
+ const timer = setTimeout(() => fail(ROUND_TIMEOUT), maxWallMs)
27
+ signal?.addEventListener('abort', abort, { once: true })
28
+ if (signal?.aborted === true) fail(ROUND_CANCELLED)
29
+ return Object.freeze({
30
+ logs,
31
+ /** Record one stream chunk; ends the round when the byte budget is exceeded. */
32
+ capture(channel, text) {
33
+ if (ended) return
34
+ capturedBytes += Buffer.byteLength(text, 'utf8')
35
+ if (capturedBytes > maxOutputBytes) { fail(ROUND_OUTPUT_LIMIT); return }
36
+ logs.push({ channel, text })
37
+ },
38
+ /**
39
+ * True when the byte budget is spent.
40
+ *
41
+ * `envelope` measures the object the caller returns with the captured `logs`
42
+ * included as a member, so log wrappers and JSON escaping count against the
43
+ * same budget; that is the candidate run's returned-envelope budget. Without
44
+ * it the raw captured bytes plus the serialized payload are measured, which is
45
+ * the workbench console's output budget.
46
+ */
47
+ exceeds(payload, { envelope = false } = {}) {
48
+ if (envelope) {
49
+ return Buffer.byteLength(JSON.stringify({ ...payload, logs }), 'utf8') > maxOutputBytes
50
+ }
51
+ return capturedBytes + Buffer.byteLength(JSON.stringify(payload), 'utf8') > maxOutputBytes
52
+ },
53
+ succeed(result) { return end({ ok: true, result }) },
54
+ fail,
55
+ })
56
+ }
@@ -0,0 +1,42 @@
1
+ import { types as t } from '@babel/core'
2
+ import traverseImport from '@babel/traverse'
3
+
4
+ const traverse = traverseImport.default ?? traverseImport
5
+
6
+ /** Parameters and computed keys evaluate before a callable body scope exists.
7
+ * Return that callable's path; an intervening callable body owns its own scope. */
8
+ export function callableDefinitionOwner(path) {
9
+ let child = path
10
+ while (child.parentPath && !child.parentPath.isFunction()) child = child.parentPath
11
+ return child.parentPath && child.key !== 'body' ? child.parentPath : undefined
12
+ }
13
+
14
+ /** Close definition helpers without losing surrounding suspension or lexical
15
+ * this/new.target. The outer owner only supports Babel's arrow conversion. */
16
+ export function closeDefinitionExpression(helpers, value, parameters = [], argumentsList = []) {
17
+ const body = t.blockStatement([...helpers, t.returnStatement(value)])
18
+ const factory = t.arrowFunctionExpression(parameters, body)
19
+ const owner = t.functionExpression(null, [], t.blockStatement([t.returnStatement(factory)]))
20
+ const tree = t.file(t.program([t.expressionStatement(owner)]))
21
+ let awaited = false, yielded = false
22
+ traverse(tree, { ArrowFunctionExpression(path) {
23
+ if (path.node !== factory) return
24
+ path.get('body').traverse(traverse.visitors.environmentVisitor({
25
+ ArrowFunctionExpression(path) { path.skip() },
26
+ AwaitExpression() { awaited = true },
27
+ YieldExpression() { yielded = true },
28
+ }))
29
+ factory.async = awaited
30
+ if (yielded) {
31
+ const converted = path.arrowFunctionToExpression()
32
+ converted.node.generator = true
33
+ }
34
+ path.stop()
35
+ } })
36
+ if (yielded) {
37
+ owner.type = 'ArrowFunctionExpression'
38
+ return t.yieldExpression(t.callExpression(t.callExpression(owner, []), argumentsList), true)
39
+ }
40
+ const expression = t.callExpression(factory, argumentsList)
41
+ return awaited ? t.awaitExpression(expression) : expression
42
+ }
@@ -0,0 +1,129 @@
1
+ import { hashText, inflateText } from './compiler-service.js'
2
+ import { moduleCompilerIntrinsics, moduleRuntimeIntrinsics as internal } from './compiler-intrinsics.js'
3
+ import { CALLABLE_SOURCE_FORMAT as FORMAT, CALLABLE_SOURCE_BLOCK_UNITS as BLOCK_UNITS } from './callable-source-format.js'
4
+
5
+ export { createCallableSourceCatalog } from './compiler-service.js'
6
+
7
+ const CACHED_BLOCKS = 8
8
+ const sourceKey = source => `${source.length}:${hashText(source, 'utf16le', 'base64')}`
9
+
10
+ function catalogKey(catalog) {
11
+ let text = ''
12
+ for (let index = 0; index < catalog.buffers.length; index++) {
13
+ const buffer = catalog.buffers[index]
14
+ text += `${buffer.length}:`
15
+ for (let block = 0; block < buffer.blocks.length; block++) {
16
+ text += `${buffer.blocks[block]};`
17
+ }
18
+ }
19
+ for (let index = 0; index < catalog.entries.length; index++) {
20
+ const entry = catalog.entries[index]
21
+ for (let item = 0; item < entry.length; item++) text += `${entry[item]}:`
22
+ text += ';'
23
+ }
24
+ return hashText(text)
25
+ }
26
+
27
+ function sameCatalog(left, right) {
28
+ if (left.buffers.length !== right.buffers.length || left.entries.length !== right.entries.length) return false
29
+ for (let index = 0; index < left.buffers.length; index++) {
30
+ const a = left.buffers[index], b = right.buffers[index]
31
+ if (a.length !== b.length || a.blocks.length !== b.blocks.length) return false
32
+ for (let block = 0; block < a.blocks.length; block++) if (a.blocks[block] !== b.blocks[block]) return false
33
+ }
34
+ for (let index = 0; index < left.entries.length; index++) {
35
+ const a = left.entries[index], b = right.entries[index]
36
+ if (a.length !== b.length) return false
37
+ for (let item = 0; item < a.length; item++) if (a[item] !== b[item]) return false
38
+ }
39
+ return true
40
+ }
41
+
42
+ /** Digests select candidates; only an exact native-source comparison owns reflection. */
43
+ export function createCallableSourceRegistry() {
44
+ const literals = new internal.Map()
45
+ const catalogs = new internal.Map()
46
+ const candidates = new internal.Map()
47
+ const decoded = new internal.Map()
48
+ let ordinal = 0
49
+ const blockText = encoded => {
50
+ let text = internal.mapGet(decoded, encoded)
51
+ if (text === undefined) {
52
+ text = inflateText(encoded, BLOCK_UNITS * 2)
53
+ internal.mapSet(decoded, encoded, text)
54
+ if (internal.mapSize(decoded) > CACHED_BLOCKS) internal.mapDelete(decoded, internal.mapFirstKey(decoded))
55
+ }
56
+ return text
57
+ }
58
+ const visitParts = (catalog, bufferIndex, start, end, visit) => {
59
+ const buffer = catalog.buffers[bufferIndex]
60
+ while (start < end) {
61
+ const index = internal.floor(start / BLOCK_UNITS)
62
+ const offset = start % BLOCK_UNITS
63
+ const length = internal.min(end - start, BLOCK_UNITS - offset)
64
+ if (visit(internal.sliceString(blockText(buffer.blocks[index]), offset, offset + length)) === false) return false
65
+ start += length
66
+ }
67
+ }
68
+ const matches = (catalog, entry, native) => {
69
+ let offset = 0
70
+ const complete = visitParts(catalog, entry[0], entry[1], entry[2], text => {
71
+ if (!internal.startsWith(native, text, offset)) return false
72
+ offset += text.length
73
+ })
74
+ return complete !== false && offset === native.length
75
+ }
76
+ return {
77
+ register(sources) {
78
+ const current = ++ordinal
79
+ if (internal.isArray(sources)) {
80
+ for (let index = 0; index < sources.length; index++) {
81
+ const entry = sources[index]
82
+ internal.mapSet(literals, entry[0], { original: entry[1], ordinal: current })
83
+ }
84
+ return
85
+ }
86
+ if (sources.format !== FORMAT) throw new moduleCompilerIntrinsics.TypeError('unsupported callable source catalog')
87
+ const key = catalogKey(sources)
88
+ let bucket = internal.mapGet(catalogs, key)
89
+ if (bucket === undefined) internal.mapSet(catalogs, key, bucket = [])
90
+ for (let index = 0; index < bucket.length; index++) {
91
+ const registration = bucket[index]
92
+ if (!sameCatalog(registration.catalog, sources)) continue
93
+ registration.ordinal = current
94
+ return
95
+ }
96
+ // Compiler transport values may be reused by their caller. Snapshot the
97
+ // compressed facts without retaining caller-owned mutable containers.
98
+ const catalog = { buffers: [], entries: [] }
99
+ for (let index = 0; index < sources.buffers.length; index++) {
100
+ const buffer = sources.buffers[index]
101
+ internal.appendArray(catalog.buffers, { length: buffer.length, blocks: internal.copyArray(buffer.blocks) })
102
+ }
103
+ for (let index = 0; index < sources.entries.length; index++) internal.appendArray(catalog.entries, internal.copyArray(sources.entries[index]))
104
+ const registration = { catalog, ordinal: current }
105
+ internal.appendArray(bucket, registration)
106
+ for (let index = 0; index < catalog.entries.length; index++) {
107
+ const entry = catalog.entries[index]
108
+ let entries = internal.mapGet(candidates, entry[6])
109
+ if (entries === undefined) internal.mapSet(candidates, entry[6], entries = [])
110
+ internal.appendArray(entries, { registration, entry })
111
+ }
112
+ },
113
+ get(native) {
114
+ let found = internal.mapGet(literals, native)
115
+ const entries = internal.mapGet(candidates, sourceKey(native))
116
+ if (entries !== undefined) for (let index = 0; index < entries.length; index++) {
117
+ const { registration, entry } = entries[index]
118
+ if (found !== undefined && found.ordinal > registration.ordinal) continue
119
+ if (matches(registration.catalog, entry, native)) found = { ...registration, entry }
120
+ }
121
+ if (found === undefined) return undefined
122
+ if (found.original !== undefined) return found.original
123
+ const entry = found.entry
124
+ let original = ''
125
+ visitParts(found.catalog, entry[3], entry[4], entry[5], text => { original += text })
126
+ return original
127
+ },
128
+ }
129
+ }
@@ -0,0 +1,47 @@
1
+ import { hashText, deflateText } from './compiler-text.js'
2
+ import { CALLABLE_SOURCE_FORMAT as FORMAT, CALLABLE_SOURCE_BLOCK_UNITS as BLOCK_UNITS } from './callable-source-format.js'
3
+
4
+ /** Keep windows around referenced callables. Neighbors share compression
5
+ * blocks; unrelated large data regions stay outside the reflection catalog. */
6
+ export function createCallableSourceCatalog(buffers, ranges) {
7
+ const selected = buffers.map(() => [])
8
+ const entries = ranges.map(range => [...range])
9
+ for (let index = 0; index < ranges.length; index++) {
10
+ const range = ranges[index]
11
+ for (const offset of [0, 3]) {
12
+ const source = buffers[range[offset]]
13
+ const start = range[offset + 1], end = range[offset + 2]
14
+ if (typeof source !== 'string' || !Number.isInteger(start) || !Number.isInteger(end)
15
+ || start < 0 || end < start || end > source.length) throw new TypeError('invalid callable source range')
16
+ selected[range[offset]].push({ start, end, index, offset })
17
+ }
18
+ const source = buffers[range[0]].slice(range[1], range[2])
19
+ entries[index].push(`${source.length}:${hashText(source, 'utf16le', 'base64')}`)
20
+ }
21
+ const encoded = []
22
+ for (let index = 0; index < selected.length; index++) {
23
+ const intervals = []
24
+ for (const item of selected[index].sort((left, right) => left.start - right.start || right.end - left.end)) {
25
+ let interval = intervals.at(-1)
26
+ if (interval === undefined || item.start - interval.end > BLOCK_UNITS) {
27
+ interval = { start: item.start, end: item.end, items: [] }
28
+ intervals.push(interval)
29
+ }
30
+ interval.end = Math.max(interval.end, item.end)
31
+ interval.items.push(item)
32
+ }
33
+ for (const interval of intervals) {
34
+ const source = buffers[index].slice(interval.start, interval.end)
35
+ const blocks = []
36
+ for (let start = 0; start < source.length; start += BLOCK_UNITS) blocks.push(deflateText(source.slice(start, start + BLOCK_UNITS)))
37
+ for (const item of interval.items) {
38
+ const entry = entries[item.index]
39
+ entry[item.offset] = encoded.length
40
+ entry[item.offset + 1] -= interval.start
41
+ entry[item.offset + 2] -= interval.start
42
+ }
43
+ encoded.push({ length: source.length, blocks })
44
+ }
45
+ }
46
+ return { format: FORMAT, length: entries.length, buffers: encoded, entries }
47
+ }