@smoothbricks/lmao 0.2.2 → 0.2.3

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 (276) hide show
  1. package/dist/allocator.wasm +0 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -0
  5. package/dist/lib/JsBufferStrategy.d.ts +4 -3
  6. package/dist/lib/JsBufferStrategy.d.ts.map +1 -1
  7. package/dist/lib/JsBufferStrategy.js +18 -11
  8. package/dist/lib/arrow/lease.d.ts +10 -0
  9. package/dist/lib/arrow/lease.d.ts.map +1 -0
  10. package/dist/lib/arrow/lease.js +33 -0
  11. package/dist/lib/arrow/utils.d.ts +3 -4
  12. package/dist/lib/arrow/utils.d.ts.map +1 -1
  13. package/dist/lib/arrow/utils.js +12 -13
  14. package/dist/lib/arrow/vocabularyDictionary.d.ts +21 -0
  15. package/dist/lib/arrow/vocabularyDictionary.d.ts.map +1 -0
  16. package/dist/lib/arrow/vocabularyDictionary.js +95 -0
  17. package/dist/lib/bufferStrategy.d.ts +3 -2
  18. package/dist/lib/bufferStrategy.d.ts.map +1 -1
  19. package/dist/lib/cloudflare/traceRows.d.ts.map +1 -1
  20. package/dist/lib/cloudflare/traceRows.js +3 -2
  21. package/dist/lib/codegen/evaluatorGenerator.d.ts.map +1 -1
  22. package/dist/lib/codegen/evaluatorGenerator.js +12 -11
  23. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts +44 -82
  24. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts.map +1 -1
  25. package/dist/lib/codegen/fixedPositionWriterGenerator.js +223 -162
  26. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts +63 -0
  27. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts.map +1 -0
  28. package/dist/lib/codegen/spanLoggerClosureMaterializer.js +447 -0
  29. package/dist/lib/codegen/spanLoggerGenerator.d.ts +36 -19
  30. package/dist/lib/codegen/spanLoggerGenerator.d.ts.map +1 -1
  31. package/dist/lib/codegen/spanLoggerGenerator.js +164 -158
  32. package/dist/lib/convertToArrow.d.ts +7 -2
  33. package/dist/lib/convertToArrow.d.ts.map +1 -1
  34. package/dist/lib/convertToArrow.js +499 -285
  35. package/dist/lib/defineOpContext.js +1 -1
  36. package/dist/lib/enumMetadata.d.ts +19 -0
  37. package/dist/lib/enumMetadata.d.ts.map +1 -0
  38. package/dist/lib/enumMetadata.js +86 -0
  39. package/dist/lib/flushScheduler.d.ts.map +1 -1
  40. package/dist/lib/flushScheduler.js +13 -4
  41. package/dist/lib/library.d.ts +16 -98
  42. package/dist/lib/library.d.ts.map +1 -1
  43. package/dist/lib/library.js +32 -525
  44. package/dist/lib/logBinding.d.ts +21 -27
  45. package/dist/lib/logBinding.d.ts.map +1 -1
  46. package/dist/lib/op.d.ts +30 -30
  47. package/dist/lib/op.d.ts.map +1 -1
  48. package/dist/lib/op.js +15 -22
  49. package/dist/lib/opContext/createOpGroup.d.ts +1 -1
  50. package/dist/lib/opContext/createOpGroup.d.ts.map +1 -1
  51. package/dist/lib/opContext/createOpGroup.js +22 -29
  52. package/dist/lib/opContext/defineOp.d.ts +4 -4
  53. package/dist/lib/opContext/defineOp.d.ts.map +1 -1
  54. package/dist/lib/opContext/defineOp.js +53 -10
  55. package/dist/lib/opContext/opGroupTypes.d.ts +2 -2
  56. package/dist/lib/opContext/opTypes.d.ts +1 -1
  57. package/dist/lib/opContext/opTypes.d.ts.map +1 -1
  58. package/dist/lib/opContext/spanContextTypes.d.ts +29 -14
  59. package/dist/lib/opContext/spanContextTypes.d.ts.map +1 -1
  60. package/dist/lib/opContext/types.d.ts +4 -4
  61. package/dist/lib/opContext/types.d.ts.map +1 -1
  62. package/dist/lib/physicalLayoutPlan.d.ts +89 -0
  63. package/dist/lib/physicalLayoutPlan.d.ts.map +1 -0
  64. package/dist/lib/physicalLayoutPlan.js +442 -0
  65. package/dist/lib/resolveMessage.d.ts +9 -0
  66. package/dist/lib/resolveMessage.d.ts.map +1 -0
  67. package/dist/lib/resolveMessage.js +63 -0
  68. package/dist/lib/result.d.ts +5 -7
  69. package/dist/lib/result.d.ts.map +1 -1
  70. package/dist/lib/result.js +19 -26
  71. package/dist/lib/runtimeHint.d.ts +35 -0
  72. package/dist/lib/runtimeHint.d.ts.map +1 -0
  73. package/dist/lib/runtimeHint.js +79 -0
  74. package/dist/lib/schema/types.d.ts +1 -1
  75. package/dist/lib/schema/types.d.ts.map +1 -1
  76. package/dist/lib/span-buffer/aot/v1.d.ts +2 -0
  77. package/dist/lib/span-buffer/aot/v1.d.ts.map +1 -0
  78. package/dist/lib/span-buffer/aot/v1.js +24 -0
  79. package/dist/lib/spanBuffer.d.ts +33 -4
  80. package/dist/lib/spanBuffer.d.ts.map +1 -1
  81. package/dist/lib/spanBuffer.js +583 -91
  82. package/dist/lib/spanBufferStats.d.ts +1 -1
  83. package/dist/lib/spanBufferStats.d.ts.map +1 -1
  84. package/dist/lib/spanContext.d.ts +27 -51
  85. package/dist/lib/spanContext.d.ts.map +1 -1
  86. package/dist/lib/spanContext.js +822 -344
  87. package/dist/lib/sqlite/sqlite-common.d.ts.map +1 -1
  88. package/dist/lib/sqlite/sqlite-common.js +20 -21
  89. package/dist/lib/testing/bun-harness.d.ts +8 -3
  90. package/dist/lib/testing/bun-harness.d.ts.map +1 -1
  91. package/dist/lib/testing/bun-harness.js +30 -18
  92. package/dist/lib/testing/extractFacts.d.ts +1 -1
  93. package/dist/lib/testing/extractFacts.d.ts.map +1 -1
  94. package/dist/lib/testing/extractFacts.js +55 -63
  95. package/dist/lib/testing/facts.d.ts +1 -1
  96. package/dist/lib/testing/facts.d.ts.map +1 -1
  97. package/dist/lib/testing/queryable-span.d.ts +1 -1
  98. package/dist/lib/testing/queryable-span.d.ts.map +1 -1
  99. package/dist/lib/testing/queryable-span.js +26 -28
  100. package/dist/lib/testing/span-query.d.ts.map +1 -1
  101. package/dist/lib/testing/span-query.js +19 -22
  102. package/dist/lib/testing/stdio-replay.d.ts.map +1 -1
  103. package/dist/lib/testing/stdio-replay.js +19 -8
  104. package/dist/lib/threadId.d.ts.map +1 -1
  105. package/dist/lib/threadId.js +6 -3
  106. package/dist/lib/traceRoot.d.ts +30 -8
  107. package/dist/lib/traceRoot.d.ts.map +1 -1
  108. package/dist/lib/traceRoot.es.d.ts +17 -15
  109. package/dist/lib/traceRoot.es.d.ts.map +1 -1
  110. package/dist/lib/traceRoot.es.js +68 -34
  111. package/dist/lib/traceRoot.js +11 -0
  112. package/dist/lib/traceRoot.node.d.ts +17 -19
  113. package/dist/lib/traceRoot.node.d.ts.map +1 -1
  114. package/dist/lib/traceRoot.node.js +66 -38
  115. package/dist/lib/traceTopology.d.ts +42 -0
  116. package/dist/lib/traceTopology.d.ts.map +1 -0
  117. package/dist/lib/traceTopology.js +260 -0
  118. package/dist/lib/tracer.d.ts +9 -5
  119. package/dist/lib/tracer.d.ts.map +1 -1
  120. package/dist/lib/tracer.js +65 -71
  121. package/dist/lib/tracers/ArrayQueueTracer.d.ts +1 -1
  122. package/dist/lib/tracers/ArrayQueueTracer.js +1 -1
  123. package/dist/lib/tracers/StdioTracer.d.ts.map +1 -1
  124. package/dist/lib/tracers/StdioTracer.js +15 -13
  125. package/dist/lib/tracers/TestTracer.d.ts +4 -6
  126. package/dist/lib/tracers/TestTracer.d.ts.map +1 -1
  127. package/dist/lib/tracers/TestTracer.js +6 -8
  128. package/dist/lib/types.d.ts +49 -32
  129. package/dist/lib/types.d.ts.map +1 -1
  130. package/dist/lib/vocabularyRegistry.d.ts +25 -0
  131. package/dist/lib/vocabularyRegistry.d.ts.map +1 -0
  132. package/dist/lib/vocabularyRegistry.js +372 -0
  133. package/dist/lib/wasm/WasmBufferStrategy.d.ts +6 -10
  134. package/dist/lib/wasm/WasmBufferStrategy.d.ts.map +1 -1
  135. package/dist/lib/wasm/WasmBufferStrategy.js +44 -37
  136. package/dist/lib/wasm/wasmAllocator.d.ts +27 -22
  137. package/dist/lib/wasm/wasmAllocator.d.ts.map +1 -1
  138. package/dist/lib/wasm/wasmAllocator.js +66 -44
  139. package/dist/lib/wasm/wasmPhysicalLayout.d.ts +67 -0
  140. package/dist/lib/wasm/wasmPhysicalLayout.d.ts.map +1 -0
  141. package/dist/lib/wasm/wasmPhysicalLayout.js +179 -0
  142. package/dist/lib/wasm/wasmSpanBuffer.d.ts +79 -31
  143. package/dist/lib/wasm/wasmSpanBuffer.d.ts.map +1 -1
  144. package/dist/lib/wasm/wasmSpanBuffer.js +442 -272
  145. package/dist/lib/wasm/wasmTraceRoot.d.ts +24 -22
  146. package/dist/lib/wasm/wasmTraceRoot.d.ts.map +1 -1
  147. package/dist/lib/wasm/wasmTraceRoot.js +110 -71
  148. package/dist/vocabulary/register/v1.d.ts +2 -0
  149. package/dist/vocabulary/register/v1.d.ts.map +1 -0
  150. package/dist/vocabulary/register/v1.js +1 -0
  151. package/dist/wasm.d.ts +5 -0
  152. package/dist/wasm.d.ts.map +1 -0
  153. package/dist/wasm.js +4 -0
  154. package/package.json +54 -6
  155. package/src/index.ts +1 -0
  156. package/src/lib/JsBufferStrategy.ts +27 -9
  157. package/src/lib/__tests__/arrow-builder-integration/arrow-conversion.test.ts +335 -37
  158. package/src/lib/__tests__/arrow-builder-integration/binary-arrow-conversion.test.ts +97 -26
  159. package/src/lib/__tests__/arrow-builder-integration/binary-comparison.test.ts +75 -15
  160. package/src/lib/__tests__/arrow-builder-integration/binary-format-compliance.test.ts +30 -6
  161. package/src/lib/__tests__/arrow-builder-integration/buffer-chaining.test.ts +18 -21
  162. package/src/lib/__tests__/arrow-builder-integration/foundation.test.ts +5 -2
  163. package/src/lib/__tests__/arrow-builder-integration/integration.test.ts +25 -7
  164. package/src/lib/__tests__/arrow-builder-integration/lazy-columns.test.ts +3 -2
  165. package/src/lib/__tests__/buffer-overflow.test.ts +24 -18
  166. package/src/lib/__tests__/capability-span-context.test.ts +505 -0
  167. package/src/lib/__tests__/capacity-tuning.test.ts +5 -3
  168. package/src/lib/__tests__/eager-columns.test.ts +345 -0
  169. package/src/lib/__tests__/enum-metadata-aot.test.ts +153 -0
  170. package/src/lib/__tests__/enum-metadata.test.ts +177 -0
  171. package/src/lib/__tests__/fixtures/empty-vocabulary-runtime.fixture.ts +15 -0
  172. package/src/lib/__tests__/flushScheduler.test.ts +5 -1
  173. package/src/lib/__tests__/identity-view.property.test.ts +179 -0
  174. package/src/lib/__tests__/library.test.ts +19 -235
  175. package/src/lib/__tests__/message-buffer-families.test.ts +878 -0
  176. package/src/lib/__tests__/nested-library-tasks.test.ts +14 -15
  177. package/src/lib/__tests__/op-metadata.test.ts +1 -1
  178. package/src/lib/__tests__/op-type-safety.test.ts +5 -16
  179. package/src/lib/__tests__/physical-layout-plan.test.ts +333 -0
  180. package/src/lib/__tests__/remap-descriptor-integration.test.ts +381 -0
  181. package/src/lib/__tests__/root-context-construction.test.ts +414 -0
  182. package/src/lib/__tests__/span-auto-runtime.test.ts +386 -0
  183. package/src/lib/__tests__/span-buffer-segment-stats.test.ts +221 -0
  184. package/src/lib/__tests__/span-lifecycle.test.ts +53 -25
  185. package/src/lib/__tests__/spanbuffer-materializer-parity.test.ts +266 -0
  186. package/src/lib/__tests__/sync-async-trace.test.ts +24 -23
  187. package/src/lib/__tests__/tag-writer-aot.test.ts +214 -0
  188. package/src/lib/__tests__/test-helpers.ts +67 -12
  189. package/src/lib/__tests__/threadId.test.ts +62 -0
  190. package/src/lib/__tests__/timestamp.test.ts +221 -93
  191. package/src/lib/__tests__/traceTopology.property.test.ts +383 -0
  192. package/src/lib/__tests__/type-narrowing.test.ts +63 -0
  193. package/src/lib/__tests__/vocabulary-dense-decoding.test.ts +405 -0
  194. package/src/lib/__tests__/vocabularyRegistry.test.ts +313 -0
  195. package/src/lib/arrow/lease.ts +43 -0
  196. package/src/lib/arrow/utils.ts +10 -14
  197. package/src/lib/arrow/vocabularyDictionary.ts +123 -0
  198. package/src/lib/bufferStrategy.ts +9 -1
  199. package/src/lib/cloudflare/traceRows.ts +3 -2
  200. package/src/lib/codegen/__tests__/evaluatorGenerator.test.ts +21 -141
  201. package/src/lib/codegen/__tests__/fixedPositionWriter-parity.test.ts +273 -0
  202. package/src/lib/codegen/__tests__/fixedPositionWriter-uint64.test.ts +61 -34
  203. package/src/lib/codegen/__tests__/nullBitmap.test.ts +33 -37
  204. package/src/lib/codegen/__tests__/spanLoggerGenerator.test.ts +34 -18
  205. package/src/lib/codegen/__tests__/spanLoggerMaterializerParity.test.ts +503 -0
  206. package/src/lib/codegen/evaluatorGenerator.ts +18 -13
  207. package/src/lib/codegen/fixedPositionWriterGenerator.ts +329 -245
  208. package/src/lib/codegen/spanLoggerClosureMaterializer.ts +598 -0
  209. package/src/lib/codegen/spanLoggerGenerator.ts +241 -177
  210. package/src/lib/convertToArrow.ts +598 -311
  211. package/src/lib/defineOpContext.ts +1 -1
  212. package/src/lib/enumMetadata.ts +121 -0
  213. package/src/lib/flushScheduler.ts +11 -5
  214. package/src/lib/library.ts +37 -595
  215. package/src/lib/logBinding.ts +21 -27
  216. package/src/lib/op.ts +75 -18
  217. package/src/lib/opContext/__tests__/retry.test.ts +27 -21
  218. package/src/lib/opContext/createOpGroup.ts +33 -31
  219. package/src/lib/opContext/defineOp.ts +88 -11
  220. package/src/lib/opContext/opGroupTypes.ts +2 -2
  221. package/src/lib/opContext/opTypes.ts +1 -1
  222. package/src/lib/opContext/spanContextTypes.ts +98 -17
  223. package/src/lib/opContext/types.ts +7 -3
  224. package/src/lib/physicalLayoutPlan.ts +598 -0
  225. package/src/lib/resolveMessage.ts +67 -0
  226. package/src/lib/result.ts +20 -33
  227. package/src/lib/runtimeHint.ts +98 -0
  228. package/src/lib/schema/__tests__/featureFlags.test.ts +2 -1
  229. package/src/lib/schema/builder.ts +1 -1
  230. package/src/lib/schema/types.ts +1 -1
  231. package/src/lib/span-buffer/aot/v1.ts +26 -0
  232. package/src/lib/spanBuffer.ts +658 -92
  233. package/src/lib/spanBufferStats.ts +1 -1
  234. package/src/lib/spanContext.ts +1350 -861
  235. package/src/lib/sqlite/sqlite-common.ts +20 -31
  236. package/src/lib/testing/__tests__/topology-traversal.test.ts +174 -0
  237. package/src/lib/testing/__tests__/vitest-harness.test.ts +2 -1
  238. package/src/lib/testing/bun-harness.ts +94 -43
  239. package/src/lib/testing/extractFacts.ts +64 -78
  240. package/src/lib/testing/facts.ts +1 -1
  241. package/src/lib/testing/queryable-span.ts +23 -30
  242. package/src/lib/testing/span-query.ts +16 -20
  243. package/src/lib/testing/stdio-replay.ts +25 -8
  244. package/src/lib/testing/vitest-harness.ts +1 -1
  245. package/src/lib/threadId.ts +6 -3
  246. package/src/lib/traceRoot.es.ts +77 -42
  247. package/src/lib/traceRoot.node.ts +75 -46
  248. package/src/lib/traceRoot.ts +41 -14
  249. package/src/lib/traceTopology.ts +279 -0
  250. package/src/lib/tracer.ts +109 -98
  251. package/src/lib/tracers/ArrayQueueTracer.ts +1 -1
  252. package/src/lib/tracers/StdioTracer.ts +15 -13
  253. package/src/lib/tracers/TestTracer.ts +6 -8
  254. package/src/lib/tracers/__tests__/ArrayQueueTracer.test.ts +15 -10
  255. package/src/lib/tracers/__tests__/TestTracer.test.ts +23 -13
  256. package/src/lib/types.ts +64 -33
  257. package/src/lib/vocabularyRegistry.ts +439 -0
  258. package/src/lib/wasm/WasmBufferStrategy.ts +56 -48
  259. package/src/lib/wasm/__tests__/WasmBufferStrategy.test.ts +215 -11
  260. package/src/lib/wasm/__tests__/allocatorFreeBlockClamp.test.ts +86 -0
  261. package/src/lib/wasm/__tests__/wasm-identity-view.test.ts +311 -0
  262. package/src/lib/wasm/__tests__/wasm-integration.test.ts +417 -44
  263. package/src/lib/wasm/__tests__/wasm-message-buffer-families.test.ts +588 -0
  264. package/src/lib/wasm/__tests__/wasmAllocator.test.ts +100 -668
  265. package/src/lib/wasm/__tests__/wasmSpanBuffer.test.ts +419 -63
  266. package/src/lib/wasm/__tests__/wasmTraceRoot.test.ts +24 -29
  267. package/src/lib/wasm/__tests__/wasmTracer.test.ts.disabled +2 -2
  268. package/src/lib/wasm/wasmAllocator.ts +131 -96
  269. package/src/lib/wasm/wasmPhysicalLayout.ts +309 -0
  270. package/src/lib/wasm/wasmSpanBuffer.ts +597 -341
  271. package/src/lib/wasm/wasmTraceRoot.ts +140 -78
  272. package/src/vocabulary/register/v1.ts +1 -0
  273. package/src/wasm.ts +19 -0
  274. package/src/lib/__tests__/remapped-buffer-view-integration.test.ts +0 -319
  275. package/src/lib/__tests__/remapped-buffer-view.test.ts +0 -635
  276. package/src/lib/wasm/allocator.zig +0 -948
