@bldrs-ai/conway 1.389.1221 → 1.394.1504
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/README.md +36 -22
- package/compiled/Dist/ConwayGeomWasmNode.js +0 -0
- package/compiled/Dist/ConwayGeomWasmNodeMT.js +0 -0
- package/compiled/Dist/ConwayGeomWasmWeb.js +0 -0
- package/compiled/Dist/ConwayGeomWasmWebMT.js +1 -1
- package/compiled/Dist/ConwayGeomWasmWebMT.wasm +0 -0
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmNode.js +0 -0
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmNodeMT.js +0 -0
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWeb.js +0 -0
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWebMT.js +1 -1
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWebMT.wasm +0 -0
- package/compiled/dependencies/conway-geom/interface/conway_geometry.d.ts +19 -0
- package/compiled/dependencies/conway-geom/interface/conway_geometry.d.ts.map +1 -1
- package/compiled/dependencies/conway-geom/interface/conway_geometry.js +17 -0
- package/compiled/dependencies/conway-geom/interface/parameters/surface_object.d.ts +6 -0
- package/compiled/dependencies/conway-geom/interface/parameters/surface_object.d.ts.map +1 -1
- package/compiled/examples/browser-bundled.cjs +1569 -51
- package/compiled/examples/cli-bundled.cjs +2790 -436
- package/compiled/examples/cli-step-bundled.cjs +1904 -229
- package/compiled/examples/validator-bundled.cjs +1569 -51
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_curve.gen.d.ts +2 -2
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_curve.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_curve.gen.js +2 -2
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_surface.gen.d.ts +3 -3
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_surface.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_surface.gen.js +3 -3
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/composite_curve.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/composite_curve.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/composite_curve.gen.js +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_2d.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_2d.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_2d.gen.js +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_3d.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_3d.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_3d.gen.js +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_surface.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_surface.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_surface.gen.js +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/presentation_style_assignment.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/presentation_style_assignment.gen.js +2 -2
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/schema_ap214.gen.js +11 -11
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/shape_aspect.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/shape_aspect.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/shape_aspect.gen.js +1 -1
- package/compiled/src/AP214E3_2010/ap214_command_line_main.js +7 -3
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.d.ts +181 -7
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.js +906 -137
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.test.js +10 -2
- package/compiled/src/AP214E3_2010/ap214_logical_attribute.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_logical_attribute.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_logical_attribute.test.js +114 -0
- package/compiled/src/AP214E3_2010/ap214_model_geometry.d.ts +6 -0
- package/compiled/src/AP214E3_2010/ap214_model_geometry.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/ap214_model_geometry.js +9 -0
- package/compiled/src/AP214E3_2010/ap214_pcurve_basis_surfaces.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_pcurve_basis_surfaces.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_pcurve_basis_surfaces.test.js +233 -0
- package/compiled/src/AP214E3_2010/ap214_sphere_vertex_loop.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_sphere_vertex_loop.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_sphere_vertex_loop.test.js +147 -0
- package/compiled/src/AP214E3_2010/ap214_step_model.d.ts +2 -1
- package/compiled/src/AP214E3_2010/ap214_step_model.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/ap214_step_model.js +1 -1
- package/compiled/src/AP214E3_2010/ap214_typed_select_enum.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_typed_select_enum.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_typed_select_enum.test.js +65 -0
- package/compiled/src/AP214E3_2010/ap214_unit_scale.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_unit_scale.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_unit_scale.test.js +111 -0
- package/compiled/src/compat/web-ifc/ap214_streamed_open.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ap214_streamed_open.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ap214_streamed_open.test.js +190 -0
- package/compiled/src/compat/web-ifc/coordination_export_order.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/coordination_export_order.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/coordination_export_order.test.js +110 -0
- package/compiled/src/compat/web-ifc/coordination_f64.d.ts +165 -0
- package/compiled/src/compat/web-ifc/coordination_f64.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/coordination_f64.js +286 -0
- package/compiled/src/compat/web-ifc/coordination_f64.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/coordination_f64.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/coordination_f64.test.js +225 -0
- package/compiled/src/compat/web-ifc/ifc_api.d.ts +154 -0
- package/compiled/src/compat/web-ifc/ifc_api.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api.js +211 -3
- package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.js +288 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough.d.ts +39 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.d.ts +30 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.js +83 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.js +383 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_coordination.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_coordination.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_coordination.test.js +124 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.d.ts +132 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.js +488 -92
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts +268 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.js +996 -149
- package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.js +129 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.d.ts +134 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.js +933 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.test.js +467 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.d.ts +187 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.js +524 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.test.js +234 -0
- package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts +306 -0
- package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/streamed_preview_channel.js +580 -0
- package/compiled/src/compat/web-ifc/web_wasm_directory.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/web_wasm_directory.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/web_wasm_directory.test.js +22 -0
- package/compiled/src/core/composed_model_skeleton.d.ts +63 -0
- package/compiled/src/core/composed_model_skeleton.d.ts.map +1 -0
- package/compiled/src/core/composed_model_skeleton.js +66 -0
- package/compiled/src/core/composed_model_skeleton.test.d.ts +2 -0
- package/compiled/src/core/composed_model_skeleton.test.d.ts.map +1 -0
- package/compiled/src/core/composed_model_skeleton.test.js +69 -0
- package/compiled/src/core/demand_geometry_queue.d.ts +147 -0
- package/compiled/src/core/demand_geometry_queue.d.ts.map +1 -0
- package/compiled/src/core/demand_geometry_queue.js +223 -0
- package/compiled/src/core/demand_geometry_queue.test.d.ts +2 -0
- package/compiled/src/core/demand_geometry_queue.test.d.ts.map +1 -0
- package/compiled/src/core/demand_geometry_queue.test.js +133 -0
- package/compiled/src/core/demand_residency_pump.d.ts +93 -0
- package/compiled/src/core/demand_residency_pump.d.ts.map +1 -0
- package/compiled/src/core/demand_residency_pump.js +120 -0
- package/compiled/src/core/demand_residency_pump.test.d.ts +2 -0
- package/compiled/src/core/demand_residency_pump.test.d.ts.map +1 -0
- package/compiled/src/core/demand_residency_pump.test.js +148 -0
- package/compiled/src/core/geometry_tile_bindings.d.ts +110 -0
- package/compiled/src/core/geometry_tile_bindings.d.ts.map +1 -0
- package/compiled/src/core/geometry_tile_bindings.js +76 -0
- package/compiled/src/core/geometry_tile_bindings.test.d.ts +2 -0
- package/compiled/src/core/geometry_tile_bindings.test.d.ts.map +1 -0
- package/compiled/src/core/geometry_tile_bindings.test.js +211 -0
- package/compiled/src/core/geometry_tile_pool.d.ts +99 -0
- package/compiled/src/core/geometry_tile_pool.d.ts.map +1 -0
- package/compiled/src/core/geometry_tile_pool.js +104 -0
- package/compiled/src/core/geometry_tile_pool.test.d.ts +2 -0
- package/compiled/src/core/geometry_tile_pool.test.d.ts.map +1 -0
- package/compiled/src/core/geometry_tile_pool.test.js +180 -0
- package/compiled/src/core/mem/chunked_pool.d.ts +116 -0
- package/compiled/src/core/mem/chunked_pool.d.ts.map +1 -0
- package/compiled/src/core/mem/chunked_pool.js +149 -0
- package/compiled/src/core/mem/chunked_pool.test.d.ts +2 -0
- package/compiled/src/core/mem/chunked_pool.test.d.ts.map +1 -0
- package/compiled/src/core/mem/chunked_pool.test.js +63 -0
- package/compiled/src/core/mem/shared_asset_pool.d.ts +82 -0
- package/compiled/src/core/mem/shared_asset_pool.d.ts.map +1 -0
- package/compiled/src/core/mem/shared_asset_pool.js +113 -0
- package/compiled/src/core/mem/shared_asset_pool.test.d.ts +2 -0
- package/compiled/src/core/mem/shared_asset_pool.test.d.ts.map +1 -0
- package/compiled/src/core/mem/shared_asset_pool.test.js +49 -0
- package/compiled/src/core/model_registry.d.ts +87 -0
- package/compiled/src/core/model_registry.d.ts.map +1 -0
- package/compiled/src/core/model_registry.js +101 -0
- package/compiled/src/core/model_registry.test.d.ts +2 -0
- package/compiled/src/core/model_registry.test.d.ts.map +1 -0
- package/compiled/src/core/model_registry.test.js +60 -0
- package/compiled/src/core/model_uri.d.ts +57 -0
- package/compiled/src/core/model_uri.d.ts.map +1 -0
- package/compiled/src/core/model_uri.js +101 -0
- package/compiled/src/core/model_uri.test.d.ts +2 -0
- package/compiled/src/core/model_uri.test.d.ts.map +1 -0
- package/compiled/src/core/model_uri.test.js +49 -0
- package/compiled/src/core/progress.d.ts +16 -2
- package/compiled/src/core/progress.d.ts.map +1 -1
- package/compiled/src/core/progress.js +31 -5
- package/compiled/src/core/progress.test.js +11 -2
- package/compiled/src/core/progress_log.d.ts +1 -0
- package/compiled/src/core/progress_log.d.ts.map +1 -1
- package/compiled/src/core/progress_log.js +7 -2
- package/compiled/src/core/progress_log.test.js +21 -0
- package/compiled/src/core/shared_byte_budget.d.ts +60 -0
- package/compiled/src/core/shared_byte_budget.d.ts.map +1 -0
- package/compiled/src/core/shared_byte_budget.js +85 -0
- package/compiled/src/core/shared_byte_budget.test.d.ts +2 -0
- package/compiled/src/core/shared_byte_budget.test.d.ts.map +1 -0
- package/compiled/src/core/shared_byte_budget.test.js +55 -0
- package/compiled/src/core/wasm_heap.d.ts +208 -0
- package/compiled/src/core/wasm_heap.d.ts.map +1 -0
- package/compiled/src/core/wasm_heap.js +417 -0
- package/compiled/src/core/wasm_heap.test.d.ts +2 -0
- package/compiled/src/core/wasm_heap.test.d.ts.map +1 -0
- package/compiled/src/core/wasm_heap.test.js +546 -0
- package/compiled/src/demand/index.d.ts +23 -0
- package/compiled/src/demand/index.d.ts.map +1 -0
- package/compiled/src/demand/index.js +22 -0
- package/compiled/src/ifc/ifc4_gen/IfcLogical.gen.d.ts +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcLogical.gen.d.ts.map +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcLogical.gen.js +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcPresentationStyleAssignment.gen.d.ts.map +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcPresentationStyleAssignment.gen.js +2 -2
- package/compiled/src/ifc/ifc4_gen/IfcRelInterferesElements.gen.d.ts +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcRelInterferesElements.gen.d.ts.map +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcRelInterferesElements.gen.js +1 -1
- package/compiled/src/ifc/ifc4_gen/schema_ifc.gen.js +2 -2
- package/compiled/src/ifc/ifc_demand_extraction.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_demand_extraction.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_demand_extraction.test.js +251 -0
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts +367 -6
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_geometry_extraction.js +1322 -389
- package/compiled/src/ifc/ifc_grid_placement.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_grid_placement.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_grid_placement.test.js +261 -0
- package/compiled/src/ifc/ifc_model_geometry.d.ts +12 -0
- package/compiled/src/ifc/ifc_model_geometry.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_model_geometry.js +15 -0
- package/compiled/src/ifc/ifc_regression_batch_main.js +210 -12
- package/compiled/src/ifc/ifc_spatial_skeleton.d.ts +145 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.js +266 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.test.js +199 -0
- package/compiled/src/ifc/ifc_step_model.d.ts +6 -2
- package/compiled/src/ifc/ifc_step_model.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_step_model.js +6 -4
- package/compiled/src/ifc/ifc_step_parser.d.ts +58 -0
- package/compiled/src/ifc/ifc_step_parser.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_step_parser.js +64 -0
- package/compiled/src/ifc/ifc_stream_model.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_stream_model.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_stream_model.test.js +70 -0
- package/compiled/src/ifc/ifc_stream_open.d.ts +131 -0
- package/compiled/src/ifc/ifc_stream_open.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_stream_open.js +116 -0
- package/compiled/src/ifc/ifc_stream_open.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_stream_open.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_stream_open.test.js +230 -0
- package/compiled/src/ifc/ifc_tile_extractor.d.ts +84 -0
- package/compiled/src/ifc/ifc_tile_extractor.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_tile_extractor.js +134 -0
- package/compiled/src/ifc/ifc_tile_extractor.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_tile_extractor.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_tile_extractor.test.js +118 -0
- package/compiled/src/ifc/ifc_typed_select_enum.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_typed_select_enum.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_typed_select_enum.test.js +60 -0
- package/compiled/src/index.d.ts +21 -1
- package/compiled/src/index.d.ts.map +1 -1
- package/compiled/src/index.js +28 -1
- package/compiled/src/logging/logger.d.ts +16 -2
- package/compiled/src/logging/logger.d.ts.map +1 -1
- package/compiled/src/logging/logger.js +34 -7
- package/compiled/src/logging/logger.test.js +30 -0
- package/compiled/src/mem/index.d.ts +17 -0
- package/compiled/src/mem/index.d.ts.map +1 -0
- package/compiled/src/mem/index.js +16 -0
- package/compiled/src/namespace_surface.test.d.ts +2 -0
- package/compiled/src/namespace_surface.test.d.ts.map +1 -0
- package/compiled/src/namespace_surface.test.js +43 -0
- package/compiled/src/parsing/parsing_buffer.d.ts +23 -0
- package/compiled/src/parsing/parsing_buffer.d.ts.map +1 -1
- package/compiled/src/parsing/parsing_buffer.js +31 -0
- package/compiled/src/scripts/model_report_displacement.test.d.ts +2 -0
- package/compiled/src/scripts/model_report_displacement.test.d.ts.map +1 -0
- package/compiled/src/scripts/model_report_displacement.test.js +104 -0
- package/compiled/src/scripts/render_glb_paths.test.d.ts +2 -0
- package/compiled/src/scripts/render_glb_paths.test.d.ts.map +1 -0
- package/compiled/src/scripts/render_glb_paths.test.js +115 -0
- package/compiled/src/step/indexing/step_type_indexer.d.ts +20 -0
- package/compiled/src/step/indexing/step_type_indexer.d.ts.map +1 -1
- package/compiled/src/step/indexing/step_type_indexer.js +67 -0
- package/compiled/src/step/parsing/byte_source.d.ts +153 -0
- package/compiled/src/step/parsing/byte_source.d.ts.map +1 -0
- package/compiled/src/step/parsing/byte_source.js +106 -0
- package/compiled/src/step/parsing/byte_source.test.d.ts +2 -0
- package/compiled/src/step/parsing/byte_source.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/byte_source.test.js +47 -0
- package/compiled/src/step/parsing/byte_source_node.d.ts +41 -0
- package/compiled/src/step/parsing/byte_source_node.d.ts.map +1 -0
- package/compiled/src/step/parsing/byte_source_node.js +54 -0
- package/compiled/src/step/parsing/columnar_index.d.ts +103 -0
- package/compiled/src/step/parsing/columnar_index.d.ts.map +1 -0
- package/compiled/src/step/parsing/columnar_index.js +224 -0
- package/compiled/src/step/parsing/columnar_index.test.d.ts +2 -0
- package/compiled/src/step/parsing/columnar_index.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/columnar_index.test.js +155 -0
- package/compiled/src/step/parsing/cross_reference_registry.d.ts +95 -0
- package/compiled/src/step/parsing/cross_reference_registry.d.ts.map +1 -0
- package/compiled/src/step/parsing/cross_reference_registry.js +91 -0
- package/compiled/src/step/parsing/cross_reference_registry.test.d.ts +2 -0
- package/compiled/src/step/parsing/cross_reference_registry.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/cross_reference_registry.test.js +66 -0
- package/compiled/src/step/parsing/decode_utf8.d.ts +15 -0
- package/compiled/src/step/parsing/decode_utf8.d.ts.map +1 -1
- package/compiled/src/step/parsing/decode_utf8.js +28 -0
- package/compiled/src/step/parsing/express_ref_scan.d.ts +20 -0
- package/compiled/src/step/parsing/express_ref_scan.d.ts.map +1 -0
- package/compiled/src/step/parsing/express_ref_scan.js +91 -0
- package/compiled/src/step/parsing/express_ref_scan.test.d.ts +2 -0
- package/compiled/src/step/parsing/express_ref_scan.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/express_ref_scan.test.js +28 -0
- package/compiled/src/step/parsing/index_sidecar.d.ts +81 -0
- package/compiled/src/step/parsing/index_sidecar.d.ts.map +1 -0
- package/compiled/src/step/parsing/index_sidecar.js +283 -0
- package/compiled/src/step/parsing/index_sidecar.test.d.ts +2 -0
- package/compiled/src/step/parsing/index_sidecar.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/index_sidecar.test.js +122 -0
- package/compiled/src/step/parsing/inf_recovery_index.test.d.ts +2 -0
- package/compiled/src/step/parsing/inf_recovery_index.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/inf_recovery_index.test.js +108 -0
- package/compiled/src/step/parsing/prefix_type_index.d.ts +124 -0
- package/compiled/src/step/parsing/prefix_type_index.d.ts.map +1 -0
- package/compiled/src/step/parsing/prefix_type_index.js +207 -0
- package/compiled/src/step/parsing/prefix_type_index.test.d.ts +2 -0
- package/compiled/src/step/parsing/prefix_type_index.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/prefix_type_index.test.js +298 -0
- package/compiled/src/step/parsing/range_byte_source.d.ts +69 -0
- package/compiled/src/step/parsing/range_byte_source.d.ts.map +1 -0
- package/compiled/src/step/parsing/range_byte_source.js +78 -0
- package/compiled/src/step/parsing/range_byte_source.test.d.ts +2 -0
- package/compiled/src/step/parsing/range_byte_source.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/range_byte_source.test.js +70 -0
- package/compiled/src/step/parsing/record_event.d.ts +23 -0
- package/compiled/src/step/parsing/record_event.d.ts.map +1 -0
- package/compiled/src/step/parsing/record_event.js +1 -0
- package/compiled/src/step/parsing/record_field_cursor.d.ts +94 -0
- package/compiled/src/step/parsing/record_field_cursor.d.ts.map +1 -0
- package/compiled/src/step/parsing/record_field_cursor.js +189 -0
- package/compiled/src/step/parsing/step_deserialization_functions.d.ts +29 -0
- package/compiled/src/step/parsing/step_deserialization_functions.d.ts.map +1 -1
- package/compiled/src/step/parsing/step_deserialization_functions.js +45 -0
- package/compiled/src/step/parsing/step_deserialization_functions.test.js +59 -1
- package/compiled/src/step/parsing/step_parser.d.ts +66 -1
- package/compiled/src/step/parsing/step_parser.d.ts.map +1 -1
- package/compiled/src/step/parsing/step_parser.js +164 -10
- package/compiled/src/step/parsing/step_string_parser.js +8 -8
- package/compiled/src/step/parsing/streaming_index_builder.d.ts +141 -0
- package/compiled/src/step/parsing/streaming_index_builder.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_index_builder.js +280 -0
- package/compiled/src/step/parsing/streaming_index_builder.test.d.ts +2 -0
- package/compiled/src/step/parsing/streaming_index_builder.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_index_builder.test.js +107 -0
- package/compiled/src/step/parsing/streaming_index_builder_async.test.d.ts +2 -0
- package/compiled/src/step/parsing/streaming_index_builder_async.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_index_builder_async.test.js +109 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.d.ts +71 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.js +88 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.test.d.ts +2 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.test.js +66 -0
- package/compiled/src/step/parsing/uint32_sink.d.ts +72 -0
- package/compiled/src/step/parsing/uint32_sink.d.ts.map +1 -0
- package/compiled/src/step/parsing/uint32_sink.js +180 -0
- package/compiled/src/step/parsing/uint32_sink.test.d.ts +2 -0
- package/compiled/src/step/parsing/uint32_sink.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/uint32_sink.test.js +199 -0
- package/compiled/src/step/step_buffer_provider.d.ts +48 -3
- package/compiled/src/step/step_buffer_provider.d.ts.map +1 -1
- package/compiled/src/step/step_buffer_provider.js +60 -11
- package/compiled/src/step/step_buffer_provider.test.js +14 -0
- package/compiled/src/step/step_entity_base.d.ts +65 -3
- package/compiled/src/step/step_entity_base.d.ts.map +1 -1
- package/compiled/src/step/step_entity_base.js +135 -3
- package/compiled/src/step/step_model_base.d.ts +221 -8
- package/compiled/src/step/step_model_base.d.ts.map +1 -1
- package/compiled/src/step/step_model_base.js +542 -7
- package/compiled/src/stream/index.d.ts +34 -0
- package/compiled/src/stream/index.d.ts.map +1 -0
- package/compiled/src/stream/index.js +32 -0
- package/compiled/src/version/version.js +1 -1
- package/compiled/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -1
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import ParsingBuffer from "../../parsing/parsing_buffer.js";
|
|
2
|
+
import { ColumnarIndexSink } from "./columnar_index.js";
|
|
3
|
+
import { ParseResult, } from "./step_parser.js";
|
|
4
|
+
/**
|
|
5
|
+
* Build the entity index by streaming a `ByteSource` through a fixed-size
|
|
6
|
+
* moving window, instead of parsing one resident buffer. The parse loop is
|
|
7
|
+
* byte-for-byte the resident one (`StepParser.parseDataBlockStreamed` drives
|
|
8
|
+
* the same generator); this coordinator only owns the window: it fills it,
|
|
9
|
+
* parses the header from the first fill, then slides the window forward at
|
|
10
|
+
* top-level record boundaries as the parser advances.
|
|
11
|
+
*
|
|
12
|
+
* Because the parser records file-absolute addresses and its rewind stack is
|
|
13
|
+
* empty at every top-level boundary, sliding there is transparent: the
|
|
14
|
+
* unconsumed tail is copied to the front, fresh bytes are appended, and the
|
|
15
|
+
* buffer is rebased so `address` keeps its file-absolute value. Peak JS heap
|
|
16
|
+
* for the index build is therefore `window + index columns`, independent of
|
|
17
|
+
* file size.
|
|
18
|
+
*
|
|
19
|
+
* The window slides only once the cursor passes `pool / 2`, bounding the
|
|
20
|
+
* memmove frequency; a record up to `pool / 2` bytes always fits after a
|
|
21
|
+
* slide. If a single record exceeds that (never on the current corpus, whose
|
|
22
|
+
* largest STEP record is ~25 KB), the whole parse restarts from the
|
|
23
|
+
* beginning with the window doubled, and repeats until every record fits —
|
|
24
|
+
* correctness over the pathological case, at the cost of a re-scan. (M1's
|
|
25
|
+
* production path will instead grow in place / restart from the last
|
|
26
|
+
* boundary; from-scratch keeps the spike simple.)
|
|
27
|
+
*
|
|
28
|
+
* @param source The byte source.
|
|
29
|
+
* @param parser The STEP parser (typed to the schema).
|
|
30
|
+
* @param pool Target window size in bytes.
|
|
31
|
+
* @param onRecordIndexed Optional per-record event, invoked live as each
|
|
32
|
+
* top-level record is indexed with its (localID, expressID, typeID) — the
|
|
33
|
+
* seam for incremental semantic consumers (M2). localIDs are dense and
|
|
34
|
+
* assigned in parse order from 0. On the rare grow-and-restart (a single
|
|
35
|
+
* record larger than the window — never on real files, whose largest STEP
|
|
36
|
+
* record is ~25 KB), the parse re-runs from the start and records re-fire
|
|
37
|
+
* from localID 0; consumers must therefore be idempotent by localID /
|
|
38
|
+
* expressID (the standard consumers — type index keyed by localID, roots
|
|
39
|
+
* registry keyed by expressID — are). Must be synchronous and cheap;
|
|
40
|
+
* expensive work belongs on a demand queue, not the parse path.
|
|
41
|
+
* @return {StreamingIndexResult} The index, header, result and diagnostics.
|
|
42
|
+
*/
|
|
43
|
+
export function buildIndexStreaming(source, parser, pool, onRecordIndexed, sink) {
|
|
44
|
+
const fileSize = source.byteLength;
|
|
45
|
+
// Grow-and-restart loop: the body runs a full streamed parse at the current
|
|
46
|
+
// window size. It only re-runs if a single record couldn't fit the window
|
|
47
|
+
// (false end-of-file before true EOF), doubling the window each time.
|
|
48
|
+
let windowBytes = Math.max(pool, MIN_WINDOW);
|
|
49
|
+
for (;;) {
|
|
50
|
+
const window = new Uint8Array(windowBytes);
|
|
51
|
+
let windowStartFile = 0;
|
|
52
|
+
let windowLen = source.read(0, windowBytes, window, 0);
|
|
53
|
+
let bytesRead = windowLen;
|
|
54
|
+
const input = new ParsingBuffer(window, 0, windowLen);
|
|
55
|
+
const [header, headerResult] = parser.parseHeader(input);
|
|
56
|
+
if (headerResult !== ParseResult.COMPLETE) {
|
|
57
|
+
// Header didn't complete in the first window: either malformed, or a
|
|
58
|
+
// header larger than the pool. Report it as-is — the resident parse
|
|
59
|
+
// would surface the same header result.
|
|
60
|
+
return {
|
|
61
|
+
header,
|
|
62
|
+
elements: [],
|
|
63
|
+
result: headerResult,
|
|
64
|
+
stats: { pool, windowBytes, slides: 0, maxRecordLen: 0, bytesRead },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// Slide once the cursor is past half the window; a record up to this much
|
|
68
|
+
// headroom always fits without a false EOF.
|
|
69
|
+
const slideThreshold = windowBytes >> 1;
|
|
70
|
+
let slides = 0;
|
|
71
|
+
let maxRecordLen = 0;
|
|
72
|
+
let prevBoundaryFile = windowStartFile + input.cursor;
|
|
73
|
+
const onRecordBoundary = (buffer) => {
|
|
74
|
+
const cursor = buffer.cursor;
|
|
75
|
+
const recordFileStart = windowStartFile + cursor;
|
|
76
|
+
const recordLen = recordFileStart - prevBoundaryFile;
|
|
77
|
+
if (recordLen > maxRecordLen) {
|
|
78
|
+
maxRecordLen = recordLen;
|
|
79
|
+
}
|
|
80
|
+
prevBoundaryFile = recordFileStart;
|
|
81
|
+
// Window already spans to EOF — nothing left to slide in.
|
|
82
|
+
if (windowStartFile + windowLen >= fileSize) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Enough headroom remains; defer the slide to bound memmove frequency.
|
|
86
|
+
if (cursor < slideThreshold) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
// Slide: move the unconsumed tail to the front, refill behind it.
|
|
90
|
+
const tail = windowLen - cursor;
|
|
91
|
+
window.copyWithin(0, cursor, windowLen);
|
|
92
|
+
const want = windowBytes - tail;
|
|
93
|
+
const got = source.read(windowStartFile + windowLen, want, window, tail);
|
|
94
|
+
bytesRead += got;
|
|
95
|
+
windowLen = tail + got;
|
|
96
|
+
windowStartFile = recordFileStart;
|
|
97
|
+
buffer.rebaseWindow(window, 0, windowLen, windowStartFile);
|
|
98
|
+
++slides;
|
|
99
|
+
};
|
|
100
|
+
const [index, result] = parser.parseDataBlockStreamed(input, onRecordBoundary, onRecordIndexed, void 0, sink);
|
|
101
|
+
// A parse that stopped short of true EOF, with the window not spanning to
|
|
102
|
+
// EOF, means a single record overflowed the window: grow and retry.
|
|
103
|
+
const stoppedShort = result !== ParseResult.COMPLETE;
|
|
104
|
+
const notAtEof = windowStartFile + windowLen < fileSize;
|
|
105
|
+
if (stoppedShort && notAtEof) {
|
|
106
|
+
windowBytes *= 2;
|
|
107
|
+
sink?.reset();
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
// Capture the final record's length (no boundary fires after the last).
|
|
111
|
+
const lastRecordLen = (windowStartFile + input.cursor) - prevBoundaryFile;
|
|
112
|
+
if (lastRecordLen > maxRecordLen) {
|
|
113
|
+
maxRecordLen = lastRecordLen;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
header,
|
|
117
|
+
elements: index.elements,
|
|
118
|
+
result,
|
|
119
|
+
stats: { pool, windowBytes, slides, maxRecordLen, bytesRead },
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Floor on the window so a pathologically tiny pool still holds the header
|
|
124
|
+
// and a record with slide headroom. Tests drive pools down to this to force
|
|
125
|
+
// many slides on a small fixture; the pool sweep uses ≥ 128 KB anyway.
|
|
126
|
+
// eslint-disable-next-line no-magic-numbers
|
|
127
|
+
const MIN_WINDOW = 4 * 1024;
|
|
128
|
+
/**
|
|
129
|
+
* Fill `into` from either a sync or async byte source. A sync `read`
|
|
130
|
+
* resolves immediately; this is what lets the cooperative builder
|
|
131
|
+
* parse from an OPFS `File.slice()` store without a worker.
|
|
132
|
+
*
|
|
133
|
+
* @param source Sync or async positioned source.
|
|
134
|
+
* @param offset Absolute source offset.
|
|
135
|
+
* @param length Maximum bytes to copy.
|
|
136
|
+
* @param into Destination buffer.
|
|
137
|
+
* @param intoOffset Offset within `into`.
|
|
138
|
+
* @return {Promise<number>} Bytes copied.
|
|
139
|
+
*/
|
|
140
|
+
async function readSource(source, offset, length, into, intoOffset) {
|
|
141
|
+
return await source.read(offset, length, into, intoOffset);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Cooperative twin of {@link buildIndexStreaming}: identical parse, window
|
|
145
|
+
* and grow-and-restart behaviour (mirrored the same way the parser mirrors
|
|
146
|
+
* parseDataBlock/parseDataBlockAsync), but the parse periodically yields to
|
|
147
|
+
* the event loop so browsers repaint progress UI mid-parse instead of
|
|
148
|
+
* flagging the tab as stalled (issue #301 §2 for the streamed path).
|
|
149
|
+
*
|
|
150
|
+
* @param source The byte source.
|
|
151
|
+
* @param parser The STEP parser (typed to the schema).
|
|
152
|
+
* @param pool Target window size in bytes.
|
|
153
|
+
* @param onRecordIndexed Optional per-record event (see buildIndexStreaming).
|
|
154
|
+
* @param sink Optional index sink (columnar builds).
|
|
155
|
+
* @param onProgress Optional progress callback with the ABSOLUTE source byte
|
|
156
|
+
* cursor (unlike the parser's window-relative cursor), so callers can report
|
|
157
|
+
* `cursor / source.byteLength` directly.
|
|
158
|
+
* @param yieldIntervalMs Minimum ms between event-loop yields.
|
|
159
|
+
* @return {Promise<StreamingIndexResult>} The index, header, result and
|
|
160
|
+
* diagnostics.
|
|
161
|
+
*/
|
|
162
|
+
export async function buildIndexStreamingAsync(source, parser, pool, onRecordIndexed, sink, onProgress, yieldIntervalMs) {
|
|
163
|
+
const fileSize = source.byteLength;
|
|
164
|
+
let windowBytes = Math.max(pool, MIN_WINDOW);
|
|
165
|
+
for (;;) {
|
|
166
|
+
const window = new Uint8Array(windowBytes);
|
|
167
|
+
let windowStartFile = 0;
|
|
168
|
+
let windowLen = await readSource(source, 0, windowBytes, window, 0);
|
|
169
|
+
let bytesRead = windowLen;
|
|
170
|
+
const input = new ParsingBuffer(window, 0, windowLen);
|
|
171
|
+
const [header, headerResult] = parser.parseHeader(input);
|
|
172
|
+
if (headerResult !== ParseResult.COMPLETE) {
|
|
173
|
+
return {
|
|
174
|
+
header,
|
|
175
|
+
elements: [],
|
|
176
|
+
result: headerResult,
|
|
177
|
+
stats: { pool, windowBytes, slides: 0, maxRecordLen: 0, bytesRead },
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const slideThreshold = windowBytes >> 1;
|
|
181
|
+
let slides = 0;
|
|
182
|
+
let maxRecordLen = 0;
|
|
183
|
+
let prevBoundaryFile = windowStartFile + input.cursor;
|
|
184
|
+
const onRecordBoundary = (buffer) => {
|
|
185
|
+
const cursor = buffer.cursor;
|
|
186
|
+
const recordFileStart = windowStartFile + cursor;
|
|
187
|
+
const recordLen = recordFileStart - prevBoundaryFile;
|
|
188
|
+
if (recordLen > maxRecordLen) {
|
|
189
|
+
maxRecordLen = recordLen;
|
|
190
|
+
}
|
|
191
|
+
prevBoundaryFile = recordFileStart;
|
|
192
|
+
if (windowStartFile + windowLen >= fileSize) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (cursor < slideThreshold) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const tail = windowLen - cursor;
|
|
199
|
+
window.copyWithin(0, cursor, windowLen);
|
|
200
|
+
const want = windowBytes - tail;
|
|
201
|
+
const fillAt = windowStartFile + windowLen;
|
|
202
|
+
// Only return a Promise when this boundary actually slides —
|
|
203
|
+
// an `async` callback would force an await at every record
|
|
204
|
+
// (millions of hops on a PSB-class file).
|
|
205
|
+
return readSource(source, fillAt, want, window, tail).then((got) => {
|
|
206
|
+
bytesRead += got;
|
|
207
|
+
windowLen = tail + got;
|
|
208
|
+
windowStartFile = recordFileStart;
|
|
209
|
+
buffer.rebaseWindow(window, 0, windowLen, windowStartFile);
|
|
210
|
+
++slides;
|
|
211
|
+
});
|
|
212
|
+
};
|
|
213
|
+
// Translate the parser's window-relative cursor to an absolute source
|
|
214
|
+
// cursor (windowStartFile advances as the window slides).
|
|
215
|
+
const progressTick = onProgress !== void 0 ?
|
|
216
|
+
(cursor) => onProgress(windowStartFile + cursor) : void 0;
|
|
217
|
+
const [index, result] = await parser.parseDataBlockStreamedAsync(input, onRecordBoundary, onRecordIndexed, progressTick, sink, yieldIntervalMs);
|
|
218
|
+
const stoppedShort = result !== ParseResult.COMPLETE;
|
|
219
|
+
const notAtEof = windowStartFile + windowLen < fileSize;
|
|
220
|
+
if (stoppedShort && notAtEof) {
|
|
221
|
+
windowBytes *= 2;
|
|
222
|
+
sink?.reset();
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
const lastRecordLen = (windowStartFile + input.cursor) - prevBoundaryFile;
|
|
226
|
+
if (lastRecordLen > maxRecordLen) {
|
|
227
|
+
maxRecordLen = lastRecordLen;
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
header,
|
|
231
|
+
elements: index.elements,
|
|
232
|
+
result,
|
|
233
|
+
stats: { pool, windowBytes, slides, maxRecordLen, bytesRead },
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Build the entity index by streaming, **directly into typed-array columns**
|
|
239
|
+
* (M7): identical parse and window behaviour to {@link buildIndexStreaming},
|
|
240
|
+
* but completed records are encoded straight into a {@link ColumnarIndexSink}
|
|
241
|
+
* so the per-record object index never materialises. Peak JS heap for the
|
|
242
|
+
* index build becomes `window + columns` — the object phase (the dominant
|
|
243
|
+
* heap cost on large models) is gone.
|
|
244
|
+
*
|
|
245
|
+
* @param source The byte source.
|
|
246
|
+
* @param parser The STEP parser (typed to the schema).
|
|
247
|
+
* @param pool Target window size in bytes.
|
|
248
|
+
* @param onRecordIndexed Optional per-record event (see buildIndexStreaming).
|
|
249
|
+
* @param sink Optional caller-owned sink. Pass one to hold the *live* columns
|
|
250
|
+
* while the parse runs — that is what a prefix-derived consumer
|
|
251
|
+
* ({@link import('./prefix_type_index').PrefixTypeIndex}) reads. Omit it and
|
|
252
|
+
* the columns only exist once this returns.
|
|
253
|
+
* @return {StreamingColumnarIndexResult} Columns, header, result, stats.
|
|
254
|
+
*/
|
|
255
|
+
export function buildColumnarIndexStreaming(source, parser, pool, onRecordIndexed, sink = new ColumnarIndexSink()) {
|
|
256
|
+
const { header, result, stats } = buildIndexStreaming(source, parser, pool, onRecordIndexed, sink);
|
|
257
|
+
return { header, columns: sink.finalize(), result, stats };
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Cooperative twin of {@link buildColumnarIndexStreaming}: identical
|
|
261
|
+
* columnar build, but the parse periodically yields to the event loop (see
|
|
262
|
+
* {@link buildIndexStreamingAsync}) and reports absolute byte-cursor
|
|
263
|
+
* progress — the browser-facing variant for large models.
|
|
264
|
+
*
|
|
265
|
+
* @param source The byte source.
|
|
266
|
+
* @param parser The STEP parser (typed to the schema).
|
|
267
|
+
* @param pool Target window size in bytes.
|
|
268
|
+
* @param onRecordIndexed Optional per-record event (see buildIndexStreaming).
|
|
269
|
+
* @param onProgress Optional absolute byte-cursor progress callback.
|
|
270
|
+
* @param yieldIntervalMs Minimum ms between event-loop yields.
|
|
271
|
+
* @param sink Optional caller-owned sink (see
|
|
272
|
+
* {@link buildColumnarIndexStreaming}) — the seam for reading the columns
|
|
273
|
+
* while the parse is still running.
|
|
274
|
+
* @return {Promise<StreamingColumnarIndexResult>} Columns, header, result,
|
|
275
|
+
* stats.
|
|
276
|
+
*/
|
|
277
|
+
export async function buildColumnarIndexStreamingAsync(source, parser, pool, onRecordIndexed, onProgress, yieldIntervalMs, sink = new ColumnarIndexSink()) {
|
|
278
|
+
const { header, result, stats } = await buildIndexStreamingAsync(source, parser, pool, onRecordIndexed, sink, onProgress, yieldIntervalMs);
|
|
279
|
+
return { header, columns: sink.finalize(), result, stats };
|
|
280
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming_index_builder.test.d.ts","sourceRoot":"","sources":["../../../../src/step/parsing/streaming_index_builder.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* eslint-disable no-magic-numbers */
|
|
2
|
+
// M0 spike: streaming index build must be byte-identical to the resident
|
|
3
|
+
// parse. The parser reads file-absolute addresses and only rewinds within a
|
|
4
|
+
// single top-level record, so feeding it from a moving window that slides at
|
|
5
|
+
// record boundaries must produce the exact same index columns — at every
|
|
6
|
+
// pool size, including one small enough to force many slides + straddles.
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import { beforeAll, describe, expect, test } from "@jest/globals";
|
|
9
|
+
import ParsingBuffer from "../../parsing/parsing_buffer.js";
|
|
10
|
+
import IfcStepParser from "../../ifc/ifc_step_parser.js";
|
|
11
|
+
import { BufferByteSource } from "./byte_source.js";
|
|
12
|
+
import { buildIndexStreaming } from "./streaming_index_builder.js";
|
|
13
|
+
import { ParseResult } from "./step_parser.js";
|
|
14
|
+
/**
|
|
15
|
+
* Flatten the index (top-level records + their inline / multi-mapping
|
|
16
|
+
* children) into a stable, comparable column dump: every field the streaming
|
|
17
|
+
* parse must reproduce identically.
|
|
18
|
+
*
|
|
19
|
+
* @param elements The index elements.
|
|
20
|
+
* @return {object[]} A flat list of column tuples in traversal order.
|
|
21
|
+
*/
|
|
22
|
+
function columns(elements) {
|
|
23
|
+
const out = [];
|
|
24
|
+
const visit = (e) => {
|
|
25
|
+
out.push({
|
|
26
|
+
address: e.address,
|
|
27
|
+
length: e.length,
|
|
28
|
+
typeID: e.typeID,
|
|
29
|
+
expressID: e.expressID ?? null,
|
|
30
|
+
});
|
|
31
|
+
for (const child of e.inlineEntities ?? []) {
|
|
32
|
+
visit(child);
|
|
33
|
+
}
|
|
34
|
+
for (const child of e.multiMapping ?? []) {
|
|
35
|
+
visit(child);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
for (const e of elements) {
|
|
39
|
+
visit(e);
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
let bytes;
|
|
44
|
+
let residentColumns;
|
|
45
|
+
let residentCount;
|
|
46
|
+
beforeAll(() => {
|
|
47
|
+
bytes = new Uint8Array(fs.readFileSync("data/index.ifc"));
|
|
48
|
+
const input = new ParsingBuffer(bytes);
|
|
49
|
+
IfcStepParser.Instance.parseHeader(input);
|
|
50
|
+
const [index, result] = IfcStepParser.Instance.parseDataBlock(input);
|
|
51
|
+
expect(result).toBe(ParseResult.COMPLETE);
|
|
52
|
+
residentColumns = columns(index.elements);
|
|
53
|
+
residentCount = index.elements.length;
|
|
54
|
+
});
|
|
55
|
+
describe("buildIndexStreaming", () => {
|
|
56
|
+
// A tiny pool relative to the 18 KB fixture forces repeated slides and at
|
|
57
|
+
// least one record straddling a window boundary; a large one takes the
|
|
58
|
+
// whole file in a single window (no slide). Both must match the resident
|
|
59
|
+
// parse exactly.
|
|
60
|
+
const POOLS = [4 * 1024, 8 * 1024, 16 * 1024, 128 * 1024];
|
|
61
|
+
test.each(POOLS)("produces the resident index at pool=%d bytes", (pool) => {
|
|
62
|
+
const source = new BufferByteSource(bytes);
|
|
63
|
+
const result = buildIndexStreaming(source, IfcStepParser.Instance, pool);
|
|
64
|
+
expect(result.result).toBe(ParseResult.COMPLETE);
|
|
65
|
+
expect(result.elements.length).toBe(residentCount);
|
|
66
|
+
expect(columns(result.elements)).toEqual(residentColumns);
|
|
67
|
+
});
|
|
68
|
+
test("the small pool actually slides the window (straddle exercised)", () => {
|
|
69
|
+
const source = new BufferByteSource(bytes);
|
|
70
|
+
const result = buildIndexStreaming(source, IfcStepParser.Instance, 4 * 1024);
|
|
71
|
+
// 18 KB fixture through a 4 KB window must slide several times.
|
|
72
|
+
expect(result.stats.slides).toBeGreaterThan(1);
|
|
73
|
+
// Physical window never grew past the pool (no record exceeds it).
|
|
74
|
+
expect(result.stats.windowBytes).toBe(4 * 1024);
|
|
75
|
+
// Every byte read once (no growth re-reads) — bounded to file size.
|
|
76
|
+
expect(result.stats.bytesRead).toBe(bytes.length);
|
|
77
|
+
});
|
|
78
|
+
test("the large pool takes the whole file in one window (no slide)", () => {
|
|
79
|
+
const source = new BufferByteSource(bytes);
|
|
80
|
+
const result = buildIndexStreaming(source, IfcStepParser.Instance, 128 * 1024);
|
|
81
|
+
expect(result.stats.slides).toBe(0);
|
|
82
|
+
expect(result.stats.maxRecordLen).toBeGreaterThan(0);
|
|
83
|
+
});
|
|
84
|
+
test("grows the window and restarts when a single record exceeds the pool", () => {
|
|
85
|
+
// Synthetic file with one record far larger than a tiny pool — the
|
|
86
|
+
// corpus never hits this (largest STEP record ~25 KB), so exercise the
|
|
87
|
+
// grow-and-restart safety valve directly. A long text literal makes one
|
|
88
|
+
// record ~12 KB; a 4 KB pool must grow past it and still index it.
|
|
89
|
+
const bigValue = "X".repeat(12000);
|
|
90
|
+
const text = "ISO-10303-21;\nHEADER;\nENDSEC;\nDATA;\n" +
|
|
91
|
+
"#1=IFCWALL('a');\n" +
|
|
92
|
+
`#2=IFCPROPERTYSINGLEVALUE('${bigValue}');\n` +
|
|
93
|
+
"#3=IFCWALL('c');\nENDSEC;\n";
|
|
94
|
+
const synthetic = new TextEncoder().encode(text);
|
|
95
|
+
const resident = new ParsingBuffer(synthetic);
|
|
96
|
+
IfcStepParser.Instance.parseHeader(resident);
|
|
97
|
+
const [residentIndex, residentResult] = IfcStepParser.Instance.parseDataBlock(resident);
|
|
98
|
+
expect(residentResult).toBe(ParseResult.COMPLETE);
|
|
99
|
+
const streamed = buildIndexStreaming(new BufferByteSource(synthetic), IfcStepParser.Instance, 4 * 1024);
|
|
100
|
+
expect(streamed.result).toBe(ParseResult.COMPLETE);
|
|
101
|
+
// Window grew past the 4 KB pool to fit the ~12 KB record.
|
|
102
|
+
expect(streamed.stats.windowBytes).toBeGreaterThan(4 * 1024);
|
|
103
|
+
expect(streamed.stats.maxRecordLen).toBeGreaterThan(12000);
|
|
104
|
+
// ...and the index is still byte-identical to the resident parse.
|
|
105
|
+
expect(columns(streamed.elements)).toEqual(columns(residentIndex.elements));
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming_index_builder_async.test.d.ts","sourceRoot":"","sources":["../../../../src/step/parsing/streaming_index_builder_async.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* eslint-disable no-magic-numbers */
|
|
2
|
+
// The cooperative streamed columnar build must be byte-identical to the
|
|
3
|
+
// synchronous build (same columns, same window mechanics) AND actually
|
|
4
|
+
// yield to the event loop mid-parse — the repaint/no-stall property
|
|
5
|
+
// (#301 §2) the streamed open path relies on. The parse generator only
|
|
6
|
+
// suspends every PARSE_PROGRESS_ELEMENT_MASK+1 (4096) records, so the
|
|
7
|
+
// yield/progress assertions use a synthesized >4096-record model; the
|
|
8
|
+
// column-parity assertions use the real fixture.
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import { describe, expect, test } from "@jest/globals";
|
|
11
|
+
import IfcStepParser from "../../ifc/ifc_step_parser.js";
|
|
12
|
+
import { BufferByteSource, StoreByteSource } from "./byte_source.js";
|
|
13
|
+
import { InMemoryStepByteStore } from "../step_buffer_provider.js";
|
|
14
|
+
import { buildColumnarIndexStreaming, buildColumnarIndexStreamingAsync, } from "./streaming_index_builder.js";
|
|
15
|
+
import { ParseResult } from "./step_parser.js";
|
|
16
|
+
const POOL = 8 * 1024; // small window → forces slides on both inputs
|
|
17
|
+
/**
|
|
18
|
+
* Synthesize a valid IFC4 file with `recordCount` simple records — enough
|
|
19
|
+
* to cross the parser's progress-suspension mask several times.
|
|
20
|
+
*
|
|
21
|
+
* @param recordCount Number of data records.
|
|
22
|
+
* @return {Uint8Array} The encoded file.
|
|
23
|
+
*/
|
|
24
|
+
function syntheticIfc(recordCount) {
|
|
25
|
+
const parts = [
|
|
26
|
+
"ISO-10303-21;\nHEADER;\n" +
|
|
27
|
+
"FILE_DESCRIPTION((''),'2;1');\n" +
|
|
28
|
+
"FILE_NAME('','',(''),(''),'','','');\n" +
|
|
29
|
+
"FILE_SCHEMA(('IFC4'));\nENDSEC;\nDATA;\n",
|
|
30
|
+
];
|
|
31
|
+
for (let where = 1; where <= recordCount; ++where) {
|
|
32
|
+
parts.push(`#${where}=IFCCARTESIANPOINT((${where}.,0.,0.));\n`);
|
|
33
|
+
}
|
|
34
|
+
parts.push("ENDSEC;\nEND-ISO-10303-21;\n");
|
|
35
|
+
return new TextEncoder().encode(parts.join(""));
|
|
36
|
+
}
|
|
37
|
+
describe("buildColumnarIndexStreamingAsync", () => {
|
|
38
|
+
test("produces identical columns to the sync build (real fixture)", async () => {
|
|
39
|
+
const bytes = new Uint8Array(fs.readFileSync("data/index.ifc"));
|
|
40
|
+
const parser = IfcStepParser.Instance;
|
|
41
|
+
const sync = buildColumnarIndexStreaming(new BufferByteSource(bytes), parser, POOL);
|
|
42
|
+
const cooperative = await buildColumnarIndexStreamingAsync(new BufferByteSource(bytes), parser, POOL, void 0, void 0, 0);
|
|
43
|
+
expect(sync.result).toBe(ParseResult.COMPLETE);
|
|
44
|
+
expect(cooperative.result).toBe(ParseResult.COMPLETE);
|
|
45
|
+
const a = sync.columns;
|
|
46
|
+
const b = cooperative.columns;
|
|
47
|
+
expect(b.count).toBe(a.count);
|
|
48
|
+
expect(b.firstInlineElement).toBe(a.firstInlineElement);
|
|
49
|
+
expect(Array.from(b.address)).toEqual(Array.from(a.address));
|
|
50
|
+
expect(Array.from(b.length)).toEqual(Array.from(a.length));
|
|
51
|
+
expect(Array.from(b.typeID)).toEqual(Array.from(a.typeID));
|
|
52
|
+
expect(Array.from(b.expressID)).toEqual(Array.from(a.expressID));
|
|
53
|
+
// Same window mechanics (slides prove the moving window really moved).
|
|
54
|
+
expect(cooperative.stats.slides).toBe(sync.stats.slides);
|
|
55
|
+
expect(cooperative.stats.slides).toBeGreaterThan(0);
|
|
56
|
+
}, 60000);
|
|
57
|
+
test("StoreByteSource fills produce the same columns as a buffer source", async () => {
|
|
58
|
+
const bytes = new Uint8Array(fs.readFileSync("data/index.ifc"));
|
|
59
|
+
const parser = IfcStepParser.Instance;
|
|
60
|
+
const fromBuffer = await buildColumnarIndexStreamingAsync(new BufferByteSource(bytes), parser, POOL, void 0, void 0, 0);
|
|
61
|
+
const fromStore = await buildColumnarIndexStreamingAsync(new StoreByteSource(new InMemoryStepByteStore(bytes)), parser, POOL, void 0, void 0, 0);
|
|
62
|
+
expect(fromStore.result).toBe(ParseResult.COMPLETE);
|
|
63
|
+
expect(Array.from(fromStore.columns.address))
|
|
64
|
+
.toEqual(Array.from(fromBuffer.columns.address));
|
|
65
|
+
expect(Array.from(fromStore.columns.expressID))
|
|
66
|
+
.toEqual(Array.from(fromBuffer.columns.expressID));
|
|
67
|
+
}, 60000);
|
|
68
|
+
test("yields to the event loop and reports absolute progress mid-parse", async () => {
|
|
69
|
+
const bytes = syntheticIfc(10000);
|
|
70
|
+
const parser = IfcStepParser.Instance;
|
|
71
|
+
// Count macrotask turns that run while the build is in flight — with a
|
|
72
|
+
// zero yield interval the parse must give the event loop real turns.
|
|
73
|
+
let turns = 0;
|
|
74
|
+
let pumping = true;
|
|
75
|
+
const pump = () => {
|
|
76
|
+
if (!pumping) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
++turns;
|
|
80
|
+
setTimeout(pump, 0);
|
|
81
|
+
};
|
|
82
|
+
setTimeout(pump, 0);
|
|
83
|
+
const progressCursors = [];
|
|
84
|
+
const cooperative = await buildColumnarIndexStreamingAsync(new BufferByteSource(bytes), parser, POOL, void 0, (cursor) => progressCursors.push(cursor), 0);
|
|
85
|
+
pumping = false;
|
|
86
|
+
expect(cooperative.result).toBe(ParseResult.COMPLETE);
|
|
87
|
+
expect(cooperative.columns.count).toBe(10000);
|
|
88
|
+
expect(turns).toBeGreaterThan(0);
|
|
89
|
+
// Progress reports absolute source cursors: monotonically
|
|
90
|
+
// non-decreasing, bounded by the file size, and past the first window —
|
|
91
|
+
// the window-relative → absolute translation must hold across slides.
|
|
92
|
+
expect(progressCursors.length).toBeGreaterThan(1);
|
|
93
|
+
for (let where = 1; where < progressCursors.length; ++where) {
|
|
94
|
+
expect(progressCursors[where])
|
|
95
|
+
.toBeGreaterThanOrEqual(progressCursors[where - 1]);
|
|
96
|
+
}
|
|
97
|
+
expect(progressCursors[progressCursors.length - 1])
|
|
98
|
+
.toBeLessThanOrEqual(bytes.byteLength);
|
|
99
|
+
expect(progressCursors[progressCursors.length - 1])
|
|
100
|
+
.toBeGreaterThan(POOL);
|
|
101
|
+
// And the synthetic build matches its own sync twin exactly.
|
|
102
|
+
const sync = buildColumnarIndexStreaming(new BufferByteSource(bytes), parser, POOL);
|
|
103
|
+
expect(Array.from(cooperative.columns.address))
|
|
104
|
+
.toEqual(Array.from(sync.columns.address));
|
|
105
|
+
expect(Array.from(cooperative.columns.expressID))
|
|
106
|
+
.toEqual(Array.from(sync.columns.expressID));
|
|
107
|
+
expect(cooperative.stats.slides).toBe(sync.stats.slides);
|
|
108
|
+
}, 60000);
|
|
109
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { StepEntityConstructorAbstract } from "../step_entity_constructor.js";
|
|
2
|
+
import { RecordEventHandler } from "./record_event.js";
|
|
3
|
+
/**
|
|
4
|
+
* A per-record event handler: a record's dense `localID` (assigned in parse
|
|
5
|
+
* order from 0), its `expressID`, its `typeID` (0 for external-mapping
|
|
6
|
+
* records), and the record's raw bytes as an un-materialised
|
|
7
|
+
* `(buffer, byteOffset, byteLength)` view over the live parse window.
|
|
8
|
+
* See {@link RecordEventHandler} — in particular, the bytes are only valid
|
|
9
|
+
* for the duration of the call.
|
|
10
|
+
*/
|
|
11
|
+
export type RecordHandler<TypeIDType> = RecordEventHandler<TypeIDType>;
|
|
12
|
+
/**
|
|
13
|
+
* Routes the streaming parse's per-record events (M2) to consumers that
|
|
14
|
+
* subscribe by **type set**. A subscription's type set is the subtype closure
|
|
15
|
+
* of the entity constructors it names — the same `query` closure the type
|
|
16
|
+
* index and `expressIDsOfTypes` use (conway #383) — so `on([IfcRoot], …)`
|
|
17
|
+
* matches every product, relationship, property set and quantity, and any
|
|
18
|
+
* future IfcRoot subtype, with no whitelist to maintain.
|
|
19
|
+
*
|
|
20
|
+
* Feed `dispatcher.onRecordIndexed` to `buildIndexStreaming` /
|
|
21
|
+
* `parseDataBlockStreamed`. Handlers run synchronously in the parse path, so
|
|
22
|
+
* they must be cheap (copy ids into a compact structure); anything expensive
|
|
23
|
+
* belongs on a demand queue, not here.
|
|
24
|
+
*
|
|
25
|
+
* Because subscriptions match on the raw parse `typeID`, external-mapping /
|
|
26
|
+
* complex records (typeID 0) are only delivered via `onAnyRecord`. Resolving
|
|
27
|
+
* their concrete types is not this class's job and never was: the columns
|
|
28
|
+
* carry the multi-mapping, so
|
|
29
|
+
* {@link import('./prefix_type_index').PrefixTypeIndex} attributes them
|
|
30
|
+
* correctly without the event stream. For the overwhelming majority of records
|
|
31
|
+
* (simple, one type each) type-set delivery is exact.
|
|
32
|
+
*/
|
|
33
|
+
export declare class StreamingRecordDispatcher<TypeIDType extends number> {
|
|
34
|
+
/**
|
|
35
|
+
* Concrete type → the handlers subscribed to it, unioned across
|
|
36
|
+
* subscriptions. Dispatch is one lookup per record no matter how many
|
|
37
|
+
* consumers are attached: the per-record cost of a subscription is the only
|
|
38
|
+
* cost this class has at 9.4 M records, so it must not scale with the
|
|
39
|
+
* subscriber count (issue #393).
|
|
40
|
+
*/
|
|
41
|
+
private readonly byType;
|
|
42
|
+
private readonly any;
|
|
43
|
+
/**
|
|
44
|
+
* Subscribe to records of the given entity types (including their
|
|
45
|
+
* subtypes).
|
|
46
|
+
*
|
|
47
|
+
* @param types The entity constructors whose subtype closures to match.
|
|
48
|
+
* @param handler Called for each matching record.
|
|
49
|
+
*/
|
|
50
|
+
on(types: StepEntityConstructorAbstract<TypeIDType>[], handler: RecordHandler<TypeIDType>): void;
|
|
51
|
+
/**
|
|
52
|
+
* Subscribe to every record regardless of type (the firehose — including
|
|
53
|
+
* external-mapping records).
|
|
54
|
+
*
|
|
55
|
+
* @param handler Called for every record.
|
|
56
|
+
*/
|
|
57
|
+
onAnyRecord(handler: RecordHandler<TypeIDType>): void;
|
|
58
|
+
/**
|
|
59
|
+
* The per-record callback to hand to the streaming parse. Dispatches each
|
|
60
|
+
* record to the matching subscribers. Bound so it can be passed directly.
|
|
61
|
+
*
|
|
62
|
+
* @param localID The record's dense local ID.
|
|
63
|
+
* @param expressID The record's express ID.
|
|
64
|
+
* @param typeID The record's type ID (0 for external-mapping records).
|
|
65
|
+
* @param buffer The live parse window holding the record's bytes.
|
|
66
|
+
* @param byteOffset Offset of the record's first byte within `buffer`.
|
|
67
|
+
* @param byteLength Length of the record in bytes.
|
|
68
|
+
*/
|
|
69
|
+
readonly onRecordIndexed: RecordHandler<TypeIDType>;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=streaming_record_dispatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming_record_dispatcher.d.ts","sourceRoot":"","sources":["../../../../src/step/parsing/streaming_record_dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAA;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAGnD;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,CAAC,UAAU,IAAI,kBAAkB,CAAC,UAAU,CAAC,CAAA;AAGtE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,yBAAyB,CAAC,UAAU,SAAS,MAAM;IAE9D;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqD;IAE5E,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkC;IAEtD;;;;;;OAMG;IACI,EAAE,CACL,KAAK,EAAE,6BAA6B,CAAC,UAAU,CAAC,EAAE,EAClD,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,GAAI,IAAI;IAkB9C;;;;;OAKG;IACI,WAAW,CAAE,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,GAAI,IAAI;IAI9D;;;;;;;;;;OAUG;IACH,SAAgB,eAAe,EAAE,aAAa,CAAC,UAAU,CAAC,CAsBvD;CACJ"}
|