@proposit/proposit-core 0.8.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1032 -0
- package/dist/cli/commands/analysis.d.ts +3 -0
- package/dist/cli/commands/analysis.d.ts.map +1 -0
- package/dist/cli/commands/analysis.js +504 -0
- package/dist/cli/commands/analysis.js.map +1 -0
- package/dist/cli/commands/arguments.d.ts +3 -0
- package/dist/cli/commands/arguments.d.ts.map +1 -0
- package/dist/cli/commands/arguments.js +187 -0
- package/dist/cli/commands/arguments.js.map +1 -0
- package/dist/cli/commands/claims.d.ts +3 -0
- package/dist/cli/commands/claims.d.ts.map +1 -0
- package/dist/cli/commands/claims.js +120 -0
- package/dist/cli/commands/claims.js.map +1 -0
- package/dist/cli/commands/diff.d.ts +3 -0
- package/dist/cli/commands/diff.d.ts.map +1 -0
- package/dist/cli/commands/diff.js +61 -0
- package/dist/cli/commands/diff.js.map +1 -0
- package/dist/cli/commands/expressions.d.ts +3 -0
- package/dist/cli/commands/expressions.d.ts.map +1 -0
- package/dist/cli/commands/expressions.js +344 -0
- package/dist/cli/commands/expressions.js.map +1 -0
- package/dist/cli/commands/graph.d.ts +13 -0
- package/dist/cli/commands/graph.d.ts.map +1 -0
- package/dist/cli/commands/graph.js +382 -0
- package/dist/cli/commands/graph.js.map +1 -0
- package/dist/cli/commands/meta.d.ts +3 -0
- package/dist/cli/commands/meta.d.ts.map +1 -0
- package/dist/cli/commands/meta.js +14 -0
- package/dist/cli/commands/meta.js.map +1 -0
- package/dist/cli/commands/parse.d.ts +3 -0
- package/dist/cli/commands/parse.d.ts.map +1 -0
- package/dist/cli/commands/parse.js +171 -0
- package/dist/cli/commands/parse.js.map +1 -0
- package/dist/cli/commands/premises.d.ts +3 -0
- package/dist/cli/commands/premises.d.ts.map +1 -0
- package/dist/cli/commands/premises.js +261 -0
- package/dist/cli/commands/premises.js.map +1 -0
- package/dist/cli/commands/render.d.ts +3 -0
- package/dist/cli/commands/render.d.ts.map +1 -0
- package/dist/cli/commands/render.js +109 -0
- package/dist/cli/commands/render.js.map +1 -0
- package/dist/cli/commands/repair.d.ts +3 -0
- package/dist/cli/commands/repair.d.ts.map +1 -0
- package/dist/cli/commands/repair.js +53 -0
- package/dist/cli/commands/repair.js.map +1 -0
- package/dist/cli/commands/roles.d.ts +3 -0
- package/dist/cli/commands/roles.d.ts.map +1 -0
- package/dist/cli/commands/roles.js +64 -0
- package/dist/cli/commands/roles.js.map +1 -0
- package/dist/cli/commands/sources.d.ts +3 -0
- package/dist/cli/commands/sources.d.ts.map +1 -0
- package/dist/cli/commands/sources.js +103 -0
- package/dist/cli/commands/sources.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +3 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +27 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/commands/variables.d.ts +3 -0
- package/dist/cli/commands/variables.d.ts.map +1 -0
- package/dist/cli/commands/variables.js +206 -0
- package/dist/cli/commands/variables.js.map +1 -0
- package/dist/cli/commands/version-show.d.ts +3 -0
- package/dist/cli/commands/version-show.d.ts.map +1 -0
- package/dist/cli/commands/version-show.js +31 -0
- package/dist/cli/commands/version-show.js.map +1 -0
- package/dist/cli/config.d.ts +8 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +24 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/engine.d.ts +19 -0
- package/dist/cli/engine.d.ts.map +1 -0
- package/dist/cli/engine.js +173 -0
- package/dist/cli/engine.js.map +1 -0
- package/dist/cli/import.d.ts +22 -0
- package/dist/cli/import.d.ts.map +1 -0
- package/dist/cli/import.js +242 -0
- package/dist/cli/import.js.map +1 -0
- package/dist/cli/llm/index.d.ts +6 -0
- package/dist/cli/llm/index.d.ts.map +1 -0
- package/dist/cli/llm/index.js +26 -0
- package/dist/cli/llm/index.js.map +1 -0
- package/dist/cli/llm/openai.d.ts +4 -0
- package/dist/cli/llm/openai.d.ts.map +1 -0
- package/dist/cli/llm/openai.js +44 -0
- package/dist/cli/llm/openai.js.map +1 -0
- package/dist/cli/llm/types.d.ts +14 -0
- package/dist/cli/llm/types.d.ts.map +1 -0
- package/dist/cli/llm/types.js +2 -0
- package/dist/cli/llm/types.js.map +1 -0
- package/dist/cli/logging.d.ts +8 -0
- package/dist/cli/logging.d.ts.map +1 -0
- package/dist/cli/logging.js +23 -0
- package/dist/cli/logging.js.map +1 -0
- package/dist/cli/output/diff-renderer.d.ts +4 -0
- package/dist/cli/output/diff-renderer.d.ts.map +1 -0
- package/dist/cli/output/diff-renderer.js +89 -0
- package/dist/cli/output/diff-renderer.js.map +1 -0
- package/dist/cli/output.d.ts +6 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +41 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/router.d.ts +14 -0
- package/dist/cli/router.d.ts.map +1 -0
- package/dist/cli/router.js +59 -0
- package/dist/cli/router.js.map +1 -0
- package/dist/cli/schemata.d.ts +74 -0
- package/dist/cli/schemata.d.ts.map +1 -0
- package/dist/cli/schemata.js +89 -0
- package/dist/cli/schemata.js.map +1 -0
- package/dist/cli/storage/analysis.d.ts +9 -0
- package/dist/cli/storage/analysis.d.ts.map +1 -0
- package/dist/cli/storage/analysis.js +108 -0
- package/dist/cli/storage/analysis.js.map +1 -0
- package/dist/cli/storage/arguments.d.ts +12 -0
- package/dist/cli/storage/arguments.d.ts.map +1 -0
- package/dist/cli/storage/arguments.js +80 -0
- package/dist/cli/storage/arguments.js.map +1 -0
- package/dist/cli/storage/libraries.d.ts +14 -0
- package/dist/cli/storage/libraries.d.ts.map +1 -0
- package/dist/cli/storage/libraries.js +80 -0
- package/dist/cli/storage/libraries.js.map +1 -0
- package/dist/cli/storage/premises.d.ts +9 -0
- package/dist/cli/storage/premises.d.ts.map +1 -0
- package/dist/cli/storage/premises.js +67 -0
- package/dist/cli/storage/premises.js.map +1 -0
- package/dist/cli/storage/roles.d.ts +4 -0
- package/dist/cli/storage/roles.d.ts.map +1 -0
- package/dist/cli/storage/roles.js +26 -0
- package/dist/cli/storage/roles.js.map +1 -0
- package/dist/cli/storage/variables.d.ts +4 -0
- package/dist/cli/storage/variables.d.ts.map +1 -0
- package/dist/cli/storage/variables.js +36 -0
- package/dist/cli/storage/variables.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +65 -0
- package/dist/cli.js.map +1 -0
- package/dist/extensions/basics/argument-parser.d.ts +12 -0
- package/dist/extensions/basics/argument-parser.d.ts.map +1 -0
- package/dist/extensions/basics/argument-parser.js +27 -0
- package/dist/extensions/basics/argument-parser.js.map +1 -0
- package/dist/extensions/basics/index.d.ts +4 -0
- package/dist/extensions/basics/index.d.ts.map +1 -0
- package/dist/extensions/basics/index.js +3 -0
- package/dist/extensions/basics/index.js.map +1 -0
- package/dist/extensions/basics/schemata.d.ts +35 -0
- package/dist/extensions/basics/schemata.d.ts.map +1 -0
- package/dist/extensions/basics/schemata.js +55 -0
- package/dist/extensions/basics/schemata.js.map +1 -0
- package/dist/extensions/ieee/formatting.d.ts +18 -0
- package/dist/extensions/ieee/formatting.d.ts.map +1 -0
- package/dist/extensions/ieee/formatting.js +57 -0
- package/dist/extensions/ieee/formatting.js.map +1 -0
- package/dist/extensions/ieee/index.d.ts +6 -0
- package/dist/extensions/ieee/index.d.ts.map +1 -0
- package/dist/extensions/ieee/index.js +6 -0
- package/dist/extensions/ieee/index.js.map +1 -0
- package/dist/extensions/ieee/references.d.ts +1379 -0
- package/dist/extensions/ieee/references.d.ts.map +1 -0
- package/dist/extensions/ieee/references.js +929 -0
- package/dist/extensions/ieee/references.js.map +1 -0
- package/dist/extensions/ieee/relaxed.d.ts +1371 -0
- package/dist/extensions/ieee/relaxed.d.ts.map +1 -0
- package/dist/extensions/ieee/relaxed.js +160 -0
- package/dist/extensions/ieee/relaxed.js.map +1 -0
- package/dist/extensions/ieee/segment-builder.d.ts +9 -0
- package/dist/extensions/ieee/segment-builder.d.ts.map +1 -0
- package/dist/extensions/ieee/segment-builder.js +98 -0
- package/dist/extensions/ieee/segment-builder.js.map +1 -0
- package/dist/extensions/ieee/segment-templates.d.ts +58 -0
- package/dist/extensions/ieee/segment-templates.d.ts.map +1 -0
- package/dist/extensions/ieee/segment-templates.js +1618 -0
- package/dist/extensions/ieee/segment-templates.js.map +1 -0
- package/dist/extensions/ieee/source.d.ts +434 -0
- package/dist/extensions/ieee/source.d.ts.map +1 -0
- package/dist/extensions/ieee/source.js +12 -0
- package/dist/extensions/ieee/source.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/consts.d.ts +21 -0
- package/dist/lib/consts.d.ts.map +1 -0
- package/dist/lib/consts.js +117 -0
- package/dist/lib/consts.js.map +1 -0
- package/dist/lib/core/argument-engine.d.ts +181 -0
- package/dist/lib/core/argument-engine.d.ts.map +1 -0
- package/dist/lib/core/argument-engine.js +1294 -0
- package/dist/lib/core/argument-engine.js.map +1 -0
- package/dist/lib/core/argument-library.d.ts +84 -0
- package/dist/lib/core/argument-library.d.ts.map +1 -0
- package/dist/lib/core/argument-library.js +122 -0
- package/dist/lib/core/argument-library.js.map +1 -0
- package/dist/lib/core/argument-validation.d.ts +74 -0
- package/dist/lib/core/argument-validation.d.ts.map +1 -0
- package/dist/lib/core/argument-validation.js +315 -0
- package/dist/lib/core/argument-validation.js.map +1 -0
- package/dist/lib/core/change-collector.d.ts +24 -0
- package/dist/lib/core/change-collector.d.ts.map +1 -0
- package/dist/lib/core/change-collector.js +63 -0
- package/dist/lib/core/change-collector.js.map +1 -0
- package/dist/lib/core/checksum.d.ts +15 -0
- package/dist/lib/core/checksum.d.ts.map +1 -0
- package/dist/lib/core/checksum.js +43 -0
- package/dist/lib/core/checksum.js.map +1 -0
- package/dist/lib/core/claim-library.d.ts +23 -0
- package/dist/lib/core/claim-library.d.ts.map +1 -0
- package/dist/lib/core/claim-library.js +21 -0
- package/dist/lib/core/claim-library.js.map +1 -0
- package/dist/lib/core/claim-source-library.d.ts +32 -0
- package/dist/lib/core/claim-source-library.d.ts.map +1 -0
- package/dist/lib/core/claim-source-library.js +193 -0
- package/dist/lib/core/claim-source-library.js.map +1 -0
- package/dist/lib/core/diff.d.ts +20 -0
- package/dist/lib/core/diff.d.ts.map +1 -0
- package/dist/lib/core/diff.js +260 -0
- package/dist/lib/core/diff.js.map +1 -0
- package/dist/lib/core/evaluation/argument-evaluation.d.ts +53 -0
- package/dist/lib/core/evaluation/argument-evaluation.d.ts.map +1 -0
- package/dist/lib/core/evaluation/argument-evaluation.js +535 -0
- package/dist/lib/core/evaluation/argument-evaluation.js.map +1 -0
- package/dist/lib/core/evaluation/grading.d.ts +28 -0
- package/dist/lib/core/evaluation/grading.d.ts.map +1 -0
- package/dist/lib/core/evaluation/grading.js +44 -0
- package/dist/lib/core/evaluation/grading.js.map +1 -0
- package/dist/lib/core/evaluation/kleene.d.ts +12 -0
- package/dist/lib/core/evaluation/kleene.d.ts.map +1 -0
- package/dist/lib/core/evaluation/kleene.js +29 -0
- package/dist/lib/core/evaluation/kleene.js.map +1 -0
- package/dist/lib/core/evaluation/validation.d.ts +10 -0
- package/dist/lib/core/evaluation/validation.d.ts.map +1 -0
- package/dist/lib/core/evaluation/validation.js +28 -0
- package/dist/lib/core/evaluation/validation.js.map +1 -0
- package/dist/lib/core/expression-manager.d.ts +278 -0
- package/dist/lib/core/expression-manager.d.ts.map +1 -0
- package/dist/lib/core/expression-manager.js +1622 -0
- package/dist/lib/core/expression-manager.js.map +1 -0
- package/dist/lib/core/fork-library.d.ts +26 -0
- package/dist/lib/core/fork-library.d.ts.map +1 -0
- package/dist/lib/core/fork-library.js +71 -0
- package/dist/lib/core/fork-library.js.map +1 -0
- package/dist/lib/core/fork-namespace.d.ts +32 -0
- package/dist/lib/core/fork-namespace.d.ts.map +1 -0
- package/dist/lib/core/fork-namespace.js +99 -0
- package/dist/lib/core/fork-namespace.js.map +1 -0
- package/dist/lib/core/fork.d.ts +30 -0
- package/dist/lib/core/fork.d.ts.map +1 -0
- package/dist/lib/core/fork.js +125 -0
- package/dist/lib/core/fork.js.map +1 -0
- package/dist/lib/core/interfaces/argument-engine.interfaces.d.ts +366 -0
- package/dist/lib/core/interfaces/argument-engine.interfaces.d.ts.map +1 -0
- package/dist/lib/core/interfaces/argument-engine.interfaces.js +2 -0
- package/dist/lib/core/interfaces/argument-engine.interfaces.js.map +1 -0
- package/dist/lib/core/interfaces/index.d.ts +5 -0
- package/dist/lib/core/interfaces/index.d.ts.map +1 -0
- package/dist/lib/core/interfaces/index.js +2 -0
- package/dist/lib/core/interfaces/index.js.map +1 -0
- package/dist/lib/core/interfaces/library.interfaces.d.ts +347 -0
- package/dist/lib/core/interfaces/library.interfaces.d.ts.map +1 -0
- package/dist/lib/core/interfaces/library.interfaces.js +2 -0
- package/dist/lib/core/interfaces/library.interfaces.js.map +1 -0
- package/dist/lib/core/interfaces/premise-engine.interfaces.d.ts +401 -0
- package/dist/lib/core/interfaces/premise-engine.interfaces.d.ts.map +1 -0
- package/dist/lib/core/interfaces/premise-engine.interfaces.js +2 -0
- package/dist/lib/core/interfaces/premise-engine.interfaces.js.map +1 -0
- package/dist/lib/core/interfaces/shared.interfaces.d.ts +28 -0
- package/dist/lib/core/interfaces/shared.interfaces.d.ts.map +1 -0
- package/dist/lib/core/interfaces/shared.interfaces.js +2 -0
- package/dist/lib/core/interfaces/shared.interfaces.js.map +1 -0
- package/dist/lib/core/invariant-violation-error.d.ts +10 -0
- package/dist/lib/core/invariant-violation-error.d.ts.map +1 -0
- package/dist/lib/core/invariant-violation-error.js +16 -0
- package/dist/lib/core/invariant-violation-error.js.map +1 -0
- package/dist/lib/core/parser/formula-gen.js +923 -0
- package/dist/lib/core/parser/formula.d.ts +24 -0
- package/dist/lib/core/parser/formula.d.ts.map +1 -0
- package/dist/lib/core/parser/formula.js +8 -0
- package/dist/lib/core/parser/formula.js.map +1 -0
- package/dist/lib/core/premise-engine.d.ts +122 -0
- package/dist/lib/core/premise-engine.d.ts.map +1 -0
- package/dist/lib/core/premise-engine.js +1362 -0
- package/dist/lib/core/premise-engine.js.map +1 -0
- package/dist/lib/core/proposit-core.d.ts +111 -0
- package/dist/lib/core/proposit-core.d.ts.map +1 -0
- package/dist/lib/core/proposit-core.js +365 -0
- package/dist/lib/core/proposit-core.js.map +1 -0
- package/dist/lib/core/relationships.d.ts +15 -0
- package/dist/lib/core/relationships.d.ts.map +1 -0
- package/dist/lib/core/relationships.js +319 -0
- package/dist/lib/core/relationships.js.map +1 -0
- package/dist/lib/core/source-library.d.ts +23 -0
- package/dist/lib/core/source-library.d.ts.map +1 -0
- package/dist/lib/core/source-library.js +21 -0
- package/dist/lib/core/source-library.js.map +1 -0
- package/dist/lib/core/variable-manager.d.ts +68 -0
- package/dist/lib/core/variable-manager.d.ts.map +1 -0
- package/dist/lib/core/variable-manager.js +200 -0
- package/dist/lib/core/variable-manager.js.map +1 -0
- package/dist/lib/core/versioned-library.d.ts +52 -0
- package/dist/lib/core/versioned-library.d.ts.map +1 -0
- package/dist/lib/core/versioned-library.js +192 -0
- package/dist/lib/core/versioned-library.js.map +1 -0
- package/dist/lib/index.d.ts +54 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +39 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/parsing/argument-parser.d.ts +49 -0
- package/dist/lib/parsing/argument-parser.d.ts.map +1 -0
- package/dist/lib/parsing/argument-parser.js +403 -0
- package/dist/lib/parsing/argument-parser.js.map +1 -0
- package/dist/lib/parsing/clamp-max-lengths.d.ts +11 -0
- package/dist/lib/parsing/clamp-max-lengths.d.ts.map +1 -0
- package/dist/lib/parsing/clamp-max-lengths.js +56 -0
- package/dist/lib/parsing/clamp-max-lengths.js.map +1 -0
- package/dist/lib/parsing/index.d.ts +7 -0
- package/dist/lib/parsing/index.d.ts.map +1 -0
- package/dist/lib/parsing/index.js +4 -0
- package/dist/lib/parsing/index.js.map +1 -0
- package/dist/lib/parsing/prompt-builder.d.ts +11 -0
- package/dist/lib/parsing/prompt-builder.d.ts.map +1 -0
- package/dist/lib/parsing/prompt-builder.js +229 -0
- package/dist/lib/parsing/prompt-builder.js.map +1 -0
- package/dist/lib/parsing/schemata.d.ts +79 -0
- package/dist/lib/parsing/schemata.d.ts.map +1 -0
- package/dist/lib/parsing/schemata.js +92 -0
- package/dist/lib/parsing/schemata.js.map +1 -0
- package/dist/lib/parsing/types.d.ts +24 -0
- package/dist/lib/parsing/types.d.ts.map +1 -0
- package/dist/lib/parsing/types.js +2 -0
- package/dist/lib/parsing/types.js.map +1 -0
- package/dist/lib/schemata/analysis.d.ts +9 -0
- package/dist/lib/schemata/analysis.d.ts.map +1 -0
- package/dist/lib/schemata/analysis.js +13 -0
- package/dist/lib/schemata/analysis.js.map +1 -0
- package/dist/lib/schemata/argument.d.ts +14 -0
- package/dist/lib/schemata/argument.d.ts.map +1 -0
- package/dist/lib/schemata/argument.js +24 -0
- package/dist/lib/schemata/argument.js.map +1 -0
- package/dist/lib/schemata/claim.d.ts +9 -0
- package/dist/lib/schemata/claim.d.ts.map +1 -0
- package/dist/lib/schemata/claim.js +18 -0
- package/dist/lib/schemata/claim.js.map +1 -0
- package/dist/lib/schemata/fork.d.ts +76 -0
- package/dist/lib/schemata/fork.d.ts.map +1 -0
- package/dist/lib/schemata/fork.js +55 -0
- package/dist/lib/schemata/fork.js.map +1 -0
- package/dist/lib/schemata/import.d.ts +33 -0
- package/dist/lib/schemata/import.d.ts.map +1 -0
- package/dist/lib/schemata/import.js +18 -0
- package/dist/lib/schemata/import.js.map +1 -0
- package/dist/lib/schemata/index.d.ts +8 -0
- package/dist/lib/schemata/index.d.ts.map +1 -0
- package/dist/lib/schemata/index.js +8 -0
- package/dist/lib/schemata/index.js.map +1 -0
- package/dist/lib/schemata/propositional.d.ts +142 -0
- package/dist/lib/schemata/propositional.d.ts.map +1 -0
- package/dist/lib/schemata/propositional.js +120 -0
- package/dist/lib/schemata/propositional.js.map +1 -0
- package/dist/lib/schemata/shared.d.ts +41 -0
- package/dist/lib/schemata/shared.d.ts.map +1 -0
- package/dist/lib/schemata/shared.js +66 -0
- package/dist/lib/schemata/shared.js.map +1 -0
- package/dist/lib/schemata/source.d.ts +18 -0
- package/dist/lib/schemata/source.d.ts.map +1 -0
- package/dist/lib/schemata/source.js +35 -0
- package/dist/lib/schemata/source.js.map +1 -0
- package/dist/lib/types/checksum.d.ts +20 -0
- package/dist/lib/types/checksum.d.ts.map +1 -0
- package/dist/lib/types/checksum.js +2 -0
- package/dist/lib/types/checksum.js.map +1 -0
- package/dist/lib/types/diff.d.ts +60 -0
- package/dist/lib/types/diff.d.ts.map +1 -0
- package/dist/lib/types/diff.js +2 -0
- package/dist/lib/types/diff.js.map +1 -0
- package/dist/lib/types/evaluation.d.ts +164 -0
- package/dist/lib/types/evaluation.d.ts.map +1 -0
- package/dist/lib/types/evaluation.js +2 -0
- package/dist/lib/types/evaluation.js.map +1 -0
- package/dist/lib/types/fork.d.ts +25 -0
- package/dist/lib/types/fork.d.ts.map +1 -0
- package/dist/lib/types/fork.js +2 -0
- package/dist/lib/types/fork.js.map +1 -0
- package/dist/lib/types/grammar.d.ts +38 -0
- package/dist/lib/types/grammar.d.ts.map +1 -0
- package/dist/lib/types/grammar.js +11 -0
- package/dist/lib/types/grammar.js.map +1 -0
- package/dist/lib/types/mutation.d.ts +31 -0
- package/dist/lib/types/mutation.d.ts.map +1 -0
- package/dist/lib/types/mutation.js +2 -0
- package/dist/lib/types/mutation.js.map +1 -0
- package/dist/lib/types/reactive.d.ts +14 -0
- package/dist/lib/types/reactive.d.ts.map +1 -0
- package/dist/lib/types/reactive.js +2 -0
- package/dist/lib/types/reactive.js.map +1 -0
- package/dist/lib/types/relationships.d.ts +36 -0
- package/dist/lib/types/relationships.d.ts.map +1 -0
- package/dist/lib/types/relationships.js +2 -0
- package/dist/lib/types/relationships.js.map +1 -0
- package/dist/lib/types/validation.d.ts +47 -0
- package/dist/lib/types/validation.d.ts.map +1 -0
- package/dist/lib/types/validation.js +43 -0
- package/dist/lib/types/validation.js.map +1 -0
- package/dist/lib/utils/changeset.d.ts +124 -0
- package/dist/lib/utils/changeset.d.ts.map +1 -0
- package/dist/lib/utils/changeset.js +221 -0
- package/dist/lib/utils/changeset.js.map +1 -0
- package/dist/lib/utils/collections.d.ts +12 -0
- package/dist/lib/utils/collections.d.ts.map +1 -0
- package/dist/lib/utils/collections.js +24 -0
- package/dist/lib/utils/collections.js.map +1 -0
- package/dist/lib/utils/default-map.d.ts +17 -0
- package/dist/lib/utils/default-map.d.ts.map +1 -0
- package/dist/lib/utils/default-map.js +33 -0
- package/dist/lib/utils/default-map.js.map +1 -0
- package/dist/lib/utils/lookup.d.ts +47 -0
- package/dist/lib/utils/lookup.d.ts.map +1 -0
- package/dist/lib/utils/lookup.js +62 -0
- package/dist/lib/utils/lookup.js.map +1 -0
- package/dist/lib/utils/position.d.ts +12 -0
- package/dist/lib/utils/position.d.ts.map +1 -0
- package/dist/lib/utils/position.js +13 -0
- package/dist/lib/utils/position.js.map +1 -0
- package/package.json +82 -0
- package/skills/proposit-core/SKILL.md +35 -0
- package/skills/proposit-core/docs/api-usage.md +442 -0
- package/skills/proposit-core/docs/architecture.md +256 -0
- package/skills/proposit-core/docs/cli.md +304 -0
- package/skills/proposit-core/docs/testing.md +281 -0
- package/skills/proposit-core/docs/types-schemas.md +648 -0
|
@@ -0,0 +1,1362 @@
|
|
|
1
|
+
import { CorePremiseSchema, isExternallyBound, isPremiseBound, } from "../schemata/index.js";
|
|
2
|
+
import { DefaultMap } from "../utils/default-map.js";
|
|
3
|
+
import { midpoint, POSITION_INITIAL, POSITION_MAX } from "../utils/position.js";
|
|
4
|
+
import { sortedCopyById, sortedUnique } from "../utils/collections.js";
|
|
5
|
+
import { kleeneAnd, kleeneIff, kleeneImplies, kleeneNot, kleeneOr, } from "./evaluation/kleene.js";
|
|
6
|
+
import { buildDirectionalVacuity, makeErrorIssue, makeValidationResult, } from "./evaluation/validation.js";
|
|
7
|
+
import { Value } from "typebox/value";
|
|
8
|
+
import { PREMISE_SCHEMA_INVALID, PREMISE_ROOT_EXPRESSION_INVALID, PREMISE_VARIABLE_REF_NOT_FOUND, } from "../types/validation.js";
|
|
9
|
+
import { defaultGenerateId, } from "./argument-engine.js";
|
|
10
|
+
import { DEFAULT_CHECKSUM_CONFIG, normalizeChecksumConfig, serializeChecksumConfig, } from "../consts.js";
|
|
11
|
+
import { ChangeCollector } from "./change-collector.js";
|
|
12
|
+
import { computeHash, entityChecksum } from "./checksum.js";
|
|
13
|
+
import { InvariantViolationError } from "./invariant-violation-error.js";
|
|
14
|
+
import { ExpressionManager } from "./expression-manager.js";
|
|
15
|
+
import { VariableManager } from "./variable-manager.js";
|
|
16
|
+
export class PremiseEngine {
|
|
17
|
+
premise;
|
|
18
|
+
rootExpressionId;
|
|
19
|
+
variables;
|
|
20
|
+
expressions;
|
|
21
|
+
expressionsByVariableId;
|
|
22
|
+
argument;
|
|
23
|
+
checksumConfig;
|
|
24
|
+
checksumDirty = true;
|
|
25
|
+
cachedMetaChecksum;
|
|
26
|
+
cachedDescendantChecksum;
|
|
27
|
+
cachedCombinedChecksum;
|
|
28
|
+
expressionIndex;
|
|
29
|
+
generateId;
|
|
30
|
+
onMutate;
|
|
31
|
+
circularityCheck;
|
|
32
|
+
emptyBoundPremiseCheck;
|
|
33
|
+
variableIdsCallback;
|
|
34
|
+
argumentValidateCallback;
|
|
35
|
+
insideValidation = false;
|
|
36
|
+
constructor(premise, deps, config) {
|
|
37
|
+
this.premise = { ...premise };
|
|
38
|
+
this.argument = deps.argument;
|
|
39
|
+
this.checksumConfig = config?.checksumConfig;
|
|
40
|
+
this.rootExpressionId = undefined;
|
|
41
|
+
this.variables = deps.variables;
|
|
42
|
+
this.expressions = new ExpressionManager(config);
|
|
43
|
+
this.expressionsByVariableId = new DefaultMap(() => new Set());
|
|
44
|
+
this.expressionIndex = deps.expressionIndex;
|
|
45
|
+
this.generateId = config?.generateId ?? defaultGenerateId;
|
|
46
|
+
}
|
|
47
|
+
setOnMutate(callback) {
|
|
48
|
+
this.onMutate = callback;
|
|
49
|
+
}
|
|
50
|
+
setCircularityCheck(check) {
|
|
51
|
+
this.circularityCheck = check;
|
|
52
|
+
}
|
|
53
|
+
setEmptyBoundPremiseCheck(check) {
|
|
54
|
+
this.emptyBoundPremiseCheck = check;
|
|
55
|
+
}
|
|
56
|
+
setVariableIdsCallback(callback) {
|
|
57
|
+
this.variableIdsCallback = callback;
|
|
58
|
+
}
|
|
59
|
+
setArgumentValidateCallback(callback) {
|
|
60
|
+
this.argumentValidateCallback = callback;
|
|
61
|
+
}
|
|
62
|
+
premiseSnapshot() {
|
|
63
|
+
const expressionIndexEntries = [];
|
|
64
|
+
if (this.expressionIndex) {
|
|
65
|
+
for (const [exprId, premiseId] of this.expressionIndex) {
|
|
66
|
+
if (premiseId === this.premise.id) {
|
|
67
|
+
expressionIndexEntries.push([exprId, premiseId]);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
premiseData: { ...this.premise },
|
|
73
|
+
rootExpressionId: this.rootExpressionId,
|
|
74
|
+
expressionSnapshot: this.expressions.snapshot(),
|
|
75
|
+
expressionIndexEntries,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
restoreFromPremiseSnapshot(snap) {
|
|
79
|
+
this.premise = snap.premiseData;
|
|
80
|
+
this.rootExpressionId = snap.rootExpressionId;
|
|
81
|
+
this.expressions = ExpressionManager.fromSnapshot(snap.expressionSnapshot);
|
|
82
|
+
// Restore expression index entries
|
|
83
|
+
if (this.expressionIndex) {
|
|
84
|
+
for (const [exprId, premiseId] of [...this.expressionIndex]) {
|
|
85
|
+
if (premiseId === this.premise.id) {
|
|
86
|
+
this.expressionIndex.delete(exprId);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
for (const [exprId, premiseId] of snap.expressionIndexEntries) {
|
|
90
|
+
this.expressionIndex.set(exprId, premiseId);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
this.rebuildVariableIndex();
|
|
94
|
+
}
|
|
95
|
+
withValidation(fn) {
|
|
96
|
+
if (this.insideValidation) {
|
|
97
|
+
return fn();
|
|
98
|
+
}
|
|
99
|
+
const snap = this.premiseSnapshot();
|
|
100
|
+
this.insideValidation = true;
|
|
101
|
+
try {
|
|
102
|
+
const result = fn();
|
|
103
|
+
const validation = this.argumentValidateCallback?.() ?? this.validate();
|
|
104
|
+
if (!validation.ok) {
|
|
105
|
+
this.restoreFromPremiseSnapshot(snap);
|
|
106
|
+
throw new InvariantViolationError(validation.violations);
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
if (!(e instanceof InvariantViolationError)) {
|
|
112
|
+
this.restoreFromPremiseSnapshot(snap);
|
|
113
|
+
}
|
|
114
|
+
throw e;
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
this.insideValidation = false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
deleteExpressionsUsingVariable(variableId) {
|
|
121
|
+
return this.withValidation(() => {
|
|
122
|
+
const expressionIds = this.expressionsByVariableId.get(variableId);
|
|
123
|
+
if (expressionIds.size === 0) {
|
|
124
|
+
return { result: [], changes: {} };
|
|
125
|
+
}
|
|
126
|
+
const collector = new ChangeCollector();
|
|
127
|
+
// Suppress onMutate during the loop to avoid redundant notifications
|
|
128
|
+
const savedOnMutate = this.onMutate;
|
|
129
|
+
this.onMutate = undefined;
|
|
130
|
+
try {
|
|
131
|
+
// Copy the set since removeExpression mutates expressionsByVariableId
|
|
132
|
+
const removed = [];
|
|
133
|
+
for (const exprId of [...expressionIds]) {
|
|
134
|
+
// The expression may already have been removed as part of a
|
|
135
|
+
// prior subtree deletion or operator collapse in this loop.
|
|
136
|
+
if (!this.expressions.getExpression(exprId))
|
|
137
|
+
continue;
|
|
138
|
+
const { result, changes } = this.removeExpression(exprId, true);
|
|
139
|
+
if (result)
|
|
140
|
+
removed.push(result);
|
|
141
|
+
if (changes.expressions) {
|
|
142
|
+
for (const e of changes.expressions.removed) {
|
|
143
|
+
collector.removedExpression(e);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Expressions in the collector already have checksums attached
|
|
148
|
+
// (from ExpressionManager which stores expressions with checksums).
|
|
149
|
+
const changes = collector.toChangeset();
|
|
150
|
+
this.syncExpressionIndex(changes);
|
|
151
|
+
// Restore and fire once if something was removed
|
|
152
|
+
this.onMutate = savedOnMutate;
|
|
153
|
+
if (removed.length > 0) {
|
|
154
|
+
this.onMutate?.();
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
result: removed,
|
|
158
|
+
changes,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
catch (e) {
|
|
162
|
+
this.onMutate = savedOnMutate;
|
|
163
|
+
throw e;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
addExpression(expression) {
|
|
168
|
+
return this.withValidation(() => {
|
|
169
|
+
this.assertBelongsToArgument(expression.argumentId, expression.argumentVersion);
|
|
170
|
+
this.assertVariableExpressionValid(expression);
|
|
171
|
+
if (expression.parentId === null) {
|
|
172
|
+
if (this.rootExpressionId !== undefined) {
|
|
173
|
+
throw new Error(`Premise "${this.premise.id}" already has a root expression.`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
if (!this.expressions.getExpression(expression.parentId)) {
|
|
178
|
+
throw new Error(`Parent expression "${expression.parentId}" does not exist in this premise.`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const collector = new ChangeCollector();
|
|
182
|
+
this.expressions.setCollector(collector);
|
|
183
|
+
try {
|
|
184
|
+
// Delegate structural validation (operator type checks, position
|
|
185
|
+
// uniqueness, child limits) to ExpressionManager.
|
|
186
|
+
this.expressions.addExpression(expression);
|
|
187
|
+
if (expression.parentId === null) {
|
|
188
|
+
this.rootExpressionId = expression.id;
|
|
189
|
+
}
|
|
190
|
+
if (expression.type === "variable") {
|
|
191
|
+
this.expressionsByVariableId
|
|
192
|
+
.get(expression.variableId)
|
|
193
|
+
.add(expression.id);
|
|
194
|
+
}
|
|
195
|
+
const changes = this.finalizeExpressionMutation(collector);
|
|
196
|
+
return {
|
|
197
|
+
result: this.expressions.getExpression(expression.id),
|
|
198
|
+
changes,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
finally {
|
|
202
|
+
this.expressions.setCollector(null);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
appendExpression(parentId, expression) {
|
|
207
|
+
return this.withValidation(() => {
|
|
208
|
+
this.assertBelongsToArgument(expression.argumentId, expression.argumentVersion);
|
|
209
|
+
this.assertVariableExpressionValid(expression);
|
|
210
|
+
if (parentId === null) {
|
|
211
|
+
if (this.rootExpressionId !== undefined) {
|
|
212
|
+
throw new Error(`Premise "${this.premise.id}" already has a root expression.`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
if (!this.expressions.getExpression(parentId)) {
|
|
217
|
+
throw new Error(`Parent expression "${parentId}" does not exist in this premise.`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const collector = new ChangeCollector();
|
|
221
|
+
this.expressions.setCollector(collector);
|
|
222
|
+
try {
|
|
223
|
+
this.expressions.appendExpression(parentId, expression);
|
|
224
|
+
if (expression.type === "variable") {
|
|
225
|
+
this.expressionsByVariableId
|
|
226
|
+
.get(expression.variableId)
|
|
227
|
+
.add(expression.id);
|
|
228
|
+
}
|
|
229
|
+
const changes = this.finalizeExpressionMutation(collector);
|
|
230
|
+
return {
|
|
231
|
+
result: this.expressions.getExpression(expression.id),
|
|
232
|
+
changes,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
this.expressions.setCollector(null);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
addExpressionRelative(siblingId, relativePosition, expression) {
|
|
241
|
+
return this.withValidation(() => {
|
|
242
|
+
this.assertBelongsToArgument(expression.argumentId, expression.argumentVersion);
|
|
243
|
+
this.assertVariableExpressionValid(expression);
|
|
244
|
+
if (!this.expressions.getExpression(siblingId)) {
|
|
245
|
+
throw new Error(`Expression "${siblingId}" not found in this premise.`);
|
|
246
|
+
}
|
|
247
|
+
const collector = new ChangeCollector();
|
|
248
|
+
this.expressions.setCollector(collector);
|
|
249
|
+
try {
|
|
250
|
+
this.expressions.addExpressionRelative(siblingId, relativePosition, expression);
|
|
251
|
+
if (expression.type === "variable") {
|
|
252
|
+
this.expressionsByVariableId
|
|
253
|
+
.get(expression.variableId)
|
|
254
|
+
.add(expression.id);
|
|
255
|
+
}
|
|
256
|
+
const changes = this.finalizeExpressionMutation(collector);
|
|
257
|
+
return {
|
|
258
|
+
result: this.expressions.getExpression(expression.id),
|
|
259
|
+
changes,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
finally {
|
|
263
|
+
this.expressions.setCollector(null);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
updateExpression(expressionId, updates) {
|
|
268
|
+
return this.withValidation(() => {
|
|
269
|
+
const existing = this.expressions.getExpression(expressionId);
|
|
270
|
+
if (!existing) {
|
|
271
|
+
throw new Error(`Expression "${expressionId}" not found in premise "${this.premise.id}".`);
|
|
272
|
+
}
|
|
273
|
+
if (updates.variableId !== undefined) {
|
|
274
|
+
if (!this.variables.hasVariable(updates.variableId)) {
|
|
275
|
+
throw new Error(`Variable expression "${expressionId}" references non-existent variable "${updates.variableId}".`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const collector = new ChangeCollector();
|
|
279
|
+
this.expressions.setCollector(collector);
|
|
280
|
+
try {
|
|
281
|
+
const oldVariableId = existing.type === "variable"
|
|
282
|
+
? existing.variableId
|
|
283
|
+
: undefined;
|
|
284
|
+
const updated = this.expressions.updateExpression(expressionId, updates);
|
|
285
|
+
if (updates.variableId !== undefined &&
|
|
286
|
+
oldVariableId !== undefined &&
|
|
287
|
+
oldVariableId !== updates.variableId) {
|
|
288
|
+
this.expressionsByVariableId
|
|
289
|
+
.get(oldVariableId)
|
|
290
|
+
?.delete(expressionId);
|
|
291
|
+
this.expressionsByVariableId
|
|
292
|
+
.get(updates.variableId)
|
|
293
|
+
.add(expressionId);
|
|
294
|
+
}
|
|
295
|
+
const changeset = this.flushAndBuildChangeset(collector);
|
|
296
|
+
if (changeset.expressions !== undefined) {
|
|
297
|
+
this.markDirty();
|
|
298
|
+
this.onMutate?.();
|
|
299
|
+
}
|
|
300
|
+
this.syncExpressionIndex(changeset);
|
|
301
|
+
return {
|
|
302
|
+
result: updated,
|
|
303
|
+
changes: changeset,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
finally {
|
|
307
|
+
this.expressions.setCollector(null);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
removeExpression(expressionId, deleteSubtree) {
|
|
312
|
+
return this.withValidation(() => {
|
|
313
|
+
// Snapshot the expression before removal (for result).
|
|
314
|
+
const snapshot = this.expressions.getExpression(expressionId);
|
|
315
|
+
const collector = new ChangeCollector();
|
|
316
|
+
this.expressions.setCollector(collector);
|
|
317
|
+
try {
|
|
318
|
+
if (!snapshot) {
|
|
319
|
+
return {
|
|
320
|
+
result: undefined,
|
|
321
|
+
changes: collector.toChangeset(),
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
if (deleteSubtree) {
|
|
325
|
+
// Snapshot the subtree before deletion so we can clean up
|
|
326
|
+
// expressionsByVariableId for cascade-deleted descendants — they are
|
|
327
|
+
// not individually surfaced by ExpressionManager.removeExpression.
|
|
328
|
+
const subtree = this.collectSubtree(expressionId);
|
|
329
|
+
this.expressions.removeExpression(expressionId, true);
|
|
330
|
+
for (const expr of subtree) {
|
|
331
|
+
if (expr.type === "variable") {
|
|
332
|
+
this.expressionsByVariableId
|
|
333
|
+
.get(expr.variableId)
|
|
334
|
+
?.delete(expr.id);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
// Only clean up expressionsByVariableId for the removed
|
|
340
|
+
// expression itself — children survive promotion.
|
|
341
|
+
if (snapshot.type === "variable") {
|
|
342
|
+
this.expressionsByVariableId
|
|
343
|
+
.get(snapshot.variableId)
|
|
344
|
+
?.delete(snapshot.id);
|
|
345
|
+
}
|
|
346
|
+
this.expressions.removeExpression(expressionId, false);
|
|
347
|
+
}
|
|
348
|
+
const changes = this.finalizeExpressionMutation(collector);
|
|
349
|
+
return {
|
|
350
|
+
result: snapshot,
|
|
351
|
+
changes,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
finally {
|
|
355
|
+
this.expressions.setCollector(null);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
insertExpression(expression, leftNodeId, rightNodeId) {
|
|
360
|
+
return this.withValidation(() => {
|
|
361
|
+
this.assertBelongsToArgument(expression.argumentId, expression.argumentVersion);
|
|
362
|
+
this.assertVariableExpressionValid(expression);
|
|
363
|
+
const collector = new ChangeCollector();
|
|
364
|
+
this.expressions.setCollector(collector);
|
|
365
|
+
try {
|
|
366
|
+
this.expressions.insertExpression(expression, leftNodeId, rightNodeId);
|
|
367
|
+
if (expression.type === "variable") {
|
|
368
|
+
this.expressionsByVariableId
|
|
369
|
+
.get(expression.variableId)
|
|
370
|
+
.add(expression.id);
|
|
371
|
+
}
|
|
372
|
+
const changes = this.finalizeExpressionMutation(collector);
|
|
373
|
+
return {
|
|
374
|
+
result: this.expressions.getExpression(expression.id),
|
|
375
|
+
changes,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
finally {
|
|
379
|
+
this.expressions.setCollector(null);
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
wrapExpression(operator, newSibling, leftNodeId, rightNodeId) {
|
|
384
|
+
return this.withValidation(() => {
|
|
385
|
+
this.assertBelongsToArgument(operator.argumentId, operator.argumentVersion);
|
|
386
|
+
this.assertBelongsToArgument(newSibling.argumentId, newSibling.argumentVersion);
|
|
387
|
+
this.assertVariableExpressionValid(newSibling);
|
|
388
|
+
const collector = new ChangeCollector();
|
|
389
|
+
this.expressions.setCollector(collector);
|
|
390
|
+
try {
|
|
391
|
+
this.expressions.wrapExpression(operator, newSibling, leftNodeId, rightNodeId);
|
|
392
|
+
if (newSibling.type === "variable") {
|
|
393
|
+
this.expressionsByVariableId
|
|
394
|
+
.get(newSibling.variableId)
|
|
395
|
+
.add(newSibling.id);
|
|
396
|
+
}
|
|
397
|
+
const changes = this.finalizeExpressionMutation(collector);
|
|
398
|
+
return {
|
|
399
|
+
result: this.expressions.getExpression(operator.id),
|
|
400
|
+
changes,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
finally {
|
|
404
|
+
this.expressions.setCollector(null);
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Performs a full normalization sweep on this premise's expression tree.
|
|
410
|
+
* Collapses unjustified formulas, operators with 0/1 children, and inserts
|
|
411
|
+
* formula buffers where needed. Works regardless of `autoNormalize` setting.
|
|
412
|
+
*/
|
|
413
|
+
normalizeExpressions() {
|
|
414
|
+
return this.withValidation(() => {
|
|
415
|
+
const collector = new ChangeCollector();
|
|
416
|
+
this.expressions.setCollector(collector);
|
|
417
|
+
try {
|
|
418
|
+
this.expressions.normalize();
|
|
419
|
+
const changes = this.finalizeExpressionMutation(collector);
|
|
420
|
+
return { result: undefined, changes };
|
|
421
|
+
}
|
|
422
|
+
finally {
|
|
423
|
+
this.expressions.setCollector(null);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
toggleNegation(expressionId, extraFields) {
|
|
428
|
+
return this.withValidation(() => {
|
|
429
|
+
const target = this.expressions.getExpression(expressionId);
|
|
430
|
+
if (!target) {
|
|
431
|
+
throw new Error(`Expression "${expressionId}" not found in this premise.`);
|
|
432
|
+
}
|
|
433
|
+
this.assertBelongsToArgument(target.argumentId, target.argumentVersion);
|
|
434
|
+
const collector = new ChangeCollector();
|
|
435
|
+
this.expressions.setCollector(collector);
|
|
436
|
+
try {
|
|
437
|
+
const parent = target.parentId
|
|
438
|
+
? this.expressions.getExpression(target.parentId)
|
|
439
|
+
: undefined;
|
|
440
|
+
// Check for direct not parent: not(target)
|
|
441
|
+
const isDirectNot = parent?.type === "operator" && parent.operator === "not";
|
|
442
|
+
// Check for formula-buffered not: not(formula(target))
|
|
443
|
+
const grandparent = parent?.type === "formula" && parent.parentId
|
|
444
|
+
? this.expressions.getExpression(parent.parentId)
|
|
445
|
+
: undefined;
|
|
446
|
+
const isBufferedNot = parent?.type === "formula" &&
|
|
447
|
+
grandparent?.type === "operator" &&
|
|
448
|
+
grandparent.operator === "not";
|
|
449
|
+
if (isDirectNot || isBufferedNot) {
|
|
450
|
+
if (isBufferedNot) {
|
|
451
|
+
// Structure is not → formula → target.
|
|
452
|
+
// Remove just the not (promotes formula into its slot).
|
|
453
|
+
// The formula remains as a transparent wrapper.
|
|
454
|
+
this.expressions.removeExpression(grandparent.id, false);
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
// Remove the NOT operator, promoting target into its slot
|
|
458
|
+
this.expressions.removeExpression(parent.id, false);
|
|
459
|
+
}
|
|
460
|
+
const changes = this.finalizeExpressionMutation(collector);
|
|
461
|
+
return { result: null, changes };
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
// When the target is a non-not operator, insert a formula
|
|
465
|
+
// buffer between the new not and the target so the tree
|
|
466
|
+
// satisfies the operator nesting restriction.
|
|
467
|
+
const needsFormula = target.type === "operator" && target.operator !== "not";
|
|
468
|
+
let notExprId;
|
|
469
|
+
if (needsFormula) {
|
|
470
|
+
// Build not → formula → target
|
|
471
|
+
const formulaExpr = {
|
|
472
|
+
...extraFields,
|
|
473
|
+
id: this.generateId(),
|
|
474
|
+
argumentId: target.argumentId,
|
|
475
|
+
argumentVersion: target.argumentVersion,
|
|
476
|
+
premiseId: target.premiseId,
|
|
477
|
+
type: "formula",
|
|
478
|
+
parentId: target.parentId,
|
|
479
|
+
position: target.position,
|
|
480
|
+
};
|
|
481
|
+
this.expressions.insertExpression(formulaExpr, expressionId);
|
|
482
|
+
const notExpr = {
|
|
483
|
+
...extraFields,
|
|
484
|
+
id: this.generateId(),
|
|
485
|
+
argumentId: target.argumentId,
|
|
486
|
+
argumentVersion: target.argumentVersion,
|
|
487
|
+
premiseId: target.premiseId,
|
|
488
|
+
type: "operator",
|
|
489
|
+
operator: "not",
|
|
490
|
+
parentId: target.parentId,
|
|
491
|
+
position: target.position,
|
|
492
|
+
};
|
|
493
|
+
this.expressions.insertExpression(notExpr, formulaExpr.id);
|
|
494
|
+
notExprId = notExpr.id;
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
// Wrap target with a new NOT operator
|
|
498
|
+
const notExpr = {
|
|
499
|
+
...extraFields,
|
|
500
|
+
id: this.generateId(),
|
|
501
|
+
argumentId: target.argumentId,
|
|
502
|
+
argumentVersion: target.argumentVersion,
|
|
503
|
+
premiseId: target.premiseId,
|
|
504
|
+
type: "operator",
|
|
505
|
+
operator: "not",
|
|
506
|
+
parentId: target.parentId,
|
|
507
|
+
position: target.position,
|
|
508
|
+
};
|
|
509
|
+
this.expressions.insertExpression(notExpr, expressionId);
|
|
510
|
+
notExprId = notExpr.id;
|
|
511
|
+
}
|
|
512
|
+
const changes = this.finalizeExpressionMutation(collector);
|
|
513
|
+
return {
|
|
514
|
+
result: this.expressions.getExpression(notExprId),
|
|
515
|
+
changes,
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
finally {
|
|
520
|
+
this.expressions.setCollector(null);
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
changeOperator(expressionId, newOperator, sourceChildId, targetChildId, extraFields) {
|
|
525
|
+
return this.withValidation(() => {
|
|
526
|
+
const target = this.expressions.getExpression(expressionId);
|
|
527
|
+
if (!target) {
|
|
528
|
+
throw new Error(`Expression "${expressionId}" not found in this premise.`);
|
|
529
|
+
}
|
|
530
|
+
if (target.type !== "operator") {
|
|
531
|
+
throw new Error(`Expression "${expressionId}" is not an operator expression (type: "${target.type}").`);
|
|
532
|
+
}
|
|
533
|
+
if (target.type === "operator" && target.operator === "not") {
|
|
534
|
+
throw new Error(`Cannot change a "not" operator. Use toggleNegation instead.`);
|
|
535
|
+
}
|
|
536
|
+
this.assertBelongsToArgument(target.argumentId, target.argumentVersion);
|
|
537
|
+
// No-op: already the requested operator
|
|
538
|
+
if (target.type === "operator" && target.operator === newOperator) {
|
|
539
|
+
return { result: target, changes: {} };
|
|
540
|
+
}
|
|
541
|
+
const children = this.expressions.getChildExpressions(expressionId);
|
|
542
|
+
const childCount = children.length;
|
|
543
|
+
const collector = new ChangeCollector();
|
|
544
|
+
this.expressions.setCollector(collector);
|
|
545
|
+
try {
|
|
546
|
+
if (childCount <= 2) {
|
|
547
|
+
// Check for merge condition: parent is same type as newOperator.
|
|
548
|
+
// Only merge when childCount < 2 (degenerate operator). With
|
|
549
|
+
// exactly 2 children the operator is well-formed — just change
|
|
550
|
+
// the type in place.
|
|
551
|
+
const parent = target.parentId
|
|
552
|
+
? this.expressions.getExpression(target.parentId)
|
|
553
|
+
: undefined;
|
|
554
|
+
let mergeTarget;
|
|
555
|
+
if (childCount < 2) {
|
|
556
|
+
// Look through formula buffer: if parent is formula, check grandparent
|
|
557
|
+
if (parent?.type === "formula" && parent.parentId) {
|
|
558
|
+
const grandparent = this.expressions.getExpression(parent.parentId);
|
|
559
|
+
if (grandparent?.type === "operator" &&
|
|
560
|
+
grandparent.operator === newOperator) {
|
|
561
|
+
mergeTarget = grandparent;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
else if (parent?.type === "operator" &&
|
|
565
|
+
parent.operator === newOperator) {
|
|
566
|
+
mergeTarget = parent;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (mergeTarget) {
|
|
570
|
+
// --- MERGE ---
|
|
571
|
+
// Reparent children of the dissolving operator under the merge target.
|
|
572
|
+
// Use the dissolving operator's position slot for the first child,
|
|
573
|
+
// compute midpoint positions for subsequent children.
|
|
574
|
+
// If parent was a formula buffer, we'll dissolve that too
|
|
575
|
+
const formulaToDissolve = parent?.type === "formula" ? parent : undefined;
|
|
576
|
+
// The position slot we're replacing
|
|
577
|
+
const slotPosition = formulaToDissolve
|
|
578
|
+
? formulaToDissolve.position
|
|
579
|
+
: target.position;
|
|
580
|
+
// Get the merge target's existing children sorted by position to find neighbors
|
|
581
|
+
const mergeChildren = this.expressions.getChildExpressions(mergeTarget.id);
|
|
582
|
+
// Find the position of the next sibling after the slot
|
|
583
|
+
const slotIndex = mergeChildren.findIndex((c) => c.id === (formulaToDissolve?.id ?? expressionId));
|
|
584
|
+
const nextSibling = mergeChildren[slotIndex + 1];
|
|
585
|
+
const nextPosition = nextSibling
|
|
586
|
+
? nextSibling.position
|
|
587
|
+
: POSITION_MAX;
|
|
588
|
+
// Reparent each child
|
|
589
|
+
for (let i = 0; i < children.length; i++) {
|
|
590
|
+
const childPosition = i === 0
|
|
591
|
+
? slotPosition
|
|
592
|
+
: midpoint(i === 1
|
|
593
|
+
? slotPosition
|
|
594
|
+
: children[i - 1].position, nextPosition);
|
|
595
|
+
this.expressions.reparentExpression(children[i].id, mergeTarget.id, childPosition);
|
|
596
|
+
}
|
|
597
|
+
// Delete the dissolving operator (now has no children)
|
|
598
|
+
this.expressions.deleteExpression(expressionId);
|
|
599
|
+
// Delete the formula buffer if it existed (now has no children)
|
|
600
|
+
if (formulaToDissolve) {
|
|
601
|
+
this.expressions.deleteExpression(formulaToDissolve.id);
|
|
602
|
+
}
|
|
603
|
+
const changes = this.finalizeExpressionMutation(collector);
|
|
604
|
+
return { result: null, changes };
|
|
605
|
+
}
|
|
606
|
+
else {
|
|
607
|
+
// --- SIMPLE CHANGE ---
|
|
608
|
+
this.expressions.changeOperatorType(expressionId, newOperator);
|
|
609
|
+
const changes = this.finalizeExpressionMutation(collector);
|
|
610
|
+
return {
|
|
611
|
+
result: this.expressions.getExpression(expressionId),
|
|
612
|
+
changes,
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
// --- SPLIT (>2 children) ---
|
|
618
|
+
if (!sourceChildId || !targetChildId) {
|
|
619
|
+
throw new Error(`Operator "${expressionId}" has ${childCount} children — sourceChildId and targetChildId are required for split.`);
|
|
620
|
+
}
|
|
621
|
+
// Validate source and target are children of the operator
|
|
622
|
+
const sourceChild = this.expressions.getExpression(sourceChildId);
|
|
623
|
+
const targetChild = this.expressions.getExpression(targetChildId);
|
|
624
|
+
if (!sourceChild || sourceChild.parentId !== expressionId) {
|
|
625
|
+
throw new Error(`Expression "${sourceChildId}" is not a child of operator "${expressionId}".`);
|
|
626
|
+
}
|
|
627
|
+
if (!targetChild || targetChild.parentId !== expressionId) {
|
|
628
|
+
throw new Error(`Expression "${targetChildId}" is not a child of operator "${expressionId}".`);
|
|
629
|
+
}
|
|
630
|
+
// Determine position for the formula buffer (min of the two children)
|
|
631
|
+
const formulaPosition = Math.min(sourceChild.position, targetChild.position);
|
|
632
|
+
// Create the sub-operator and formula first as detached nodes,
|
|
633
|
+
// then reparent children away from the parent (freeing their
|
|
634
|
+
// position slots), and finally add formula + sub-operator.
|
|
635
|
+
const formulaId = this.generateId();
|
|
636
|
+
const newOpId = this.generateId();
|
|
637
|
+
// Reparent source and target children to a temporary holding
|
|
638
|
+
// position under the new sub-operator. We must reparent them
|
|
639
|
+
// away from the parent BEFORE adding the formula at their old
|
|
640
|
+
// position slot.
|
|
641
|
+
const firstChild = sourceChild.position <= targetChild.position
|
|
642
|
+
? sourceChild
|
|
643
|
+
: targetChild;
|
|
644
|
+
const secondChild = sourceChild.position <= targetChild.position
|
|
645
|
+
? targetChild
|
|
646
|
+
: sourceChild;
|
|
647
|
+
// Reparent children to null temporarily (detach from parent)
|
|
648
|
+
// so their position slots are freed.
|
|
649
|
+
this.expressions.reparentExpression(firstChild.id, null, firstChild.position);
|
|
650
|
+
this.expressions.reparentExpression(secondChild.id, null, secondChild.position);
|
|
651
|
+
// Now add the formula buffer at the freed position
|
|
652
|
+
const formulaExpr = {
|
|
653
|
+
...extraFields,
|
|
654
|
+
id: formulaId,
|
|
655
|
+
argumentId: target.argumentId,
|
|
656
|
+
argumentVersion: target.argumentVersion,
|
|
657
|
+
premiseId: target.premiseId,
|
|
658
|
+
type: "formula",
|
|
659
|
+
parentId: expressionId,
|
|
660
|
+
position: formulaPosition,
|
|
661
|
+
};
|
|
662
|
+
this.expressions.addExpression(formulaExpr);
|
|
663
|
+
// Add the new sub-operator under the formula
|
|
664
|
+
const newOpExpr = {
|
|
665
|
+
...extraFields,
|
|
666
|
+
id: newOpId,
|
|
667
|
+
argumentId: target.argumentId,
|
|
668
|
+
argumentVersion: target.argumentVersion,
|
|
669
|
+
premiseId: target.premiseId,
|
|
670
|
+
type: "operator",
|
|
671
|
+
operator: newOperator,
|
|
672
|
+
parentId: formulaId,
|
|
673
|
+
position: POSITION_INITIAL,
|
|
674
|
+
};
|
|
675
|
+
this.expressions.addExpression(newOpExpr);
|
|
676
|
+
// Now reparent the children under the new sub-operator
|
|
677
|
+
this.expressions.reparentExpression(firstChild.id, newOpId, POSITION_INITIAL);
|
|
678
|
+
this.expressions.reparentExpression(secondChild.id, newOpId, midpoint(POSITION_INITIAL, POSITION_MAX));
|
|
679
|
+
const changes = this.finalizeExpressionMutation(collector);
|
|
680
|
+
return {
|
|
681
|
+
result: this.expressions.getExpression(newOpId),
|
|
682
|
+
changes,
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
finally {
|
|
687
|
+
this.expressions.setCollector(null);
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
getExpression(id) {
|
|
692
|
+
return this.expressions.getExpression(id);
|
|
693
|
+
}
|
|
694
|
+
getId() {
|
|
695
|
+
return this.premise.id;
|
|
696
|
+
}
|
|
697
|
+
getExtras() {
|
|
698
|
+
const { id: _id, argumentId: _argumentId, argumentVersion: _argumentVersion, checksum: _checksum, descendantChecksum: _descendantChecksum, combinedChecksum: _combinedChecksum, ...extras } = this.premise;
|
|
699
|
+
return { ...extras };
|
|
700
|
+
}
|
|
701
|
+
setExtras(extras) {
|
|
702
|
+
return this.withValidation(() => {
|
|
703
|
+
// Strip old extras and replace with new ones
|
|
704
|
+
const { id, argumentId, argumentVersion, checksum, descendantChecksum, combinedChecksum, } = this.premise;
|
|
705
|
+
this.premise = {
|
|
706
|
+
...extras,
|
|
707
|
+
id,
|
|
708
|
+
argumentId,
|
|
709
|
+
argumentVersion,
|
|
710
|
+
...(checksum !== undefined ? { checksum } : {}),
|
|
711
|
+
...(descendantChecksum !== undefined
|
|
712
|
+
? { descendantChecksum }
|
|
713
|
+
: {}),
|
|
714
|
+
...(combinedChecksum !== undefined ? { combinedChecksum } : {}),
|
|
715
|
+
};
|
|
716
|
+
this.markDirty();
|
|
717
|
+
this.onMutate?.();
|
|
718
|
+
return { result: this.getExtras(), changes: {} };
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
getRootExpressionId() {
|
|
722
|
+
return this.rootExpressionId;
|
|
723
|
+
}
|
|
724
|
+
getRootExpression() {
|
|
725
|
+
if (this.rootExpressionId === undefined) {
|
|
726
|
+
return undefined;
|
|
727
|
+
}
|
|
728
|
+
return this.expressions.getExpression(this.rootExpressionId);
|
|
729
|
+
}
|
|
730
|
+
getVariables() {
|
|
731
|
+
return sortedCopyById(this.variables.toArray());
|
|
732
|
+
}
|
|
733
|
+
getExpressions() {
|
|
734
|
+
return sortedCopyById(this.expressions.toArray());
|
|
735
|
+
}
|
|
736
|
+
getChildExpressions(parentId) {
|
|
737
|
+
return this.expressions.getChildExpressions(parentId);
|
|
738
|
+
}
|
|
739
|
+
isInference() {
|
|
740
|
+
const root = this.getRootExpression();
|
|
741
|
+
return (root?.type === "operator" &&
|
|
742
|
+
(root.operator === "implies" || root.operator === "iff"));
|
|
743
|
+
}
|
|
744
|
+
isConstraint() {
|
|
745
|
+
return !this.isInference();
|
|
746
|
+
}
|
|
747
|
+
validateEvaluability() {
|
|
748
|
+
const issues = [];
|
|
749
|
+
const roots = this.expressions.getChildExpressions(null);
|
|
750
|
+
if (this.expressions.toArray().length === 0) {
|
|
751
|
+
issues.push(makeErrorIssue({
|
|
752
|
+
code: "PREMISE_EMPTY",
|
|
753
|
+
message: `Premise "${this.premise.id}" has no expressions to evaluate.`,
|
|
754
|
+
premiseId: this.premise.id,
|
|
755
|
+
}));
|
|
756
|
+
return makeValidationResult(issues);
|
|
757
|
+
}
|
|
758
|
+
if (roots.length === 0) {
|
|
759
|
+
issues.push(makeErrorIssue({
|
|
760
|
+
code: "PREMISE_ROOT_MISSING",
|
|
761
|
+
message: `Premise "${this.premise.id}" has expressions but no root expression.`,
|
|
762
|
+
premiseId: this.premise.id,
|
|
763
|
+
}));
|
|
764
|
+
}
|
|
765
|
+
if (this.rootExpressionId === undefined) {
|
|
766
|
+
issues.push(makeErrorIssue({
|
|
767
|
+
code: "PREMISE_ROOT_MISSING",
|
|
768
|
+
message: `Premise "${this.premise.id}" does not have rootExpressionId set.`,
|
|
769
|
+
premiseId: this.premise.id,
|
|
770
|
+
}));
|
|
771
|
+
}
|
|
772
|
+
else if (!this.expressions.getExpression(this.rootExpressionId)) {
|
|
773
|
+
issues.push(makeErrorIssue({
|
|
774
|
+
code: "PREMISE_ROOT_MISMATCH",
|
|
775
|
+
message: `Premise "${this.premise.id}" rootExpressionId "${this.rootExpressionId}" does not exist.`,
|
|
776
|
+
premiseId: this.premise.id,
|
|
777
|
+
expressionId: this.rootExpressionId,
|
|
778
|
+
}));
|
|
779
|
+
}
|
|
780
|
+
else if (roots[0] && roots[0].id !== this.rootExpressionId) {
|
|
781
|
+
issues.push(makeErrorIssue({
|
|
782
|
+
code: "PREMISE_ROOT_MISMATCH",
|
|
783
|
+
message: `Premise "${this.premise.id}" rootExpressionId "${this.rootExpressionId}" does not match actual root "${roots[0].id}".`,
|
|
784
|
+
premiseId: this.premise.id,
|
|
785
|
+
expressionId: this.rootExpressionId,
|
|
786
|
+
}));
|
|
787
|
+
}
|
|
788
|
+
for (const expr of this.expressions.toArray()) {
|
|
789
|
+
if (expr.type === "variable" &&
|
|
790
|
+
!this.variables.hasVariable(expr.variableId)) {
|
|
791
|
+
issues.push(makeErrorIssue({
|
|
792
|
+
code: "EXPR_VARIABLE_UNDECLARED",
|
|
793
|
+
message: `Expression "${expr.id}" references undeclared variable "${expr.variableId}".`,
|
|
794
|
+
premiseId: this.premise.id,
|
|
795
|
+
expressionId: expr.id,
|
|
796
|
+
variableId: expr.variableId,
|
|
797
|
+
}));
|
|
798
|
+
}
|
|
799
|
+
if (expr.type === "variable" &&
|
|
800
|
+
this.emptyBoundPremiseCheck?.(expr.variableId)) {
|
|
801
|
+
issues.push({
|
|
802
|
+
code: "EXPR_BOUND_PREMISE_EMPTY",
|
|
803
|
+
severity: "warning",
|
|
804
|
+
message: `Variable "${expr.variableId}" is bound to a premise with no expression tree`,
|
|
805
|
+
expressionId: expr.id,
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
if (expr.type !== "operator" && expr.type !== "formula") {
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
811
|
+
const children = this.expressions.getChildExpressions(expr.id);
|
|
812
|
+
if (expr.type === "formula") {
|
|
813
|
+
if (children.length !== 1) {
|
|
814
|
+
issues.push(makeErrorIssue({
|
|
815
|
+
code: "EXPR_CHILD_COUNT_INVALID",
|
|
816
|
+
message: `Formula expression "${expr.id}" must have exactly 1 child; found ${children.length}.`,
|
|
817
|
+
premiseId: this.premise.id,
|
|
818
|
+
expressionId: expr.id,
|
|
819
|
+
}));
|
|
820
|
+
}
|
|
821
|
+
continue;
|
|
822
|
+
}
|
|
823
|
+
if (expr.operator === "not" && children.length !== 1) {
|
|
824
|
+
issues.push(makeErrorIssue({
|
|
825
|
+
code: "EXPR_CHILD_COUNT_INVALID",
|
|
826
|
+
message: `Operator "${expr.id}" (not) must have exactly 1 child; found ${children.length}.`,
|
|
827
|
+
premiseId: this.premise.id,
|
|
828
|
+
expressionId: expr.id,
|
|
829
|
+
}));
|
|
830
|
+
}
|
|
831
|
+
if ((expr.operator === "implies" || expr.operator === "iff") &&
|
|
832
|
+
children.length !== 2) {
|
|
833
|
+
issues.push(makeErrorIssue({
|
|
834
|
+
code: "EXPR_CHILD_COUNT_INVALID",
|
|
835
|
+
message: `Operator "${expr.id}" (${expr.operator}) must have exactly 2 children; found ${children.length}.`,
|
|
836
|
+
premiseId: this.premise.id,
|
|
837
|
+
expressionId: expr.id,
|
|
838
|
+
}));
|
|
839
|
+
}
|
|
840
|
+
if ((expr.operator === "and" || expr.operator === "or") &&
|
|
841
|
+
children.length < 2) {
|
|
842
|
+
issues.push(makeErrorIssue({
|
|
843
|
+
code: "EXPR_CHILD_COUNT_INVALID",
|
|
844
|
+
message: `Operator "${expr.id}" (${expr.operator}) must have at least 2 children; found ${children.length}.`,
|
|
845
|
+
premiseId: this.premise.id,
|
|
846
|
+
expressionId: expr.id,
|
|
847
|
+
}));
|
|
848
|
+
}
|
|
849
|
+
if (expr.operator === "implies" || expr.operator === "iff") {
|
|
850
|
+
const childPositions = new Set(children.map((child) => child.position));
|
|
851
|
+
if (children.length !== 2 || childPositions.size !== 2) {
|
|
852
|
+
issues.push(makeErrorIssue({
|
|
853
|
+
code: "EXPR_BINARY_POSITIONS_INVALID",
|
|
854
|
+
message: `Operator "${expr.id}" (${expr.operator}) must have exactly 2 children with distinct positions.`,
|
|
855
|
+
premiseId: this.premise.id,
|
|
856
|
+
expressionId: expr.id,
|
|
857
|
+
}));
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
return makeValidationResult(issues);
|
|
862
|
+
}
|
|
863
|
+
evaluate(assignment, options) {
|
|
864
|
+
const validation = this.validateEvaluability();
|
|
865
|
+
if (!validation.ok) {
|
|
866
|
+
throw new Error(`Premise "${this.premise.id}" is not evaluable: ${validation.issues
|
|
867
|
+
.map((issue) => issue.code)
|
|
868
|
+
.join(", ")}`);
|
|
869
|
+
}
|
|
870
|
+
const rootExpressionId = this.rootExpressionId;
|
|
871
|
+
const referencedVariableIds = sortedUnique(this.expressions
|
|
872
|
+
.toArray()
|
|
873
|
+
.filter((expr) => expr.type === "variable")
|
|
874
|
+
.map((expr) => expr.variableId));
|
|
875
|
+
if (options?.strictUnknownKeys || options?.requireExactCoverage) {
|
|
876
|
+
const knownVariableIds = new Set(referencedVariableIds);
|
|
877
|
+
const unknownKeys = Object.keys(assignment.variables).filter((variableId) => !knownVariableIds.has(variableId));
|
|
878
|
+
if (unknownKeys.length > 0) {
|
|
879
|
+
throw new Error(`Assignment contains unknown variable IDs for premise "${this.premise.id}": ${unknownKeys.join(", ")}`);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
const expressionValues = {};
|
|
883
|
+
const evaluateExpression = (expressionId) => {
|
|
884
|
+
const expression = this.expressions.getExpression(expressionId);
|
|
885
|
+
if (!expression) {
|
|
886
|
+
throw new Error(`Expression "${expressionId}" was not found.`);
|
|
887
|
+
}
|
|
888
|
+
const operatorState = assignment.operatorAssignments[expression.id];
|
|
889
|
+
if (operatorState === "rejected") {
|
|
890
|
+
expressionValues[expression.id] = false;
|
|
891
|
+
return false;
|
|
892
|
+
}
|
|
893
|
+
if (expression.type === "variable") {
|
|
894
|
+
let value;
|
|
895
|
+
if (options?.resolver) {
|
|
896
|
+
const variable = this.variables.getVariable(expression.variableId);
|
|
897
|
+
if (variable &&
|
|
898
|
+
isPremiseBound(variable) &&
|
|
899
|
+
!isExternallyBound(variable, this.argument.id)) {
|
|
900
|
+
value = options.resolver(expression.variableId);
|
|
901
|
+
}
|
|
902
|
+
else {
|
|
903
|
+
value =
|
|
904
|
+
assignment.variables[expression.variableId] ?? null;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
else {
|
|
908
|
+
value = assignment.variables[expression.variableId] ?? null;
|
|
909
|
+
}
|
|
910
|
+
expressionValues[expression.id] = value;
|
|
911
|
+
return value;
|
|
912
|
+
}
|
|
913
|
+
const children = this.expressions.getChildExpressions(expression.id);
|
|
914
|
+
let value;
|
|
915
|
+
if (expression.type === "formula") {
|
|
916
|
+
value = evaluateExpression(children[0].id);
|
|
917
|
+
expressionValues[expression.id] = value;
|
|
918
|
+
return value;
|
|
919
|
+
}
|
|
920
|
+
switch (expression.operator) {
|
|
921
|
+
case "not":
|
|
922
|
+
value = kleeneNot(evaluateExpression(children[0].id));
|
|
923
|
+
break;
|
|
924
|
+
case "and":
|
|
925
|
+
value = children.reduce((acc, child) => kleeneAnd(acc, evaluateExpression(child.id)), true);
|
|
926
|
+
break;
|
|
927
|
+
case "or":
|
|
928
|
+
value = children.reduce((acc, child) => kleeneOr(acc, evaluateExpression(child.id)), false);
|
|
929
|
+
break;
|
|
930
|
+
case "implies": {
|
|
931
|
+
const left = children[0];
|
|
932
|
+
const right = children[1];
|
|
933
|
+
value = kleeneImplies(evaluateExpression(left.id), evaluateExpression(right.id));
|
|
934
|
+
break;
|
|
935
|
+
}
|
|
936
|
+
case "iff": {
|
|
937
|
+
const left = children[0];
|
|
938
|
+
const right = children[1];
|
|
939
|
+
value = kleeneIff(evaluateExpression(left.id), evaluateExpression(right.id));
|
|
940
|
+
break;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
expressionValues[expression.id] = value;
|
|
944
|
+
return value;
|
|
945
|
+
};
|
|
946
|
+
const rootValue = evaluateExpression(rootExpressionId);
|
|
947
|
+
const variableValues = {};
|
|
948
|
+
for (const variableId of referencedVariableIds) {
|
|
949
|
+
if (options?.resolver) {
|
|
950
|
+
const variable = this.variables.getVariable(variableId);
|
|
951
|
+
if (variable && isPremiseBound(variable)) {
|
|
952
|
+
variableValues[variableId] = options.resolver(variableId);
|
|
953
|
+
continue;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
variableValues[variableId] =
|
|
957
|
+
assignment.variables[variableId] ?? null;
|
|
958
|
+
}
|
|
959
|
+
let inferenceDiagnostic;
|
|
960
|
+
if (this.isInference() &&
|
|
961
|
+
assignment.operatorAssignments[rootExpressionId] !== "rejected") {
|
|
962
|
+
const root = this.expressions.getExpression(rootExpressionId);
|
|
963
|
+
if (root?.type === "operator") {
|
|
964
|
+
const children = this.expressions.getChildExpressions(root.id);
|
|
965
|
+
const left = children[0];
|
|
966
|
+
const right = children[1];
|
|
967
|
+
if (left && right) {
|
|
968
|
+
const leftValue = expressionValues[left.id];
|
|
969
|
+
const rightValue = expressionValues[right.id];
|
|
970
|
+
if (root.operator === "implies") {
|
|
971
|
+
inferenceDiagnostic = {
|
|
972
|
+
kind: "implies",
|
|
973
|
+
premiseId: this.premise.id,
|
|
974
|
+
rootExpressionId,
|
|
975
|
+
leftValue,
|
|
976
|
+
rightValue,
|
|
977
|
+
rootValue,
|
|
978
|
+
antecedentTrue: leftValue,
|
|
979
|
+
consequentTrue: rightValue,
|
|
980
|
+
isVacuouslyTrue: kleeneNot(leftValue),
|
|
981
|
+
fired: leftValue,
|
|
982
|
+
firedAndHeld: kleeneAnd(leftValue, rightValue),
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
else if (root.operator === "iff") {
|
|
986
|
+
const leftToRight = buildDirectionalVacuity(leftValue, rightValue);
|
|
987
|
+
const rightToLeft = buildDirectionalVacuity(rightValue, leftValue);
|
|
988
|
+
inferenceDiagnostic = {
|
|
989
|
+
kind: "iff",
|
|
990
|
+
premiseId: this.premise.id,
|
|
991
|
+
rootExpressionId,
|
|
992
|
+
leftValue,
|
|
993
|
+
rightValue,
|
|
994
|
+
rootValue,
|
|
995
|
+
leftToRight,
|
|
996
|
+
rightToLeft,
|
|
997
|
+
bothSidesTrue: kleeneAnd(leftValue, rightValue),
|
|
998
|
+
bothSidesFalse: kleeneAnd(kleeneNot(leftValue), kleeneNot(rightValue)),
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
return {
|
|
1005
|
+
premiseId: this.premise.id,
|
|
1006
|
+
premiseType: this.isInference() ? "inference" : "constraint",
|
|
1007
|
+
rootExpressionId,
|
|
1008
|
+
rootValue,
|
|
1009
|
+
expressionValues,
|
|
1010
|
+
variableValues,
|
|
1011
|
+
inferenceDiagnostic,
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
toDisplayString() {
|
|
1015
|
+
if (this.rootExpressionId === undefined) {
|
|
1016
|
+
return "";
|
|
1017
|
+
}
|
|
1018
|
+
return this.renderExpression(this.rootExpressionId);
|
|
1019
|
+
}
|
|
1020
|
+
getReferencedVariableIds() {
|
|
1021
|
+
const ids = new Set();
|
|
1022
|
+
for (const expr of this.expressions.toArray()) {
|
|
1023
|
+
if (expr.type === "variable") {
|
|
1024
|
+
ids.add(expr.variableId);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return ids;
|
|
1028
|
+
}
|
|
1029
|
+
toPremiseData() {
|
|
1030
|
+
this.flushChecksums();
|
|
1031
|
+
return {
|
|
1032
|
+
...this.premise,
|
|
1033
|
+
checksum: this.cachedMetaChecksum,
|
|
1034
|
+
descendantChecksum: this.cachedDescendantChecksum,
|
|
1035
|
+
combinedChecksum: this.cachedCombinedChecksum,
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
checksum() {
|
|
1039
|
+
if (this.checksumDirty || this.cachedMetaChecksum === undefined) {
|
|
1040
|
+
this.flushChecksums();
|
|
1041
|
+
}
|
|
1042
|
+
return this.cachedMetaChecksum;
|
|
1043
|
+
}
|
|
1044
|
+
descendantChecksum() {
|
|
1045
|
+
if (this.checksumDirty || this.cachedDescendantChecksum === undefined) {
|
|
1046
|
+
this.flushChecksums();
|
|
1047
|
+
}
|
|
1048
|
+
return this.cachedDescendantChecksum;
|
|
1049
|
+
}
|
|
1050
|
+
combinedChecksum() {
|
|
1051
|
+
if (this.checksumDirty || this.cachedCombinedChecksum === undefined) {
|
|
1052
|
+
this.flushChecksums();
|
|
1053
|
+
}
|
|
1054
|
+
return this.cachedCombinedChecksum;
|
|
1055
|
+
}
|
|
1056
|
+
getCollectionChecksum(_name) {
|
|
1057
|
+
return this.descendantChecksum();
|
|
1058
|
+
}
|
|
1059
|
+
flushChecksums() {
|
|
1060
|
+
this.expressions.flushExpressionChecksums();
|
|
1061
|
+
const premiseFields = this.checksumConfig?.premiseFields ??
|
|
1062
|
+
DEFAULT_CHECKSUM_CONFIG.premiseFields;
|
|
1063
|
+
this.cachedMetaChecksum = entityChecksum(this.premise, premiseFields);
|
|
1064
|
+
const rootId = this.rootExpressionId;
|
|
1065
|
+
if (rootId) {
|
|
1066
|
+
const rootExpr = this.expressions.getExpression(rootId);
|
|
1067
|
+
this.cachedDescendantChecksum = rootExpr
|
|
1068
|
+
? rootExpr.combinedChecksum
|
|
1069
|
+
: null;
|
|
1070
|
+
}
|
|
1071
|
+
else {
|
|
1072
|
+
this.cachedDescendantChecksum = null;
|
|
1073
|
+
}
|
|
1074
|
+
this.cachedCombinedChecksum =
|
|
1075
|
+
this.cachedDescendantChecksum === null
|
|
1076
|
+
? this.cachedMetaChecksum
|
|
1077
|
+
: computeHash(this.cachedMetaChecksum + this.cachedDescendantChecksum);
|
|
1078
|
+
this.checksumDirty = false;
|
|
1079
|
+
}
|
|
1080
|
+
validate() {
|
|
1081
|
+
const violations = [];
|
|
1082
|
+
const premiseId = this.premise.id;
|
|
1083
|
+
// 1. Schema check (use toPremiseData() to include computed checksums)
|
|
1084
|
+
const premiseData = this.toPremiseData();
|
|
1085
|
+
if (!Value.Check(CorePremiseSchema, premiseData)) {
|
|
1086
|
+
violations.push({
|
|
1087
|
+
code: PREMISE_SCHEMA_INVALID,
|
|
1088
|
+
message: `Premise "${premiseId}" does not conform to CorePremiseSchema.`,
|
|
1089
|
+
entityType: "premise",
|
|
1090
|
+
entityId: premiseId,
|
|
1091
|
+
premiseId,
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
// 2. Delegate to expression-level validation, attaching premiseId
|
|
1095
|
+
const exprResult = this.expressions.validate();
|
|
1096
|
+
for (const v of exprResult.violations) {
|
|
1097
|
+
violations.push({ ...v, premiseId });
|
|
1098
|
+
}
|
|
1099
|
+
// 3. Root expression consistency
|
|
1100
|
+
if (this.rootExpressionId !== undefined) {
|
|
1101
|
+
const rootExpr = this.expressions.getExpression(this.rootExpressionId);
|
|
1102
|
+
if (!rootExpr) {
|
|
1103
|
+
violations.push({
|
|
1104
|
+
code: PREMISE_ROOT_EXPRESSION_INVALID,
|
|
1105
|
+
message: `Premise "${premiseId}" rootExpressionId "${this.rootExpressionId}" does not exist in expression store.`,
|
|
1106
|
+
entityType: "premise",
|
|
1107
|
+
entityId: premiseId,
|
|
1108
|
+
premiseId,
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
else if (rootExpr.parentId !== null) {
|
|
1112
|
+
violations.push({
|
|
1113
|
+
code: PREMISE_ROOT_EXPRESSION_INVALID,
|
|
1114
|
+
message: `Premise "${premiseId}" rootExpressionId "${this.rootExpressionId}" has non-null parentId "${rootExpr.parentId}".`,
|
|
1115
|
+
entityType: "premise",
|
|
1116
|
+
entityId: premiseId,
|
|
1117
|
+
premiseId,
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
// 4. Variable references: every variable-type expression must
|
|
1122
|
+
// reference a variableId that exists in the argument's variable set
|
|
1123
|
+
if (this.variableIdsCallback) {
|
|
1124
|
+
const variableIds = this.variableIdsCallback();
|
|
1125
|
+
for (const expr of this.expressions.toArray()) {
|
|
1126
|
+
if (expr.type === "variable") {
|
|
1127
|
+
const varExpr = expr;
|
|
1128
|
+
if (!variableIds.has(varExpr.variableId)) {
|
|
1129
|
+
violations.push({
|
|
1130
|
+
code: PREMISE_VARIABLE_REF_NOT_FOUND,
|
|
1131
|
+
message: `Expression "${expr.id}" in premise "${premiseId}" references non-existent variable "${varExpr.variableId}".`,
|
|
1132
|
+
entityType: "expression",
|
|
1133
|
+
entityId: expr.id,
|
|
1134
|
+
premiseId,
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
return {
|
|
1141
|
+
ok: violations.length === 0,
|
|
1142
|
+
violations,
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
// -------------------------------------------------------------------------
|
|
1146
|
+
// Private helpers
|
|
1147
|
+
// -------------------------------------------------------------------------
|
|
1148
|
+
/**
|
|
1149
|
+
* Loads expressions in BFS order with the nesting check bypassed.
|
|
1150
|
+
* Bypasses all PremiseEngine validation (ownership, variable existence, circularity)
|
|
1151
|
+
* since restoration paths trust existing data completely.
|
|
1152
|
+
*/
|
|
1153
|
+
loadExpressions(expressions) {
|
|
1154
|
+
this.expressions.loadExpressions(expressions);
|
|
1155
|
+
// Rebuild root and variable tracking after bulk load.
|
|
1156
|
+
for (const expr of this.expressions.toArray()) {
|
|
1157
|
+
if (expr.parentId === null) {
|
|
1158
|
+
this.rootExpressionId = expr.id;
|
|
1159
|
+
}
|
|
1160
|
+
if (expr.type === "variable") {
|
|
1161
|
+
this.expressionsByVariableId.get(expr.variableId).add(expr.id);
|
|
1162
|
+
}
|
|
1163
|
+
if (this.expressionIndex) {
|
|
1164
|
+
this.expressionIndex.set(expr.id, this.premise.id);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
this.markDirty();
|
|
1168
|
+
}
|
|
1169
|
+
markDirty() {
|
|
1170
|
+
this.checksumDirty = true;
|
|
1171
|
+
}
|
|
1172
|
+
/**
|
|
1173
|
+
* Re-reads the single root from ExpressionManager after any operation
|
|
1174
|
+
* that may have caused operator collapse to silently change the root.
|
|
1175
|
+
*/
|
|
1176
|
+
syncRootExpressionId() {
|
|
1177
|
+
const roots = this.expressions.getChildExpressions(null);
|
|
1178
|
+
this.rootExpressionId = roots[0]?.id;
|
|
1179
|
+
}
|
|
1180
|
+
collectSubtree(rootId) {
|
|
1181
|
+
const result = [];
|
|
1182
|
+
const stack = [rootId];
|
|
1183
|
+
while (stack.length > 0) {
|
|
1184
|
+
const id = stack.pop();
|
|
1185
|
+
const expr = this.expressions.getExpression(id);
|
|
1186
|
+
if (!expr)
|
|
1187
|
+
continue;
|
|
1188
|
+
result.push(expr);
|
|
1189
|
+
for (const child of this.expressions.getChildExpressions(id)) {
|
|
1190
|
+
stack.push(child.id);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
return result;
|
|
1194
|
+
}
|
|
1195
|
+
assertBelongsToArgument(argumentId, argumentVersion) {
|
|
1196
|
+
if (argumentId !== this.argument.id) {
|
|
1197
|
+
throw new Error(`Entity argumentId "${argumentId}" does not match engine argument ID "${this.argument.id}".`);
|
|
1198
|
+
}
|
|
1199
|
+
if (argumentVersion !== this.argument.version) {
|
|
1200
|
+
throw new Error(`Entity argumentVersion "${argumentVersion}" does not match engine argument version "${this.argument.version}".`);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
assertVariableExpressionValid(expression) {
|
|
1204
|
+
if (expression.type === "variable" &&
|
|
1205
|
+
!this.variables.hasVariable(expression.variableId)) {
|
|
1206
|
+
throw new Error(`Variable expression "${expression.id}" references non-existent variable "${expression.variableId}".`);
|
|
1207
|
+
}
|
|
1208
|
+
if (expression.type === "variable" && this.circularityCheck) {
|
|
1209
|
+
if (this.circularityCheck(expression.variableId, this.premise.id)) {
|
|
1210
|
+
throw new Error(`Circular binding: variable "${expression.variableId}" is bound to this premise (directly or transitively)`);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
renderExpression(expressionId) {
|
|
1215
|
+
const expression = this.expressions.getExpression(expressionId);
|
|
1216
|
+
if (!expression) {
|
|
1217
|
+
throw new Error(`Expression "${expressionId}" was not found.`);
|
|
1218
|
+
}
|
|
1219
|
+
if (expression.type === "variable") {
|
|
1220
|
+
const variable = this.variables.getVariable(expression.variableId);
|
|
1221
|
+
if (!variable) {
|
|
1222
|
+
throw new Error(`Variable "${expression.variableId}" for expression "${expressionId}" was not found.`);
|
|
1223
|
+
}
|
|
1224
|
+
return variable.symbol;
|
|
1225
|
+
}
|
|
1226
|
+
if (expression.type === "formula") {
|
|
1227
|
+
const children = this.expressions.getChildExpressions(expression.id);
|
|
1228
|
+
if (children.length === 0) {
|
|
1229
|
+
return "(?)";
|
|
1230
|
+
}
|
|
1231
|
+
return `(${this.renderExpression(children[0].id)})`;
|
|
1232
|
+
}
|
|
1233
|
+
const children = this.expressions.getChildExpressions(expression.id);
|
|
1234
|
+
if (expression.operator === "not") {
|
|
1235
|
+
if (children.length === 0) {
|
|
1236
|
+
return `${this.operatorSymbol(expression.operator)} (?)`;
|
|
1237
|
+
}
|
|
1238
|
+
return `${this.operatorSymbol(expression.operator)}(${this.renderExpression(children[0].id)})`;
|
|
1239
|
+
}
|
|
1240
|
+
if (children.length === 0) {
|
|
1241
|
+
return "(?)";
|
|
1242
|
+
}
|
|
1243
|
+
const renderedChildren = children.map((child) => this.renderExpression(child.id));
|
|
1244
|
+
return `(${renderedChildren.join(` ${this.operatorSymbol(expression.operator)} `)})`;
|
|
1245
|
+
}
|
|
1246
|
+
operatorSymbol(operator) {
|
|
1247
|
+
switch (operator) {
|
|
1248
|
+
case "and":
|
|
1249
|
+
return "∧";
|
|
1250
|
+
case "or":
|
|
1251
|
+
return "∨";
|
|
1252
|
+
case "implies":
|
|
1253
|
+
return "→";
|
|
1254
|
+
case "iff":
|
|
1255
|
+
return "↔";
|
|
1256
|
+
case "not":
|
|
1257
|
+
return "¬";
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
snapshot() {
|
|
1261
|
+
this.flushChecksums();
|
|
1262
|
+
const exprSnapshot = this.expressions.snapshot();
|
|
1263
|
+
return {
|
|
1264
|
+
premise: {
|
|
1265
|
+
...this.premise,
|
|
1266
|
+
checksum: this.cachedMetaChecksum,
|
|
1267
|
+
descendantChecksum: this.cachedDescendantChecksum,
|
|
1268
|
+
combinedChecksum: this.cachedCombinedChecksum,
|
|
1269
|
+
},
|
|
1270
|
+
rootExpressionId: this.rootExpressionId,
|
|
1271
|
+
expressions: exprSnapshot,
|
|
1272
|
+
config: {
|
|
1273
|
+
...exprSnapshot.config,
|
|
1274
|
+
checksumConfig: serializeChecksumConfig(this.checksumConfig),
|
|
1275
|
+
},
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
/** Creates a new PremiseEngine from a previously captured snapshot. */
|
|
1279
|
+
static fromSnapshot(snapshot, argument, variables, expressionIndex, grammarConfig, generateId) {
|
|
1280
|
+
// Normalize checksumConfig in case the snapshot went through a JSON
|
|
1281
|
+
// round-trip that converted Sets to arrays or empty objects.
|
|
1282
|
+
const normalizedConfig = snapshot.config
|
|
1283
|
+
? {
|
|
1284
|
+
...snapshot.config,
|
|
1285
|
+
checksumConfig: normalizeChecksumConfig(snapshot.config.checksumConfig),
|
|
1286
|
+
generateId: generateId ?? snapshot.config.generateId,
|
|
1287
|
+
}
|
|
1288
|
+
: generateId
|
|
1289
|
+
? { generateId }
|
|
1290
|
+
: snapshot.config;
|
|
1291
|
+
const pe = new PremiseEngine(snapshot.premise, { argument, variables, expressionIndex }, normalizedConfig);
|
|
1292
|
+
// Restore expressions from the snapshot
|
|
1293
|
+
pe.expressions = ExpressionManager.fromSnapshot(snapshot.expressions, grammarConfig, generateId);
|
|
1294
|
+
// Restore rootExpressionId from snapshot
|
|
1295
|
+
pe.rootExpressionId = snapshot.rootExpressionId;
|
|
1296
|
+
// Rebuild the expressionsByVariableId index
|
|
1297
|
+
pe.rebuildVariableIndex();
|
|
1298
|
+
// Populate the shared expression index if provided
|
|
1299
|
+
if (expressionIndex) {
|
|
1300
|
+
for (const expr of pe.expressions.toArray()) {
|
|
1301
|
+
expressionIndex.set(expr.id, pe.getId());
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
return pe;
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* Flushes hierarchical expression checksums and rebuilds the changeset
|
|
1308
|
+
* so that added/modified expressions carry correct `descendantChecksum`
|
|
1309
|
+
* and `combinedChecksum` values (rather than the stale ones captured
|
|
1310
|
+
* at mutation time by the ChangeCollector).
|
|
1311
|
+
*/
|
|
1312
|
+
finalizeExpressionMutation(collector) {
|
|
1313
|
+
this.syncRootExpressionId();
|
|
1314
|
+
this.markDirty();
|
|
1315
|
+
const changes = this.flushAndBuildChangeset(collector);
|
|
1316
|
+
this.syncExpressionIndex(changes);
|
|
1317
|
+
this.onMutate?.();
|
|
1318
|
+
return changes;
|
|
1319
|
+
}
|
|
1320
|
+
flushAndBuildChangeset(collector) {
|
|
1321
|
+
// Snapshot premise combinedChecksum before flush
|
|
1322
|
+
const premiseCombinedBefore = this.cachedCombinedChecksum ?? null;
|
|
1323
|
+
this.expressions.flushExpressionChecksums();
|
|
1324
|
+
const changes = collector.toChangeset();
|
|
1325
|
+
if (changes.expressions) {
|
|
1326
|
+
changes.expressions.added = changes.expressions.added.map((expr) => {
|
|
1327
|
+
const current = this.expressions.getExpression(expr.id);
|
|
1328
|
+
return current ? { ...current } : expr;
|
|
1329
|
+
});
|
|
1330
|
+
changes.expressions.modified = changes.expressions.modified.map((expr) => {
|
|
1331
|
+
const current = this.expressions.getExpression(expr.id);
|
|
1332
|
+
return current ? { ...current } : expr;
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
// Recompute premise checksum and include if changed
|
|
1336
|
+
this.flushChecksums();
|
|
1337
|
+
if (this.cachedCombinedChecksum !== premiseCombinedBefore) {
|
|
1338
|
+
changes.premises ??= { added: [], modified: [], removed: [] };
|
|
1339
|
+
changes.premises.modified.push(this.toPremiseData());
|
|
1340
|
+
}
|
|
1341
|
+
return changes;
|
|
1342
|
+
}
|
|
1343
|
+
syncExpressionIndex(changes) {
|
|
1344
|
+
if (!this.expressionIndex || !changes.expressions)
|
|
1345
|
+
return;
|
|
1346
|
+
for (const expr of changes.expressions.added) {
|
|
1347
|
+
this.expressionIndex.set(expr.id, this.premise.id);
|
|
1348
|
+
}
|
|
1349
|
+
for (const expr of changes.expressions.removed) {
|
|
1350
|
+
this.expressionIndex.delete(expr.id);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
rebuildVariableIndex() {
|
|
1354
|
+
this.expressionsByVariableId = new DefaultMap(() => new Set());
|
|
1355
|
+
for (const expr of this.expressions.toArray()) {
|
|
1356
|
+
if (expr.type === "variable") {
|
|
1357
|
+
this.expressionsByVariableId.get(expr.variableId).add(expr.id);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
//# sourceMappingURL=premise-engine.js.map
|