@@ -1,27 +1,17 @@
1
1
  import { describe, expect, test } from 'bun:test';
2
- import { createBuffer, createTestLogBinding, createTestSchema } from '../../__tests__/test-helpers.js';
2
+ import { createBuffer, createTestSchema, createTestSpanContext } from '../../__tests__/test-helpers.js';
3
3
  import type { OpContext } from '../../opContext/types.js';
4
+ import { resolveEntryType } from '../../resolveMessage.js';
4
5
  import { S } from '../../schema/builder.js';
5
6
  import type { FeatureFlagSchema } from '../../schema/defineFeatureFlags.js';
6
7
  import { defineFeatureFlags } from '../../schema/defineFeatureFlags.js';
7
8
  import { InMemoryFlagEvaluator } from '../../schema/evaluator.js';
8
9
  import { ENTRY_TYPE_FF_ACCESS, ENTRY_TYPE_FF_USAGE } from '../../schema/systemSchema.js';
9
- import type { LogSchema } from '../../schema/types.js';
10
- import { createSpanContextClass, type SpanContextInstance } from '../../spanContext.js';
10
+ import type { LogSchema, SchemaFields } from '../../schema/types.js';
11
11
  import type { AnySpanBuffer, SpanBuffer } from '../../types.js';
12
12
  import { createEvaluatorClass, generateEvaluatorClass } from '../evaluatorGenerator.js';
