@githolon/dsl 0.108.6 → 0.110.0
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/assets/operation-contract.wasm +0 -0
- package/check_package.mjs +12 -15
- package/compile_package.mjs +17 -18
- package/compile_proof.mjs +16 -1
- package/dart/CHANGELOG.md +76 -1
- package/dart/README.md +25 -2
- package/dart/lib/src/admission_decision.dart +41 -0
- package/dart/lib/src/application_framework_calls.dart +52 -2
- package/dart/lib/src/application_model_adoption.dart +187 -0
- package/dart/lib/src/application_status.dart +73 -0
- package/dart/lib/src/console_enrolment.dart +271 -0
- package/dart/lib/src/console_http_io.dart +26 -0
- package/dart/lib/src/console_http_stub.dart +7 -0
- package/dart/lib/src/dev_cloud.dart +69 -22
- package/dart/lib/src/generated_call.dart +83 -23
- package/dart/lib/src/kernel_primitives.dart +119 -0
- package/dart/lib/src/nms_conformance_runtime.dart +1 -1
- package/dart/lib/src/nms_generated_runtime.dart +32 -10
- package/dart/lib/src/nms_test_environment.dart +1 -1
- package/dart/lib/src/node_runner_transport.dart +41 -46
- package/dart/lib/src/observed_session_directory.dart +70 -0
- package/dart/lib/src/operation_receipts.dart +112 -0
- package/dart/lib/src/peer_application_streams.dart +103 -0
- package/dart/lib/src/reception/dart_reception.dart +4280 -0
- package/dart/lib/src/reception/event_desk.dart +211 -0
- package/dart/lib/src/reception/extremum_read.dart +46 -0
- package/dart/lib/src/reception/local_copies.dart +371 -0
- package/dart/lib/src/reception/peer_office_connection.dart +11 -0
- package/dart/lib/src/reception/progress_desk.dart +267 -0
- package/dart/lib/src/reception/reception_contract.dart +11 -0
- package/dart/lib/src/reception/reception_session.dart +284 -0
- package/dart/lib/src/reception/sync_diagnostics.dart +26 -0
- package/dart/lib/src/reception/workspace_preparation_report.dart +126 -0
- package/dart/lib/src/replica_readiness.dart +123 -0
- package/dart/lib/src/runner/node-entry.mjs +23905 -15774
- package/dart/lib/src/runtime_v2_gateway.dart +56 -3
- package/dart/lib/src/runtime_v2_transport.dart +544 -3
- package/dart/lib/src/session_bound.dart +200 -311
- package/dart/lib/src/signing_identity_kernel.dart +84 -0
- package/dart/lib/src/sync_status_projection.dart +548 -0
- package/dart/lib/src/sync_status_reducer.dart +170 -0
- package/dart/lib/src/test_harness.dart +809 -1153
- package/dart/lib/src/testing/test_custody.dart +66 -0
- package/dart/lib/src/testing/test_peer.dart +328 -0
- package/dart/lib/src/typed_watch_registry.dart +169 -0
- package/dart/lib/src/workspace_open_progress.dart +27 -0
- package/dart/pubspec.lock +24 -1
- package/dart/pubspec.yaml +7 -2
- package/dart/pubspec_overrides.yaml +2 -0
- package/dart/test/admission_decision_test.dart +48 -0
- package/dart/test/background_model_adoption_test.dart +228 -0
- package/dart/test/bundle_version_pairing_test.dart +4 -4
- package/dart/test/child_authentication_repair_test.dart +359 -0
- package/dart/test/cloud_bound_local_shell_test.dart +119 -0
- package/dart/test/console_enrolment_refusal_test.dart +52 -0
- package/dart/test/console_enrolment_test.dart +227 -0
- package/dart/test/errors_test.dart +5 -5
- package/dart/test/event_plane_seam_test.dart +50 -164
- package/dart/test/extremum_read_test.dart +58 -0
- package/dart/test/fixtures/wedge/wedge-entry.mjs +3 -21
- package/dart/test/generated_query_test.dart +32 -0
- package/dart/test/harness_phase_timeout_test.dart +18 -23
- package/dart/test/kernel_author_after_read_test.dart +242 -0
- package/dart/test/kernel_fence_test.dart +137 -0
- package/dart/test/local_copies_test.dart +222 -0
- package/dart/test/model_adoption_test.dart +198 -0
- package/dart/test/node_peer_local_custody_test.dart +153 -0
- package/dart/test/offer_authentication_proof_test.dart +352 -52
- package/dart/test/operation_compatibility_test.dart +151 -0
- package/dart/test/platform_credential_effect_test.dart +386 -0
- package/dart/test/receiving_group_open_test.dart +213 -0
- package/dart/test/reception/workspace_preparation_report_test.dart +103 -0
- package/dart/test/reception_span_trace_test.dart +23 -0
- package/dart/test/replica_readiness_test.dart +156 -0
- package/dart/test/runtime_projections_test.dart +92 -0
- package/dart/test/runtime_v2_gateway_test.dart +131 -0
- package/dart/test/signing_identity_kernel_test.dart +75 -0
- package/dart/test/sync_status_preparation_report_test.dart +29 -0
- package/dart/test/sync_status_reducer_test.dart +419 -0
- package/dart/test/test_harness_test.dart +71 -95
- package/dart/test/typed_query_watch_test.dart +170 -0
- package/dart/test/typed_watch_registry_test.dart +249 -0
- package/dart_lints/README.md +18 -0
- package/dart_lints/lib/nomos_lints.dart +70 -0
- package/dart_lints/pubspec.lock +580 -0
- package/dart_lints/pubspec.yaml +12 -0
- package/dart_lints/test/reference_identity_test.dart +75 -0
- package/dart_types/CHANGELOG.md +18 -0
- package/dart_types/lib/nomos_kernel_protocol.dart +21 -1
- package/dart_types/lib/nomos_types.dart +9 -1
- package/dart_types/lib/src/admission_decision.dart +37 -0
- package/dart_types/lib/src/aggregate_meta.dart +1 -1
- package/dart_types/lib/src/approved_model.dart +65 -0
- package/dart_types/lib/src/custody.dart +10 -18
- package/dart_types/lib/src/error_info.dart +4 -4
- package/dart_types/lib/src/errors.dart +29 -29
- package/dart_types/lib/src/foreign_ref.dart +62 -33
- package/dart_types/lib/src/local_work_rejected.dart +3 -3
- package/dart_types/lib/src/nomos_ref.dart +3 -1
- package/dart_types/lib/src/principal.dart +2 -2
- package/dart_types/lib/src/proto/google/protobuf/any.pb.dart +163 -0
- package/dart_types/lib/src/proto/google/protobuf/any.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pb.dart +137 -0
- package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +20721 -10433
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +555 -27
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +387 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pbenum.dart +46 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pb.dart +295 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pbenum.dart +139 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pb.dart +269 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pbenum.dart +103 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pb.dart +417 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pbenum.dart +62 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +9968 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +133 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pb.dart +204 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pbenum.dart +54 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pb.dart +1550 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pb.dart +710 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pb.dart +845 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pb.dart +198 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pb.dart +369 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pb.dart +609 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pbenum.dart +65 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +358 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pbenum.dart +100 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +2231 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pbenum.dart +271 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pb.dart +1286 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +636 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pbenum.dart +116 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +1637 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pbenum.dart +175 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pb.dart +1269 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pbenum.dart +129 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +2782 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pbenum.dart +97 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +2232 -8627
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +0 -358
- package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pb.dart +1639 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pbenum.dart +46 -0
- package/dart_types/lib/src/runtime_outcome.dart +133 -0
- package/dart_types/lib/src/subscriptions.dart +116 -23
- package/dart_types/pubspec.yaml +1 -1
- package/dart_types/test/extremum_subscriptions_test.dart +40 -0
- package/dart_types/test/foreign_ref_resolution_test.dart +75 -0
- package/dart_types/test/nomos_ref_address_test.dart +25 -0
- package/dart_types/test/ordered_subscriptions_test.dart +34 -0
- package/operation_contract_check.mjs +24 -0
- package/package.json +11 -6
- package/src/aggregate.ts +70 -10
- package/src/application_topology.ts +18 -11
- package/src/attested.ts +3 -0
- package/src/attested_core.ts +46 -3
- package/src/birth_meter_ensure.ts +19 -7
- package/src/births.ts +29 -4
- package/src/build_package.ts +140 -13
- package/src/business_birth.ts +181 -4
- package/src/codegen_call_proto.ts +1274 -0
- package/src/codegen_call_usda.ts +49 -6
- package/src/codegen_dart.ts +79 -44
- package/src/codegen_dart_client.ts +458 -800
- package/src/{codegen_dart_application.ts → codegen_dart_facade.ts} +331 -582
- package/src/codegen_dart_framework_calls.ts +320 -37
- package/src/codegen_dart_indexed_variant.ts +159 -0
- package/src/codegen_dart_scenario.ts +42 -13
- package/src/codegen_proof.ts +3 -3
- package/src/codegen_provider_dart.ts +5 -0
- package/src/codegen_query_proto.ts +158 -0
- package/src/codegen_refusal.ts +189 -0
- package/src/codegen_result_proto.ts +931 -0
- package/src/codegen_result_usda.ts +4 -0
- package/src/codegen_ts.ts +464 -616
- package/src/codegen_workspace_access.ts +105 -0
- package/src/compatibility_graph.ts +759 -0
- package/src/compatibility_usda.ts +264 -0
- package/src/compile_package_main.ts +2083 -1248
- package/src/custody_placement.ts +156 -0
- package/src/custody_placement_usda.ts +91 -0
- package/src/decl_shapes.ts +21 -2
- package/src/describe_model.ts +1 -0
- package/src/directive.ts +59 -2
- package/src/drivers.ts +51 -0
- package/src/engine_entry.ts +52 -8
- package/src/evolve_preview.ts +11 -4
- package/src/exists.ts +2 -0
- package/src/fields.ts +75 -11
- package/src/flow_gate.ts +2 -1
- package/src/framework/application_home.ts +170 -18
- package/src/framework/attested_receipts.ts +8 -3
- package/src/framework/auth_provider_law.ts +169 -9
- package/src/framework/birth_certificate_law.ts +4 -0
- package/src/framework/capability.ts +34 -3
- package/src/framework/child_authentication.ts +346 -0
- package/src/framework/console_governance.ts +295 -0
- package/src/framework/delegated_roles.ts +301 -0
- package/src/framework/domain_lifecycle.ts +26 -13
- package/src/framework/founding_genesis.ts +193 -0
- package/src/framework/framework_aggregates.ts +1 -1
- package/src/framework/genesis.ts +6 -1
- package/src/framework/governance_relations.ts +19 -0
- package/src/framework/home.ts +5 -734
- package/src/framework/legacy/child_auth_provider_epoch.ts +73 -0
- package/src/framework/model_authority_repair.ts +116 -0
- package/src/framework/model_authority_seed.ts +185 -0
- package/src/framework/model_transition.ts +211 -0
- package/src/framework/owned_custody.ts +1 -1
- package/src/framework/principal_enrollment.ts +302 -0
- package/src/framework/receiving_group.ts +857 -0
- package/src/framework/receiving_group_recovery.ts +314 -0
- package/src/framework/relations.ts +4 -8
- package/src/framework/signing_identity.ts +242 -95
- package/src/framework/source_roster.ts +11 -5
- package/src/framework/workspace_access.ts +149 -0
- package/src/framework/workspace_invariant.ts +73 -52
- package/src/framework/workspaces.ts +407 -40
- package/src/framework_call_definitions.ts +32 -3
- package/src/generated_client_bundle_boundary.ts +97 -0
- package/src/generated_client_names.ts +1 -0
- package/src/identity_usda.ts +27 -0
- package/src/index.ts +183 -12
- package/src/indexed_variant.ts +83 -0
- package/src/intent.ts +173 -45
- package/src/law_check.ts +8 -5
- package/src/law_dependency_index.ts +231 -0
- package/src/law_graph.ts +508 -71
- package/src/law_graph_usda.ts +170 -24
- package/src/law_identity.ts +119 -81
- package/src/law_source_map.ts +4 -1
- package/src/law_units.ts +498 -0
- package/src/law_value_type.ts +7 -3
- package/src/member_authentication.ts +302 -0
- package/src/null_meta.ts +1 -1
- package/src/openusd_compiled_layer.ts +132 -0
- package/src/operation_contract_check.ts +31 -0
- package/src/ordered_read.ts +2 -1
- package/src/package_config.ts +33 -12
- package/src/package_dependencies.ts +1 -0
- package/src/plan_source_slice.ts +30 -1
- package/src/protobuf_field_number.ts +36 -0
- package/src/provenance_wire.ts +6 -0
- package/src/query.ts +2 -1
- package/src/read.ts +50 -0
- package/src/relation.ts +4 -1
- package/src/relation_schema.ts +15 -2
- package/src/report.ts +2 -2
- package/src/sqlite_computation_bundle.ts +78 -0
- package/src/sqlite_computed.ts +102 -0
- package/src/sqlite_counts.ts +154 -0
- package/src/sqlite_layout.ts +823 -0
- package/src/sqlite_reads.ts +275 -0
- package/src/sqlite_samples.ts +185 -0
- package/src/stable_id_identity_bridge.ts +1 -1
- package/src/stable_ids_for_module.ts +16 -4
- package/src/test_call_usda.ts +6 -6
- package/src/usda_relationship_integrity.ts +20 -3
- package/src/usda_text.ts +21 -1
- package/src/value_object.ts +81 -11
- package/src/wire.ts +22 -0
- package/src/wire_encode.ts +227 -20
- package/src/workspace_sharding.ts +15 -6
- package/src/workspace_sharing.ts +51 -49
- package/src/zod_introspection.ts +2 -0
- package/compat_package.mjs +0 -46
- package/dart/lib/src/home.dart +0 -15
- package/dart/lib/src/runner/offline-install.mjs +0 -15367
- package/dart/lib/src/source_trust.dart +0 -51
- package/dart/lib/src/webview_bridge.dart +0 -6540
- package/dart/lib/src/workspace_name.dart +0 -30
- package/dart/test/acquire_session_credentials_test.dart +0 -150
- package/dart/test/acquire_session_test.dart +0 -534
- package/dart/test/adv_realm_interference_test.dart +0 -600
- package/dart/test/cloud_bound_topology_test.dart +0 -168
- package/dart/test/cluster_births_test.dart +0 -202
- package/dart/test/cluster_device_keyed_acceptance_test.dart +0 -105
- package/dart/test/cluster_local_autosync_test.dart +0 -123
- package/dart/test/cluster_scale_test.dart +0 -122
- package/dart/test/compat_test.dart +0 -61
- package/dart/test/dlq_session_surface_test.dart +0 -222
- package/dart/test/first_app_gauntlet_test.dart +0 -386
- package/dart/test/fixtures/wedge/fake-install.mjs +0 -11
- package/dart/test/four_layer_nested_topology_test.dart +0 -290
- package/dart/test/home_parity_test.dart +0 -13
- package/dart/test/local_sync_inert_test.dart +0 -107
- package/dart/test/node_runner_transport_test.dart +0 -78
- package/dart/test/parent_signer_recovery_test.dart +0 -155
- package/dart/test/residency_refusal_test.dart +0 -49
- package/dart/test/sealing_client_test.dart +0 -181
- package/dart/test/session_bound_test.dart +0 -285
- package/dart/test/stale_bundle_test.dart +0 -80
- package/dart/test/vo_read_typing_test.dart +0 -131
- package/dart/test/watch_after_offer_stall_test.dart +0 -100
- package/dart/test/webview_bridge_test.dart +0 -1930
- package/dart/test/workspace_name_test.dart +0 -24
- package/runtime/generated-application-host.js +0 -22860
- package/src/codegen_query_usda.ts +0 -214
- package/src/compat_manifest.ts +0 -26
- package/src/compat_package_main.ts +0 -224
- package/src/shape_compat.ts +0 -352
- package/src/usd_state.ts +0 -505
|
@@ -0,0 +1,931 @@
|
|
|
1
|
+
import { admitsNull, isGitObjectIdSchema, isSha256DigestSchema, type Field } from "./fields.js";
|
|
2
|
+
import type {
|
|
3
|
+
LawAnonymousValueFieldNode,
|
|
4
|
+
LawAnonymousValueTypeNode,
|
|
5
|
+
LawGraph,
|
|
6
|
+
LawRowReadNode,
|
|
7
|
+
LawReadNode,
|
|
8
|
+
LawStructuralRef,
|
|
9
|
+
LawTypeNode,
|
|
10
|
+
LawValueTypeRef,
|
|
11
|
+
} from "./law_graph.js";
|
|
12
|
+
import {
|
|
13
|
+
composedWireIdentity,
|
|
14
|
+
operationMessageIdentity,
|
|
15
|
+
protobufFieldNumber,
|
|
16
|
+
protoFieldName,
|
|
17
|
+
protoMessageName,
|
|
18
|
+
structuralGeometryKind,
|
|
19
|
+
} from "./codegen_call_proto.js";
|
|
20
|
+
import type { TsResultAggregate } from "./codegen_result_usda.js";
|
|
21
|
+
import {
|
|
22
|
+
dartMemberName,
|
|
23
|
+
unionArmClassName,
|
|
24
|
+
type AggFieldSpec,
|
|
25
|
+
} from "./codegen_dart.js";
|
|
26
|
+
import { contractTypeName } from "./contract.js";
|
|
27
|
+
import { zodEnumValues } from "./zod_introspection.js";
|
|
28
|
+
import { provenanceRowIdentity, provenanceFieldIdentity, provenanceAuthorIdentity, provenanceContestedIdentity } from "./provenance_wire.js";
|
|
29
|
+
|
|
30
|
+
const symbol = (value: string): string =>
|
|
31
|
+
value.replace(/[^A-Za-z0-9_$]+/g, "_").replace(/^[^A-Za-z_$]/, "_$&");
|
|
32
|
+
|
|
33
|
+
const valueObjectDecoder = (name: string): string =>
|
|
34
|
+
`_nmsDecodeValueObject_${symbol(name)}`;
|
|
35
|
+
|
|
36
|
+
/** Tiny generated-boundary helpers shared by every direct Protobuf result
|
|
37
|
+
* decoder. Presence is checked here rather than asserted away in each query,
|
|
38
|
+
* so an incompatible kernel result fails with the exact authored field path. */
|
|
39
|
+
export const TS_RESULT_PROTO_PRELUDE = [
|
|
40
|
+
`const _nmsResultRequired = <T>(value: T | undefined, path: string): T => {`,
|
|
41
|
+
` if (value === undefined) throw new TypeError(path + " is absent");`,
|
|
42
|
+
` return value;`,
|
|
43
|
+
`};`,
|
|
44
|
+
`const _nmsResultInteger = (value: bigint, path: string): number => {`,
|
|
45
|
+
` const result = Number(value);`,
|
|
46
|
+
` if (!Number.isSafeInteger(result)) throw new TypeError(path + " is outside the exact integer range");`,
|
|
47
|
+
` return result;`,
|
|
48
|
+
`};`,
|
|
49
|
+
``,
|
|
50
|
+
] as const;
|
|
51
|
+
|
|
52
|
+
const dartInteger = (raw: string, path: string): string =>
|
|
53
|
+
`((Int64 integer) { if (integer > Int64(9007199254740991) || integer < Int64(-9007199254740991)) throw FormatException(${dartString(`${path} is outside the exact integer range`)}); return integer.toInt(); })(${raw})`;
|
|
54
|
+
|
|
55
|
+
const dartNullable = (raw: string, explicitNull: string, present: string, path: string): string =>
|
|
56
|
+
`() { if (${raw}.hasIsNull() && ${raw}.isNull) return ${explicitNull}; if (${raw}.hasValue()) return ${present}; throw FormatException(${dartString(`${path} selects no valid nullable arm`)}); }()`;
|
|
57
|
+
|
|
58
|
+
const tsNullable = (raw: string, present: string, path: string): string =>
|
|
59
|
+
`(() => { const nullable = ${raw}.selected; if (nullable.case === "isNull" && nullable.value === true) return null; if (nullable.case === "value") return ${present}; throw new TypeError(${JSON.stringify(`${path} selects no valid nullable arm`)}); })()`;
|
|
60
|
+
|
|
61
|
+
const dartGeometryCoordinates = (
|
|
62
|
+
geometry: NonNullable<LawTypeNode["geometry"]>,
|
|
63
|
+
raw: string,
|
|
64
|
+
): string => {
|
|
65
|
+
if (geometry === "Point") return `${raw}.coordinates.toList(growable: false)`;
|
|
66
|
+
const positions = `() { final flat = ${raw}.coordinates; var start = 0; final result = <List<double>>[]; for (final end in ${raw}.positionEnds) { result.add(flat.sublist(start, end)); start = end; } return result; }()`;
|
|
67
|
+
if (geometry !== "Polygon") return positions;
|
|
68
|
+
return `() { final positions = ${positions}; var start = 0; final result = <List<List<double>>>[]; for (final end in ${raw}.ringEnds) { result.add(positions.sublist(start, end)); start = end; } return result; }()`;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const tsGeometryCoordinates = (
|
|
72
|
+
geometry: NonNullable<LawTypeNode["geometry"]>,
|
|
73
|
+
raw: string,
|
|
74
|
+
): string => {
|
|
75
|
+
if (geometry === "Point") return `[...${raw}.coordinates]`;
|
|
76
|
+
const positions = `(() => { let start = 0; return ${raw}.positionEnds.map((end) => { const position = ${raw}.coordinates.slice(start, end); start = end; return position; }); })()`;
|
|
77
|
+
if (geometry !== "Polygon") return positions;
|
|
78
|
+
return `(() => { const positions = ${positions}; let start = 0; return ${raw}.ringEnds.map((end) => { const ring = positions.slice(start, end); start = end; return ring; }); })()`;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const enumUnion = (field: Field): string => {
|
|
82
|
+
try {
|
|
83
|
+
const values = zodEnumValues(field.zod);
|
|
84
|
+
return values.length
|
|
85
|
+
? values.map((value) => JSON.stringify(value)).join(" | ")
|
|
86
|
+
: "string";
|
|
87
|
+
} catch {
|
|
88
|
+
return "string";
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
function authoredFieldValue(
|
|
93
|
+
field: Field,
|
|
94
|
+
value: string,
|
|
95
|
+
workspace: string,
|
|
96
|
+
holon: string,
|
|
97
|
+
foreignWorkspace?: string,
|
|
98
|
+
): string {
|
|
99
|
+
const decode = (selected: string): string => {
|
|
100
|
+
if (field.nomosRef !== undefined) {
|
|
101
|
+
const target = field.nomosRef.targetIsContract === true
|
|
102
|
+
? contractTypeName(field.nomosRef.targetAggregateId)
|
|
103
|
+
: field.nomosRef.targetAggregateId;
|
|
104
|
+
return `((address) => _nmsRef<${target}>(address.workspace, address.type, address.id))(${selected})`;
|
|
105
|
+
}
|
|
106
|
+
if (field.versionedForeignRef !== undefined) {
|
|
107
|
+
const versioned = field.versionedForeignRef;
|
|
108
|
+
const target = versioned.targetIsContract === true
|
|
109
|
+
? contractTypeName(versioned.targetAggregateId)
|
|
110
|
+
: versioned.targetAggregateId;
|
|
111
|
+
const series = versioned.seriesIsContract === true
|
|
112
|
+
? contractTypeName(versioned.seriesAggregateId)
|
|
113
|
+
: versioned.seriesAggregateId;
|
|
114
|
+
return `_versionedNomosRef<${target}, ${series}>(${holon}, ${selected}, ${JSON.stringify(versioned.currentField)})`;
|
|
115
|
+
}
|
|
116
|
+
if (field.foreignRef !== undefined) {
|
|
117
|
+
if (foreignWorkspace === undefined) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`result Protobuf codegen: foreign ref '${field.foreignRef.targetAggregateId}' has no workspace value`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
const target = field.foreignRef.targetIsContract === true
|
|
123
|
+
? contractTypeName(field.foreignRef.targetAggregateId)
|
|
124
|
+
: field.foreignRef.targetAggregateId;
|
|
125
|
+
return `foreignRef<${target}>(${holon}, ${JSON.stringify(field.foreignRef.targetAggregateId)}, ${selected}, ${foreignWorkspace})`;
|
|
126
|
+
}
|
|
127
|
+
switch (field.kind) {
|
|
128
|
+
case "string":
|
|
129
|
+
return isSha256DigestSchema(field.zod)
|
|
130
|
+
? `sha256Digest(${selected})`
|
|
131
|
+
: isGitObjectIdSchema(field.zod)
|
|
132
|
+
? `gitObjectId(${selected})`
|
|
133
|
+
: selected;
|
|
134
|
+
case "position": return selected;
|
|
135
|
+
case "ref":
|
|
136
|
+
return field.foreignRef === undefined &&
|
|
137
|
+
field.nomosRef === undefined &&
|
|
138
|
+
field.versionedForeignRef === undefined &&
|
|
139
|
+
field.refAggregateId !== undefined
|
|
140
|
+
? `_nmsRef<${field.refAggregateId}>(${workspace}, ${JSON.stringify(field.refAggregateId)}, ${selected})`
|
|
141
|
+
: selected;
|
|
142
|
+
case "int":
|
|
143
|
+
case "counter": return selected;
|
|
144
|
+
case "bool": return selected;
|
|
145
|
+
case "enum": return `${selected} as ${enumUnion(field)}`;
|
|
146
|
+
case "set": return selected;
|
|
147
|
+
case "json":
|
|
148
|
+
return field.valueObject === undefined
|
|
149
|
+
? selected
|
|
150
|
+
: `${valueObjectDecoder(field.valueObject.name)}(${selected}, ${workspace})`;
|
|
151
|
+
case "evidence": return `${selected} as EvidenceRef`;
|
|
152
|
+
case "map":
|
|
153
|
+
return field.mapValueVo === undefined
|
|
154
|
+
? selected
|
|
155
|
+
: `Object.fromEntries(Object.entries(${selected}).map(([key, value]) => [key, ${valueObjectDecoder(field.mapValueVo.name)}(value, ${workspace})]))`;
|
|
156
|
+
default:
|
|
157
|
+
throw new Error(`result Protobuf codegen does not support field kind '${field.kind}'`);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
if (!admitsNull(field)) return decode(value);
|
|
161
|
+
const selected = "_nmsAuthoredValue";
|
|
162
|
+
return `((${selected}) => ${selected} === null ? null : ${decode(selected)})(${value})`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface TsQueryResultDecoder {
|
|
166
|
+
readonly rowsFunction: string;
|
|
167
|
+
readonly pageFunction: string;
|
|
168
|
+
readonly typeUrl: string;
|
|
169
|
+
readonly source: readonly string[];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface DartQueryResultAggregate {
|
|
173
|
+
readonly model: string;
|
|
174
|
+
readonly refType: string;
|
|
175
|
+
readonly runtimeType: string;
|
|
176
|
+
readonly baseFields: readonly {
|
|
177
|
+
readonly name: string;
|
|
178
|
+
readonly spec: AggFieldSpec;
|
|
179
|
+
readonly required: boolean;
|
|
180
|
+
readonly foreignWorkspaceName?: string;
|
|
181
|
+
}[];
|
|
182
|
+
readonly computedFields: readonly {
|
|
183
|
+
readonly name: string;
|
|
184
|
+
readonly required: boolean;
|
|
185
|
+
readonly enumType?: string;
|
|
186
|
+
}[];
|
|
187
|
+
readonly attributedFields: readonly string[];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface DartQueryResultDecoder {
|
|
191
|
+
readonly rowsFunction: string;
|
|
192
|
+
readonly pageFunction: string;
|
|
193
|
+
readonly typeUrl: string;
|
|
194
|
+
readonly source: readonly string[];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const dartString = (value: string): string =>
|
|
198
|
+
`'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\$/g, "\\$")}'`;
|
|
199
|
+
|
|
200
|
+
const dartHas = (member: string): string => `has${member[0]!.toUpperCase()}${member.slice(1)}()`;
|
|
201
|
+
const protoBindingMember = (sid: string): string =>
|
|
202
|
+
protoFieldName(sid).replace(/_([a-zA-Z0-9])/g, (_match, next: string) => next.toUpperCase());
|
|
203
|
+
|
|
204
|
+
/** Dart twin of {@link emitTsQueryResultProtoDecoder}. Public read methods and
|
|
205
|
+
* models do not change; only their private decoder moves from a handwritten
|
|
206
|
+
* USDA interpretation to the operation-specific protoc class emitted from the
|
|
207
|
+
* same law graph. */
|
|
208
|
+
export function emitDartQueryResultProtoDecoder(
|
|
209
|
+
graph: LawGraph,
|
|
210
|
+
paths: ReadonlyMap<string, string>,
|
|
211
|
+
query: LawRowReadNode,
|
|
212
|
+
aggregate: DartQueryResultAggregate,
|
|
213
|
+
): DartQueryResultDecoder {
|
|
214
|
+
const nodes = new Map<string, LawGraph["nodes"][number]>(
|
|
215
|
+
graph.nodes.map((node) => [node.entity.id, node]),
|
|
216
|
+
);
|
|
217
|
+
const contract = nodes.get(query.contract.id);
|
|
218
|
+
if (contract?.kind !== "read-contract" || contract.returns.kind !== "rows") {
|
|
219
|
+
throw new Error(`result Protobuf codegen: '${query.entity.label}' has no row contract`);
|
|
220
|
+
}
|
|
221
|
+
const aggregateNode = nodes.get(contract.returns.aggregate.id);
|
|
222
|
+
if (aggregateNode?.kind !== "aggregate") {
|
|
223
|
+
throw new Error(`result Protobuf codegen: '${query.entity.label}' returns no aggregate`);
|
|
224
|
+
}
|
|
225
|
+
const structuralField = (ref: LawStructuralRef<"value-field">): LawAnonymousValueFieldNode => {
|
|
226
|
+
const node = nodes.get(ref.id);
|
|
227
|
+
if (node?.kind !== "structural" || node.structuralKind !== "value-field") {
|
|
228
|
+
throw new Error(`result Protobuf codegen: '${ref.id}' is not a structural field`);
|
|
229
|
+
}
|
|
230
|
+
return node;
|
|
231
|
+
};
|
|
232
|
+
const structuralType = (id: string): LawAnonymousValueTypeNode => {
|
|
233
|
+
const node = nodes.get(id);
|
|
234
|
+
if (node?.kind !== "structural" || node.structuralKind !== "value-type") {
|
|
235
|
+
throw new Error(`result Protobuf codegen: '${id}' is not a structural value type`);
|
|
236
|
+
}
|
|
237
|
+
return node;
|
|
238
|
+
};
|
|
239
|
+
const required = (raw: string, member: string, decoded: string, path: string): string =>
|
|
240
|
+
`() { if (!${raw}.${dartHas(member)}) throw FormatException(${dartString(`${path} is absent`)}); return ${decoded}; }()`;
|
|
241
|
+
const emitRef = (ref: LawValueTypeRef, raw: string, path: string): string => {
|
|
242
|
+
const node = nodes.get(ref.id);
|
|
243
|
+
if (node?.kind === "structural" && node.structuralKind === "value-type") {
|
|
244
|
+
return emitStructural(node, raw, path);
|
|
245
|
+
}
|
|
246
|
+
if (node?.kind === "type") return emitDeclared(node, raw, path);
|
|
247
|
+
throw new Error(`result Protobuf codegen: '${path}' has no declared value type`);
|
|
248
|
+
};
|
|
249
|
+
const emitDeclared = (node: LawTypeNode, raw: string, path: string): string => {
|
|
250
|
+
if (node.form === "geometry") {
|
|
251
|
+
if (node.geometry === undefined) throw new Error(`result Protobuf codegen: '${path}' has no geometry kind`);
|
|
252
|
+
const coordinates = dartGeometryCoordinates(node.geometry, raw);
|
|
253
|
+
return `${node.entity.label}(coordinates: ${coordinates})`;
|
|
254
|
+
}
|
|
255
|
+
if (node.form === "sum") {
|
|
256
|
+
const arms = node.variants.map((ref) => {
|
|
257
|
+
const variant = nodes.get(ref.id);
|
|
258
|
+
if (variant?.kind !== "structural" || variant.structuralKind !== "value-variant" || variant.label === undefined) {
|
|
259
|
+
throw new Error(`result Protobuf codegen: '${path}' has an invalid declared sum arm '${ref.id}'`);
|
|
260
|
+
}
|
|
261
|
+
const target = nodes.get(variant.value.id);
|
|
262
|
+
const member = protoBindingMember(composedWireIdentity(paths, variant.entity));
|
|
263
|
+
const selected = `${raw}.${member}`;
|
|
264
|
+
const decoded = target?.kind === "type"
|
|
265
|
+
? `${unionArmClassName(node.entity.label, variant.label)}(${emitDeclared(target, selected, `${path}.${variant.label}.value`)})`
|
|
266
|
+
: target?.kind === "structural" && target.structuralKind === "value-type"
|
|
267
|
+
? emitRecordArm(target, selected, `${path}.${variant.label}`, unionArmClassName(node.entity.label, variant.label))
|
|
268
|
+
: (() => { throw new Error(`result Protobuf codegen: '${path}.${variant.label}' has no value type`); })();
|
|
269
|
+
return `if (${raw}.${dartHas(member)}) return ${decoded};`;
|
|
270
|
+
});
|
|
271
|
+
return `() { ${arms.join(" ")} throw FormatException(${dartString(`${path} selects no nominal union arm`)}); }()`;
|
|
272
|
+
}
|
|
273
|
+
const members = node.fields.flatMap((ref) => {
|
|
274
|
+
const field = nodes.get(ref.id);
|
|
275
|
+
if (field?.kind !== "field") {
|
|
276
|
+
throw new Error(`result Protobuf codegen: '${ref.id}' is not a field`);
|
|
277
|
+
}
|
|
278
|
+
const member = protoBindingMember(composedWireIdentity(paths, field.entity));
|
|
279
|
+
const selected = `${raw}.${member}`;
|
|
280
|
+
const decoded = emitRef(field.value, selected, `${path}.${field.entity.label}`);
|
|
281
|
+
if (field.required) {
|
|
282
|
+
return [`${dartMemberName(field.entity.label)}: ${required(raw, member, decoded, `${path}.${field.entity.label}`)}`];
|
|
283
|
+
}
|
|
284
|
+
return [`${dartMemberName(field.entity.label)}: ${raw}.${dartHas(member)} ? ${decoded} : null`];
|
|
285
|
+
});
|
|
286
|
+
return `${node.entity.label}(${members.join(", ")})`;
|
|
287
|
+
};
|
|
288
|
+
const emitRecordArm = (
|
|
289
|
+
node: LawAnonymousValueTypeNode,
|
|
290
|
+
raw: string,
|
|
291
|
+
path: string,
|
|
292
|
+
className: string,
|
|
293
|
+
): string => {
|
|
294
|
+
if (node.expression.kind !== "record") {
|
|
295
|
+
throw new Error(`result Protobuf codegen: '${path}' is not a record arm`);
|
|
296
|
+
}
|
|
297
|
+
const members = node.expression.fields.map(structuralField).flatMap((field) => {
|
|
298
|
+
const value = nodes.get(field.value.id);
|
|
299
|
+
if (
|
|
300
|
+
value?.kind === "structural" &&
|
|
301
|
+
value.structuralKind === "value-type" &&
|
|
302
|
+
value.expression.kind === "literal" &&
|
|
303
|
+
field.name === "type"
|
|
304
|
+
) return [];
|
|
305
|
+
const member = protoBindingMember(composedWireIdentity(paths, field.entity));
|
|
306
|
+
const decoded = emitRef(field.value, `${raw}.${member}`, `${path}.${field.name}`);
|
|
307
|
+
return [field.required
|
|
308
|
+
? `${dartMemberName(field.name)}: ${required(raw, member, decoded, `${path}.${field.name}`)}`
|
|
309
|
+
: `${dartMemberName(field.name)}: ${raw}.${dartHas(member)} ? ${decoded} : null`];
|
|
310
|
+
});
|
|
311
|
+
return `${className}(${members.join(", ")})`;
|
|
312
|
+
};
|
|
313
|
+
const emitStructural = (node: LawAnonymousValueTypeNode, raw: string, path: string): string => {
|
|
314
|
+
const semantic = node.expression.semantic;
|
|
315
|
+
if (semantic?.kind === "sha256-digest") return `Sha256Digest(${raw})`;
|
|
316
|
+
if (semantic?.kind === "git-object-id") return `GitObjectId(${raw})`;
|
|
317
|
+
if (semantic?.kind === "branded-id") return `${semantic.name}(${raw})`;
|
|
318
|
+
if (semantic?.kind === "id-reference") {
|
|
319
|
+
const target = semantic.targetKind === "contract"
|
|
320
|
+
? contractTypeName(semantic.target)
|
|
321
|
+
: semantic.target;
|
|
322
|
+
return `NmsInternalNomosRefs.create<${target}>(workspace: workspace, type: ${dartString(semantic.target)}, id: ${raw})`;
|
|
323
|
+
}
|
|
324
|
+
if (semantic?.kind === "unit") {
|
|
325
|
+
const value = node.expression.kind === "integer" ? `${raw}.toDouble()` : raw;
|
|
326
|
+
return `${semantic.name}(${value})`;
|
|
327
|
+
}
|
|
328
|
+
if (semantic?.kind === "address-reference") {
|
|
329
|
+
if (node.expression.kind !== "record") {
|
|
330
|
+
throw new Error(`result Protobuf codegen: address reference '${path}' is not a record`);
|
|
331
|
+
}
|
|
332
|
+
const members = new Map(
|
|
333
|
+
node.expression.fields.map(structuralField).map((field) => [field.name, field]),
|
|
334
|
+
);
|
|
335
|
+
const addressPart = (name: "workspace" | "type" | "id"): string => {
|
|
336
|
+
const field = members.get(name);
|
|
337
|
+
if (field === undefined) {
|
|
338
|
+
throw new Error(`result Protobuf codegen: address reference '${path}' has no '${name}' field`);
|
|
339
|
+
}
|
|
340
|
+
const member = protoBindingMember(composedWireIdentity(paths, field.entity));
|
|
341
|
+
const decoded = emitStructural(structuralType(field.value.id), `${raw}.${member}`, `${path}.${name}`);
|
|
342
|
+
return required(raw, member, decoded, `${path}.${name}`);
|
|
343
|
+
};
|
|
344
|
+
return `(workspace: ${addressPart("workspace")}, type: ${addressPart("type")}, id: ${addressPart("id")})`;
|
|
345
|
+
}
|
|
346
|
+
if (semantic?.kind === "versioned-reference") {
|
|
347
|
+
if (node.expression.kind !== "record") {
|
|
348
|
+
throw new Error(`result Protobuf codegen: versioned reference '${path}' is not a record`);
|
|
349
|
+
}
|
|
350
|
+
const members = new Map(
|
|
351
|
+
node.expression.fields.map(structuralField).map((field) => [field.name, field]),
|
|
352
|
+
);
|
|
353
|
+
const referencePart = (name: "pinned" | "series"): string => {
|
|
354
|
+
const field = members.get(name);
|
|
355
|
+
if (field === undefined) {
|
|
356
|
+
throw new Error(`result Protobuf codegen: versioned reference '${path}' has no '${name}' field`);
|
|
357
|
+
}
|
|
358
|
+
const member = protoBindingMember(composedWireIdentity(paths, field.entity));
|
|
359
|
+
const decoded = emitStructural(structuralType(field.value.id), `${raw}.${member}`, `${path}.${name}`);
|
|
360
|
+
return required(raw, member, decoded, `${path}.${name}`);
|
|
361
|
+
};
|
|
362
|
+
return `(pinned: ${referencePart("pinned")}, series: ${referencePart("series")})`;
|
|
363
|
+
}
|
|
364
|
+
const geometry = structuralGeometryKind(nodes, node);
|
|
365
|
+
if (geometry !== undefined) {
|
|
366
|
+
const semantic = node.expression.kind === "record"
|
|
367
|
+
? node.expression.semantic
|
|
368
|
+
: undefined;
|
|
369
|
+
if (semantic?.kind !== "value-object") {
|
|
370
|
+
throw new Error(`result Protobuf codegen: geometry '${path}' has no public Dart value type`);
|
|
371
|
+
}
|
|
372
|
+
return `${semantic.name}(coordinates: ${dartGeometryCoordinates(geometry, raw)})`;
|
|
373
|
+
}
|
|
374
|
+
switch (node.expression.kind) {
|
|
375
|
+
case "default": return emitRef(node.expression.value, raw, path);
|
|
376
|
+
case "recursive": throw new Error(`result Protobuf codegen: '${path}' contains recursive values`);
|
|
377
|
+
case "string": return raw;
|
|
378
|
+
case "enum": return node.expression.name === undefined
|
|
379
|
+
? raw
|
|
380
|
+
: `${node.expression.name}.fromWire(${raw})`;
|
|
381
|
+
case "integer": return dartInteger(raw, path);
|
|
382
|
+
case "number": return raw;
|
|
383
|
+
case "boolean": return raw;
|
|
384
|
+
case "null": return "null";
|
|
385
|
+
case "literal": return JSON.stringify(node.expression.value);
|
|
386
|
+
case "nullable": return dartNullable(raw, "null", emitRef(node.expression.value, `${raw}.value`, path), path);
|
|
387
|
+
case "record": {
|
|
388
|
+
const semantic = node.expression.semantic;
|
|
389
|
+
if (semantic?.kind !== "value-object") {
|
|
390
|
+
throw new Error(`result Protobuf codegen: anonymous record '${path}' has no public Dart value type`);
|
|
391
|
+
}
|
|
392
|
+
const members = node.expression.fields.map(structuralField).flatMap((field) => {
|
|
393
|
+
const value = nodes.get(field.value.id);
|
|
394
|
+
if (
|
|
395
|
+
value?.kind === "structural" &&
|
|
396
|
+
value.structuralKind === "value-type" &&
|
|
397
|
+
value.expression.kind === "literal" &&
|
|
398
|
+
field.name === "type"
|
|
399
|
+
) return [];
|
|
400
|
+
const member = protoBindingMember(composedWireIdentity(paths, field.entity));
|
|
401
|
+
const decoded = emitRef(field.value, `${raw}.${member}`, `${path}.${field.name}`);
|
|
402
|
+
return [field.required
|
|
403
|
+
? `${dartMemberName(field.name)}: ${required(raw, member, decoded, `${path}.${field.name}`)}`
|
|
404
|
+
: `${dartMemberName(field.name)}: ${raw}.${dartHas(member)} ? ${decoded} : null`];
|
|
405
|
+
});
|
|
406
|
+
return `${semantic.name}(${members.join(", ")})`;
|
|
407
|
+
}
|
|
408
|
+
case "list": return `${raw}.items.map((value) => ${emitRef(node.expression.element, "value", `${path}[]`)}).toList(growable: false)`;
|
|
409
|
+
case "map": return `{for (final entry in ${raw}.entries) entry.key: ${emitRef(node.expression.value, "entry.value", `${path}.*`)}}`;
|
|
410
|
+
case "sum": {
|
|
411
|
+
const semantic = node.expression.semantic;
|
|
412
|
+
if (semantic?.kind !== "value-object") {
|
|
413
|
+
throw new Error(`result Protobuf codegen: structural sum '${path}' is not nominal`);
|
|
414
|
+
}
|
|
415
|
+
const arms = node.expression.variants.map((ref) => {
|
|
416
|
+
const variant = nodes.get(ref.id);
|
|
417
|
+
if (variant?.kind !== "structural" || variant.structuralKind !== "value-variant") {
|
|
418
|
+
throw new Error(`result Protobuf codegen: '${path}' has a non-variant arm`);
|
|
419
|
+
}
|
|
420
|
+
const value = structuralType(variant.value.id);
|
|
421
|
+
const discriminator = value.expression.kind === "record"
|
|
422
|
+
? value.expression.fields.map(structuralField).flatMap((field) => {
|
|
423
|
+
const type = structuralType(field.value.id);
|
|
424
|
+
return field.name === "type" && type.expression.kind === "literal" && typeof type.expression.value === "string"
|
|
425
|
+
? [type.expression.value]
|
|
426
|
+
: [];
|
|
427
|
+
})[0]
|
|
428
|
+
: undefined;
|
|
429
|
+
if (discriminator === undefined) {
|
|
430
|
+
throw new Error(`result Protobuf codegen: '${path}' union arm has no discriminator`);
|
|
431
|
+
}
|
|
432
|
+
const member = protoBindingMember(composedWireIdentity(paths, variant.entity));
|
|
433
|
+
return { member, value, discriminator };
|
|
434
|
+
});
|
|
435
|
+
const body = arms.map((arm) =>
|
|
436
|
+
`if (${raw}.${dartHas(arm.member)}) return ${emitRecordArm(arm.value, `${raw}.${arm.member}`, `${path}.${arm.discriminator}`, unionArmClassName(semantic.name, arm.discriminator))};`,
|
|
437
|
+
);
|
|
438
|
+
return `() { ${body.join(" ")} throw FormatException(${dartString(`${path} selects no nominal union arm`)}); }()`;
|
|
439
|
+
}
|
|
440
|
+
case "unknown": throw new Error(`result Protobuf codegen: '${path}' is unstructured`);
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
const readFields = new Map<string, LawReadNode>();
|
|
445
|
+
for (const node of graph.nodes) {
|
|
446
|
+
if (node.kind === "read" && node.of.id === aggregateNode.entity.id) {
|
|
447
|
+
readFields.set(node.entity.label, node);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
const decodedField = (field: DartQueryResultAggregate["baseFields"][number]): string => {
|
|
451
|
+
const lawField = aggregateNode.fields
|
|
452
|
+
.map((ref) => nodes.get(ref.id))
|
|
453
|
+
.find((node) => node?.kind === "field" && node.entity.label === field.name);
|
|
454
|
+
if (lawField?.kind !== "field") {
|
|
455
|
+
throw new Error(`result Protobuf codegen: '${aggregate.model}.${field.name}' has no law field`);
|
|
456
|
+
}
|
|
457
|
+
const member = protoBindingMember(composedWireIdentity(paths, lawField.entity));
|
|
458
|
+
const raw = `row.${member}`;
|
|
459
|
+
const valueTypeNode = nodes.get(lawField.value.id);
|
|
460
|
+
const spec = field.spec;
|
|
461
|
+
const valueRaw = spec.surfaced === true
|
|
462
|
+
? `${raw}.resolved`
|
|
463
|
+
: spec.nullAdmits === true
|
|
464
|
+
? `${raw}.value`
|
|
465
|
+
: raw;
|
|
466
|
+
const structural = emitRef(lawField.value, valueRaw, `${aggregate.model}.${field.name}`);
|
|
467
|
+
const present = (() => {
|
|
468
|
+
if (spec.nomosRefTarget !== undefined) {
|
|
469
|
+
return `() { final value = ${structural}; return NmsInternalNomosRefs.create<${spec.nomosRefTarget}>(workspace: value.workspace, type: value.type, id: value.id); }()`;
|
|
470
|
+
}
|
|
471
|
+
if (spec.versionedRefTarget !== undefined) {
|
|
472
|
+
return `() { final value = ${structural}; return NmsInternalVersionedNomosRefs.create<${spec.versionedRefTarget}, ${spec.versionedRefSeries}>(pinned: NmsInternalNomosRefs.create<${spec.versionedRefTarget}>(workspace: value.pinned.workspace, type: value.pinned.type, id: value.pinned.id), series: NmsInternalNomosRefs.create<${spec.versionedRefSeries}>(workspace: value.series.workspace, type: value.series.type, id: value.series.id), currentField: ${dartString(spec.versionedRefCurrentField!)}); }()`;
|
|
473
|
+
}
|
|
474
|
+
if (spec.valueClass !== undefined) {
|
|
475
|
+
return `NmsInternalNomosRefs.create<${spec.valueClass}>(workspace: workspace, type: ${dartString(spec.valueAggregateType!)}, id: ${structural})`;
|
|
476
|
+
}
|
|
477
|
+
if (spec.foreignRefTarget !== undefined) {
|
|
478
|
+
const workspaceField = aggregateNode.fields
|
|
479
|
+
.map((ref) => nodes.get(ref.id))
|
|
480
|
+
.find((node) => node?.kind === "field" && node.entity.label === field.foreignWorkspaceName);
|
|
481
|
+
if (workspaceField?.kind !== "field") throw new Error(`result Protobuf codegen: foreign ref '${field.name}' has no workspace field`);
|
|
482
|
+
const workspaceMember = protoBindingMember(composedWireIdentity(paths, workspaceField.entity));
|
|
483
|
+
return `NmsInternalForeignRefs.create<${spec.foreignRefTarget}>(id: ${structural}, workspace: row.${workspaceMember}, type: ${dartString(spec.foreignRefAggregateType!)})`;
|
|
484
|
+
}
|
|
485
|
+
if (spec.refIdClass !== undefined) {
|
|
486
|
+
return `NmsInternalNomosRefs.create<${spec.refIdClass}>(workspace: workspace, type: ${dartString(spec.refAggregateType!)}, id: ${structural})`;
|
|
487
|
+
}
|
|
488
|
+
// Semantic scalar wrapping belongs to the law graph. Applying the public
|
|
489
|
+
// field spec as well would decode the same Protobuf string twice (for
|
|
490
|
+
// example Sha256Digest(Sha256Digest(raw))). Aggregate enums created before
|
|
491
|
+
// named structural vocabulary remain unnamed in the graph, so only that
|
|
492
|
+
// legacy-free scalar case needs the public enum name supplied here.
|
|
493
|
+
if (spec.kind === "enum" && !(
|
|
494
|
+
valueTypeNode?.kind === "structural" &&
|
|
495
|
+
valueTypeNode.structuralKind === "value-type" &&
|
|
496
|
+
valueTypeNode.expression.kind === "enum" &&
|
|
497
|
+
valueTypeNode.expression.name !== undefined
|
|
498
|
+
)) return `${spec.dartType}.fromWire(${structural})`;
|
|
499
|
+
if (spec.kind === "set") return `${structural}.toSet()`;
|
|
500
|
+
return structural;
|
|
501
|
+
})();
|
|
502
|
+
if (spec.surfaced === true) {
|
|
503
|
+
const valueType = spec.dartType.replace(/\?$/, "");
|
|
504
|
+
const observed = "observation";
|
|
505
|
+
const observedValue = emitRef(
|
|
506
|
+
lawField.value,
|
|
507
|
+
`${observed}.value`,
|
|
508
|
+
`${aggregate.model}.${field.name}.pending.value`,
|
|
509
|
+
);
|
|
510
|
+
const surfaced = `() { ` +
|
|
511
|
+
`if (${raw}.hasResolved()) return SurfacedResolved<${valueType}>(${present}); ` +
|
|
512
|
+
`if (${raw}.hasPending()) return SurfacedPending<${valueType}>(${raw}.pending.observations.map((${observed}) { ` +
|
|
513
|
+
`if (!${observed}.hasValue()) throw FormatException(${dartString(`${aggregate.model}.${field.name} pending observation has no value`)}); ` +
|
|
514
|
+
`if (!${observed}.hasPhysical() || !${observed}.hasLogical() || !${observed}.hasReplica()) throw FormatException(${dartString(`${aggregate.model}.${field.name} pending observation has no complete clock`)}); ` +
|
|
515
|
+
`return SurfacedObservation<${valueType}>(value: ${observedValue}, occurredAt: Hlc(physical: ${observed}.physical.toInt(), logical: ${observed}.logical.toInt(), replica: int.parse(${observed}.replica)), author: ${observed}.hasAuthor() ? ${observed}.author : null); ` +
|
|
516
|
+
`}).toList(growable: false)); ` +
|
|
517
|
+
`throw FormatException(${dartString(`${aggregate.model}.${field.name} selects no surfaced result`)}); }()`;
|
|
518
|
+
return field.required
|
|
519
|
+
? required("row", member, surfaced, `${aggregate.model}.${field.name}`)
|
|
520
|
+
: `row.${dartHas(member)} ? ${surfaced} : null`;
|
|
521
|
+
}
|
|
522
|
+
if (spec.nullAdmits === true) {
|
|
523
|
+
const slotType = spec.dartType.replace(/\?$/, "");
|
|
524
|
+
const decoded = required(raw, "value", present, `${aggregate.model}.${field.name}`);
|
|
525
|
+
return `!row.${dartHas(member)} ? const NomosSlot<${slotType}>.omitted() : ${dartNullable(raw, `const NomosSlot<${slotType}>.explicitNull()`, `NomosSlot<${slotType}>.of(${decoded})`, `${aggregate.model}.${field.name}`)}`;
|
|
526
|
+
}
|
|
527
|
+
if (spec.kind === "set") return `row.${dartHas(member)} ? ${present} : const <String>{}`;
|
|
528
|
+
if (spec.kind === "map") return `row.${dartHas(member)} ? ${present} : const {}`;
|
|
529
|
+
return field.required
|
|
530
|
+
? required("row", member, present, `${aggregate.model}.${field.name}`)
|
|
531
|
+
: `row.${dartHas(member)} ? ${present} : null`;
|
|
532
|
+
};
|
|
533
|
+
const decodedComputed = (field: DartQueryResultAggregate["computedFields"][number]): string => {
|
|
534
|
+
const read = readFields.get(field.name);
|
|
535
|
+
const readContract = read === undefined ? undefined : nodes.get(read.contract.id);
|
|
536
|
+
if (read === undefined || readContract?.kind !== "read-contract" || readContract.returns.kind !== "scalar") {
|
|
537
|
+
throw new Error(`result Protobuf codegen: '${aggregate.model}.${field.name}' has no scalar read`);
|
|
538
|
+
}
|
|
539
|
+
const member = protoBindingMember(composedWireIdentity(paths, read.entity));
|
|
540
|
+
const raw = `row.${member}`;
|
|
541
|
+
const value = emitRef(readContract.returns.value, raw, `${aggregate.model}.${field.name}`);
|
|
542
|
+
const decoded = field.enumType === undefined ? value : `${field.enumType}.fromWire(${value})`;
|
|
543
|
+
return field.required
|
|
544
|
+
? required("row", member, decoded, `${aggregate.model}.${field.name}`)
|
|
545
|
+
: `row.${dartHas(member)} ? ${decoded} : null`;
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
const resultMessage = protoMessageName(
|
|
549
|
+
"QueryResult",
|
|
550
|
+
operationMessageIdentity(graph, query.entity.sid),
|
|
551
|
+
);
|
|
552
|
+
const rowIdSid = `${aggregateNode.entity.sid}:result:id`;
|
|
553
|
+
const rowsSid = `${query.entity.sid}:result:rows`;
|
|
554
|
+
const cursorSid = `${query.entity.sid}:result:cursor`;
|
|
555
|
+
const doneSid = `${query.entity.sid}:result:done`;
|
|
556
|
+
const rowsFunction = `_nmsDecodeQuery_${symbol(graph.domain.entity.label)}_${symbol(query.entity.label)}Rows`;
|
|
557
|
+
const pageFunction = `_nmsDecodeQuery_${symbol(graph.domain.entity.label)}_${symbol(query.entity.label)}Page`;
|
|
558
|
+
const decodeRows = `_nmsDecodeRows_${symbol(graph.domain.entity.label)}_${symbol(query.entity.label)}`;
|
|
559
|
+
const typeUrl = `type.nomos.dev/nomos.operation.v1.QueryResult_${query.entity.sid}`;
|
|
560
|
+
const rowId = protoBindingMember(rowIdSid);
|
|
561
|
+
const rows = protoBindingMember(rowsSid);
|
|
562
|
+
const cursor = protoBindingMember(cursorSid);
|
|
563
|
+
const done = protoBindingMember(doneSid);
|
|
564
|
+
const provenanceMember = protoBindingMember(provenanceRowIdentity(aggregateNode.entity.sid));
|
|
565
|
+
const provenanceEntries = aggregate.attributedFields.map(name => {
|
|
566
|
+
const field = aggregateNode.fields.map(ref => nodes.get(ref.id))
|
|
567
|
+
.find(node => node?.kind === "field" && node.entity.label === name);
|
|
568
|
+
if (field?.kind !== "field" || field.mergeDrivers[0]?.kind !== "Attributed") {
|
|
569
|
+
throw new Error(`result Protobuf codegen: '${aggregate.model}.${name}' has no attributed law field`);
|
|
570
|
+
}
|
|
571
|
+
const member = protoBindingMember(provenanceFieldIdentity(composedWireIdentity(paths, field.entity)));
|
|
572
|
+
const raw = `row.${provenanceMember}.${member}`;
|
|
573
|
+
const author = protoBindingMember(provenanceAuthorIdentity);
|
|
574
|
+
const contested = protoBindingMember(provenanceContestedIdentity);
|
|
575
|
+
const path = `${aggregate.model}.${name} provenance`;
|
|
576
|
+
return `if (row.${provenanceMember}.${dartHas(member)}) ${dartString(name)}: FieldProvenance(` +
|
|
577
|
+
`author: ${required(raw, author, dartNullable(`${raw}.${author}`, "null", `${raw}.${author}.value`, `${path}.author`), `${path}.author`)}, ` +
|
|
578
|
+
`wasContested: ${required(raw, contested, `${raw}.${contested}`, `${path}.wasContested`)}),`;
|
|
579
|
+
});
|
|
580
|
+
return {
|
|
581
|
+
rowsFunction,
|
|
582
|
+
pageFunction,
|
|
583
|
+
typeUrl,
|
|
584
|
+
source: [
|
|
585
|
+
`List<${aggregate.model}> ${decodeRows}(NmsGeneratedResult result, String workspace) {`,
|
|
586
|
+
` if (result.protobufType != ${dartString(typeUrl)}) throw const FormatException('Query result type does not match generated realm contract');`,
|
|
587
|
+
` final message = _nmsop.${resultMessage}.fromBuffer(result.protobufPayload);`,
|
|
588
|
+
...(query.readKind === "ordered" ? [
|
|
589
|
+
` if (message.${rows}.length > ${query.limit}) throw const FormatException('Ordered result exceeds its declared limit');`,
|
|
590
|
+
` if (message.${dartHas(cursor)} || message.${dartHas(done)}) throw const FormatException('Ordered result cannot carry page metadata');`,
|
|
591
|
+
] : []),
|
|
592
|
+
` return message.${rows}.map((row) {`,
|
|
593
|
+
` if (!row.${dartHas(rowId)}) throw const FormatException('Query row has no stable identity');`,
|
|
594
|
+
` return NmsInternalRecordOrigins.remember(${aggregate.model}(`,
|
|
595
|
+
` ref: NmsInternalNomosRefs.create<${aggregate.refType}>(workspace: workspace, type: ${dartString(aggregate.runtimeType)}, id: row.${rowId}),`,
|
|
596
|
+
...aggregate.baseFields.map((field) => ` ${field.spec.name}: ${decodedField(field)},`),
|
|
597
|
+
...aggregate.computedFields.map((field) => ` ${dartMemberName(field.name)}: ${decodedComputed(field)},`),
|
|
598
|
+
...(provenanceEntries.length > 0 ? [
|
|
599
|
+
` \$provenance: row.${dartHas(provenanceMember)} ? { ${provenanceEntries.join(" ")} } : const {},`,
|
|
600
|
+
] : []),
|
|
601
|
+
` ), workspace: workspace, type: ${dartString(aggregate.runtimeType)}, id: row.${rowId});`,
|
|
602
|
+
` }).toList(growable: false);`,
|
|
603
|
+
`}`,
|
|
604
|
+
`List<${aggregate.model}> ${rowsFunction}(NmsGeneratedResult result, String workspace) => ${decodeRows}(result, workspace);`,
|
|
605
|
+
`NomosPage<${aggregate.model}> ${pageFunction}(NmsGeneratedResult result, String workspace) {`,
|
|
606
|
+
` if (result.protobufType != ${dartString(typeUrl)}) throw const FormatException('Query result type does not match generated realm contract');`,
|
|
607
|
+
` final message = _nmsop.${resultMessage}.fromBuffer(result.protobufPayload);`,
|
|
608
|
+
` return NomosPage(rows: ${decodeRows}(result, workspace), cursor: message.${dartHas(cursor)} ? message.${cursor} : null, done: message.${dartHas(done)} && message.${done});`,
|
|
609
|
+
`}`,
|
|
610
|
+
``,
|
|
611
|
+
],
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/** Generate one query-specific decoder over protoc-gen-es bindings. The
|
|
616
|
+
* application sees the same Row<T> and nested nominal values as before; no
|
|
617
|
+
* USDA parser, generic map, or asserted transport object sits on this path. */
|
|
618
|
+
export function emitTsQueryResultProtoDecoder(
|
|
619
|
+
graph: LawGraph,
|
|
620
|
+
paths: ReadonlyMap<string, string>,
|
|
621
|
+
query: LawRowReadNode,
|
|
622
|
+
aggregate: TsResultAggregate,
|
|
623
|
+
emitAggregateDecoder = true,
|
|
624
|
+
): TsQueryResultDecoder {
|
|
625
|
+
const nodes = new Map<string, LawGraph["nodes"][number]>(
|
|
626
|
+
graph.nodes.map((node) => [node.entity.id, node]),
|
|
627
|
+
);
|
|
628
|
+
const contract = nodes.get(query.contract.id);
|
|
629
|
+
if (contract?.kind !== "read-contract" || contract.returns.kind !== "rows") {
|
|
630
|
+
throw new Error(`result Protobuf codegen: '${query.entity.label}' has no row contract`);
|
|
631
|
+
}
|
|
632
|
+
const aggregateNode = nodes.get(contract.returns.aggregate.id);
|
|
633
|
+
if (aggregateNode?.kind !== "aggregate") {
|
|
634
|
+
throw new Error(`result Protobuf codegen: '${query.entity.label}' returns no aggregate`);
|
|
635
|
+
}
|
|
636
|
+
let local = 0;
|
|
637
|
+
const fresh = (prefix: string): string => `_${prefix}${local++}`;
|
|
638
|
+
const structuralField = (ref: LawStructuralRef<"value-field">): LawAnonymousValueFieldNode => {
|
|
639
|
+
const node = nodes.get(ref.id);
|
|
640
|
+
if (node?.kind !== "structural" || node.structuralKind !== "value-field") {
|
|
641
|
+
throw new Error(`result Protobuf codegen: '${ref.id}' is not a structural field`);
|
|
642
|
+
}
|
|
643
|
+
return node;
|
|
644
|
+
};
|
|
645
|
+
const structuralType = (id: string): LawAnonymousValueTypeNode => {
|
|
646
|
+
const node = nodes.get(id);
|
|
647
|
+
if (node?.kind !== "structural" || node.structuralKind !== "value-type") {
|
|
648
|
+
throw new Error(`result Protobuf codegen: '${id}' is not a structural value type`);
|
|
649
|
+
}
|
|
650
|
+
return node;
|
|
651
|
+
};
|
|
652
|
+
const emitRef = (ref: LawValueTypeRef, raw: string, path: string): string => {
|
|
653
|
+
const node = nodes.get(ref.id);
|
|
654
|
+
if (node?.kind === "structural" && node.structuralKind === "value-type") {
|
|
655
|
+
return emitStructural(node, raw, path);
|
|
656
|
+
}
|
|
657
|
+
if (node?.kind === "type") return emitDeclared(node, raw, path);
|
|
658
|
+
throw new Error(`result Protobuf codegen: '${path}' has no declared value type`);
|
|
659
|
+
};
|
|
660
|
+
const emitDeclared = (node: LawTypeNode, raw: string, path: string): string => {
|
|
661
|
+
if (node.form === "geometry") {
|
|
662
|
+
if (node.geometry === undefined) throw new Error(`result Protobuf codegen: '${path}' has no geometry kind`);
|
|
663
|
+
const coordinates = tsGeometryCoordinates(node.geometry, raw);
|
|
664
|
+
return `({ type: ${JSON.stringify(node.geometry)}, coordinates: ${coordinates} })`;
|
|
665
|
+
}
|
|
666
|
+
if (node.form === "sum") {
|
|
667
|
+
const selected = fresh("sum");
|
|
668
|
+
const cases = node.variants.map((ref) => {
|
|
669
|
+
const variant = nodes.get(ref.id);
|
|
670
|
+
if (variant?.kind !== "structural" || variant.structuralKind !== "value-variant" || variant.label === undefined) {
|
|
671
|
+
throw new Error(`result Protobuf codegen: '${path}' has an invalid declared sum arm '${ref.id}'`);
|
|
672
|
+
}
|
|
673
|
+
const target = nodes.get(variant.value.id);
|
|
674
|
+
const member = protoBindingMember(composedWireIdentity(paths, variant.entity));
|
|
675
|
+
const decoded = target?.kind === "type"
|
|
676
|
+
? `{ type: ${JSON.stringify(variant.label)}, value: ${emitDeclared(target, `${selected}.choice.value!`, `${path}.${variant.label}.value`)} }`
|
|
677
|
+
: target?.kind === "structural" && target.structuralKind === "value-type"
|
|
678
|
+
? `({ type: ${JSON.stringify(variant.label)}, ...${emitStructural(target, `${selected}.choice.value!`, `${path}.${variant.label}`)} })`
|
|
679
|
+
: (() => { throw new Error(`result Protobuf codegen: '${path}.${variant.label}' has no value type`); })();
|
|
680
|
+
return `case ${JSON.stringify(member)}: return ${decoded};`;
|
|
681
|
+
});
|
|
682
|
+
return `((${selected}) => { switch (${selected}.choice.case) { ${cases.join(" ")} default: throw new TypeError(${JSON.stringify(path)} + " selects no nominal union arm"); } })(${raw})`;
|
|
683
|
+
}
|
|
684
|
+
const members = node.fields.map((ref) => {
|
|
685
|
+
const field = nodes.get(ref.id);
|
|
686
|
+
if (field?.kind !== "field") throw new Error(`result Protobuf codegen: '${ref.id}' is not a field`);
|
|
687
|
+
const sid = composedWireIdentity(paths, field.entity);
|
|
688
|
+
const selected = `${raw}.${protoBindingMember(sid)}`;
|
|
689
|
+
const fieldPath = `${path}.${field.entity.label}`;
|
|
690
|
+
if (field.required) {
|
|
691
|
+
const decoded = emitRef(
|
|
692
|
+
field.value,
|
|
693
|
+
`_nmsResultRequired(${selected}, ${JSON.stringify(fieldPath)})`,
|
|
694
|
+
fieldPath,
|
|
695
|
+
);
|
|
696
|
+
return `${JSON.stringify(field.entity.label)}: ${decoded}`;
|
|
697
|
+
}
|
|
698
|
+
const captured = fresh("field");
|
|
699
|
+
const decoded = emitRef(field.value, captured, fieldPath);
|
|
700
|
+
return `...(((${captured}) => ${captured} === undefined ? {} : { ${JSON.stringify(field.entity.label)}: ${decoded} })(${selected}))`;
|
|
701
|
+
});
|
|
702
|
+
return `({ ${members.join(", ")} })`;
|
|
703
|
+
};
|
|
704
|
+
const emitStructural = (node: LawAnonymousValueTypeNode, raw: string, path: string): string => {
|
|
705
|
+
const geometry = structuralGeometryKind(nodes, node);
|
|
706
|
+
if (geometry !== undefined) {
|
|
707
|
+
return `({ type: ${JSON.stringify(geometry)}, coordinates: ${tsGeometryCoordinates(geometry, raw)} })`;
|
|
708
|
+
}
|
|
709
|
+
switch (node.expression.kind) {
|
|
710
|
+
case "default": return emitRef(node.expression.value, raw, path);
|
|
711
|
+
case "recursive": throw new Error(`result Protobuf codegen: '${path}' contains recursive values`);
|
|
712
|
+
case "string": return `_nmsVoString(${raw}, ${JSON.stringify(path)})`;
|
|
713
|
+
case "enum": return `_nmsVoEnum(${raw}, ${JSON.stringify(node.expression.values)}, ${JSON.stringify(path)})`;
|
|
714
|
+
case "integer": return `_nmsResultInteger(${raw}, ${JSON.stringify(path)})`;
|
|
715
|
+
case "number": return `_nmsVoNumber(${raw}, ${JSON.stringify(path)}, false)`;
|
|
716
|
+
case "boolean": return `_nmsVoBoolean(${raw}, ${JSON.stringify(path)})`;
|
|
717
|
+
case "null": return `null`;
|
|
718
|
+
case "literal": return JSON.stringify(node.expression.value);
|
|
719
|
+
case "nullable": return tsNullable(raw, emitRef(node.expression.value, "nullable.value", path), path);
|
|
720
|
+
case "record": {
|
|
721
|
+
const members = node.expression.fields.map(structuralField).map((field) => {
|
|
722
|
+
const sid = composedWireIdentity(paths, field.entity);
|
|
723
|
+
const selected = `${raw}.${protoBindingMember(sid)}`;
|
|
724
|
+
const fieldPath = `${path}.${field.name}`;
|
|
725
|
+
if (field.required) {
|
|
726
|
+
const decoded = emitRef(
|
|
727
|
+
field.value,
|
|
728
|
+
`_nmsResultRequired(${selected}, ${JSON.stringify(fieldPath)})`,
|
|
729
|
+
fieldPath,
|
|
730
|
+
);
|
|
731
|
+
return `${JSON.stringify(field.name)}: ${decoded}`;
|
|
732
|
+
}
|
|
733
|
+
const captured = fresh("field");
|
|
734
|
+
const decoded = emitRef(
|
|
735
|
+
field.value,
|
|
736
|
+
captured,
|
|
737
|
+
fieldPath,
|
|
738
|
+
);
|
|
739
|
+
return `...(((${captured}) => ${captured} === undefined ? {} : { ${JSON.stringify(field.name)}: ${decoded} })(${selected}))`;
|
|
740
|
+
});
|
|
741
|
+
return `({ ${members.join(", ")} })`;
|
|
742
|
+
}
|
|
743
|
+
case "list": {
|
|
744
|
+
const item = fresh("item");
|
|
745
|
+
return `${raw}.items.map((${item}) => ${emitRef(node.expression.element, item, `${path}[]`)})`;
|
|
746
|
+
}
|
|
747
|
+
case "map": {
|
|
748
|
+
const entry = fresh("entry");
|
|
749
|
+
// Protobuf message presence makes an entry value optional in the
|
|
750
|
+
// generated binding even though Nomos map law requires every key to
|
|
751
|
+
// carry a value. The kernel-authored result guarantees presence; keep
|
|
752
|
+
// that invariant explicit at this exact generated boundary rather
|
|
753
|
+
// than allowing `T | undefined` to infect every nested decoder.
|
|
754
|
+
return `Object.fromEntries(${raw}.entries.map((${entry}) => [${entry}.key, ${emitRef(node.expression.value, `${entry}.value!`, `${path}.*`)}]))`;
|
|
755
|
+
}
|
|
756
|
+
case "sum": {
|
|
757
|
+
const selected = fresh("sum");
|
|
758
|
+
const cases = node.expression.variants.map((ref) => {
|
|
759
|
+
const variant = nodes.get(ref.id);
|
|
760
|
+
if (variant?.kind !== "structural" || variant.structuralKind !== "value-variant") {
|
|
761
|
+
throw new Error(`result Protobuf codegen: '${path}' has a non-variant arm`);
|
|
762
|
+
}
|
|
763
|
+
const value = nodes.get(variant.value.id);
|
|
764
|
+
if (value?.kind !== "structural" || value.structuralKind !== "value-type") {
|
|
765
|
+
throw new Error(`result Protobuf codegen: '${path}' variant has no value`);
|
|
766
|
+
}
|
|
767
|
+
const field = protoBindingMember(composedWireIdentity(paths, variant.entity));
|
|
768
|
+
return `case ${JSON.stringify(field)}: return ${emitStructural(value, `${selected}.choice.value!`, path)};`;
|
|
769
|
+
});
|
|
770
|
+
return `(( ${selected} ) => { switch (${selected}.choice.case) { ${cases.join(" ")} default: throw new TypeError(${JSON.stringify(path)} + " selects no nominal union arm"); } })(${raw})`;
|
|
771
|
+
}
|
|
772
|
+
case "unknown": throw new Error(`result Protobuf codegen: '${path}' is unstructured`);
|
|
773
|
+
}
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
const readFields = new Map<string, LawReadNode>();
|
|
777
|
+
for (const node of graph.nodes) {
|
|
778
|
+
if (node.kind === "read" && node.of.id === aggregateNode.entity.id) {
|
|
779
|
+
readFields.set(node.entity.label, node);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
const members = emitAggregateDecoder ? aggregate.fields.map(({ name, field, projectionSchema, required }) => {
|
|
783
|
+
const lawField = aggregateNode.fields
|
|
784
|
+
.map((ref) => nodes.get(ref.id))
|
|
785
|
+
.find((node) => node?.kind === "field" && node.entity.label === name);
|
|
786
|
+
const read = readFields.get(name);
|
|
787
|
+
const sid = lawField?.kind === "field"
|
|
788
|
+
? composedWireIdentity(paths, lawField.entity)
|
|
789
|
+
: read === undefined
|
|
790
|
+
? undefined
|
|
791
|
+
: composedWireIdentity(paths, read.entity);
|
|
792
|
+
if (sid === undefined) throw new Error(`result Protobuf codegen: '${aggregate.typeName}.${name}' has no law identity`);
|
|
793
|
+
const raw = `row.${protoBindingMember(sid)}`;
|
|
794
|
+
const valueRef = lawField?.kind === "field"
|
|
795
|
+
? lawField.value
|
|
796
|
+
: (() => {
|
|
797
|
+
const readContract = read === undefined ? undefined : nodes.get(read.contract.id);
|
|
798
|
+
if (readContract?.kind !== "read-contract" || readContract.returns.kind !== "scalar") {
|
|
799
|
+
throw new Error(`result Protobuf codegen: '${aggregate.typeName}.${name}' has no scalar contract`);
|
|
800
|
+
}
|
|
801
|
+
return readContract.returns.value;
|
|
802
|
+
})();
|
|
803
|
+
const fieldPath = `${aggregate.typeName}.${name}`;
|
|
804
|
+
const selected = required
|
|
805
|
+
? `_nmsResultRequired(${raw}, ${JSON.stringify(fieldPath)})`
|
|
806
|
+
: `${raw}!`;
|
|
807
|
+
const surfaced = lawField?.kind === "field" && lawField.mergeDrivers[0]?.kind === "Surfaced";
|
|
808
|
+
const surfacedSelection = surfaced ? fresh("selection") : undefined;
|
|
809
|
+
const selectedValue = surfaced ? `${surfacedSelection}.value!` : selected;
|
|
810
|
+
const structural = lawField?.kind === "field" && lawField.nullable
|
|
811
|
+
? tsNullable(selected, emitRef(valueRef, "nullable.value", fieldPath), fieldPath)
|
|
812
|
+
: emitRef(valueRef, selectedValue, fieldPath);
|
|
813
|
+
const foreignWorkspace = field?.foreignRef === undefined
|
|
814
|
+
? undefined
|
|
815
|
+
: (() => {
|
|
816
|
+
const workspaceField = aggregateNode.fields
|
|
817
|
+
.map((ref) => nodes.get(ref.id))
|
|
818
|
+
.find((node) =>
|
|
819
|
+
node?.kind === "field" &&
|
|
820
|
+
node.entity.label === field.foreignRef!.workspaceField
|
|
821
|
+
);
|
|
822
|
+
if (workspaceField?.kind !== "field") {
|
|
823
|
+
throw new Error(
|
|
824
|
+
`result Protobuf codegen: foreign ref '${aggregate.typeName}.${name}' has no declared workspace field '${field.foreignRef.workspaceField}'`,
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
const member = protoBindingMember(composedWireIdentity(paths, workspaceField.entity));
|
|
828
|
+
const selected = `row.${member}`;
|
|
829
|
+
return `(() => { const value = ${selected}; if (value === undefined) throw new TypeError(${JSON.stringify(`${aggregate.typeName}.${field.foreignRef.workspaceField} is absent`)}); return value; })()`;
|
|
830
|
+
})();
|
|
831
|
+
const decodedInner = field !== undefined
|
|
832
|
+
? authoredFieldValue(field, structural, "holon.workspace", "holon", foreignWorkspace)
|
|
833
|
+
: projectionSchema !== undefined
|
|
834
|
+
? structural
|
|
835
|
+
: (() => { throw new Error(`result Protobuf codegen: '${aggregate.typeName}.${name}' has no public schema`); })();
|
|
836
|
+
const decoded = surfaced
|
|
837
|
+
? (() => {
|
|
838
|
+
const observation = fresh("observation");
|
|
839
|
+
const selection = surfacedSelection!;
|
|
840
|
+
const observationValue = emitRef(
|
|
841
|
+
valueRef,
|
|
842
|
+
`_nmsResultRequired(${observation}.value, ${JSON.stringify(`${fieldPath}.pending.value`)})`,
|
|
843
|
+
`${fieldPath}.pending.value`,
|
|
844
|
+
);
|
|
845
|
+
const typedObservationValue = field === undefined
|
|
846
|
+
? observationValue
|
|
847
|
+
: authoredFieldValue(field, observationValue, "holon.workspace", "holon", foreignWorkspace);
|
|
848
|
+
return `(() => { ` +
|
|
849
|
+
`const ${selection} = ${selected}.selected; ` +
|
|
850
|
+
`switch (${selection}.case) { ` +
|
|
851
|
+
`case "resolved": return ${decodedInner}; ` +
|
|
852
|
+
`case "pending": return { __surfaced: { status: "pending", pending: ${selection}.value.observations.map((${observation}) => ({ ` +
|
|
853
|
+
`value: ${typedObservationValue}, occurredAt: { ` +
|
|
854
|
+
`physical: Number(_nmsResultRequired(${observation}.physical, ${JSON.stringify(`${fieldPath}.pending.occurredAt.physical`)})), ` +
|
|
855
|
+
`logical: _nmsResultRequired(${observation}.logical, ${JSON.stringify(`${fieldPath}.pending.occurredAt.logical`)}), ` +
|
|
856
|
+
`replica: _nmsResultRequired(${observation}.replica, ${JSON.stringify(`${fieldPath}.pending.occurredAt.replica`)}) }, ` +
|
|
857
|
+
`...(${observation}.author === undefined ? {} : { author: ${observation}.author }) })) } }; ` +
|
|
858
|
+
`default: throw new TypeError(${JSON.stringify(fieldPath)} + " selects no surfaced result"); } })()`;
|
|
859
|
+
})()
|
|
860
|
+
: decodedInner;
|
|
861
|
+
return required
|
|
862
|
+
? `${JSON.stringify(name)}: ${decoded}`
|
|
863
|
+
: `...(${raw} === undefined ? {} : { ${JSON.stringify(name)}: ${decoded} })`;
|
|
864
|
+
}) : [];
|
|
865
|
+
const resultMessage = protoMessageName(
|
|
866
|
+
"QueryResult",
|
|
867
|
+
operationMessageIdentity(graph, query.entity.sid),
|
|
868
|
+
);
|
|
869
|
+
const rowIdSid = `${aggregateNode.entity.sid}:result:id`;
|
|
870
|
+
const rowsSid = `${query.entity.sid}:result:rows`;
|
|
871
|
+
const cursorSid = `${query.entity.sid}:result:cursor`;
|
|
872
|
+
const doneSid = `${query.entity.sid}:result:done`;
|
|
873
|
+
if (emitAggregateDecoder) {
|
|
874
|
+
const attributed = aggregateNode.fields.map(ref => nodes.get(ref.id)).filter(
|
|
875
|
+
(node): node is Extract<LawGraph["nodes"][number], { kind: "field" }> =>
|
|
876
|
+
node?.kind === "field" && node.mergeDrivers[0]?.kind === "Attributed",
|
|
877
|
+
);
|
|
878
|
+
if (attributed.length > 0) {
|
|
879
|
+
const raw = `row.${protoBindingMember(provenanceRowIdentity(aggregateNode.entity.sid))}`;
|
|
880
|
+
const entries = attributed.map(field => {
|
|
881
|
+
const entry = `${raw}.${protoBindingMember(provenanceFieldIdentity(composedWireIdentity(paths, field.entity)))}`;
|
|
882
|
+
const author = `${entry}.${protoBindingMember(provenanceAuthorIdentity)}`;
|
|
883
|
+
const contested = `${entry}.${protoBindingMember(provenanceContestedIdentity)}`;
|
|
884
|
+
const path = `${aggregate.typeName}.${field.entity.label} provenance`;
|
|
885
|
+
return `...(${entry} === undefined ? {} : { ${JSON.stringify(field.entity.label)}: { ` +
|
|
886
|
+
`author: ${tsNullable(`_nmsResultRequired(${author}, ${JSON.stringify(`${path}.author`)})`, "nullable.value", `${path}.author`)}, ` +
|
|
887
|
+
`wasContested: _nmsResultRequired(${contested}, ${JSON.stringify(`${path}.wasContested`)}) } })`;
|
|
888
|
+
});
|
|
889
|
+
members.push(`...(${raw} === undefined ? {} : { __prov: { ${entries.join(", ")} } })`);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
const rowMessage = protoMessageName(
|
|
893
|
+
"Read",
|
|
894
|
+
operationMessageIdentity(graph, aggregateNode.entity.sid),
|
|
895
|
+
);
|
|
896
|
+
const rowFunction = `_nmsDecodeRow_${symbol(graph.domain.entity.label)}_${symbol(aggregate.typeName)}`;
|
|
897
|
+
const rowsFunction = `_nmsDecodeQuery_${symbol(graph.domain.entity.label)}_${symbol(query.entity.label)}Rows`;
|
|
898
|
+
const pageFunction = `_nmsDecodeQuery_${symbol(graph.domain.entity.label)}_${symbol(query.entity.label)}Page`;
|
|
899
|
+
const decodeRows = `_nmsDecodeRows_${symbol(graph.domain.entity.label)}_${symbol(query.entity.label)}`;
|
|
900
|
+
const typeUrl = `type.nomos.dev/nomos.operation.v1.QueryResult_${query.entity.sid}`;
|
|
901
|
+
return {
|
|
902
|
+
rowsFunction,
|
|
903
|
+
pageFunction,
|
|
904
|
+
typeUrl,
|
|
905
|
+
source: [
|
|
906
|
+
...(emitAggregateDecoder ? [
|
|
907
|
+
`const ${rowFunction} = (row: _nmsop.${rowMessage}, holon: NomosHolon): Row<${aggregate.typeName}> => {`,
|
|
908
|
+
` const id = row.${protoBindingMember(rowIdSid)}; if (id === undefined) throw new TypeError("Query row has no stable identity");`,
|
|
909
|
+
` return { data: { ${members.join(", ")} } satisfies ${aggregate.typeName}, ref: _nmsRef<${aggregate.typeName}>(holon.workspace, ${JSON.stringify(aggregate.typeName)}, id), type: ${JSON.stringify(aggregate.typeName)} };`,
|
|
910
|
+
`};`,
|
|
911
|
+
``,
|
|
912
|
+
] : []),
|
|
913
|
+
`const ${decodeRows} = (result: NmsGeneratedResult, holon: NomosHolon): Row<${aggregate.typeName}>[] => {`,
|
|
914
|
+
` if (result.protobufType !== ${JSON.stringify(typeUrl)}) throw new TypeError("Query result type does not match generated realm contract");`,
|
|
915
|
+
` const message = fromBinary(_nmsop.${resultMessage}Schema, result.protobufPayload);`,
|
|
916
|
+
...(query.readKind === "ordered" ? [
|
|
917
|
+
` if (message.${protoBindingMember(rowsSid)}.length > ${query.limit}) throw new TypeError("Ordered result exceeds its declared limit");`,
|
|
918
|
+
` if (message.${protoBindingMember(cursorSid)} !== undefined || message.${protoBindingMember(doneSid)} !== undefined) throw new TypeError("Ordered result cannot carry page metadata");`,
|
|
919
|
+
] : []),
|
|
920
|
+
` return message.${protoBindingMember(rowsSid)}.map((row) => ${rowFunction}(row, holon));`,
|
|
921
|
+
`};`,
|
|
922
|
+
`const ${rowsFunction} = (result: NmsGeneratedResult, holon: NomosHolon): Row<${aggregate.typeName}>[] => ${decodeRows}(result, holon);`,
|
|
923
|
+
`const ${pageFunction} = (result: NmsGeneratedResult, holon: NomosHolon): { rows: Row<${aggregate.typeName}>[]; cursor: string | null; done: boolean } => {`,
|
|
924
|
+
` if (result.protobufType !== ${JSON.stringify(typeUrl)}) throw new TypeError("Query result type does not match generated realm contract");`,
|
|
925
|
+
` const message = fromBinary(_nmsop.${resultMessage}Schema, result.protobufPayload);`,
|
|
926
|
+
` return { rows: ${decodeRows}(result, holon), cursor: message.${protoBindingMember(cursorSid)} ?? null, done: message.${protoBindingMember(doneSid)} ?? false };`,
|
|
927
|
+
`};`,
|
|
928
|
+
``,
|
|
929
|
+
],
|
|
930
|
+
};
|
|
931
|
+
}
|