domainforge 0.13.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/.cargo/config.toml +6 -0
- package/.claude/settings.local.json +18 -0
- package/.coderabbit.yml +43 -0
- package/.codex/skills/release-management/SKILL.md +151 -0
- package/.codex/skills/release-management/agents/openai.yaml +4 -0
- package/.github/actions/decrypt-secrets/action.yml +121 -0
- package/.github/agents/Coder.agent.md +97 -0
- package/.github/agents/DeepResearch.agent.md +61 -0
- package/.github/chatmodes/tdd.vibepro.chatmode.md +1183 -0
- package/.github/copilot-instructions.md +13 -0
- package/.github/dependabot.yml +68 -0
- package/.github/workflows/README.md +165 -0
- package/.github/workflows/ci.yml +335 -0
- package/.github/workflows/dependabot-automerge.yml +114 -0
- package/.github/workflows/dependency-review.yml +27 -0
- package/.github/workflows/deploy.yml +87 -0
- package/.github/workflows/prepare-release.yml +168 -0
- package/.github/workflows/release-crates.yml +42 -0
- package/.github/workflows/release-npm.yml +137 -0
- package/.github/workflows/release-please.yml +29 -0
- package/.github/workflows/release-pypi.yml +96 -0
- package/.gitkeep +1 -0
- package/.release-please-manifest.json +5 -0
- package/.sea-registry.toml +10 -0
- package/.serena/project.yml +133 -0
- package/.sops.yaml +10 -0
- package/AGENTS.md +216 -0
- package/CHANGELOG.md +400 -0
- package/CLAUDE.md +62 -0
- package/CONTRIBUTING.md +323 -0
- package/Cargo.lock +3612 -0
- package/Cargo.toml +12 -0
- package/LICENSE +201 -0
- package/README.md +660 -0
- package/README_PYTHON.md +256 -0
- package/README_TYPESCRIPT.md +305 -0
- package/README_WASM.md +329 -0
- package/RELEASE_NOTES.md +41 -0
- package/bun.lock +378 -0
- package/bunfig.toml +11 -0
- package/check_output.txt +83 -0
- package/clippy_output.txt +80 -0
- package/commitlint.config.cjs +8 -0
- package/deny.toml +42 -0
- package/devbox.json +14 -0
- package/devbox.lock +76 -0
- package/docs/RELEASE_PROCESS.md +360 -0
- package/docs/diagnostics.md +161 -0
- package/docs/doc_guidelines.md +53 -0
- package/docs/explanations/README.md +21 -0
- package/docs/explanations/architecture-overview.md +109 -0
- package/docs/explanations/cross-language-binding-strategy.md +68 -0
- package/docs/explanations/graph-store-design.md +47 -0
- package/docs/explanations/performance-benchmarks.md +63 -0
- package/docs/explanations/policy-evaluation-logic.md +106 -0
- package/docs/explanations/semantic-modeling-concepts.md +109 -0
- package/docs/explanations/three-valued-logic.md +66 -0
- package/docs/explanations/versioning-strategy.md +45 -0
- package/docs/governance.md +168 -0
- package/docs/how-tos/README.md +46 -0
- package/docs/how-tos/ci-cd-validation.md +93 -0
- package/docs/how-tos/create-custom-units.md +125 -0
- package/docs/how-tos/define-policies.md +119 -0
- package/docs/how-tos/export-to-calm.md +110 -0
- package/docs/how-tos/export-to-protobuf.md +312 -0
- package/docs/how-tos/extend-grammar.md +133 -0
- package/docs/how-tos/generate-rdf-turtle.md +106 -0
- package/docs/how-tos/import-from-calm.md +114 -0
- package/docs/how-tos/import-from-sbvr.md +249 -0
- package/docs/how-tos/install-cli.md +126 -0
- package/docs/how-tos/parse-sea-files.md +132 -0
- package/docs/how-tos/policy-evaluation-modes.md +30 -0
- package/docs/how-tos/run-cross-language-tests.md +115 -0
- package/docs/how-tos/troubleshoot-napi-builds.md +55 -0
- package/docs/how-tos/use-modules-imports.md +285 -0
- package/docs/index.md +13 -0
- package/docs/plans/canonical-normalizer.md +121 -0
- package/docs/plans/cd_improvement.md +112 -0
- package/docs/plans/cli-ast.md +29 -0
- package/docs/plans/expression-bindings-and-normalizer-integration.md +174 -0
- package/docs/plans/protobuf_advanced_features_plan.md +597 -0
- package/docs/plans/protobuf_plan.yml +525 -0
- package/docs/plans/refactor_dsl_architecture.md +131 -0
- package/docs/plans/release-plan.md +163 -0
- package/docs/plans/sea_fmt_implementation_plan.md +516 -0
- package/docs/playbooks/README.md +18 -0
- package/docs/playbooks/adding-new-primitive.md +68 -0
- package/docs/playbooks/debugging-parser-failures.md +42 -0
- package/docs/playbooks/local-release-preparation.md +139 -0
- package/docs/playbooks/migrating-schema-versions.md +43 -0
- package/docs/playbooks/onboarding-contributors.md +64 -0
- package/docs/playbooks/releasing-beta.md +86 -0
- package/docs/playbooks/secret-management.md +64 -0
- package/docs/reference/README.md +199 -0
- package/docs/reference/ast-json-api.md +427 -0
- package/docs/reference/calm-mapping.md +519 -0
- package/docs/reference/cli-commands.md +588 -0
- package/docs/reference/configuration.md +202 -0
- package/docs/reference/error-codes.md +664 -0
- package/docs/reference/generated-artifacts-policy.md +53 -0
- package/docs/reference/grammar-spec.md +255 -0
- package/docs/reference/primitives-api.md +317 -0
- package/docs/reference/protobuf-api.md +426 -0
- package/docs/reference/python-api.md +485 -0
- package/docs/reference/registry.md +50 -0
- package/docs/reference/sea-dsl-ai-cheatsheet.yaml +913 -0
- package/docs/reference/security-model.md +74 -0
- package/docs/reference/typescript-api.md +508 -0
- package/docs/reference/wasm-api.md +420 -0
- package/docs/semantic-pack-review.md +144 -0
- package/docs/semantic-pack-signing.md +234 -0
- package/docs/semantic-packs.md +284 -0
- package/docs/specs/ADR-001-sea-dsl-semantic-source-of-truth.md +33 -0
- package/docs/specs/ADR-002-projection-first-class-construct.md +50 -0
- package/docs/specs/ADR-003-protobuf-projection-target.md +51 -0
- package/docs/specs/ADR-004-projection-compatibility-semantics.md +57 -0
- package/docs/specs/ADR-005-multi-language-support-strategy.md +112 -0
- package/docs/specs/ADR-006-error-handling-strategy.md +115 -0
- package/docs/specs/ADR-007-policy-evaluation-engine.md +95 -0
- package/docs/specs/ADR-008-knowledge-graph-integration.md +90 -0
- package/docs/specs/ADR-009-module-resolution-strategy.md +115 -0
- package/docs/specs/ADR-010-unit-system.md +106 -0
- package/docs/specs/PRD-001-sea-projection-framework.md +155 -0
- package/docs/specs/PRD-002-sea-cli-tooling.md +169 -0
- package/docs/specs/PRD-003-dsl-core-capabilities.md +275 -0
- package/docs/specs/README.md +62 -0
- package/docs/specs/SDS-001-protobuf-projection-engine.md +451 -0
- package/docs/specs/SDS-002-sea-core-architecture.md +268 -0
- package/docs/specs/SDS-003-parser-semantic-graph.md +377 -0
- package/docs/specs/SDS-004-policy-engine-design.md +362 -0
- package/docs/specs/SDS-005-knowledge-graph-module.md +364 -0
- package/docs/specs/SDS-006-calm-integration.md +367 -0
- package/docs/specs/SDS-007-sbvr-import.md +347 -0
- package/docs/templates/template_explanation.md +14 -0
- package/docs/templates/template_howto.md +21 -0
- package/docs/templates/template_playbook.md +21 -0
- package/docs/templates/template_reference.md +17 -0
- package/docs/templates/template_tutorial.md +24 -0
- package/docs/tutorials/README.md +12 -0
- package/docs/tutorials/first-sea-model.md +85 -0
- package/docs/tutorials/getting-started.md +98 -0
- package/docs/tutorials/python-binding-quickstart.md +107 -0
- package/docs/tutorials/typescript-binding-quickstart.md +91 -0
- package/docs/tutorials/wasm-in-browser.md +75 -0
- package/domainforge-core/CHANGELOG.md +138 -0
- package/domainforge-core/Cargo.toml +101 -0
- package/domainforge-core/MIGRATING.md +32 -0
- package/domainforge-core/README.md +197 -0
- package/domainforge-core/benchmark_results.txt +51 -0
- package/domainforge-core/build.rs +6 -0
- package/domainforge-core/deny.toml +31 -0
- package/domainforge-core/docs/specs/projections/sbvr_kg_mapping.md +43 -0
- package/domainforge-core/examples/basic.sea +7 -0
- package/domainforge-core/examples/cli/import_export_workflow.sh +38 -0
- package/domainforge-core/examples/cli/validate_example.sh +30 -0
- package/domainforge-core/examples/evolution_semantics.sea +31 -0
- package/domainforge-core/examples/parser_demo.rs +203 -0
- package/domainforge-core/grammar/sea.pest +408 -0
- package/domainforge-core/schemas/calm-v1.schema.json +170 -0
- package/domainforge-core/schemas/shacl/sea_shapes.ttl +19 -0
- package/domainforge-core/src/authority/compiler.rs +309 -0
- package/domainforge-core/src/authority/environment.rs +203 -0
- package/domainforge-core/src/authority/error.rs +164 -0
- package/domainforge-core/src/authority/fact_resolver.rs +224 -0
- package/domainforge-core/src/authority/mod.rs +25 -0
- package/domainforge-core/src/authority/pack.rs +133 -0
- package/domainforge-core/src/authority/policy.rs +224 -0
- package/domainforge-core/src/authority/resolver.rs +446 -0
- package/domainforge-core/src/authority/trace.rs +217 -0
- package/domainforge-core/src/authority/transform.rs +168 -0
- package/domainforge-core/src/authority/types.rs +617 -0
- package/domainforge-core/src/bin/domainforge.rs +25 -0
- package/domainforge-core/src/calm/export.rs +538 -0
- package/domainforge-core/src/calm/import.rs +1220 -0
- package/domainforge-core/src/calm/mod.rs +9 -0
- package/domainforge-core/src/calm/models.rs +108 -0
- package/domainforge-core/src/calm/sbvr_import.rs +9 -0
- package/domainforge-core/src/cli/authority.rs +149 -0
- package/domainforge-core/src/cli/format.rs +85 -0
- package/domainforge-core/src/cli/import.rs +133 -0
- package/domainforge-core/src/cli/mod.rs +64 -0
- package/domainforge-core/src/cli/normalize.rs +180 -0
- package/domainforge-core/src/cli/pack.rs +904 -0
- package/domainforge-core/src/cli/parse.rs +112 -0
- package/domainforge-core/src/cli/project.rs +294 -0
- package/domainforge-core/src/cli/registry.rs +41 -0
- package/domainforge-core/src/cli/test.rs +12 -0
- package/domainforge-core/src/cli/validate.rs +195 -0
- package/domainforge-core/src/cli/validate_kg.rs +80 -0
- package/domainforge-core/src/concept_id.rs +89 -0
- package/domainforge-core/src/error/diagnostics.rs +426 -0
- package/domainforge-core/src/error/fuzzy.rs +253 -0
- package/domainforge-core/src/error/mod.rs +13 -0
- package/domainforge-core/src/formatter/comments.rs +223 -0
- package/domainforge-core/src/formatter/config.rs +114 -0
- package/domainforge-core/src/formatter/mod.rs +22 -0
- package/domainforge-core/src/formatter/printer.rs +906 -0
- package/domainforge-core/src/graph/mod.rs +858 -0
- package/domainforge-core/src/graph/to_ast.rs +66 -0
- package/domainforge-core/src/kg.rs +1476 -0
- package/domainforge-core/src/kg_import.rs +251 -0
- package/domainforge-core/src/lib.rs +203 -0
- package/domainforge-core/src/module/mod.rs +1 -0
- package/domainforge-core/src/module/resolver.rs +260 -0
- package/domainforge-core/src/parser/ast.rs +2919 -0
- package/domainforge-core/src/parser/ast_convert.rs +494 -0
- package/domainforge-core/src/parser/ast_schema.rs +491 -0
- package/domainforge-core/src/parser/error.rs +291 -0
- package/domainforge-core/src/parser/lint.rs +39 -0
- package/domainforge-core/src/parser/mod.rs +193 -0
- package/domainforge-core/src/parser/printer.rs +702 -0
- package/domainforge-core/src/parser/profiles.rs +71 -0
- package/domainforge-core/src/parser/string_utils.rs +138 -0
- package/domainforge-core/src/patterns.rs +68 -0
- package/domainforge-core/src/policy/core.rs +1148 -0
- package/domainforge-core/src/policy/expression.rs +399 -0
- package/domainforge-core/src/policy/mod.rs +18 -0
- package/domainforge-core/src/policy/normalize.rs +1028 -0
- package/domainforge-core/src/policy/quantifier.rs +940 -0
- package/domainforge-core/src/policy/three_valued.rs +140 -0
- package/domainforge-core/src/policy/three_valued_microbench.rs +104 -0
- package/domainforge-core/src/policy/type_inference.rs +67 -0
- package/domainforge-core/src/policy/violation.rs +36 -0
- package/domainforge-core/src/primitives/concept_change.rs +61 -0
- package/domainforge-core/src/primitives/entity.rs +224 -0
- package/domainforge-core/src/primitives/flow.rs +111 -0
- package/domainforge-core/src/primitives/instance.rs +93 -0
- package/domainforge-core/src/primitives/mapping_contract.rs +50 -0
- package/domainforge-core/src/primitives/metric.rs +79 -0
- package/domainforge-core/src/primitives/mod.rs +25 -0
- package/domainforge-core/src/primitives/projection_contract.rs +50 -0
- package/domainforge-core/src/primitives/quantity.rs +56 -0
- package/domainforge-core/src/primitives/relation.rs +68 -0
- package/domainforge-core/src/primitives/resource.rs +237 -0
- package/domainforge-core/src/primitives/resource_instance.rs +88 -0
- package/domainforge-core/src/primitives/role.rs +49 -0
- package/domainforge-core/src/projection/buf.rs +404 -0
- package/domainforge-core/src/projection/contracts.rs +22 -0
- package/domainforge-core/src/projection/engine.rs +19 -0
- package/domainforge-core/src/projection/mod.rs +16 -0
- package/domainforge-core/src/projection/protobuf.rs +3331 -0
- package/domainforge-core/src/projection/registry.rs +43 -0
- package/domainforge-core/src/python/authority.rs +253 -0
- package/domainforge-core/src/python/error.rs +227 -0
- package/domainforge-core/src/python/formatter.rs +86 -0
- package/domainforge-core/src/python/graph.rs +366 -0
- package/domainforge-core/src/python/mod.rs +9 -0
- package/domainforge-core/src/python/policy.rs +651 -0
- package/domainforge-core/src/python/primitives.rs +796 -0
- package/domainforge-core/src/python/registry.rs +98 -0
- package/domainforge-core/src/python/semantic_pack.rs +619 -0
- package/domainforge-core/src/python/units.rs +96 -0
- package/domainforge-core/src/registry/mod.rs +432 -0
- package/domainforge-core/src/registry/tests.rs +210 -0
- package/domainforge-core/src/sbvr.rs +744 -0
- package/domainforge-core/src/semantic_pack/builder.rs +470 -0
- package/domainforge-core/src/semantic_pack/canonical_json.rs +184 -0
- package/domainforge-core/src/semantic_pack/diagnostics.rs +214 -0
- package/domainforge-core/src/semantic_pack/diff.rs +216 -0
- package/domainforge-core/src/semantic_pack/mod.rs +31 -0
- package/domainforge-core/src/semantic_pack/pack_set.rs +240 -0
- package/domainforge-core/src/semantic_pack/resolver.rs +437 -0
- package/domainforge-core/src/semantic_pack/review.rs +125 -0
- package/domainforge-core/src/semantic_pack/schema.rs +342 -0
- package/domainforge-core/src/semantic_pack/signing.rs +105 -0
- package/domainforge-core/src/semantic_pack/validator.rs +368 -0
- package/domainforge-core/src/semantic_version.rs +140 -0
- package/domainforge-core/src/test_utils.rs +12 -0
- package/domainforge-core/src/typescript/authority.rs +184 -0
- package/domainforge-core/src/typescript/error.rs +146 -0
- package/domainforge-core/src/typescript/formatter.rs +76 -0
- package/domainforge-core/src/typescript/graph.rs +391 -0
- package/domainforge-core/src/typescript/mod.rs +9 -0
- package/domainforge-core/src/typescript/policy.rs +564 -0
- package/domainforge-core/src/typescript/primitives.rs +784 -0
- package/domainforge-core/src/typescript/registry.rs +88 -0
- package/domainforge-core/src/typescript/semantic_pack.rs +470 -0
- package/domainforge-core/src/typescript/units.rs +76 -0
- package/domainforge-core/src/units/mod.rs +462 -0
- package/domainforge-core/src/uuid_module.rs +42 -0
- package/domainforge-core/src/validation_error.rs +818 -0
- package/domainforge-core/src/validation_result.rs +30 -0
- package/domainforge-core/src/wasm/authority.rs +192 -0
- package/domainforge-core/src/wasm/error.rs +145 -0
- package/domainforge-core/src/wasm/formatter.rs +69 -0
- package/domainforge-core/src/wasm/graph.rs +471 -0
- package/domainforge-core/src/wasm/mod.rs +16 -0
- package/domainforge-core/src/wasm/policy.rs +607 -0
- package/domainforge-core/src/wasm/primitives.rs +295 -0
- package/domainforge-core/src/wasm/semantic_pack.rs +471 -0
- package/domainforge-core/src/wasm/units.rs +62 -0
- package/domainforge-core/std/aws.sea +6 -0
- package/domainforge-core/std/core.sea +6 -0
- package/domainforge-core/std/http.sea +27 -0
- package/domainforge-core/tests/aggregation_enhanced_tests.rs +162 -0
- package/domainforge-core/tests/aggregation_eval_tests.rs +248 -0
- package/domainforge-core/tests/aggregation_integration_tests.rs +379 -0
- package/domainforge-core/tests/aggregation_parser_tests.rs +92 -0
- package/domainforge-core/tests/aggregation_tests.rs +102 -0
- package/domainforge-core/tests/authority_conformance_tests.rs +1173 -0
- package/domainforge-core/tests/calm_round_trip_tests.rs +283 -0
- package/domainforge-core/tests/calm_schema_validation_tests.rs +137 -0
- package/domainforge-core/tests/cast_operator_tests.rs +85 -0
- package/domainforge-core/tests/cli_binary_check.rs +37 -0
- package/domainforge-core/tests/cli_import_tests.rs +291 -0
- package/domainforge-core/tests/cli_path_traversal_tests.rs +124 -0
- package/domainforge-core/tests/cli_tests.rs +63 -0
- package/domainforge-core/tests/diagnostics_tests.rs +203 -0
- package/domainforge-core/tests/dimension_unit_tests.rs +80 -0
- package/domainforge-core/tests/entity_tests.rs +69 -0
- package/domainforge-core/tests/evolution_semantics_tests.rs +157 -0
- package/domainforge-core/tests/flow_tests.rs +78 -0
- package/domainforge-core/tests/flow_unit_validation_tests.rs +31 -0
- package/domainforge-core/tests/graph_integration_tests.rs +218 -0
- package/domainforge-core/tests/graph_tests.rs +626 -0
- package/domainforge-core/tests/import_parsing_tests.rs +23 -0
- package/domainforge-core/tests/instance_integration_tests.rs +98 -0
- package/domainforge-core/tests/instance_parsing_tests.rs +58 -0
- package/domainforge-core/tests/instance_tests.rs +61 -0
- package/domainforge-core/tests/kg_uri_encoding_tests.rs +53 -0
- package/domainforge-core/tests/lint_tests.rs +19 -0
- package/domainforge-core/tests/metric_tests.rs +143 -0
- package/domainforge-core/tests/module_resolution_tests.rs +100 -0
- package/domainforge-core/tests/namespace_registry_tests.rs +247 -0
- package/domainforge-core/tests/null_handling_tests.rs +26 -0
- package/domainforge-core/tests/parser_ast_v3.rs +53 -0
- package/domainforge-core/tests/parser_dimension_registry_tests.rs +20 -0
- package/domainforge-core/tests/parser_integration_tests.rs +294 -0
- package/domainforge-core/tests/parser_metadata_tests.rs +97 -0
- package/domainforge-core/tests/parser_resource_domain_only_graph_test.rs +21 -0
- package/domainforge-core/tests/parser_resource_limits_tests.rs +122 -0
- package/domainforge-core/tests/parser_tests.rs +512 -0
- package/domainforge-core/tests/pattern_semantics_tests.rs +87 -0
- package/domainforge-core/tests/phase_14_determinism_tests.rs +166 -0
- package/domainforge-core/tests/phase_15_validation_error_tests.rs +136 -0
- package/domainforge-core/tests/phase_16_unicode_tests.rs +248 -0
- package/domainforge-core/tests/phase_17_export_tests.rs +285 -0
- package/domainforge-core/tests/phase_17_round_trip_tests.rs +264 -0
- package/domainforge-core/tests/policy_tests.rs +635 -0
- package/domainforge-core/tests/primitives_integration_tests.rs +151 -0
- package/domainforge-core/tests/print_rdf_xml.rs +14 -0
- package/domainforge-core/tests/printer_tests.rs +204 -0
- package/domainforge-core/tests/profile_tests.rs +35 -0
- package/domainforge-core/tests/projection_contracts_tests.rs +154 -0
- package/domainforge-core/tests/protobuf_projection_tests.rs +199 -0
- package/domainforge-core/tests/quantity_tests.rs +41 -0
- package/domainforge-core/tests/rdf_xml_typed_literal_tests.rs +105 -0
- package/domainforge-core/tests/registry_schema_tests.rs +33 -0
- package/domainforge-core/tests/resource_tests.rs +50 -0
- package/domainforge-core/tests/resource_unit_tests.rs +24 -0
- package/domainforge-core/tests/roles_relations_tests.rs +61 -0
- package/domainforge-core/tests/round_trip_tests.rs +34 -0
- package/domainforge-core/tests/runtime_toggle_tests.rs +70 -0
- package/domainforge-core/tests/sbvr_fact_schema_tests.rs +60 -0
- package/domainforge-core/tests/sbvr_flow_facts_tests.rs +55 -0
- package/domainforge-core/tests/sbvr_parsing_tests.rs +53 -0
- package/domainforge-core/tests/semantic_pack_alias_resolution.rs +197 -0
- package/domainforge-core/tests/semantic_pack_build.rs +302 -0
- package/domainforge-core/tests/semantic_pack_consumer_smoke.rs +150 -0
- package/domainforge-core/tests/semantic_pack_pack_set.rs +160 -0
- package/domainforge-core/tests/semantic_pack_signing.rs +157 -0
- package/domainforge-core/tests/semantic_pack_three_valued.rs +250 -0
- package/domainforge-core/tests/semantic_pack_validate.rs +196 -0
- package/domainforge-core/tests/std_lib_tests.rs +37 -0
- package/domainforge-core/tests/temporal_evaluation_tests.rs +159 -0
- package/domainforge-core/tests/temporal_semantics_tests.rs +214 -0
- package/domainforge-core/tests/three_valued_quantifiers_tests.rs +164 -0
- package/domainforge-core/tests/turtle_entity_export_tests.rs +38 -0
- package/domainforge-core/tests/turtle_escaping_tests.rs +53 -0
- package/domainforge-core/tests/turtle_resource_export_tests.rs +34 -0
- package/domainforge-core/tests/type_inference_tests.rs +40 -0
- package/domainforge-core/tests/unicode_validation_tests.rs +169 -0
- package/domainforge-core/tests/unit_tests.rs +81 -0
- package/domainforge-core/tests/validate_tests.rs +38 -0
- package/domainforge-core/tests/validation_unit_mismatch_tests.rs +83 -0
- package/domainforge-core/tests/wasm_tests.rs +229 -0
- package/domainforge-python/CHANGELOG-python.md +12 -0
- package/domainforge-python/MIGRATING.md +24 -0
- package/domainforge-python/README.md +256 -0
- package/domainforge-python/domainforge/__init__.py +95 -0
- package/domainforge-python/domainforge/domainforge.pyi +519 -0
- package/domainforge-python/pyproject.toml +36 -0
- package/domainforge-typescript/CHANGELOG-typescript.md +12 -0
- package/domainforge-typescript/LICENSE +201 -0
- package/domainforge-typescript/MIGRATING.md +24 -0
- package/domainforge-typescript/README.md +305 -0
- package/domainforge-typescript/index.d.ts +452 -0
- package/domainforge-typescript/index.js +361 -0
- package/domainforge-typescript/package.json +60 -0
- package/example.js +61 -0
- package/examples/browser.html +366 -0
- package/examples/namespaces/finance/cashflow.sea +5 -0
- package/examples/namespaces/logistics/core.sea +7 -0
- package/examples/observability_metrics.sea +38 -0
- package/fixtures/semantic_packs/acme_procurement/domain/entities.sea +39 -0
- package/fixtures/semantic_packs/acme_procurement/domain/metrics.sea +11 -0
- package/fixtures/semantic_packs/acme_procurement/domain/relations.sea +7 -0
- package/fixtures/semantic_packs/acme_procurement/domain/resources.sea +9 -0
- package/fixtures/semantic_packs/acme_procurement/review/acme.procurement.semantic-review.jsonl +7 -0
- package/fixtures/semantic_packs/acme_procurement/tests/ambiguous_vendor_alias.sea +8 -0
- package/fixtures/semantic_packs/acme_procurement/tests/deprecated_vendor_alias.sea +8 -0
- package/fixtures/semantic_packs/acme_procurement/tests/invalid_relation.sea +3 -0
- package/fixtures/semantic_packs/acme_procurement/tests/proposed_concept.sea +8 -0
- package/fixtures/semantic_packs/acme_procurement/tests/rejected_concept.sea +8 -0
- package/fixtures/semantic_packs/acme_procurement/tests/unit_mismatch.sea +7 -0
- package/fixtures/semantic_packs/acme_procurement/tests/unknown_vendor_policy.sea +8 -0
- package/fixtures/semantic_packs/acme_procurement/tests/valid_purchase_policy.sea +8 -0
- package/index.d.ts +2 -0
- package/index.js +8 -0
- package/justfile +200 -0
- package/lefthook.yml +13 -0
- package/lib/validate_native_exports.d.ts +4 -0
- package/lib/validate_native_exports.js +12 -0
- package/package.json +22 -0
- package/pytest.ini +5 -0
- package/python/tests/test_registry.py +75 -0
- package/python/tests/test_units.py +18 -0
- package/release-please-config.json +49 -0
- package/requirements-dev.txt +3 -0
- package/requirements.txt +3 -0
- package/rust-toolchain.toml +3 -0
- package/schemas/ast-v1.schema.json +72 -0
- package/schemas/ast-v2.schema.json +1200 -0
- package/schemas/ast-v3.schema.json +1200 -0
- package/schemas/sea-registry.schema.json +45 -0
- package/scripts/build-python.sh +37 -0
- package/scripts/build-release.sh +279 -0
- package/scripts/build-typescript.sh +13 -0
- package/scripts/build-wasm.sh +113 -0
- package/scripts/bump-version.sh +245 -0
- package/scripts/check_unused_test_imports.py +85 -0
- package/scripts/ci_tasks.py +379 -0
- package/scripts/clear_debug_test.sh +10 -0
- package/scripts/create-github-release.sh +262 -0
- package/scripts/create-tag.sh +203 -0
- package/scripts/find_and_link_test_binary.sh +70 -0
- package/scripts/generate-changelog.sh +271 -0
- package/scripts/generate-release-notes.sh +205 -0
- package/scripts/lint_release_security.py +96 -0
- package/scripts/lint_release_workflows.py +82 -0
- package/scripts/lint_workflow_gates.py +113 -0
- package/scripts/optimized-wasm-build.sh +61 -0
- package/scripts/patch_napi_types.py +62 -0
- package/scripts/pre-release-check.sh +289 -0
- package/scripts/prepare_rust_debug.sh +52 -0
- package/scripts/release.sh +373 -0
- package/scripts/resolve_rust_binary.py +230 -0
- package/scripts/run_commitlint.sh +29 -0
- package/scripts/test-all.sh +77 -0
- package/scripts/update_launch_program.py +93 -0
- package/secrets/README.md +27 -0
- package/secrets/secrets.yaml +21 -0
- package/test_integration.py +67 -0
- package/tests/test_authority.py +328 -0
- package/tests/test_ci_tasks.py +143 -0
- package/tests/test_expression.py +256 -0
- package/tests/test_golden_payment_flow.py +42 -0
- package/tests/test_graph.py +127 -0
- package/tests/test_instance.py +136 -0
- package/tests/test_parser.py +82 -0
- package/tests/test_primitives.py +68 -0
- package/tests/test_role_relation_parity.py +56 -0
- package/tests/test_runtime_toggle.py +156 -0
- package/tests/test_semantic_pack.py +639 -0
- package/tests/test_three_valued_eval.py +159 -0
- package/tsconfig.json +30 -0
- package/typescript-tests/advanced.test.ts +165 -0
- package/typescript-tests/authority.test.ts +216 -0
- package/typescript-tests/expression.test.ts +228 -0
- package/typescript-tests/golden-payment-flow.test.ts +51 -0
- package/typescript-tests/graph.test.ts +142 -0
- package/typescript-tests/native-binding.test.ts +20 -0
- package/typescript-tests/primitives.test.ts +88 -0
- package/typescript-tests/registry.test.ts +122 -0
- package/typescript-tests/role_relation.test.ts +63 -0
- package/typescript-tests/runtime_toggle.test.ts +141 -0
- package/typescript-tests/semantic-pack.test.ts +556 -0
- package/typescript-tests/three_valued_eval.test.ts +135 -0
- package/typescript-tests/units.test.ts +36 -0
- package/vitest.config.ts +13 -0
- package/wasm_demo.html +225 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"""Tests for Expression and NormalizedExpression bindings."""
|
|
2
|
+
|
|
3
|
+
from domainforge import (
|
|
4
|
+
Expression,
|
|
5
|
+
NormalizedExpression,
|
|
6
|
+
BinaryOp,
|
|
7
|
+
UnaryOp,
|
|
8
|
+
Quantifier,
|
|
9
|
+
AggregateFunction,
|
|
10
|
+
WindowSpec,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestExpressionFactoryMethods:
|
|
15
|
+
"""Tests for Expression factory methods."""
|
|
16
|
+
|
|
17
|
+
def test_literal_bool(self):
|
|
18
|
+
"""Test creating boolean literal expressions."""
|
|
19
|
+
expr = Expression.literal(True)
|
|
20
|
+
assert str(expr) == "true"
|
|
21
|
+
|
|
22
|
+
expr_false = Expression.literal(False)
|
|
23
|
+
assert str(expr_false) == "false"
|
|
24
|
+
|
|
25
|
+
def test_literal_number(self):
|
|
26
|
+
"""Test creating number literal expressions."""
|
|
27
|
+
expr = Expression.literal(42)
|
|
28
|
+
assert str(expr) == "42"
|
|
29
|
+
|
|
30
|
+
expr_float = Expression.literal(3.14)
|
|
31
|
+
assert "3.14" in str(expr_float)
|
|
32
|
+
|
|
33
|
+
def test_literal_string(self):
|
|
34
|
+
"""Test creating string literal expressions."""
|
|
35
|
+
expr = Expression.literal("hello")
|
|
36
|
+
assert "hello" in str(expr)
|
|
37
|
+
|
|
38
|
+
def test_variable(self):
|
|
39
|
+
"""Test creating variable expressions."""
|
|
40
|
+
expr = Expression.variable("x")
|
|
41
|
+
assert str(expr) == "x"
|
|
42
|
+
|
|
43
|
+
def test_quantity(self):
|
|
44
|
+
"""Test creating quantity literal expressions."""
|
|
45
|
+
expr = Expression.quantity("100", "USD")
|
|
46
|
+
assert "100" in str(expr)
|
|
47
|
+
assert "USD" in str(expr)
|
|
48
|
+
|
|
49
|
+
def test_time(self):
|
|
50
|
+
"""Test creating time literal expressions."""
|
|
51
|
+
expr = Expression.time("2025-01-01T00:00:00Z")
|
|
52
|
+
assert "2025-01-01" in str(expr)
|
|
53
|
+
|
|
54
|
+
def test_interval(self):
|
|
55
|
+
"""Test creating interval literal expressions."""
|
|
56
|
+
expr = Expression.interval("2025-01-01T09:00:00Z", "2025-01-01T17:00:00Z")
|
|
57
|
+
assert "09:00:00" in str(expr)
|
|
58
|
+
assert "17:00:00" in str(expr)
|
|
59
|
+
|
|
60
|
+
def test_binary(self):
|
|
61
|
+
"""Test creating binary expressions."""
|
|
62
|
+
left = Expression.variable("a")
|
|
63
|
+
right = Expression.variable("b")
|
|
64
|
+
expr = Expression.binary(BinaryOp.And, left, right)
|
|
65
|
+
result = str(expr)
|
|
66
|
+
assert "AND" in result
|
|
67
|
+
assert "a" in result
|
|
68
|
+
assert "b" in result
|
|
69
|
+
|
|
70
|
+
def test_unary_not(self):
|
|
71
|
+
"""Test creating unary NOT expressions."""
|
|
72
|
+
operand = Expression.variable("x")
|
|
73
|
+
expr = Expression.unary(UnaryOp.Not, operand)
|
|
74
|
+
result = str(expr)
|
|
75
|
+
assert "NOT" in result
|
|
76
|
+
assert "x" in result
|
|
77
|
+
|
|
78
|
+
def test_unary_negate(self):
|
|
79
|
+
"""Test creating unary negation expressions."""
|
|
80
|
+
operand = Expression.variable("x")
|
|
81
|
+
expr = Expression.unary(UnaryOp.Negate, operand)
|
|
82
|
+
assert "x" in str(expr)
|
|
83
|
+
|
|
84
|
+
def test_member_access(self):
|
|
85
|
+
"""Test creating member access expressions."""
|
|
86
|
+
expr = Expression.member_access("user", "name")
|
|
87
|
+
result = str(expr)
|
|
88
|
+
assert "user" in result
|
|
89
|
+
assert "name" in result
|
|
90
|
+
|
|
91
|
+
def test_cast(self):
|
|
92
|
+
"""Test creating cast expressions."""
|
|
93
|
+
operand = Expression.variable("x")
|
|
94
|
+
expr = Expression.cast(operand, "Money")
|
|
95
|
+
result = str(expr)
|
|
96
|
+
assert "x" in result
|
|
97
|
+
assert "Money" in result
|
|
98
|
+
|
|
99
|
+
def test_quantifier_forall(self):
|
|
100
|
+
"""Test creating ForAll quantifier expressions."""
|
|
101
|
+
collection = Expression.variable("items")
|
|
102
|
+
condition = Expression.variable("valid")
|
|
103
|
+
expr = Expression.quantifier(Quantifier.ForAll, "x", collection, condition)
|
|
104
|
+
result = str(expr)
|
|
105
|
+
assert "ForAll" in result or "forall" in result.lower()
|
|
106
|
+
|
|
107
|
+
def test_aggregation(self):
|
|
108
|
+
"""Test creating aggregation expressions."""
|
|
109
|
+
collection = Expression.variable("items")
|
|
110
|
+
expr = Expression.aggregation(AggregateFunction.Count, collection)
|
|
111
|
+
result = str(expr)
|
|
112
|
+
assert "COUNT" in result or "count" in result.lower()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class TestNormalization:
|
|
116
|
+
"""Tests for expression normalization."""
|
|
117
|
+
|
|
118
|
+
def test_normalize_returns_normalized_expression(self):
|
|
119
|
+
"""Test that normalize() returns a NormalizedExpression."""
|
|
120
|
+
expr = Expression.variable("x")
|
|
121
|
+
normalized = expr.normalize()
|
|
122
|
+
assert isinstance(normalized, NormalizedExpression)
|
|
123
|
+
|
|
124
|
+
def test_identity_elimination_and_true(self):
|
|
125
|
+
"""Test that `true AND x` normalizes to `x`."""
|
|
126
|
+
true_expr = Expression.literal(True)
|
|
127
|
+
x_expr = Expression.variable("x")
|
|
128
|
+
expr = Expression.binary(BinaryOp.And, true_expr, x_expr)
|
|
129
|
+
normalized = expr.normalize()
|
|
130
|
+
assert str(normalized) == "x"
|
|
131
|
+
|
|
132
|
+
def test_identity_elimination_or_false(self):
|
|
133
|
+
"""Test that `false OR x` normalizes to `x`."""
|
|
134
|
+
false_expr = Expression.literal(False)
|
|
135
|
+
x_expr = Expression.variable("x")
|
|
136
|
+
expr = Expression.binary(BinaryOp.Or, false_expr, x_expr)
|
|
137
|
+
normalized = expr.normalize()
|
|
138
|
+
assert str(normalized) == "x"
|
|
139
|
+
|
|
140
|
+
def test_commutative_sorting(self):
|
|
141
|
+
"""Test that commutative operators sort operands."""
|
|
142
|
+
b = Expression.variable("b")
|
|
143
|
+
a = Expression.variable("a")
|
|
144
|
+
expr = Expression.binary(BinaryOp.And, b, a)
|
|
145
|
+
normalized = expr.normalize()
|
|
146
|
+
# After normalization, should be (a AND b)
|
|
147
|
+
result = str(normalized)
|
|
148
|
+
assert result == "(a AND b)"
|
|
149
|
+
|
|
150
|
+
def test_idempotence(self):
|
|
151
|
+
"""Test that `a AND a` normalizes to `a`."""
|
|
152
|
+
a = Expression.variable("a")
|
|
153
|
+
expr = Expression.binary(BinaryOp.And, a, a)
|
|
154
|
+
normalized = expr.normalize()
|
|
155
|
+
assert str(normalized) == "a"
|
|
156
|
+
|
|
157
|
+
def test_double_negation_elimination(self):
|
|
158
|
+
"""Test that `NOT NOT x` normalizes to `x`."""
|
|
159
|
+
x = Expression.variable("x")
|
|
160
|
+
not_x = Expression.unary(UnaryOp.Not, x)
|
|
161
|
+
not_not_x = Expression.unary(UnaryOp.Not, not_x)
|
|
162
|
+
normalized = not_not_x.normalize()
|
|
163
|
+
assert str(normalized) == "x"
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class TestEquivalence:
|
|
167
|
+
"""Tests for expression equivalence checking."""
|
|
168
|
+
|
|
169
|
+
def test_equivalent_expressions(self):
|
|
170
|
+
"""Test that equivalent expressions are recognized as equivalent."""
|
|
171
|
+
a1 = Expression.variable("a")
|
|
172
|
+
b1 = Expression.variable("b")
|
|
173
|
+
expr1 = Expression.binary(BinaryOp.And, a1, b1)
|
|
174
|
+
|
|
175
|
+
a2 = Expression.variable("a")
|
|
176
|
+
b2 = Expression.variable("b")
|
|
177
|
+
expr2 = Expression.binary(BinaryOp.And, b2, a2)
|
|
178
|
+
|
|
179
|
+
assert expr1.is_equivalent(expr2)
|
|
180
|
+
|
|
181
|
+
def test_non_equivalent_expressions(self):
|
|
182
|
+
"""Test that non-equivalent expressions are recognized as non-equivalent."""
|
|
183
|
+
a = Expression.variable("a")
|
|
184
|
+
b = Expression.variable("b")
|
|
185
|
+
c = Expression.variable("c")
|
|
186
|
+
|
|
187
|
+
expr1 = Expression.binary(BinaryOp.And, a, b)
|
|
188
|
+
expr2 = Expression.binary(BinaryOp.And, a, c)
|
|
189
|
+
|
|
190
|
+
assert not expr1.is_equivalent(expr2)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class TestStableHash:
|
|
194
|
+
"""Tests for stable hash functionality."""
|
|
195
|
+
|
|
196
|
+
def test_stable_hash_is_deterministic(self):
|
|
197
|
+
"""Test that stable hash is deterministic."""
|
|
198
|
+
expr = Expression.variable("x")
|
|
199
|
+
hash1 = expr.normalize().stable_hash()
|
|
200
|
+
hash2 = expr.normalize().stable_hash()
|
|
201
|
+
assert hash1 == hash2
|
|
202
|
+
|
|
203
|
+
def test_equivalent_expressions_have_same_hash(self):
|
|
204
|
+
"""Test that equivalent expressions have the same hash."""
|
|
205
|
+
a1 = Expression.variable("a")
|
|
206
|
+
b1 = Expression.variable("b")
|
|
207
|
+
expr1 = Expression.binary(BinaryOp.And, a1, b1)
|
|
208
|
+
|
|
209
|
+
a2 = Expression.variable("a")
|
|
210
|
+
b2 = Expression.variable("b")
|
|
211
|
+
expr2 = Expression.binary(BinaryOp.And, b2, a2)
|
|
212
|
+
|
|
213
|
+
assert expr1.normalize().stable_hash() == expr2.normalize().stable_hash()
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class TestNormalizedExpressionMethods:
|
|
217
|
+
"""Tests for NormalizedExpression methods."""
|
|
218
|
+
|
|
219
|
+
def test_inner_expression(self):
|
|
220
|
+
"""Test that inner_expression returns an Expression."""
|
|
221
|
+
expr = Expression.variable("x")
|
|
222
|
+
normalized = expr.normalize()
|
|
223
|
+
inner = normalized.inner_expression()
|
|
224
|
+
assert isinstance(inner, Expression)
|
|
225
|
+
assert str(inner) == "x"
|
|
226
|
+
|
|
227
|
+
def test_str_representation(self):
|
|
228
|
+
"""Test string representation of NormalizedExpression."""
|
|
229
|
+
expr = Expression.variable("x")
|
|
230
|
+
normalized = expr.normalize()
|
|
231
|
+
assert str(normalized) == "x"
|
|
232
|
+
|
|
233
|
+
def test_repr_includes_hash(self):
|
|
234
|
+
"""Test that repr includes hash information."""
|
|
235
|
+
expr = Expression.variable("x")
|
|
236
|
+
normalized = expr.normalize()
|
|
237
|
+
repr_str = repr(normalized)
|
|
238
|
+
assert "NormalizedExpression" in repr_str
|
|
239
|
+
assert "hash" in repr_str.lower()
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class TestWindowSpec:
|
|
243
|
+
"""Tests for WindowSpec."""
|
|
244
|
+
|
|
245
|
+
def test_window_spec_creation(self):
|
|
246
|
+
"""Test WindowSpec creation."""
|
|
247
|
+
ws = WindowSpec(30, "days")
|
|
248
|
+
assert ws.duration == 30
|
|
249
|
+
assert ws.unit == "days"
|
|
250
|
+
|
|
251
|
+
def test_window_spec_repr(self):
|
|
252
|
+
"""Test WindowSpec repr."""
|
|
253
|
+
ws = WindowSpec(24, "hours")
|
|
254
|
+
repr_str = repr(ws)
|
|
255
|
+
assert "24" in repr_str
|
|
256
|
+
assert "hours" in repr_str
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from domainforge import Graph
|
|
2
|
+
|
|
3
|
+
PAYMENT_DSL = """
|
|
4
|
+
Role "Payer"
|
|
5
|
+
Role "Payee"
|
|
6
|
+
|
|
7
|
+
Resource "Money" units
|
|
8
|
+
|
|
9
|
+
Entity "Alice"
|
|
10
|
+
Entity "Bob"
|
|
11
|
+
|
|
12
|
+
Flow "Money" from "Alice" to "Bob" quantity 10
|
|
13
|
+
|
|
14
|
+
Relation "Payment"
|
|
15
|
+
subject: "Payer"
|
|
16
|
+
predicate: "pays"
|
|
17
|
+
object: "Payee"
|
|
18
|
+
via: flow "Money"
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_payment_flow_parity_from_dsl():
|
|
23
|
+
graph = Graph.parse(PAYMENT_DSL)
|
|
24
|
+
|
|
25
|
+
assert graph.entity_count() == 2
|
|
26
|
+
assert graph.resource_count() == 1
|
|
27
|
+
assert graph.flow_count() == 1
|
|
28
|
+
|
|
29
|
+
flows = graph.all_flows()
|
|
30
|
+
assert len(flows) == 1
|
|
31
|
+
flow = flows[0]
|
|
32
|
+
# Validate flow quantity and resource name (resource API supported by Python binding)
|
|
33
|
+
assert flow.quantity == 10
|
|
34
|
+
alice_id = graph.find_entity_by_name("Alice")
|
|
35
|
+
bob_id = graph.find_entity_by_name("Bob")
|
|
36
|
+
assert alice_id is not None
|
|
37
|
+
assert bob_id is not None
|
|
38
|
+
assert flow.from_id == alice_id
|
|
39
|
+
assert flow.to_id == bob_id
|
|
40
|
+
res = graph.get_resource(flow.resource_id)
|
|
41
|
+
assert res is not None
|
|
42
|
+
assert res.name == "Money"
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import domainforge
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_graph_creation():
|
|
6
|
+
graph = domainforge.Graph()
|
|
7
|
+
assert graph.entity_count() == 0
|
|
8
|
+
assert graph.resource_count() == 0
|
|
9
|
+
assert graph.flow_count() == 0
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_graph_add_entity():
|
|
13
|
+
graph = domainforge.Graph()
|
|
14
|
+
entity = domainforge.Entity("Warehouse")
|
|
15
|
+
|
|
16
|
+
graph.add_entity(entity)
|
|
17
|
+
assert graph.entity_count() == 1
|
|
18
|
+
assert graph.has_entity(entity.id)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_graph_add_resource():
|
|
22
|
+
graph = domainforge.Graph()
|
|
23
|
+
resource = domainforge.Resource("Cameras", "units")
|
|
24
|
+
|
|
25
|
+
graph.add_resource(resource)
|
|
26
|
+
assert graph.resource_count() == 1
|
|
27
|
+
assert graph.has_resource(resource.id)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_graph_add_flow():
|
|
31
|
+
graph = domainforge.Graph()
|
|
32
|
+
warehouse = domainforge.Entity("Warehouse")
|
|
33
|
+
factory = domainforge.Entity("Factory")
|
|
34
|
+
cameras = domainforge.Resource("Cameras", "units")
|
|
35
|
+
|
|
36
|
+
graph.add_entity(warehouse)
|
|
37
|
+
graph.add_entity(factory)
|
|
38
|
+
graph.add_resource(cameras)
|
|
39
|
+
|
|
40
|
+
flow = domainforge.Flow(cameras.id, warehouse.id, factory.id, 100.0)
|
|
41
|
+
graph.add_flow(flow)
|
|
42
|
+
|
|
43
|
+
assert graph.flow_count() == 1
|
|
44
|
+
assert graph.has_flow(flow.id)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_graph_flow_validation():
|
|
48
|
+
graph = domainforge.Graph()
|
|
49
|
+
warehouse = domainforge.Entity("Warehouse")
|
|
50
|
+
factory = domainforge.Entity("Factory")
|
|
51
|
+
cameras = domainforge.Resource("Cameras", "units")
|
|
52
|
+
|
|
53
|
+
graph.add_entity(warehouse)
|
|
54
|
+
graph.add_resource(cameras)
|
|
55
|
+
|
|
56
|
+
flow = domainforge.Flow(cameras.id, warehouse.id, factory.id, 100.0)
|
|
57
|
+
|
|
58
|
+
with pytest.raises(ValueError, match="Target entity not found"):
|
|
59
|
+
graph.add_flow(flow)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_graph_get_entity():
|
|
63
|
+
graph = domainforge.Graph()
|
|
64
|
+
entity = domainforge.Entity("Warehouse")
|
|
65
|
+
graph.add_entity(entity)
|
|
66
|
+
|
|
67
|
+
retrieved = graph.get_entity(entity.id)
|
|
68
|
+
assert retrieved is not None
|
|
69
|
+
assert retrieved.id == entity.id
|
|
70
|
+
assert retrieved.name == entity.name
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_graph_find_entity_by_name():
|
|
74
|
+
graph = domainforge.Graph()
|
|
75
|
+
entity = domainforge.Entity("Warehouse")
|
|
76
|
+
graph.add_entity(entity)
|
|
77
|
+
|
|
78
|
+
found_id = graph.find_entity_by_name("Warehouse")
|
|
79
|
+
assert found_id == entity.id
|
|
80
|
+
|
|
81
|
+
not_found = graph.find_entity_by_name("Nonexistent")
|
|
82
|
+
assert not_found is None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_graph_flows_from():
|
|
86
|
+
graph = domainforge.Graph()
|
|
87
|
+
warehouse = domainforge.Entity("Warehouse")
|
|
88
|
+
factory1 = domainforge.Entity("Factory1")
|
|
89
|
+
factory2 = domainforge.Entity("Factory2")
|
|
90
|
+
cameras = domainforge.Resource("Cameras", "units")
|
|
91
|
+
|
|
92
|
+
graph.add_entity(warehouse)
|
|
93
|
+
graph.add_entity(factory1)
|
|
94
|
+
graph.add_entity(factory2)
|
|
95
|
+
graph.add_resource(cameras)
|
|
96
|
+
|
|
97
|
+
flow1 = domainforge.Flow(cameras.id, warehouse.id, factory1.id, 100.0)
|
|
98
|
+
flow2 = domainforge.Flow(cameras.id, warehouse.id, factory2.id, 50.0)
|
|
99
|
+
|
|
100
|
+
graph.add_flow(flow1)
|
|
101
|
+
graph.add_flow(flow2)
|
|
102
|
+
|
|
103
|
+
flows = graph.flows_from(warehouse.id)
|
|
104
|
+
assert len(flows) == 2
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_graph_all_methods():
|
|
108
|
+
graph = domainforge.Graph()
|
|
109
|
+
e1 = domainforge.Entity("E1")
|
|
110
|
+
e2 = domainforge.Entity("E2")
|
|
111
|
+
r1 = domainforge.Resource("R1", "units")
|
|
112
|
+
|
|
113
|
+
graph.add_entity(e1)
|
|
114
|
+
graph.add_entity(e2)
|
|
115
|
+
graph.add_resource(r1)
|
|
116
|
+
|
|
117
|
+
flow = domainforge.Flow(r1.id, e1.id, e2.id, 10.0)
|
|
118
|
+
graph.add_flow(flow)
|
|
119
|
+
|
|
120
|
+
all_entities = graph.all_entities()
|
|
121
|
+
assert len(all_entities) == 2
|
|
122
|
+
|
|
123
|
+
all_resources = graph.all_resources()
|
|
124
|
+
assert len(all_resources) == 1
|
|
125
|
+
|
|
126
|
+
all_flows = graph.all_flows()
|
|
127
|
+
assert len(all_flows) == 1
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Additional Python tests for SEA DSL bindings - ResourceInstance support
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
import domainforge
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_instance_creation():
|
|
10
|
+
"""Test creating a ResourceInstance"""
|
|
11
|
+
entity = domainforge.Entity("Warehouse")
|
|
12
|
+
resource = domainforge.Resource("Camera", "units")
|
|
13
|
+
|
|
14
|
+
instance = domainforge.ResourceInstance(resource.id, entity.id)
|
|
15
|
+
assert instance.resource_id == resource.id
|
|
16
|
+
assert instance.entity_id == entity.id
|
|
17
|
+
assert len(instance.id) == 36
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_instance_with_namespace():
|
|
21
|
+
"""Test creating a ResourceInstance with namespace"""
|
|
22
|
+
entity = domainforge.Entity("Warehouse", "logistics")
|
|
23
|
+
resource = domainforge.Resource("Camera", "units", "inventory")
|
|
24
|
+
|
|
25
|
+
instance = domainforge.ResourceInstance(resource.id, entity.id, "inventory")
|
|
26
|
+
assert instance.namespace == "inventory"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_instance_attributes():
|
|
30
|
+
"""Test ResourceInstance attributes"""
|
|
31
|
+
entity = domainforge.Entity("Warehouse")
|
|
32
|
+
resource = domainforge.Resource("Camera", "units")
|
|
33
|
+
|
|
34
|
+
instance = domainforge.ResourceInstance(resource.id, entity.id)
|
|
35
|
+
instance.set_attribute("serial_number", "CAM-12345")
|
|
36
|
+
assert instance.get_attribute("serial_number") == "CAM-12345"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_graph_add_instance():
|
|
40
|
+
"""Test adding a ResourceInstance to a Graph"""
|
|
41
|
+
graph = domainforge.Graph()
|
|
42
|
+
entity = domainforge.Entity("Warehouse")
|
|
43
|
+
resource = domainforge.Resource("Camera", "units")
|
|
44
|
+
|
|
45
|
+
graph.add_entity(entity)
|
|
46
|
+
graph.add_resource(resource)
|
|
47
|
+
|
|
48
|
+
instance = domainforge.ResourceInstance(resource.id, entity.id)
|
|
49
|
+
graph.add_instance(instance)
|
|
50
|
+
|
|
51
|
+
assert graph.instance_count() == 1
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_graph_instance_validation():
|
|
55
|
+
"""Test Graph validates ResourceInstance references"""
|
|
56
|
+
graph = domainforge.Graph()
|
|
57
|
+
entity = domainforge.Entity("Warehouse")
|
|
58
|
+
resource = domainforge.Resource("Camera", "units")
|
|
59
|
+
|
|
60
|
+
graph.add_entity(entity)
|
|
61
|
+
# Not adding resource
|
|
62
|
+
|
|
63
|
+
instance = domainforge.ResourceInstance(resource.id, entity.id)
|
|
64
|
+
|
|
65
|
+
with pytest.raises(ValueError, match="Resource not found"):
|
|
66
|
+
graph.add_instance(instance)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_round_trip_serialization():
|
|
70
|
+
"""Test that primitives can be serialized and remain valid"""
|
|
71
|
+
graph = domainforge.Graph()
|
|
72
|
+
|
|
73
|
+
# Create a complete model
|
|
74
|
+
warehouse = domainforge.Entity("Warehouse", "logistics")
|
|
75
|
+
warehouse.set_attribute("location", "NYC")
|
|
76
|
+
|
|
77
|
+
factory = domainforge.Entity("Factory", "manufacturing")
|
|
78
|
+
factory.set_attribute("capacity", 10000)
|
|
79
|
+
|
|
80
|
+
cameras = domainforge.Resource("Camera", "units", "inventory")
|
|
81
|
+
cameras.set_attribute("model", "X100")
|
|
82
|
+
|
|
83
|
+
graph.add_entity(warehouse)
|
|
84
|
+
graph.add_entity(factory)
|
|
85
|
+
graph.add_resource(cameras)
|
|
86
|
+
|
|
87
|
+
flow = domainforge.Flow(cameras.id, warehouse.id, factory.id, 500.0)
|
|
88
|
+
flow.set_attribute("priority", "high")
|
|
89
|
+
graph.add_flow(flow)
|
|
90
|
+
|
|
91
|
+
instance = domainforge.ResourceInstance(cameras.id, warehouse.id, "inventory")
|
|
92
|
+
instance.set_attribute("serial", "SN-001")
|
|
93
|
+
graph.add_instance(instance)
|
|
94
|
+
|
|
95
|
+
# Verify the graph state
|
|
96
|
+
assert graph.entity_count() == 2
|
|
97
|
+
assert graph.resource_count() == 1
|
|
98
|
+
assert graph.flow_count() == 1
|
|
99
|
+
assert graph.instance_count() == 1
|
|
100
|
+
|
|
101
|
+
# Verify we can retrieve and check attributes
|
|
102
|
+
retrieved_entity = graph.get_entity(warehouse.id)
|
|
103
|
+
assert retrieved_entity.get_attribute("location") == "NYC"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_error_handling_invalid_references():
|
|
107
|
+
"""Test that proper errors are raised for invalid references"""
|
|
108
|
+
graph = domainforge.Graph()
|
|
109
|
+
warehouse = domainforge.Entity("Warehouse")
|
|
110
|
+
graph.add_entity(warehouse)
|
|
111
|
+
|
|
112
|
+
# Try to create flow with non-existent IDs
|
|
113
|
+
fake_resource_id = "00000000-0000-0000-0000-000000000000"
|
|
114
|
+
fake_entity_id = "11111111-1111-1111-1111-111111111111"
|
|
115
|
+
|
|
116
|
+
flow = domainforge.Flow(fake_resource_id, warehouse.id, fake_entity_id, 100.0)
|
|
117
|
+
|
|
118
|
+
with pytest.raises(ValueError):
|
|
119
|
+
graph.add_flow(flow)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_namespace_isolation():
|
|
123
|
+
"""Test that namespaces properly isolate entities"""
|
|
124
|
+
graph = domainforge.Graph()
|
|
125
|
+
|
|
126
|
+
warehouse_logistics = domainforge.Entity("Warehouse", "logistics")
|
|
127
|
+
warehouse_storage = domainforge.Entity("Warehouse", "storage")
|
|
128
|
+
|
|
129
|
+
graph.add_entity(warehouse_logistics)
|
|
130
|
+
graph.add_entity(warehouse_storage)
|
|
131
|
+
|
|
132
|
+
assert graph.entity_count() == 2
|
|
133
|
+
|
|
134
|
+
# Both should exist independently
|
|
135
|
+
assert graph.has_entity(warehouse_logistics.id)
|
|
136
|
+
assert graph.has_entity(warehouse_storage.id)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import domainforge
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_parse_basic():
|
|
6
|
+
source = '''
|
|
7
|
+
Entity "Warehouse" in logistics
|
|
8
|
+
Entity "Factory" in logistics
|
|
9
|
+
Resource "Cameras" units
|
|
10
|
+
'''
|
|
11
|
+
|
|
12
|
+
graph = domainforge.Graph.parse(source)
|
|
13
|
+
assert graph.entity_count() == 2
|
|
14
|
+
assert graph.resource_count() == 1
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_parse_with_flow():
|
|
18
|
+
source = '''
|
|
19
|
+
Entity "Warehouse"
|
|
20
|
+
Entity "Factory"
|
|
21
|
+
Resource "Cameras" units
|
|
22
|
+
Flow "Cameras" from "Warehouse" to "Factory" quantity 100
|
|
23
|
+
'''
|
|
24
|
+
|
|
25
|
+
graph = domainforge.Graph.parse(source)
|
|
26
|
+
assert graph.entity_count() == 2
|
|
27
|
+
assert graph.resource_count() == 1
|
|
28
|
+
assert graph.flow_count() == 1
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_parse_complex():
|
|
32
|
+
source = '''
|
|
33
|
+
Entity "Supplier" in supply_chain
|
|
34
|
+
Entity "Warehouse" in supply_chain
|
|
35
|
+
Entity "Store" in retail
|
|
36
|
+
|
|
37
|
+
Resource "Widgets" units
|
|
38
|
+
Resource "Gadgets" units
|
|
39
|
+
|
|
40
|
+
Flow "Widgets" from "Supplier" to "Warehouse" quantity 500
|
|
41
|
+
Flow "Widgets" from "Warehouse" to "Store" quantity 300
|
|
42
|
+
Flow "Gadgets" from "Supplier" to "Warehouse" quantity 200
|
|
43
|
+
'''
|
|
44
|
+
|
|
45
|
+
graph = domainforge.Graph.parse(source)
|
|
46
|
+
assert graph.entity_count() == 3
|
|
47
|
+
assert graph.resource_count() == 2
|
|
48
|
+
assert graph.flow_count() == 3
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_parse_invalid_syntax():
|
|
52
|
+
source = '''
|
|
53
|
+
Entity "Warehouse"
|
|
54
|
+
Invalid syntax here
|
|
55
|
+
'''
|
|
56
|
+
|
|
57
|
+
with pytest.raises(ValueError, match="Parse error"):
|
|
58
|
+
domainforge.Graph.parse(source)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_parse_empty():
|
|
62
|
+
source = ""
|
|
63
|
+
graph = domainforge.Graph.parse(source)
|
|
64
|
+
assert graph.entity_count() == 0
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_parsed_graph_query():
|
|
68
|
+
source = '''
|
|
69
|
+
Entity "Warehouse"
|
|
70
|
+
Entity "Factory"
|
|
71
|
+
Resource "Steel" tons
|
|
72
|
+
Flow "Steel" from "Warehouse" to "Factory" quantity 50
|
|
73
|
+
'''
|
|
74
|
+
|
|
75
|
+
graph = domainforge.Graph.parse(source)
|
|
76
|
+
|
|
77
|
+
warehouse_id = graph.find_entity_by_name("Warehouse")
|
|
78
|
+
assert warehouse_id is not None
|
|
79
|
+
|
|
80
|
+
flows = graph.flows_from(warehouse_id)
|
|
81
|
+
assert len(flows) == 1
|
|
82
|
+
assert flows[0].quantity == 50.0
|