13
- import { createTagWriter } from '../fixedPositionWriterGenerator.js';
14
- import { createSpanLogger } from '../spanLoggerGenerator.js';
15
13
 
16
- /**
17
- * Create a mock SpanContext for testing FeatureFlagEvaluator
18
- *
19
- * The evaluator needs:
20
- * - _buffer with scopeValues and writeIndex
21
- * - log with ffAccess, ffUsage, and _writeIndex
22
- * - buffer getter that returns _buffer
23
- *
24
- */
14
+ /** Create a real shared SpanContext for testing FeatureFlagEvaluator. */
25
15
  type EvaluatorTestContext<TLogSchema extends LogSchema, TFlags extends FeatureFlagSchema> = OpContext<
26
16
  TLogSchema,
27
17
  TFlags,
@@ -29,96 +19,16 @@ type EvaluatorTestContext<TLogSchema extends LogSchema, TFlags extends FeatureFl
29
19
  Record<string, never>
30
20
  >;
31
21
 
32
- function createMockSpanContext<TLogSchema extends LogSchema, TFlags extends FeatureFlagSchema>(
33
- schema: TLogSchema,
34
- spanBuffer: SpanBuffer<TLogSchema>,
35
- ): SpanContextInstance<EvaluatorTestContext<TLogSchema, TFlags>> {
36
- const logger = createSpanLogger(schema, spanBuffer);
37
- const tagWriter = createTagWriter(schema, spanBuffer);
38
- const SpanContextClass = createSpanContextClass<EvaluatorTestContext<TLogSchema, TFlags>>(
39
- schema,
40
- createTestLogBinding(schema),
41
- );
42
- const ctx = new SpanContextClass(spanBuffer, schema, logger, tagWriter);
43
- ctx.deps = {};
44
- return ctx;
22
+ function createMockSpanContext<TFields extends SchemaFields, const TFlags extends FeatureFlagSchema>(
23
+ schema: LogSchema<TFields>,
24
+ spanBuffer: SpanBuffer<LogSchema<TFields>>,
25
+ _flags: TFlags,
26
+ ) {
27
+ return createTestSpanContext<TFields, EvaluatorTestContext<LogSchema<TFields>, TFlags>>(schema, spanBuffer);
45
28
  }
46
29
 
47
30
  describe('EvaluatorGenerator', () => {
48
- describe('generateEvaluatorClass', () => {
49
- test('generates valid JavaScript class code', () => {
50
- const schema = defineFeatureFlags({
51
- debugMode: S.boolean().default(false).sync(),
52
- maxRetries: S.number().default(3).sync(),
53
- });
54
-
55
- const code = generateEvaluatorClass(schema.schema);
56
-
57
- expect(code).toContain('class GeneratedEvaluator extends WorkerSafeGeneratedEvaluator');
58
- expect(code).toContain('Object.defineProperties(GeneratedEvaluator.prototype');
59
-
60
- // Should describe the generated getters for each flag
61
- expect(code).toContain("return this.getFlag('debugMode')");
62
- expect(code).toContain("return this.getFlag('maxRetries')");
63
-
64
- // Should have new API methods (not old ones)
65
- expect(code).toContain('forContext(ctx)');
66
- expect(code).toContain('super(spanContext, evaluator, SCHEMA, validateFlagValue, ENTRY_TYPE_FF_ACCESS);');
67
-
68
- // Should NOT have old API methods
69
- expect(code).not.toContain('withBuffer(');
70
- expect(code).not.toContain('getContext()');
71
- expect(code).not.toContain('new Function');
72
- });
73
-
74
- test('generates unique getter for each flag', () => {
75
- const schema = defineFeatureFlags({
76
- featureA: S.boolean().default(false).sync(),
77
- featureB: S.boolean().default(false).sync(),
78
- featureC: S.number().default(0).sync(),
79
- featureD: S.enum(['a', 'b', 'c'] as const)
80
- .default('a')
81
- .sync(),
82
- });
83
-
84
- const code = generateEvaluatorClass(schema.schema);
85
-
86
- expect(code).toContain('featureA: {');
87
- expect(code).toContain('featureB: {');
88
- expect(code).toContain('featureC: {');
89
- expect(code).toContain('featureD: {');
90
-
91
- // Each getter should call getFlag with the flag name
92
- expect(code).toContain("this.getFlag('featureA')");
93
- expect(code).toContain("this.getFlag('featureB')");
94
- expect(code).toContain("this.getFlag('featureC')");
95
- expect(code).toContain("this.getFlag('featureD')");
96
- });
97
- });
98
-
99
31
  describe('createEvaluatorClass', () => {
100
- test('creates a functional class constructor', () => {
101
- const ffSchema = defineFeatureFlags({
102
- debugMode: S.boolean().default(false).sync(),
103
- });
104
- const logSchema = createTestSchema({});
105
- const spanBuffer = createBuffer(logSchema);
106
- type Ctx = EvaluatorTestContext<typeof logSchema, typeof ffSchema.schema>;
107
- const mockCtx = createMockSpanContext<typeof logSchema, typeof ffSchema.schema>(logSchema, spanBuffer);
108
-
109
- const GeneratedClass = createEvaluatorClass<Ctx>(
110
- ffSchema.schema,
111
- (value, _schema, def) => value ?? def,
112
- ENTRY_TYPE_FF_ACCESS,
113
- );
114
-
115
- expect(typeof GeneratedClass).toBe('function');
116
-
117
- const evaluator = new InMemoryFlagEvaluator<Ctx>(ffSchema.schema, { debugMode: true });
118
- const instance = new GeneratedClass(mockCtx, evaluator);
119
- expect(instance).toBeDefined();
120
- });
121
-
122
32
  test('caches generated classes by schema', () => {
123
33
  const schema = defineFeatureFlags({
124
34
  testFlag: S.boolean().default(false).sync(),
@@ -158,7 +68,7 @@ describe('EvaluatorGenerator', () => {
158
68
  const logSchema = createTestSchema({});
159
69
  const spanBuffer = createBuffer(logSchema);
160
70
  type Ctx = EvaluatorTestContext<typeof logSchema, typeof ffSchema.schema>;
161
- const mockCtx = createMockSpanContext<typeof logSchema, typeof ffSchema.schema>(logSchema, spanBuffer);
71
+ const mockCtx = createMockSpanContext(logSchema, spanBuffer, ffSchema.schema);
162
72
 
163
73
  const GeneratedClass = createEvaluatorClass<Ctx>(
164
74
  ffSchema.schema,
@@ -184,7 +94,7 @@ describe('EvaluatorGenerator', () => {
184
94
  const logSchema = createTestSchema({});
185
95
  const spanBuffer = createBuffer(logSchema);
186
96
  type Ctx = EvaluatorTestContext<typeof logSchema, typeof ffSchema.schema>;
187
- const mockCtx = createMockSpanContext<typeof logSchema, typeof ffSchema.schema>(logSchema, spanBuffer);
97
+ const mockCtx = createMockSpanContext(logSchema, spanBuffer, ffSchema.schema);
188
98
 
189
99
  const GeneratedClass = createEvaluatorClass<Ctx>(
190
100
  ffSchema.schema,
@@ -206,7 +116,7 @@ describe('EvaluatorGenerator', () => {
206
116
  const logSchema = createTestSchema({});
207
117
  const spanBuffer = createBuffer(logSchema);
208
118
  type Ctx = EvaluatorTestContext<typeof logSchema, typeof ffSchema.schema>;
209
- const mockCtx = createMockSpanContext<typeof logSchema, typeof ffSchema.schema>(logSchema, spanBuffer);
119
+ const mockCtx = createMockSpanContext(logSchema, spanBuffer, ffSchema.schema);
210
120
 
211
121
  const GeneratedClass = createEvaluatorClass<Ctx>(
212
122
  ffSchema.schema,
@@ -219,7 +129,7 @@ describe('EvaluatorGenerator', () => {
219
129
 
220
130
  // Create a new SpanContext for child span
221
131
  const childBuffer = createBuffer(logSchema);
222
- const childCtx = createMockSpanContext<typeof logSchema, typeof ffSchema.schema>(logSchema, childBuffer);
132
+ const childCtx = createMockSpanContext(logSchema, childBuffer, ffSchema.schema);
223
133
 
224
134
  const childInstance = instance.forContext(childCtx);
225
135
 
@@ -229,14 +139,11 @@ describe('EvaluatorGenerator', () => {
229
139
  });
230
140
 
231
141
  test('span context scope getter returns the typed buffer scope contract', () => {
232
- const ffSchema = defineFeatureFlags({
233
- debugMode: S.boolean().default(false).sync(),
234
- });
235
142
  const logSchema = createTestSchema({
236
143
  requestId: S.category(),
237
144
  });
238
145
  const spanBuffer = createBuffer(logSchema);
239
- const mockCtx = createMockSpanContext<typeof logSchema, typeof ffSchema.schema>(logSchema, spanBuffer);
146
+ const mockCtx = createTestSpanContext(logSchema, spanBuffer);
240
147
 
241
148
  spanBuffer._scopeValues = Object.freeze({ requestId: 'req-123' });
242
149
 
@@ -258,7 +165,7 @@ describe('EvaluatorGenerator', () => {
258
165
  const logSchema = createTestSchema({});
259
166
  const spanBuffer = createBuffer(logSchema);
260
167
  type Ctx = EvaluatorTestContext<typeof logSchema, typeof ffSchema.schema>;
261
- const mockCtx = createMockSpanContext<typeof logSchema, typeof ffSchema.schema>(logSchema, spanBuffer);
168
+ const mockCtx = createMockSpanContext(logSchema, spanBuffer, ffSchema.schema);
262
169
 
263
170
  let evalCount = 0;
264
171
  const trackingEvaluator = new InMemoryFlagEvaluator<Ctx>(ffSchema.schema, { debugMode: true });
@@ -296,7 +203,7 @@ describe('EvaluatorGenerator', () => {
296
203
  const logSchema = createTestSchema({});
297
204
  const spanBuffer = createBuffer(logSchema);
298
205
  type Ctx = EvaluatorTestContext<typeof logSchema, typeof ffSchema.schema>;
299
- const mockCtx = createMockSpanContext<typeof logSchema, typeof ffSchema.schema>(logSchema, spanBuffer);
206
+ const mockCtx = createMockSpanContext(logSchema, spanBuffer, ffSchema.schema);
300
207
 
301
208
  const GeneratedClass = createEvaluatorClass<Ctx>(
302
209
  ffSchema.schema,
@@ -325,7 +232,7 @@ describe('EvaluatorGenerator', () => {
325
232
  });
326
233
  const spanBuffer = createBuffer(logSchema);
327
234
  type Ctx = EvaluatorTestContext<typeof logSchema, typeof ffSchema.schema>;
328
- const mockCtx = createMockSpanContext<typeof logSchema, typeof ffSchema.schema>(logSchema, spanBuffer);
235
+ const mockCtx = createMockSpanContext(logSchema, spanBuffer, ffSchema.schema);
329
236
 
330
237
  const GeneratedClass = createEvaluatorClass<Ctx>(
331
238
  ffSchema.schema,
@@ -346,7 +253,7 @@ describe('EvaluatorGenerator', () => {
346
253
  // Context should be applied via with(context)
347
254
  let usageIdx = -1;
348
255
  for (let i = 0; i < spanBuffer._writeIndex; i++) {
349
- if (spanBuffer.entry_type[i] === ENTRY_TYPE_FF_USAGE) {
256
+ if (resolveEntryType(spanBuffer, i) === ENTRY_TYPE_FF_USAGE) {
350
257
  usageIdx = i;
351
258
  break;
352
259
  }
@@ -376,7 +283,7 @@ describe('EvaluatorGenerator', () => {
376
283
 
377
284
  const createInstance = () => {
378
285
  const spanBuffer = createBuffer(logSchema);
379
- const mockCtx = createMockSpanContext<typeof logSchema, typeof schema.schema>(logSchema, spanBuffer);
286
+ const mockCtx = createMockSpanContext(logSchema, spanBuffer, schema.schema);
380
287
  return new GeneratedClass(mockCtx, mockEvaluator);
381
288
  };
382
289
 
@@ -414,33 +321,6 @@ describe('EvaluatorGenerator', () => {
414
321
  expect(descriptor?.enumerable).toBe(false);
415
322
  expect(descriptor?.configurable).toBe(true);
416
323
  });
417
-
418
- test('no Proxy in generated class', () => {
419
- const schema = defineFeatureFlags({
420
- testFlag: S.boolean().default(false).sync(),
421
- });
422
-
423
- const code = generateEvaluatorClass(schema.schema);
424
-
425
- // Generated code should not contain Proxy
426
- expect(code).not.toContain('new Proxy');
427
- expect(code).not.toContain('Proxy(');
428
- });
429
-
430
- test('runtime path stays worker-safe', () => {
431
- const schema = defineFeatureFlags({
432
- testFlag: S.boolean().default(false).sync(),
433
- });
434
-
435
- const GeneratedClass = createEvaluatorClass(
436
- schema.schema,
437
- (value, _schema, def) => value ?? def,
438
- ENTRY_TYPE_FF_ACCESS,
439
- );
440
-
441
- expect(() => GeneratedClass).not.toThrow();
442
- expect(GeneratedClass.toString()).not.toContain('new Function');
443
- });
444
324
  });
445
325
  });
446
326
 
@@ -506,7 +386,7 @@ function countEntryType(buffer: AnySpanBuffer, entryType: number): number {
506
386
  while (current) {
507
387
  const writeIndex = current._writeIndex;
508
388
  for (let i = 0; i < writeIndex; i++) {
509
- if (current.entry_type[i] === entryType) {
389
+ if (resolveEntryType(current, i) === entryType) {
510
390
  count++;
511
391
  }
512
392
  }
@@ -0,0 +1,273 @@
1
+ /**
2
+ * Compiled vs closure-composed fixed-position writer parity.
3
+ *
4
+ * getResultWriterClass selects between the compiled renderer (new Function)
5
+ * and the closure-composed materializer via activeMaterializerMode(). This
6
+ * suite drives identical write scripts through both classes against real
7
+ * SpanBuffers and byte-compares every touched lane (values, null bitmaps,
8
+ * message lanes). TagWriter ships closure-only, so its closure class is
9
+ * compared against a compiled reference built from the still-exported
10
+ * generateFixedPositionWriterClass source.
11
+ *
12
+ * Both materializers run under bun via the explicit override hook
13
+ * (setMaterializerModeOverride); afterEach restores probe-based selection.
14
+ */
15
+
16
+ import { afterEach, describe, expect, it } from 'bun:test';
17
+ import { activeMaterializerMode, bufferHelpers, setMaterializerModeOverride } from '@smoothbricks/arrow-builder';
18
+ import {
19
+ createTestOpMetadata,
20
+ createTestSchema,
21
+ createTestSpanContext,
22
+ createTestTraceRoot,
23
+ } from '../../__tests__/test-helpers.js';
24
+ import { resolveEnumLookupDescriptor } from '../../enumMetadata.js';
25
+ import type { MessageLayoutFamily } from '../../runtimeHint.js';
26
+ import { S } from '../../schema/builder.js';
27
+ import type { LogSchema, SchemaFields } from '../../schema/types.js';
28
+ import { createSpanBuffer, getSpanBufferClass } from '../../spanBuffer.js';
29
+ import type { AnySpanBuffer } from '../../types.js';
30
+ import {
31
+ generateFixedPositionWriterClass,
32
+ getResultWriterClass,
33
+ getTagWriterClass,
34
+ type WriterState,
35
+ } from '../fixedPositionWriterGenerator.js';
36
+
37
+ afterEach(() => {
38
+ setMaterializerModeOverride(undefined);
39
+ });
40
+
41
+ // ---------------------------------------------------------------------------
42
+ // Fixtures
43
+ // ---------------------------------------------------------------------------
44
+
45
+ // >256 values force the Uint16 enum index lane, the widest special case.
46
+ const wideEnumValues = Array.from({ length: 300 }, (_, i) => `value_${i}`);
47
+
48
+ // Every value family the writer generator can route to a SpanBuffer setter.
49
+ function createParityFields() {
50
+ return {
51
+ status: S.enum(['ok', 'err']),
52
+ wide: S.enum(wideEnumValues),
53
+ cat: S.category(),
54
+ txt: S.text(),
55
+ num: S.number(),
56
+ bool: S.boolean(),
57
+ bin: S.binary(),
58
+ obj: S.object<{ a: number }>(),
59
+ };
60
+ }
61
+
62
+ const USER_LANES = ['status', 'wide', 'cat', 'txt', 'num', 'bool', 'bin', 'obj'] as const;
63
+ const SYSTEM_LANES = ['uint64_value', 'line'] as const;
64
+
65
+ // SpanBuffer classes still require string codegen, so buffers and contexts are
66
+ // created under the default (compiled) mode; only writer-class creation runs
67
+ // under the closure override.
68
+ function createBufferPair<T extends SchemaFields>(schema: LogSchema<T>, family: MessageLayoutFamily) {
69
+ const BufferClass = getSpanBufferClass(schema, family);
70
+ const bufferA = createSpanBuffer(schema, createTestTraceRoot('a'), createTestOpMetadata(), 8, BufferClass);
71
+ const bufferB = createSpanBuffer(schema, createTestTraceRoot('b'), createTestOpMetadata(), 8, BufferClass);
72
+ return {
73
+ bufferA,
74
+ bufferB,
75
+ contextA: createTestSpanContext(schema, bufferA),
76
+ contextB: createTestSpanContext(schema, bufferB),
77
+ };
78
+ }
79
+
80
+ function withClosureMode<T>(create: () => T): T {
81
+ setMaterializerModeOverride('closure');
82
+ try {
83
+ return create();
84
+ } finally {
85
+ setMaterializerModeOverride(undefined);
86
+ }
87
+ }
88
+
89
+ // ---------------------------------------------------------------------------
90
+ // Reflect helpers (schema-dynamic methods; repo lint bans unsafe assertions)
91
+ // ---------------------------------------------------------------------------
92
+
93
+ function constructWriter(ctor: unknown, state: WriterState): object {
94
+ if (typeof ctor !== 'function') throw new Error('writer constructor is not callable');
95
+ const instance: unknown = Reflect.construct(ctor, [state]);
96
+ if (typeof instance !== 'object' || instance === null) throw new Error('writer construction failed');
97
+ return instance;
98
+ }
99
+
100
+ function call(writer: object, method: string, value: unknown): unknown {
101
+ const fn = Reflect.get(writer, method);
102
+ if (typeof fn !== 'function') throw new Error(`missing writer method ${JSON.stringify(method)}`);
103
+ return Reflect.apply(fn, writer, [value]);
104
+ }
105
+
106
+ function prototypeOf(ctor: unknown): object {
107
+ if (typeof ctor !== 'function') throw new Error('expected a constructor');
108
+ const proto: unknown = Reflect.get(ctor, 'prototype');
109
+ if (typeof proto !== 'object' || proto === null) throw new Error('expected a prototype object');
110
+ return proto;
111
+ }
112
+
113
+ function nameOf(ctor: unknown): string {
114
+ if (typeof ctor !== 'function') throw new Error('expected a constructor');
115
+ return ctor.name;
116
+ }
117
+
118
+ // ---------------------------------------------------------------------------
119
+ // Write scripts (identical for both materializers)
120
+ // ---------------------------------------------------------------------------
121
+
122
+ function runFieldScript(writer: object): void {
123
+ // Invalid enum values encode to ordinal 0 before the valid overwrite.
124
+ expect(call(writer, 'status', 'not-a-value')).toBe(writer);
125
+ call(writer, 'status', 'err');
126
+ call(writer, 'wide', 'value_299');
127
+ call(writer, 'cat', 'checkout');
128
+ call(writer, 'txt', 'unique text \u2713');
129
+ call(writer, 'num', 42.5);
130
+ call(writer, 'bool', true);
131
+ call(writer, 'bin', Uint8Array.of(1, 2, 3));
132
+ call(writer, 'obj', { a: 7 });
133
+ call(writer, 'uint64_value', 123456789n);
134
+ // Bulk set: null/undefined entries are skipped, unknown keys ignored.
135
+ call(writer, 'with', { status: 'ok', num: 7, cat: null, txt: undefined, notAColumn: 'ignored' });
136
+ }
137
+
138
+ function runResultScript(writer: object): void {
139
+ runFieldScript(writer);
140
+ call(writer, 'message', 'span message');
141
+ call(writer, 'line', 1234);
142
+ }
143
+
144
+ // ---------------------------------------------------------------------------
145
+ // Lane comparison
146
+ // ---------------------------------------------------------------------------
147
+
148
+ function expectIdenticalLanes(actual: AnySpanBuffer, expected: AnySpanBuffer, lanes: readonly string[]): void {
149
+ for (const lane of lanes) {
150
+ const actualValues = actual.getColumnIfAllocated(lane);
151
+ const expectedValues = expected.getColumnIfAllocated(lane);
152
+ expect(actualValues?.constructor).toBe(expectedValues?.constructor);
153
+ expect(actualValues).toEqual(expectedValues);
154
+ expect(actual.getNullsIfAllocated(lane)).toEqual(expected.getNullsIfAllocated(lane));
155
+ }
156
+ }
157
+
158
+ // ---------------------------------------------------------------------------
159
+ // ResultWriter parity (compiled vs closure)
160
+ // ---------------------------------------------------------------------------
161
+
162
+ describe('ResultWriter compiled/closure parity', () => {
163
+ const families: readonly MessageLayoutFamily[] = ['mixed', 'dynamic-only', 'static-only'];
164
+
165
+ for (const family of families) {
166
+ it(`writes byte-identical lanes for the ${family} message layout family`, () => {
167
+ expect(activeMaterializerMode()).toBe('compiled');
168
+ const schema = createTestSchema(createParityFields());
169
+ const { bufferA, bufferB, contextA, contextB } = createBufferPair(schema, family);
170
+
171
+ const Compiled = getResultWriterClass(schema, family, 'current');
172
+ const Closure = withClosureMode(() => getResultWriterClass(schema, family, 'current'));
173
+ expect(Closure).not.toBe(Compiled);
174
+ expect(nameOf(Closure)).toBe(nameOf(Compiled));
175
+
176
+ const compiledWriter = constructWriter(Compiled, contextA);
177
+ const closureWriter = constructWriter(Closure, contextB);
178
+ expect(Reflect.ownKeys(closureWriter)).toEqual(Reflect.ownKeys(compiledWriter));
179
+
180
+ runResultScript(compiledWriter);
181
+ runResultScript(closureWriter);
182
+
183
+ expectIdenticalLanes(bufferB, bufferA, [...USER_LANES, ...SYSTEM_LANES]);
184
+ if (family === 'static-only') {
185
+ expect(bufferA._terminalMessage).toBe('span message');
186
+ expect(bufferB._terminalMessage).toBe(bufferA._terminalMessage);
187
+ expect(bufferB.message_values).toBeUndefined();
188
+ expect(bufferA.message_values).toBeUndefined();
189
+ } else {
190
+ expect(bufferA.message_values?.[1]).toBe('span message');
191
+ expect(bufferB.message_values).toEqual(bufferA.message_values);
192
+ expect(bufferB._terminalMessage).toBe(bufferA._terminalMessage);
193
+ }
194
+ });
195
+ }
196
+
197
+ it('installs class-member-equivalent prototype descriptors', () => {
198
+ const schema = createTestSchema(createParityFields());
199
+ const Compiled = getResultWriterClass(schema, 'mixed', 'current');
200
+ const Closure = withClosureMode(() => getResultWriterClass(schema, 'mixed', 'current'));
201
+
202
+ const compiledProto = prototypeOf(Compiled);
203
+ const closureProto = prototypeOf(Closure);
204
+ const members = [...schema._columns.map(([fieldName]) => fieldName), 'with', 'message', 'line', 'uint64_value'];
205
+
206
+ for (const member of members) {
207
+ const compiledDescriptor = Object.getOwnPropertyDescriptor(compiledProto, member);
208
+ const closureDescriptor = Object.getOwnPropertyDescriptor(closureProto, member);
209
+ if (!compiledDescriptor || !closureDescriptor) {
210
+ throw new Error(`missing prototype member ${JSON.stringify(member)}`);
211
+ }
212
+ expect(closureDescriptor.writable).toBe(compiledDescriptor.writable);
213
+ expect(closureDescriptor.configurable).toBe(compiledDescriptor.configurable);
214
+ expect(closureDescriptor.enumerable).toBe(compiledDescriptor.enumerable);
215
+ expect(typeof closureDescriptor.value).toBe(typeof compiledDescriptor.value);
216
+ if (typeof closureDescriptor.value === 'function' && typeof compiledDescriptor.value === 'function') {
217
+ expect(closureDescriptor.value.name).toBe(compiledDescriptor.value.name);
218
+ }
219
+ }
220
+ });
221
+
222
+ it('caches classes per materializer mode and restores on override reset', () => {
223
+ const schema = createTestSchema({ n: S.number() });
224
+ const compiled = getResultWriterClass(schema);
225
+ expect(getResultWriterClass(schema)).toBe(compiled);
226
+
227
+ setMaterializerModeOverride('closure');
228
+ const closure = getResultWriterClass(schema);
229
+ expect(getResultWriterClass(schema)).toBe(closure);
230
+ expect(closure).not.toBe(compiled);
231
+
232
+ setMaterializerModeOverride(undefined);
233
+ expect(getResultWriterClass(schema)).toBe(compiled);
234
+ });
235
+ });
236
+
237
+ // ---------------------------------------------------------------------------
238
+ // TagWriter parity (shipped closure class vs compiled-source reference)
239
+ // ---------------------------------------------------------------------------
240
+
241
+ describe('TagWriter closure vs compiled-source reference parity', () => {
242
+ it('writes byte-identical row-0 lanes', () => {
243
+ const schema = createTestSchema(createParityFields());
244
+ const enumLookup = resolveEnumLookupDescriptor(schema);
245
+ const { bufferA, bufferB, contextA, contextB } = createBufferPair(schema, 'mixed');
246
+
247
+ // Compiled reference assembled here (tests run under bun where string
248
+ // codegen is allowed); production tag writers never eval.
249
+ const classCode = generateFixedPositionWriterClass(
250
+ schema,
251
+ 0,
252
+ 'GeneratedTagWriter',
253
+ undefined,
254
+ [],
255
+ enumLookup,
256
+ ).trim();
257
+ const factory = new Function('helpers', 'enumLookup', classCode);
258
+ const CompiledTag: unknown = factory(bufferHelpers, enumLookup);
259
+
260
+ const ClosureTag = withClosureMode(() => getTagWriterClass(schema));
261
+ expect(getTagWriterClass(schema)).toBe(ClosureTag);
262
+ expect(nameOf(ClosureTag)).toBe(nameOf(CompiledTag));
263
+
264
+ const compiledWriter = constructWriter(CompiledTag, contextA);
265
+ const closureWriter = constructWriter(ClosureTag, contextB);
266
+ expect(Reflect.ownKeys(closureWriter)).toEqual(Reflect.ownKeys(compiledWriter));
267
+
268
+ runFieldScript(compiledWriter);
269
+ runFieldScript(closureWriter);
270
+
271
+ expectIdenticalLanes(bufferB, bufferA, [...USER_LANES, 'uint64_value']);
272
+ });
273
+ });