@ybotok/loam 0.2.0-alpha.6 → 0.2.0-alpha.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/CHANGELOG.md +1477 -1
- package/COMPARISON.md +91 -3
- package/CONTRIBUTING.md +37 -0
- package/MIGRATING-from-OpenSpec.md +40 -22
- package/QUICKSTART.md +181 -9
- package/README.md +256 -57
- package/ROADMAP.md +108 -11
- package/SCHEMA.md +721 -130
- package/WORKFLOW.md +272 -62
- package/dist/cli.js +26 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +5 -10
- package/dist/commands/adopt/adopt.js.map +1 -1
- package/dist/commands/archive/archive.js +15 -18
- package/dist/commands/archive/archive.js.map +1 -1
- package/dist/commands/archive/plan/contracts/asyncapi.js +27 -41
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/consumers.js +56 -0
- package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +25 -42
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/verdict-lines.js +41 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +3 -7
- package/dist/commands/archive/plan/gate.js.map +1 -1
- package/dist/commands/archive/plan/landscape.js +4 -4
- package/dist/commands/archive/plan/landscape.js.map +1 -1
- package/dist/commands/archive/plan/refusal.js +8 -18
- package/dist/commands/archive/plan/refusal.js.map +1 -1
- package/dist/commands/archive/plan/specs.js +134 -25
- package/dist/commands/archive/plan/specs.js.map +1 -1
- package/dist/commands/archive/plan/state.js +1 -0
- package/dist/commands/archive/plan/state.js.map +1 -1
- package/dist/commands/archive/run.js +82 -33
- package/dist/commands/archive/run.js.map +1 -1
- package/dist/commands/archive/shipped.js +49 -0
- package/dist/commands/archive/shipped.js.map +1 -0
- package/dist/commands/context/context.js +4 -7
- package/dist/commands/context/context.js.map +1 -1
- package/dist/commands/context/print.js +2 -2
- package/dist/commands/context/print.js.map +1 -1
- package/dist/commands/delta/delta.js +44 -12
- package/dist/commands/delta/delta.js.map +1 -1
- package/dist/commands/delta/print.js +1 -1
- package/dist/commands/delta/print.js.map +1 -1
- package/dist/commands/dependencies.js +3 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +20 -27
- package/dist/commands/diff/diff.js.map +1 -1
- package/dist/commands/explore.js +4 -8
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +45 -8
- package/dist/commands/gate/gate.js.map +1 -1
- package/dist/commands/gate/print.js +15 -3
- package/dist/commands/gate/print.js.map +1 -1
- package/dist/commands/gherkin/commit.js +13 -54
- package/dist/commands/gherkin/commit.js.map +1 -1
- package/dist/commands/gherkin/gherkin.js +36 -20
- package/dist/commands/gherkin/gherkin.js.map +1 -1
- package/dist/commands/gherkin/reconcile.js +10 -13
- package/dist/commands/gherkin/reconcile.js.map +1 -1
- package/dist/commands/init/first-hour.js +44 -0
- package/dist/commands/init/first-hour.js.map +1 -1
- package/dist/commands/init/init.js +18 -22
- package/dist/commands/init/init.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +4 -6
- package/dist/commands/list/campaign/campaign.js.map +1 -1
- package/dist/commands/list/json.js +0 -4
- package/dist/commands/list/json.js.map +1 -1
- package/dist/commands/list/list.js +38 -23
- package/dist/commands/list/list.js.map +1 -1
- package/dist/commands/list/print.js +38 -6
- package/dist/commands/list/print.js.map +1 -1
- package/dist/commands/list/suites/suites.js +140 -0
- package/dist/commands/list/suites/suites.js.map +1 -0
- package/dist/commands/list/views.js +28 -33
- package/dist/commands/list/views.js.map +1 -1
- package/dist/commands/mcp/dispatch.js +91 -36
- package/dist/commands/mcp/dispatch.js.map +1 -1
- package/dist/commands/mcp/mcp.js +56 -15
- package/dist/commands/mcp/mcp.js.map +1 -1
- package/dist/commands/mcp/serve.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/active.js +27 -22
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/target.js +2 -2
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/error.js +7 -8
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
- package/dist/commands/new/capability-template.js +118 -0
- package/dist/commands/new/capability-template.js.map +1 -0
- package/dist/commands/new/commit.js +8 -22
- package/dist/commands/new/commit.js.map +1 -1
- package/dist/commands/new/modifies.js +206 -0
- package/dist/commands/new/modifies.js.map +1 -0
- package/dist/commands/new/new.js +59 -14
- package/dist/commands/new/new.js.map +1 -1
- package/dist/commands/new/templates.js +48 -124
- package/dist/commands/new/templates.js.map +1 -1
- package/dist/commands/open.js +3 -7
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/policy/gate.js +27 -0
- package/dist/commands/policy/gate.js.map +1 -1
- package/dist/commands/rebase/plan.js +2 -2
- package/dist/commands/rebase/plan.js.map +1 -1
- package/dist/commands/rebase/rebase.js +60 -35
- package/dist/commands/rebase/rebase.js.map +1 -1
- package/dist/commands/seed/commit.js +55 -26
- package/dist/commands/seed/commit.js.map +1 -1
- package/dist/commands/seed/plan.js +64 -13
- package/dist/commands/seed/plan.js.map +1 -1
- package/dist/commands/seed/seed.js +6 -9
- package/dist/commands/seed/seed.js.map +1 -1
- package/dist/commands/show/show.js +3 -7
- package/dist/commands/show/show.js.map +1 -1
- package/dist/commands/status/print.js +13 -4
- package/dist/commands/status/print.js.map +1 -1
- package/dist/commands/status/status.js +3 -7
- package/dist/commands/status/status.js.map +1 -1
- package/dist/commands/steps/steps.js +3 -7
- package/dist/commands/steps/steps.js.map +1 -1
- package/dist/commands/subsystem/edit.js +7 -7
- package/dist/commands/subsystem/edit.js.map +1 -1
- package/dist/commands/subsystem/move.js +60 -25
- package/dist/commands/subsystem/move.js.map +1 -1
- package/dist/commands/subsystem/query.js +2 -4
- package/dist/commands/subsystem/query.js.map +1 -1
- package/dist/commands/subsystem/subsystem.js +4 -7
- package/dist/commands/subsystem/subsystem.js.map +1 -1
- package/dist/commands/subsystem/sync.js +141 -71
- package/dist/commands/subsystem/sync.js.map +1 -1
- package/dist/commands/subsystem/txn/report.js +55 -5
- package/dist/commands/subsystem/txn/report.js.map +1 -1
- package/dist/commands/subsystem/txn/txn.js +121 -45
- package/dist/commands/subsystem/txn/txn.js.map +1 -1
- package/dist/commands/subsystem/txn/views.js +82 -12
- package/dist/commands/subsystem/txn/views.js.map +1 -1
- package/dist/commands/tasks/render.js +116 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +113 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +6 -9
- package/dist/commands/unarchive/manifest.js.map +1 -1
- package/dist/commands/unarchive/restore.js +17 -28
- package/dist/commands/unarchive/restore.js.map +1 -1
- package/dist/commands/unarchive/unarchive.js +22 -30
- package/dist/commands/unarchive/unarchive.js.map +1 -1
- package/dist/commands/validate/arch-coverage.js +6 -15
- package/dist/commands/validate/arch-coverage.js.map +1 -1
- package/dist/commands/validate/checks/fleet-shape.js +4 -49
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
- package/dist/commands/validate/checks/health-deps.js +9 -6
- package/dist/commands/validate/checks/health-deps.js.map +1 -1
- package/dist/commands/validate/checks/requirements.js +18 -8
- package/dist/commands/validate/checks/requirements.js.map +1 -1
- package/dist/commands/validate/checks/sources.js +6 -2
- package/dist/commands/validate/checks/sources.js.map +1 -1
- package/dist/commands/validate/feature.js +23 -19
- package/dist/commands/validate/feature.js.map +1 -1
- package/dist/commands/validate/fleet/census.js +26 -3
- package/dist/commands/validate/fleet/census.js.map +1 -1
- package/dist/commands/validate/fleet/landscape.js +35 -32
- package/dist/commands/validate/fleet/landscape.js.map +1 -1
- package/dist/commands/validate/fleet/map/attest.js +7 -12
- package/dist/commands/validate/fleet/map/attest.js.map +1 -1
- package/dist/commands/validate/fleet/map/bindings.js +16 -5
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -1
- package/dist/commands/validate/fleet/map/consumers.js +43 -122
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -1
- package/dist/commands/validate/fleet/map/usecases.js +5 -11
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -1
- package/dist/commands/validate/fleet/obligations.js +1 -5
- package/dist/commands/validate/fleet/obligations.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/print.js +5 -1
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
- package/dist/commands/validate/fleet/usecases/usecases.js +6 -4
- package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -1
- package/dist/commands/validate/fleet/views/fleet-project.js +1 -1
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -1
- package/dist/commands/validate/fleet/views/ids.js +33 -7
- package/dist/commands/validate/fleet/views/ids.js.map +1 -1
- package/dist/commands/validate/fleet/views/root-documents.js +17 -35
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -1
- package/dist/commands/validate/fleet/views/stale.js +31 -14
- package/dist/commands/validate/fleet/views/stale.js.map +1 -1
- package/dist/commands/validate/links/corpus.js +1 -4
- package/dist/commands/validate/links/corpus.js.map +1 -1
- package/dist/commands/validate/links/glossary.js.map +1 -1
- package/dist/commands/validate/report.js +5 -4
- package/dist/commands/validate/report.js.map +1 -1
- package/dist/commands/validate/scope.js +113 -0
- package/dist/commands/validate/scope.js.map +1 -0
- package/dist/commands/validate/service/api.js +16 -104
- package/dist/commands/validate/service/api.js.map +1 -1
- package/dist/commands/validate/service/contracts/generated.js +134 -0
- package/dist/commands/validate/service/contracts/generated.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +1 -1
- package/dist/commands/validate/service/events/events.js.map +1 -1
- package/dist/commands/validate/service/events/message-producers.js +1 -1
- package/dist/commands/validate/service/events/message-producers.js.map +1 -1
- package/dist/commands/validate/service/evidence-pins.js +56 -10
- package/dist/commands/validate/service/evidence-pins.js.map +1 -1
- package/dist/commands/validate/service/service.js +16 -26
- package/dist/commands/validate/service/service.js.map +1 -1
- package/dist/commands/validate/service/specs.js +31 -38
- package/dist/commands/validate/service/specs.js.map +1 -1
- package/dist/commands/validate/service/spine.js +8 -11
- package/dist/commands/validate/service/spine.js.map +1 -1
- package/dist/commands/validate/service/usecases/usecases.js +3 -3
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -1
- package/dist/commands/validate/validate.js +44 -26
- package/dist/commands/validate/validate.js.map +1 -1
- package/dist/commands/verify/cross/diff.js +2 -6
- package/dist/commands/verify/cross/diff.js.map +1 -1
- package/dist/commands/verify/evidence/contract.js +1 -1
- package/dist/commands/verify/evidence/contract.js.map +1 -1
- package/dist/commands/verify/evidence/read.js +12 -3
- package/dist/commands/verify/evidence/read.js.map +1 -1
- package/dist/commands/verify/frozen.js +45 -23
- package/dist/commands/verify/frozen.js.map +1 -1
- package/dist/commands/verify/record.js +69 -17
- package/dist/commands/verify/record.js.map +1 -1
- package/dist/commands/verify/report.js +27 -44
- package/dist/commands/verify/report.js.map +1 -1
- package/dist/commands/verify/results.js +112 -30
- package/dist/commands/verify/results.js.map +1 -1
- package/dist/commands/verify/verify.js +54 -51
- package/dist/commands/verify/verify.js.map +1 -1
- package/dist/commands/vouch/pack/pack.js +2 -2
- package/dist/commands/vouch/pack/pack.js.map +1 -1
- package/dist/commands/vouch/pack/print.js +1 -6
- package/dist/commands/vouch/pack/print.js.map +1 -1
- package/dist/commands/vouch/pack/sections.js +1 -2
- package/dist/commands/vouch/pack/sections.js.map +1 -1
- package/dist/commands/vouch/run.js +26 -81
- package/dist/commands/vouch/run.js.map +1 -1
- package/dist/commands/vouch/sample/plan.js +20 -34
- package/dist/commands/vouch/sample/plan.js.map +1 -1
- package/dist/commands/vouch/vet/verify.js +39 -7
- package/dist/commands/vouch/vet/verify.js.map +1 -1
- package/dist/commands/vouch/vouch.js +10 -17
- package/dist/commands/vouch/vouch.js.map +1 -1
- package/dist/core/agent/agents-md/command-map.js +57 -102
- package/dist/core/agent/agents-md/command-map.js.map +1 -1
- package/dist/core/agent/agents-md/map/explain.js +4 -3
- package/dist/core/agent/agents-md/map/explain.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/context.js +4 -3
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
- package/dist/core/agent/agents-md/map/mcp.js +10 -7
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
- package/dist/core/agent/agents-md/map/status.js +9 -3
- package/dist/core/agent/agents-md/map/status.js.map +1 -1
- package/dist/core/agent/agents-md/map/subsystem.js +31 -17
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
- package/dist/core/agent/agents-md/map/usecases.js +24 -6
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
- package/dist/core/agent/agents-md/refusals.js +37 -21
- package/dist/core/agent/agents-md/refusals.js.map +1 -1
- package/dist/core/agent/agents-md.js +25 -10
- package/dist/core/agent/agents-md.js.map +1 -1
- package/dist/core/agent/agents-stamp.js +10 -0
- package/dist/core/agent/agents-stamp.js.map +1 -1
- package/dist/core/agent/scaffold.js +10 -15
- package/dist/core/agent/scaffold.js.map +1 -1
- package/dist/core/agent/tools/dialects.js +1 -0
- package/dist/core/agent/tools/dialects.js.map +1 -1
- package/dist/core/agent/tools/registry.js +41 -76
- package/dist/core/agent/tools/registry.js.map +1 -1
- package/dist/core/agent/workflows/adopt.js +5 -3
- package/dist/core/agent/workflows/adopt.js.map +1 -1
- package/dist/core/agent/workflows/check.js +25 -22
- package/dist/core/agent/workflows/check.js.map +1 -1
- package/dist/core/agent/workflows/closing.js +54 -21
- package/dist/core/agent/workflows/closing.js.map +1 -1
- package/dist/core/agent/workflows/feature.js +79 -11
- package/dist/core/agent/workflows/feature.js.map +1 -1
- package/dist/core/agent/workflows/implement.js +91 -13
- package/dist/core/agent/workflows/implement.js.map +1 -1
- package/dist/core/agent/workflows/reference/authoring.js +3 -1
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
- package/dist/core/agent/workflows/reference/codes.js +8 -6
- package/dist/core/agent/workflows/reference/codes.js.map +1 -1
- package/dist/core/agent/workflows/reference/done-check.js +37 -15
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
- package/dist/core/agent/workflows/reference/reference.js.map +1 -1
- package/dist/core/agent/workflows/reference/spine.js +62 -24
- package/dist/core/agent/workflows/reference/spine.js.map +1 -1
- package/dist/core/asyncapi/baseline/plan.js +14 -81
- package/dist/core/asyncapi/baseline/plan.js.map +1 -1
- package/dist/core/asyncapi/digest.js +30 -25
- package/dist/core/asyncapi/digest.js.map +1 -1
- package/dist/core/asyncapi/merge/components.js +5 -4
- package/dist/core/asyncapi/merge/components.js.map +1 -1
- package/dist/core/asyncapi/merge/error.js +7 -2
- package/dist/core/asyncapi/merge/error.js.map +1 -1
- package/dist/core/asyncapi/merge/markers.js +30 -50
- package/dist/core/asyncapi/merge/markers.js.map +1 -1
- package/dist/core/asyncapi/merge/merge.js +31 -53
- package/dist/core/asyncapi/merge/merge.js.map +1 -1
- package/dist/core/asyncapi/merge/pin.js +10 -36
- package/dist/core/asyncapi/merge/pin.js.map +1 -1
- package/dist/core/asyncapi/model.js.map +1 -1
- package/dist/core/asyncapi/read.js +36 -12
- package/dist/core/asyncapi/read.js.map +1 -1
- package/dist/core/brief/brief.js +30 -25
- package/dist/core/brief/brief.js.map +1 -1
- package/dist/core/brief/landscape.js +8 -12
- package/dist/core/brief/landscape.js.map +1 -1
- package/dist/core/brief/map/extend.js +8 -5
- package/dist/core/brief/map/extend.js.map +1 -1
- package/dist/core/brief/map/owed.js +8 -26
- package/dist/core/brief/map/owed.js.map +1 -1
- package/dist/core/brief/targets.js +79 -5
- package/dist/core/brief/targets.js.map +1 -1
- package/dist/core/brief/unchecked.js +1 -1
- package/dist/core/brief/unchecked.js.map +1 -1
- package/dist/core/c4/likec4.js +147 -16
- package/dist/core/c4/likec4.js.map +1 -1
- package/dist/core/c4/locate/unlocated.js +150 -0
- package/dist/core/c4/locate/unlocated.js.map +1 -0
- package/dist/core/c4/parsed/values.js +54 -1
- package/dist/core/c4/parsed/values.js.map +1 -1
- package/dist/core/c4/prefetch/fleet.js +1 -9
- package/dist/core/c4/prefetch/fleet.js.map +1 -1
- package/dist/core/c4/project/architecture.js +31 -9
- package/dist/core/c4/project/architecture.js.map +1 -1
- package/dist/core/c4/project/documents.js +36 -10
- package/dist/core/c4/project/documents.js.map +1 -1
- package/dist/core/c4/project/load.js +14 -21
- package/dist/core/c4/project/load.js.map +1 -1
- package/dist/core/c4/project/staged.js +7 -3
- package/dist/core/c4/project/staged.js.map +1 -1
- package/dist/core/c4/resolve/external.js +51 -0
- package/dist/core/c4/resolve/external.js.map +1 -0
- package/dist/core/c4/resolve/service.js +25 -1
- package/dist/core/c4/resolve/service.js.map +1 -1
- package/dist/core/c4/seed/template.js +15 -1
- package/dist/core/c4/seed/template.js.map +1 -1
- package/dist/core/c4/service-model/shape.js +2 -22
- package/dist/core/c4/service-model/shape.js.map +1 -1
- package/dist/core/c4/source-mask.js +288 -4
- package/dist/core/c4/source-mask.js.map +1 -1
- package/dist/core/c4/source-scan.js +203 -147
- package/dist/core/c4/source-scan.js.map +1 -1
- package/dist/core/c4/splice/authored-source.js +19 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -1
- package/dist/core/c4/splice/delta-blocks.js +5 -18
- package/dist/core/c4/splice/delta-blocks.js.map +1 -1
- package/dist/core/c4/splice/landscape-merge.js +13 -8
- package/dist/core/c4/splice/landscape-merge.js.map +1 -1
- package/dist/core/c4/splice/model/merge.js +10 -6
- package/dist/core/c4/splice/model/merge.js.map +1 -1
- package/dist/core/c4/splice/placement.js +108 -18
- package/dist/core/c4/splice/placement.js.map +1 -1
- package/dist/core/c4/workspace.js +13 -22
- package/dist/core/c4/workspace.js.map +1 -1
- package/dist/core/capabilities/capabilities.js +6 -6
- package/dist/core/capabilities/capabilities.js.map +1 -1
- package/dist/core/capabilities/delta/doc.js +7 -10
- package/dist/core/capabilities/delta/doc.js.map +1 -1
- package/dist/core/capabilities/findings.js +15 -20
- package/dist/core/capabilities/findings.js.map +1 -1
- package/dist/core/capabilities/realizes/findings.js +12 -19
- package/dist/core/capabilities/realizes/findings.js.map +1 -1
- package/dist/core/capabilities/realizes/join.js +0 -20
- package/dist/core/capabilities/realizes/join.js.map +1 -1
- package/dist/core/capabilities/rollup.js +6 -0
- package/dist/core/capabilities/rollup.js.map +1 -1
- package/dist/core/capabilities/tree.js +6 -28
- package/dist/core/capabilities/tree.js.map +1 -1
- package/dist/core/capabilities/usecase-join.js +3 -13
- package/dist/core/capabilities/usecase-join.js.map +1 -1
- package/dist/core/coherence/authoring/scaffold.js +11 -3
- package/dist/core/coherence/authoring/scaffold.js.map +1 -1
- package/dist/core/coherence/authoring/sentinels.js +2 -1
- package/dist/core/coherence/authoring/sentinels.js.map +1 -1
- package/dist/core/coherence/coherence.js +30 -16
- package/dist/core/coherence/coherence.js.map +1 -1
- package/dist/core/coherence/consumed/operations.js +70 -0
- package/dist/core/coherence/consumed/operations.js.map +1 -0
- package/dist/core/coherence/consumed/refusal.js +38 -0
- package/dist/core/coherence/consumed/refusal.js.map +1 -0
- package/dist/core/coherence/declared.js +60 -34
- package/dist/core/coherence/declared.js.map +1 -1
- package/dist/core/coherence/events/declared.js +44 -59
- package/dist/core/coherence/events/declared.js.map +1 -1
- package/dist/core/coherence/events/events.js +119 -8
- package/dist/core/coherence/events/events.js.map +1 -1
- package/dist/core/coherence/events/grades.js +31 -8
- package/dist/core/coherence/events/grades.js.map +1 -1
- package/dist/core/coherence/events/lookups.js +14 -82
- package/dist/core/coherence/events/lookups.js.map +1 -1
- package/dist/core/coherence/lookups.js +18 -78
- package/dist/core/coherence/lookups.js.map +1 -1
- package/dist/core/coherence/retired/archived.js +285 -0
- package/dist/core/coherence/retired/archived.js.map +1 -0
- package/dist/core/coherence/retired/event-pair.js +62 -0
- package/dist/core/coherence/retired/event-pair.js.map +1 -0
- package/dist/core/coherence/retired/merged.js +79 -0
- package/dist/core/coherence/retired/merged.js.map +1 -0
- package/dist/core/coherence/retired/retirement.js +49 -0
- package/dist/core/coherence/retired/retirement.js.map +1 -0
- package/dist/core/coherence/retired/revival/arrivals.js +131 -0
- package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
- package/dist/core/coherence/retired/revival/revived.js +297 -0
- package/dist/core/coherence/retired/revival/revived.js.map +1 -0
- package/dist/core/consumers/after.js +113 -0
- package/dist/core/consumers/after.js.map +1 -0
- package/dist/core/consumers/consumers.js +296 -0
- package/dist/core/consumers/consumers.js.map +1 -0
- package/dist/core/consumers/current.js +211 -0
- package/dist/core/consumers/current.js.map +1 -0
- package/dist/core/consumers/scan.js +46 -0
- package/dist/core/consumers/scan.js.map +1 -0
- package/dist/core/consumers/state.js +27 -0
- package/dist/core/consumers/state.js.map +1 -0
- package/dist/core/delta/delta.js +1 -1
- package/dist/core/delta/delta.js.map +1 -1
- package/dist/core/deployment/delta.js +15 -16
- package/dist/core/deployment/delta.js.map +1 -1
- package/dist/core/diff/base-git.js +94 -12
- package/dist/core/diff/base-git.js.map +1 -1
- package/dist/core/diff/base-state.js +28 -16
- package/dist/core/diff/base-state.js.map +1 -1
- package/dist/core/diff/joins.js +136 -0
- package/dist/core/diff/joins.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +22 -6
- package/dist/core/diff/scope/changed-paths.js.map +1 -1
- package/dist/core/diff/scope/edges.js +82 -0
- package/dist/core/diff/scope/edges.js.map +1 -0
- package/dist/core/diff/semantic.js +100 -31
- package/dist/core/diff/semantic.js.map +1 -1
- package/dist/core/doctor/agents.js +34 -18
- package/dist/core/doctor/agents.js.map +1 -1
- package/dist/core/doctor/report.js.map +1 -1
- package/dist/core/document/apply.js +10 -2
- package/dist/core/document/apply.js.map +1 -1
- package/dist/core/document/frontmatter.js +55 -0
- package/dist/core/document/frontmatter.js.map +1 -1
- package/dist/core/document/parse.js +29 -6
- package/dist/core/document/parse.js.map +1 -1
- package/dist/core/document/scenarios.js +17 -0
- package/dist/core/document/scenarios.js.map +1 -1
- package/dist/core/document/spec.js +4 -11
- package/dist/core/document/spec.js.map +1 -1
- package/dist/core/envelope/config.js +10 -0
- package/dist/core/envelope/config.js.map +1 -1
- package/dist/core/envelope/json.js +34 -0
- package/dist/core/envelope/json.js.map +1 -1
- package/dist/core/explain/families.js +17 -12
- package/dist/core/explain/families.js.map +1 -1
- package/dist/core/explain/refusals.js +3 -3
- package/dist/core/explain/refusals.js.map +1 -1
- package/dist/core/explain/terms.js +18 -9
- package/dist/core/explain/terms.js.map +1 -1
- package/dist/core/explore/explore.js +2 -7
- package/dist/core/explore/explore.js.map +1 -1
- package/dist/core/fleet-context.js +34 -95
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +10 -3
- package/dist/core/gate/checks.js.map +1 -1
- package/dist/core/gate/partners.js +64 -19
- package/dist/core/gate/partners.js.map +1 -1
- package/dist/core/gate/report.js.map +1 -1
- package/dist/core/gate/verification.js +75 -12
- package/dist/core/gate/verification.js.map +1 -1
- package/dist/core/gherkin/stale.js +13 -37
- package/dist/core/gherkin/stale.js.map +1 -1
- package/dist/core/glossary/tree.js +6 -19
- package/dist/core/glossary/tree.js.map +1 -1
- package/dist/core/kernel/concurrency.js +19 -0
- package/dist/core/kernel/concurrency.js.map +1 -1
- package/dist/core/kernel/records.js +11 -0
- package/dist/core/kernel/records.js.map +1 -1
- package/dist/core/links/backlinks.js +1 -3
- package/dist/core/links/backlinks.js.map +1 -1
- package/dist/core/links/corpus.js +5 -36
- package/dist/core/links/corpus.js.map +1 -1
- package/dist/core/mcp/argv.js +101 -0
- package/dist/core/mcp/argv.js.map +1 -1
- package/dist/core/mcp/author-tools.js +2 -1
- package/dist/core/mcp/author-tools.js.map +1 -1
- package/dist/core/mcp/protocol.js +2 -2
- package/dist/core/mcp/protocol.js.map +1 -1
- package/dist/core/mcp/tools.js +43 -33
- package/dist/core/mcp/tools.js.map +1 -1
- package/dist/core/openapi/baseline/gate.js +53 -12
- package/dist/core/openapi/baseline/gate.js.map +1 -1
- package/dist/core/openapi/baseline/plan.js +22 -8
- package/dist/core/openapi/baseline/plan.js.map +1 -1
- package/dist/core/openapi/baseline/record.js +0 -1
- package/dist/core/openapi/baseline/record.js.map +1 -1
- package/dist/core/openapi/contract-text.js +33 -0
- package/dist/core/openapi/contract-text.js.map +1 -0
- package/dist/core/openapi/contract-tree.js +56 -0
- package/dist/core/openapi/contract-tree.js.map +1 -0
- package/dist/core/openapi/depth.js +38 -24
- package/dist/core/openapi/depth.js.map +1 -1
- package/dist/core/openapi/digest.js +52 -2
- package/dist/core/openapi/digest.js.map +1 -1
- package/dist/core/openapi/doc.js +12 -4
- package/dist/core/openapi/doc.js.map +1 -1
- package/dist/core/openapi/merge/components.js +25 -60
- package/dist/core/openapi/merge/components.js.map +1 -1
- package/dist/core/openapi/merge/error.js +3 -13
- package/dist/core/openapi/merge/error.js.map +1 -1
- package/dist/core/openapi/merge/markers.js +26 -30
- package/dist/core/openapi/merge/markers.js.map +1 -1
- package/dist/core/openapi/merge/merge.js +26 -52
- package/dist/core/openapi/merge/merge.js.map +1 -1
- package/dist/core/openapi/merge/pin.js +15 -35
- package/dist/core/openapi/merge/pin.js.map +1 -1
- package/dist/core/openspec/decide/verdict.js.map +1 -1
- package/dist/core/openspec/inventory.js +4 -5
- package/dist/core/openspec/inventory.js.map +1 -1
- package/dist/core/openspec/model/mapping.js +30 -28
- package/dist/core/openspec/model/mapping.js.map +1 -1
- package/dist/core/openspec/model/model.js +12 -7
- package/dist/core/openspec/model/model.js.map +1 -1
- package/dist/core/openspec/scan/changes.js +10 -4
- package/dist/core/openspec/scan/changes.js.map +1 -1
- package/dist/core/openspec/scan/config.js +7 -16
- package/dist/core/openspec/scan/config.js.map +1 -1
- package/dist/core/openspec/scan/shape.js +63 -19
- package/dist/core/openspec/scan/shape.js.map +1 -1
- package/dist/core/openspec/scan/walk.js +21 -38
- package/dist/core/openspec/scan/walk.js.map +1 -1
- package/dist/core/pack/living.js +2 -16
- package/dist/core/pack/living.js.map +1 -1
- package/dist/core/provenance/findings.js +48 -12
- package/dist/core/provenance/findings.js.map +1 -1
- package/dist/core/provenance/git.js +33 -57
- package/dist/core/provenance/git.js.map +1 -1
- package/dist/core/provenance/gitq/moves.js +71 -114
- package/dist/core/provenance/gitq/moves.js.map +1 -1
- package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
- package/dist/core/provenance/sources.js +23 -6
- package/dist/core/provenance/sources.js.map +1 -1
- package/dist/core/provenance/stamp.js +5 -17
- package/dist/core/provenance/stamp.js.map +1 -1
- package/dist/core/repo/entries.js.map +1 -1
- package/dist/core/repo/paths.js +34 -29
- package/dist/core/repo/paths.js.map +1 -1
- package/dist/core/repo/repo.js +24 -14
- package/dist/core/repo/repo.js.map +1 -1
- package/dist/core/repo/tree/find.js +12 -3
- package/dist/core/repo/tree/find.js.map +1 -1
- package/dist/core/repo/tree/fs.js +27 -1
- package/dist/core/repo/tree/fs.js.map +1 -1
- package/dist/core/repo/tree/render/body.js +45 -6
- package/dist/core/repo/tree/render/body.js.map +1 -1
- package/dist/core/repo/tree/render/service/header.js +125 -0
- package/dist/core/repo/tree/render/service/header.js.map +1 -0
- package/dist/core/repo/tree/render/service/peers.js +28 -0
- package/dist/core/repo/tree/render/service/peers.js.map +1 -0
- package/dist/core/repo/tree/render/service/view-id.js +67 -0
- package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
- package/dist/core/repo/tree/render/service/views.js +78 -0
- package/dist/core/repo/tree/render/service/views.js.map +1 -0
- package/dist/core/repo/tree/render/stale.js +19 -2
- package/dist/core/repo/tree/render/stale.js.map +1 -1
- package/dist/core/repo/tree/render/views.js +102 -33
- package/dist/core/repo/tree/render/views.js.map +1 -1
- package/dist/core/repo/tree/walk.js +8 -30
- package/dist/core/repo/tree/walk.js.map +1 -1
- package/dist/core/results.js +47 -12
- package/dist/core/results.js.map +1 -1
- package/dist/core/staging/commit.js +10 -12
- package/dist/core/staging/commit.js.map +1 -1
- package/dist/core/staging/lock.js +74 -12
- package/dist/core/staging/lock.js.map +1 -1
- package/dist/core/staging/recovery/intent.js +2 -5
- package/dist/core/staging/recovery/intent.js.map +1 -1
- package/dist/core/staging/recovery/recover.js +60 -1
- package/dist/core/staging/recovery/recover.js.map +1 -1
- package/dist/core/staging/snapshot/manifest.js +152 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +10 -34
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/status/actions/execution.js +11 -0
- package/dist/core/status/actions/execution.js.map +1 -1
- package/dist/core/status/feature/artifacts.js +2 -2
- package/dist/core/status/feature/artifacts.js.map +1 -1
- package/dist/core/status/feature/feature.js +5 -11
- package/dist/core/status/feature/feature.js.map +1 -1
- package/dist/core/status/fleet/fleet.js +6 -2
- package/dist/core/status/fleet/fleet.js.map +1 -1
- package/dist/core/status/fleet/next.js +26 -3
- package/dist/core/status/fleet/next.js.map +1 -1
- package/dist/core/status/report.js.map +1 -1
- package/dist/core/status/verification.js +30 -15
- package/dist/core/status/verification.js.map +1 -1
- package/dist/core/tasks/packet.js +174 -0
- package/dist/core/tasks/packet.js.map +1 -0
- package/dist/core/tasks/record.js +43 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/sources.js +181 -0
- package/dist/core/tasks/sources.js.map +1 -0
- package/dist/core/tasks/stamps.js +76 -0
- package/dist/core/tasks/stamps.js.map +1 -0
- package/dist/core/tasks/unit.js +0 -0
- package/dist/core/tasks/unit.js.map +1 -0
- package/dist/core/usecases/capability.js +11 -14
- package/dist/core/usecases/capability.js.map +1 -1
- package/dist/core/usecases/delta/flows.js +5 -7
- package/dist/core/usecases/delta/flows.js.map +1 -1
- package/dist/core/usecases/fleet.js +178 -31
- package/dist/core/usecases/fleet.js.map +1 -1
- package/dist/core/usecases/operations.js +5 -4
- package/dist/core/usecases/operations.js.map +1 -1
- package/dist/core/usecases/service/flows.js +9 -6
- package/dist/core/usecases/service/flows.js.map +1 -1
- package/dist/core/usecases/suites/participants.js +83 -0
- package/dist/core/usecases/suites/participants.js.map +1 -0
- package/dist/core/usecases/suites/suites.js +45 -0
- package/dist/core/usecases/suites/suites.js.map +1 -0
- package/dist/core/verify/answers.js +12 -5
- package/dist/core/verify/answers.js.map +1 -1
- package/dist/core/verify/build.js +102 -82
- package/dist/core/verify/build.js.map +1 -1
- package/dist/core/verify/checklist.js +45 -10
- package/dist/core/verify/checklist.js.map +1 -1
- package/dist/core/verify/location.js +67 -0
- package/dist/core/verify/location.js.map +1 -0
- package/dist/core/verify/pins/lint.js +3 -2
- package/dist/core/verify/pins/lint.js.map +1 -1
- package/dist/core/verify/pins/pin.js +1 -1
- package/dist/core/verify/pins/pin.js.map +1 -1
- package/dist/core/verify/read/file.js +224 -0
- package/dist/core/verify/read/file.js.map +1 -0
- package/dist/core/verify/{file.js → read/shape.js} +16 -104
- package/dist/core/verify/read/shape.js.map +1 -0
- package/dist/core/verify/read/union.js +105 -0
- package/dist/core/verify/read/union.js.map +1 -0
- package/dist/core/verify/record.js +35 -12
- package/dist/core/verify/record.js.map +1 -1
- package/dist/core/verify/store/commit.js +40 -30
- package/dist/core/verify/store/commit.js.map +1 -1
- package/dist/core/verify/store/render.js +8 -4
- package/dist/core/verify/store/render.js.map +1 -1
- package/dist/core/vocabulary/issue.js +1 -0
- package/dist/core/vocabulary/issue.js.map +1 -1
- package/dist/core/vocabulary/maturity.js +53 -3
- package/dist/core/vocabulary/maturity.js.map +1 -1
- package/examples/README.md +28 -9
- package/examples/docs/architecture/landscape.likec4 +21 -7
- package/examples/docs/architecture/services.likec4 +70 -0
- package/examples/docs/architecture/subsystems.likec4 +3 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +6 -2
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
- package/examples/docs/services/order-service/asyncapi.yaml +3 -2
- package/examples/docs/services/order-service/model.likec4 +10 -8
- package/examples/docs/services/payment-service/model.likec4 +6 -4
- package/examples/docs/services/platform/identity-service/model.likec4 +9 -7
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
- package/examples/docs/services/platform/notification-service/model.likec4 +4 -5
- package/package.json +1 -1
- package/dist/commands/validate/checks/vocabulary.js +0 -16
- package/dist/commands/validate/checks/vocabulary.js.map +0 -1
- package/dist/core/agent/agents-md/artifacts.js +0 -221
- package/dist/core/agent/agents-md/artifacts.js.map +0 -1
- package/dist/core/agent/agents-md/cycle.js +0 -180
- package/dist/core/agent/agents-md/cycle.js.map +0 -1
- package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
- package/dist/core/agent/agents-md/spine.js +0 -40
- package/dist/core/agent/agents-md/spine.js.map +0 -1
- package/dist/core/coherence/events/merged.js +0 -40
- package/dist/core/coherence/events/merged.js.map +0 -1
- package/dist/core/diff/current-state.js +0 -96
- package/dist/core/diff/current-state.js.map +0 -1
- package/dist/core/diff/victims.js +0 -256
- package/dist/core/diff/victims.js.map +0 -1
- package/dist/core/staging/snapshot.js.map +0 -1
- package/dist/core/verify/file.js.map +0 -1
|
@@ -8,15 +8,19 @@
|
|
|
8
8
|
* declaration physically is. A key only one of them reads is a key the merge
|
|
9
9
|
* silently drops, which is why `metadata` handling is spelled out in both.
|
|
10
10
|
*/
|
|
11
|
-
import { maskSource, matchBrace } from "./source-mask.js";
|
|
11
|
+
import { maskSource, matchBrace, statementEnd, statementHead, topLevelBlocks } from "./source-mask.js";
|
|
12
12
|
/**
|
|
13
13
|
* Locate every element and relationship declaration inside the top-level
|
|
14
|
-
* `model { ... }`
|
|
14
|
+
* `model { ... }` blocks of a LikeC4 source, with the byte range each one
|
|
15
15
|
* occupies. This is the splice map `loam archive` merges the landscape with:
|
|
16
16
|
* the parsed model says WHAT exists, this says WHERE its authored text is —
|
|
17
17
|
* verbatim, so nothing the parser does not model (technology, style, links)
|
|
18
18
|
* can be lost by rebuilding it.
|
|
19
19
|
*
|
|
20
|
+
* Every block is read, in document order, and each declaration records which
|
|
21
|
+
* one it sits in (`block`); ids, endpoints and nesting are one namespace
|
|
22
|
+
* across all of them, because that is how LikeC4 merges them.
|
|
23
|
+
*
|
|
20
24
|
* Both declaration forms are recognised — `name = kind ...` always, and
|
|
21
25
|
* `kind name ...` for any kind the document's own `specification` block
|
|
22
26
|
* declares. Relationship endpoints are resolved the way LikeC4 reads them:
|
|
@@ -25,27 +29,42 @@ import { maskSource, matchBrace } from "./source-mask.js";
|
|
|
25
29
|
* element. A name that resolves nowhere is left as written — the caller's
|
|
26
30
|
* match against the parsed model then fails loudly instead of guessing.
|
|
27
31
|
*
|
|
28
|
-
* Returns null when there is no model block. Callers only hand in documents
|
|
32
|
+
* Returns null when there is no model block at all. Callers only hand in documents
|
|
29
33
|
* LikeC4 has already parsed, so the scan can trust balanced braces.
|
|
30
34
|
*/
|
|
31
35
|
export function scanModel(text) {
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
const masked = maskSource(text);
|
|
37
|
+
const { code, literals } = masked;
|
|
38
|
+
// EVERY top-level `model { }` block, and only those (`topLevelBlocks`): a
|
|
39
|
+
// document may hold any number, and LikeC4 reads them as one model. The
|
|
40
|
+
// scan used to stop at the FIRST match, so every declaration in a later
|
|
41
|
+
// block was invisible — the landscape parsed, `validate --all` was green,
|
|
42
|
+
// and archive refused with a message about two declarations sharing a line
|
|
43
|
+
// (a fleet on 0.2.0-alpha.7, 2026-10). Depth zero is the other half of the
|
|
44
|
+
// same fix: the bare first match also took a nested `model {` — a kind or a
|
|
45
|
+
// view NAMED model (`element model { … }`), written above the real block —
|
|
46
|
+
// for the model.
|
|
47
|
+
const blocks = [];
|
|
48
|
+
for (const { match } of topLevelBlocks(code, /\bmodel\s*\{/g)) {
|
|
49
|
+
const open = match.index + match[0].length - 1;
|
|
50
|
+
const close = matchBrace(code, open);
|
|
51
|
+
if (close === -1)
|
|
52
|
+
break;
|
|
53
|
+
blocks.push({ open, close });
|
|
54
|
+
}
|
|
55
|
+
if (blocks.length === 0)
|
|
39
56
|
return null;
|
|
40
57
|
// Element kinds from the specification block(s): the `<kind> <name>`
|
|
41
58
|
// declaration form is recognisable only by its first token being a kind.
|
|
59
|
+
// Relationship kinds likewise, for the `source .kind target` edge form.
|
|
42
60
|
const kinds = new Set();
|
|
61
|
+
const relKinds = new Set();
|
|
43
62
|
for (const sm of code.matchAll(/\bspecification\s*\{/g)) {
|
|
44
63
|
const sClose = matchBrace(code, sm.index + sm[0].length - 1);
|
|
45
64
|
if (sClose === -1)
|
|
46
65
|
continue;
|
|
47
|
-
for (const em of code.slice(sm.index, sClose).matchAll(/\
|
|
48
|
-
kinds.add(em[
|
|
66
|
+
for (const em of code.slice(sm.index, sClose).matchAll(/\b(element|relationship)\s+([A-Za-z_][\w-]*)/g)) {
|
|
67
|
+
(em[1] === "element" ? kinds : relKinds).add(em[2]);
|
|
49
68
|
}
|
|
50
69
|
}
|
|
51
70
|
const indentOf = (at) => {
|
|
@@ -54,157 +73,171 @@ export function scanModel(text) {
|
|
|
54
73
|
return /^[ \t]*$/.test(ws) ? ws : "";
|
|
55
74
|
};
|
|
56
75
|
const literalIn = (from, to) => literals.find((l) => l.start >= from && l.end <= to);
|
|
57
|
-
|
|
58
|
-
|
|
76
|
+
// A key is a whole identifier, and LikeC4's identifiers carry hyphens. `\b`
|
|
77
|
+
// took the `-` for a boundary, so `op-version 'v2'` above `op 'cancelOrdr'`
|
|
78
|
+
// was read as op `'v2'`, a `#op-critical` tag as the key `op` naming the
|
|
79
|
+
// literal after it — the next property's — and `validate --all --base`
|
|
80
|
+
// graded neither op the branch wrote: the scanned edge matched no parsed one,
|
|
81
|
+
// so the misspelt `cancelOrdr` went green where the plain run reports
|
|
82
|
+
// `spine.op-undefined` (probed on main at 171555d; 57b33ad fixed the same
|
|
83
|
+
// hyphen for ids and not here).
|
|
84
|
+
const keyedLiteral = (key, range) => {
|
|
85
|
+
if (range === null)
|
|
59
86
|
return undefined;
|
|
60
|
-
const re = new RegExp(
|
|
61
|
-
re.lastIndex = from;
|
|
87
|
+
const re = new RegExp(`(?<![\\w-])${key}(?![\\w-])`, "g");
|
|
88
|
+
re.lastIndex = range.from;
|
|
62
89
|
const km = re.exec(code);
|
|
63
|
-
if (km === null || km.index >= to)
|
|
90
|
+
if (km === null || km.index >= range.to)
|
|
64
91
|
return undefined;
|
|
65
|
-
return literalIn(km.index, to)?.value;
|
|
92
|
+
return literalIn(km.index, range.to)?.value;
|
|
66
93
|
};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
94
|
+
// The spine keys are METADATA keys — the parsed `Rel` reads them out of
|
|
95
|
+
// `metadata { }` and nowhere else (`likec4.ts`) — so the scan reads them only
|
|
96
|
+
// there. Read from the whole body, a bare `#op` tag (a legal tag name) above a
|
|
97
|
+
// `description` was the key `op` once more, whatever the boundary rule.
|
|
98
|
+
const metadataOf = (body) => {
|
|
99
|
+
if (body === null)
|
|
100
|
+
return null;
|
|
101
|
+
const re = /(?<![\w-])metadata\s*\{/g;
|
|
102
|
+
re.lastIndex = body.from;
|
|
103
|
+
const mm = re.exec(code);
|
|
104
|
+
if (mm === null || mm.index >= body.to)
|
|
105
|
+
return null;
|
|
106
|
+
const open = mm.index + mm[0].length - 1;
|
|
107
|
+
const shut = matchBrace(code, open);
|
|
108
|
+
return shut === -1 || shut > body.to ? null : { from: open + 1, to: shut };
|
|
72
109
|
};
|
|
110
|
+
// A bodyless statement's end — its trailing comment included, unless that
|
|
111
|
+
// comment runs on past the line (`statementEnd` says why).
|
|
112
|
+
const bodylessEnd = (from, to) => statementEnd(text, masked, { start: from, end: to });
|
|
73
113
|
const elements = [];
|
|
74
114
|
const raw = [];
|
|
75
115
|
const stack = [];
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (ch === "}") {
|
|
84
|
-
const frame = stack.pop();
|
|
85
|
-
if (frame !== undefined) {
|
|
86
|
-
frame.el.bodyClose = i;
|
|
87
|
-
frame.el.end = i + 1;
|
|
88
|
-
elements.push(frame.el);
|
|
89
|
-
}
|
|
90
|
-
i += 1;
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
// A statement's head: up to its own `{`, the end of the line, or the
|
|
94
|
-
// enclosing block's `}` on the same line — whichever comes first.
|
|
95
|
-
const stmtStart = i;
|
|
96
|
-
let headEnd = close;
|
|
97
|
-
let opener = -1;
|
|
98
|
-
for (let j = i; j < close; j += 1) {
|
|
99
|
-
const c = code[j];
|
|
100
|
-
if (c === "\n" || c === "}") {
|
|
101
|
-
headEnd = j;
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
if (c === "{") {
|
|
105
|
-
opener = j;
|
|
106
|
-
headEnd = j;
|
|
107
|
-
break;
|
|
116
|
+
for (const [block, { open, close }] of blocks.entries()) {
|
|
117
|
+
let i = open + 1;
|
|
118
|
+
while (i < close) {
|
|
119
|
+
const ch = code[i];
|
|
120
|
+
if (/\s/.test(ch)) {
|
|
121
|
+
i += 1;
|
|
122
|
+
continue;
|
|
108
123
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
// map instead (verification 2026-09-04, E1).
|
|
119
|
-
const extended = opener === -1 ? null : /^extend\s+([A-Za-z_][\w.-]*)\s*$/.exec(head);
|
|
120
|
-
if (extended !== null) {
|
|
121
|
-
const id = parentId === "" ? extended[1] : `${parentId}.${extended[1]}`;
|
|
122
|
-
const el = {
|
|
123
|
-
id,
|
|
124
|
-
start: stmtStart,
|
|
125
|
-
end: headEnd,
|
|
126
|
-
bodyOpen: opener,
|
|
127
|
-
bodyClose: -1,
|
|
128
|
-
indent: indentOf(stmtStart),
|
|
129
|
-
extend: true,
|
|
130
|
-
};
|
|
131
|
-
stack.push({ id, el });
|
|
132
|
-
i = opener + 1;
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
// Classify: `name = kind` first, then a relationship (the arrow cannot hide
|
|
136
|
-
// in a string — the head is masked), then the `kind name` form, else a
|
|
137
|
-
// property/tag line that is consumed whole, nested block included.
|
|
138
|
-
let localName = null;
|
|
139
|
-
const assign = /^([A-Za-z_]\w*)\s*=\s*[A-Za-z_]/.exec(head);
|
|
140
|
-
if (assign !== null) {
|
|
141
|
-
localName = assign[1];
|
|
142
|
-
}
|
|
143
|
-
else if (!head.includes("->")) {
|
|
144
|
-
const toks = head.trim().split(/\s+/);
|
|
145
|
-
if (toks.length >= 2 && kinds.has(toks[0]) && /^[A-Za-z_]\w*$/.test(toks[1])) {
|
|
146
|
-
localName = toks[1];
|
|
124
|
+
if (ch === "}") {
|
|
125
|
+
const frame = stack.pop();
|
|
126
|
+
if (frame !== undefined) {
|
|
127
|
+
frame.el.bodyClose = i;
|
|
128
|
+
frame.el.end = i + 1;
|
|
129
|
+
elements.push(frame.el);
|
|
130
|
+
}
|
|
131
|
+
i += 1;
|
|
132
|
+
continue;
|
|
147
133
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
134
|
+
// A statement's head: up to its own `{`, the end of the line, or the
|
|
135
|
+
// enclosing block's `}` on the same line — whichever comes first, unless
|
|
136
|
+
// LikeC4 reads on past the newline (`statementHead` says when it does).
|
|
137
|
+
const stmtStart = i;
|
|
138
|
+
const { end: headEnd, opener } = statementHead(masked, i, close);
|
|
139
|
+
const head = code.slice(stmtStart, headEnd);
|
|
140
|
+
const parentId = stack.length > 0 ? stack[stack.length - 1].id : "";
|
|
141
|
+
// `extend <fqn> { … }` — the extending model's one construct, and the only
|
|
142
|
+
// frame here whose id is not minted from the enclosing scope: it names an
|
|
143
|
+
// element the fleet map already declares, so its children are `<fqn>.<name>`
|
|
144
|
+
// and a reference inside it resolves against that scope. Without this the
|
|
145
|
+
// block fell through to the property-line arm and everything in it was
|
|
146
|
+
// invisible, which is why the archive spliced a service's interior into the
|
|
147
|
+
// map instead (verification 2026-09-04, E1).
|
|
148
|
+
const extended = opener === -1 ? null : /^extend\s+([A-Za-z_][\w.-]*)\s*$/.exec(head);
|
|
149
|
+
if (extended !== null) {
|
|
150
|
+
const id = parentId === "" ? extended[1] : `${parentId}.${extended[1]}`;
|
|
151
|
+
const el = {
|
|
152
|
+
id,
|
|
153
|
+
start: stmtStart,
|
|
154
|
+
end: headEnd,
|
|
155
|
+
bodyOpen: opener,
|
|
156
|
+
bodyClose: -1,
|
|
157
|
+
indent: indentOf(stmtStart),
|
|
158
|
+
block,
|
|
159
|
+
extend: true,
|
|
160
|
+
};
|
|
163
161
|
stack.push({ id, el });
|
|
164
162
|
i = opener + 1;
|
|
163
|
+
continue;
|
|
165
164
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
// Classify: `name = kind` first, then a relationship (the arrow cannot hide
|
|
166
|
+
// in a string — the head is masked), then the `kind name` form, else a
|
|
167
|
+
// property/tag line that is consumed whole, nested block included.
|
|
168
|
+
let localName = null;
|
|
169
|
+
const assign = /^([A-Za-z_][\w-]*)\s*=\s*[A-Za-z_]/.exec(head);
|
|
170
|
+
if (assign !== null) {
|
|
171
|
+
localName = assign[1];
|
|
170
172
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (
|
|
178
|
-
const
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
const title = literalIn(arrowEnd, headEnd)?.value ?? keyedLiteral("title", bodyFrom, bodyTo);
|
|
182
|
-
const tags = [];
|
|
183
|
-
for (const tm of code.slice(stmtStart, stmtEnd).matchAll(/#([\w-]+)/g))
|
|
184
|
-
tags.push(tm[1]);
|
|
185
|
-
raw.push({
|
|
186
|
-
srcLit: am[1],
|
|
187
|
-
tgtLit: am[2],
|
|
188
|
-
parent: parentId,
|
|
173
|
+
else if (!head.includes("->")) {
|
|
174
|
+
const toks = head.trim().split(/\s+/);
|
|
175
|
+
if (toks.length >= 2 && kinds.has(toks[0]) && /^[A-Za-z_][\w-]*$/.test(toks[1])) {
|
|
176
|
+
localName = toks[1];
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (localName !== null) {
|
|
180
|
+
const id = parentId === "" ? localName : `${parentId}.${localName}`;
|
|
181
|
+
const el = {
|
|
182
|
+
id,
|
|
189
183
|
start: stmtStart,
|
|
190
|
-
end:
|
|
184
|
+
end: headEnd,
|
|
185
|
+
bodyOpen: opener,
|
|
186
|
+
bodyClose: -1,
|
|
191
187
|
indent: indentOf(stmtStart),
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
188
|
+
block,
|
|
189
|
+
};
|
|
190
|
+
const titled = literalIn(stmtStart, headEnd)?.value;
|
|
191
|
+
if (titled !== undefined)
|
|
192
|
+
el.title = titled;
|
|
193
|
+
if (opener !== -1) {
|
|
194
|
+
stack.push({ id, el });
|
|
195
|
+
i = opener + 1;
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
el.end = bodylessEnd(stmtStart, headEnd);
|
|
199
|
+
elements.push(el);
|
|
200
|
+
i = headEnd;
|
|
201
|
+
}
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const am = relationHead(head, relKinds);
|
|
205
|
+
if (am !== null || head.includes("->")) {
|
|
206
|
+
const bClose = opener === -1 ? -1 : matchBrace(code, opener);
|
|
207
|
+
const stmtEnd = opener === -1 ? bodylessEnd(stmtStart, headEnd) : bClose === -1 ? close : bClose + 1;
|
|
208
|
+
if (am !== null) {
|
|
209
|
+
const arrowEnd = stmtStart + am.length;
|
|
210
|
+
const body = opener === -1 ? null : { from: opener + 1, to: stmtEnd - 1 };
|
|
211
|
+
const meta = metadataOf(body);
|
|
212
|
+
const title = literalIn(arrowEnd, headEnd)?.value ?? keyedLiteral("title", body);
|
|
213
|
+
const tags = [];
|
|
214
|
+
for (const tm of code.slice(stmtStart, stmtEnd).matchAll(/#([\w-]+)/g))
|
|
215
|
+
tags.push(tm[1]);
|
|
216
|
+
raw.push({
|
|
217
|
+
srcLit: am.src,
|
|
218
|
+
tgtLit: am.tgt,
|
|
219
|
+
parent: parentId,
|
|
220
|
+
start: stmtStart,
|
|
221
|
+
end: stmtEnd,
|
|
222
|
+
indent: indentOf(stmtStart),
|
|
223
|
+
block,
|
|
224
|
+
title,
|
|
225
|
+
op: keyedLiteral("op", meta),
|
|
226
|
+
publishes: keyedLiteral("publishes", meta),
|
|
227
|
+
consumes: keyedLiteral("consumes", meta),
|
|
228
|
+
tags,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
i = Math.max(stmtEnd, headEnd);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (opener !== -1) {
|
|
235
|
+
const bClose = matchBrace(code, opener);
|
|
236
|
+
i = bClose === -1 ? close : bClose + 1;
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
i = headEnd;
|
|
198
240
|
}
|
|
199
|
-
i = Math.max(stmtEnd, headEnd);
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
|
-
if (opener !== -1) {
|
|
203
|
-
const bClose = matchBrace(code, opener);
|
|
204
|
-
i = bClose === -1 ? close : bClose + 1;
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
i = headEnd;
|
|
208
241
|
}
|
|
209
242
|
}
|
|
210
243
|
// Resolve relationship endpoints against everything declared anywhere in the
|
|
@@ -246,8 +279,31 @@ export function scanModel(text) {
|
|
|
246
279
|
start: r.start,
|
|
247
280
|
end: r.end,
|
|
248
281
|
indent: r.indent,
|
|
282
|
+
block: r.block,
|
|
249
283
|
}));
|
|
250
284
|
elements.sort((a, b) => a.start - b.start);
|
|
251
|
-
return {
|
|
285
|
+
return { blocks, elements, rels };
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* A relationship head's endpoints as written, and where its arrow form ends —
|
|
289
|
+
* null for any other head. Three forms, each with the source omittable inside
|
|
290
|
+
* an element: `a -> b`, `a -[kind]-> b`, and `a .kind b` for a relationship
|
|
291
|
+
* kind the specification declares, which the scan used to skip as a property
|
|
292
|
+
* line, so archive refused a valid map on a relationship count.
|
|
293
|
+
*
|
|
294
|
+
* Ids carry hyphens (`entity-service`): LikeC4's identifier is
|
|
295
|
+
* `[a-zA-Z_][-\w]*`, and the `\w`-only spelling here made such an element, or
|
|
296
|
+
* an edge naming one, invisible. The lexer's greed is why `a->b` without a
|
|
297
|
+
* space is not a form worth reading — LikeC4 takes `a-` for the id and rejects
|
|
298
|
+
* the document.
|
|
299
|
+
*/
|
|
300
|
+
function relationHead(head, relKinds) {
|
|
301
|
+
const arrow = /^([A-Za-z_][\w.-]*)?\s*(?:-\[[^\]]*\])?->\s*([A-Za-z_][\w.-]*)/.exec(head);
|
|
302
|
+
if (arrow !== null)
|
|
303
|
+
return { src: arrow[1], tgt: arrow[2], length: arrow[0].length };
|
|
304
|
+
const dotted = /^(?:([A-Za-z_][\w.-]*)\s+)?\.([A-Za-z_][\w-]*)\s+([A-Za-z_][\w.-]*)/.exec(head);
|
|
305
|
+
if (dotted === null || !relKinds.has(dotted[2]))
|
|
306
|
+
return null;
|
|
307
|
+
return { src: dotted[1], tgt: dotted[3], length: dotted[0].length };
|
|
252
308
|
}
|
|
253
309
|
//# sourceMappingURL=source-scan.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-scan.js","sourceRoot":"","sources":["../../../src/core/c4/source-scan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The text-level view of a LikeC4 document: which bytes each declaration owns.\n *\n * loam's archive merges the landscape by SPLICING authored text, not by\n * re-rendering a parsed model — a re-render would reformat every line somebody\n * wrote. So the merge needs both views of the same file: the parsed one\n * (`likec4.ts`) for what the model MEANS, and this one for where each\n * declaration physically is. A key only one of them reads is a key the merge\n * silently drops, which is why `metadata` handling is spelled out in both.\n */\nimport { maskSource, matchBrace, type SourceLiteral } from \"./source-mask.js\";\n\nexport interface ScannedElement {\n /** Full dotted id — `parent.child` for a nested declaration. */\n id: string;\n /** Span of the whole declaration: first head character to one past its end. */\n start: number;\n end: number;\n /** Its own body braces; -1 when the declaration has no body. */\n bodyOpen: number;\n bodyClose: number;\n /** Leading whitespace of the declaration's first line. */\n indent: string;\n /**\n * The title the declaration's HEAD names — the first string literal before\n * its body, which is where both declaration forms write it (pinned against\n * the parser by `test/likec4-scan-parity.test.ts`).\n *\n * Absent when the head names none: LikeC4 then titles the element after its\n * own name, and a default title is one the archive's title join must not\n * match on — `splice/identity/declared.ts` says why, and why losing it costs\n * that join nothing.\n */\n title?: string;\n /**\n * True for an `extend <fqn> { … }` frame — a block that DECLARES nothing and\n * reopens an element another document owns. Its id is the fqn as written, and\n * its children hang off that, which is what lets the archive splice a\n * service's interior into the model that owns it. Placement must skip it: it\n * is not a top-level declaration of this document, so anchoring beside it\n * would group additions around a box that lives somewhere else.\n */\n extend?: true;\n}\n\n/** A relationship statement located in source, endpoints resolved to full ids (best effort). */\nexport interface ScannedRel {\n source: string;\n target: string;\n title?: string;\n op?: string;\n /** `metadata { publishes '...' }` — see `Rel.publishes`. */\n publishes?: string;\n /** `metadata { consumes '...' }` — see `Rel.consumes`. */\n consumes?: string;\n tags: string[];\n start: number;\n end: number;\n indent: string;\n}\n\nexport interface ScannedModel {\n /** The `model` block's own braces. */\n open: number;\n close: number;\n /** In document order. A nested declaration's span lies inside its parent's. */\n elements: ScannedElement[];\n rels: ScannedRel[];\n}\n\n/**\n * Locate every element and relationship declaration inside the top-level\n * `model { ... }` block of a LikeC4 source, with the byte range each one\n * occupies. This is the splice map `loam archive` merges the landscape with:\n * the parsed model says WHAT exists, this says WHERE its authored text is —\n * verbatim, so nothing the parser does not model (technology, style, links)\n * can be lost by rebuilding it.\n *\n * Both declaration forms are recognised — `name = kind ...` always, and\n * `kind name ...` for any kind the document's own `specification` block\n * declares. Relationship endpoints are resolved the way LikeC4 reads them:\n * innermost enclosing scope outward, then the top level, then a unique leaf\n * name anywhere; `it`/`this` (and an omitted source) mean the enclosing\n * element. A name that resolves nowhere is left as written — the caller's\n * match against the parsed model then fails loudly instead of guessing.\n *\n * Returns null when there is no model block. Callers only hand in documents\n * LikeC4 has already parsed, so the scan can trust balanced braces.\n */\nexport function scanModel(text: string): ScannedModel | null {\n const { code, literals } = maskSource(text);\n const m = /\\bmodel\\s*\\{/.exec(code);\n if (!m) return null;\n const open = m.index + m[0].length - 1;\n const close = matchBrace(code, open);\n if (close === -1) return null;\n\n // Element kinds from the specification block(s): the `<kind> <name>`\n // declaration form is recognisable only by its first token being a kind.\n const kinds = new Set<string>();\n for (const sm of code.matchAll(/\\bspecification\\s*\\{/g)) {\n const sClose = matchBrace(code, sm.index + sm[0].length - 1);\n if (sClose === -1) continue;\n for (const em of code.slice(sm.index, sClose).matchAll(/\\belement\\s+([A-Za-z_][\\w-]*)/g)) {\n kinds.add(em[1]!);\n }\n }\n\n const indentOf = (at: number): string => {\n const nl = text.lastIndexOf(\"\\n\", at - 1);\n const ws = text.slice(nl + 1, at);\n return /^[ \\t]*$/.test(ws) ? ws : \"\";\n };\n const literalIn = (from: number, to: number): SourceLiteral | undefined =>\n literals.find((l) => l.start >= from && l.end <= to);\n const keyedLiteral = (key: string, from: number, to: number): string | undefined => {\n if (from === -1) return undefined;\n const re = new RegExp(`\\\\b${key}\\\\b`, \"g\");\n re.lastIndex = from;\n const km = re.exec(code);\n if (km === null || km.index >= to) return undefined;\n return literalIn(km.index, to)?.value;\n };\n const trimmedEnd = (from: number, to: number): number => {\n let e = to;\n while (e > from && /\\s/.test(text[e - 1]!)) e -= 1;\n return e;\n };\n\n const elements: ScannedElement[] = [];\n interface RawRel {\n srcLit?: string;\n tgtLit: string;\n parent: string;\n start: number;\n end: number;\n indent: string;\n title?: string;\n op?: string;\n publishes?: string;\n consumes?: string;\n tags: string[];\n }\n const raw: RawRel[] = [];\n const stack: Array<{ id: string; el: ScannedElement }> = [];\n\n let i = open + 1;\n while (i < close) {\n const ch = code[i]!;\n if (/\\s/.test(ch)) {\n i += 1;\n continue;\n }\n if (ch === \"}\") {\n const frame = stack.pop();\n if (frame !== undefined) {\n frame.el.bodyClose = i;\n frame.el.end = i + 1;\n elements.push(frame.el);\n }\n i += 1;\n continue;\n }\n\n // A statement's head: up to its own `{`, the end of the line, or the\n // enclosing block's `}` on the same line — whichever comes first.\n const stmtStart = i;\n let headEnd = close;\n let opener = -1;\n for (let j = i; j < close; j += 1) {\n const c = code[j]!;\n if (c === \"\\n\" || c === \"}\") {\n headEnd = j;\n break;\n }\n if (c === \"{\") {\n opener = j;\n headEnd = j;\n break;\n }\n }\n const head = code.slice(stmtStart, headEnd);\n const parentId = stack.length > 0 ? stack[stack.length - 1]!.id : \"\";\n\n // `extend <fqn> { … }` — the extending model's one construct, and the only\n // frame here whose id is not minted from the enclosing scope: it names an\n // element the fleet map already declares, so its children are `<fqn>.<name>`\n // and a reference inside it resolves against that scope. Without this the\n // block fell through to the property-line arm and everything in it was\n // invisible, which is why the archive spliced a service's interior into the\n // map instead (verification 2026-09-04, E1).\n const extended = opener === -1 ? null : /^extend\\s+([A-Za-z_][\\w.-]*)\\s*$/.exec(head);\n if (extended !== null) {\n const id = parentId === \"\" ? extended[1]! : `${parentId}.${extended[1]!}`;\n const el: ScannedElement = {\n id,\n start: stmtStart,\n end: headEnd,\n bodyOpen: opener,\n bodyClose: -1,\n indent: indentOf(stmtStart),\n extend: true,\n };\n stack.push({ id, el });\n i = opener + 1;\n continue;\n }\n\n // Classify: `name = kind` first, then a relationship (the arrow cannot hide\n // in a string — the head is masked), then the `kind name` form, else a\n // property/tag line that is consumed whole, nested block included.\n let localName: string | null = null;\n const assign = /^([A-Za-z_]\\w*)\\s*=\\s*[A-Za-z_]/.exec(head);\n if (assign !== null) {\n localName = assign[1]!;\n } else if (!head.includes(\"->\")) {\n const toks = head.trim().split(/\\s+/);\n if (toks.length >= 2 && kinds.has(toks[0]!) && /^[A-Za-z_]\\w*$/.test(toks[1]!)) {\n localName = toks[1]!;\n }\n }\n\n if (localName !== null) {\n const id = parentId === \"\" ? localName : `${parentId}.${localName}`;\n const el: ScannedElement = {\n id,\n start: stmtStart,\n end: headEnd,\n bodyOpen: opener,\n bodyClose: -1,\n indent: indentOf(stmtStart),\n };\n const titled = literalIn(stmtStart, headEnd)?.value;\n if (titled !== undefined) el.title = titled;\n if (opener !== -1) {\n stack.push({ id, el });\n i = opener + 1;\n } else {\n el.end = trimmedEnd(stmtStart, headEnd);\n elements.push(el);\n i = headEnd;\n }\n continue;\n }\n\n if (head.includes(\"->\")) {\n const bClose = opener === -1 ? -1 : matchBrace(code, opener);\n const stmtEnd = opener === -1 ? trimmedEnd(stmtStart, headEnd) : bClose === -1 ? close : bClose + 1;\n const am = /^([A-Za-z_][\\w.]*)?\\s*(?:-\\[[^\\]]*\\])?->\\s*([A-Za-z_][\\w.]*)/.exec(head);\n if (am !== null) {\n const arrowEnd = stmtStart + am[0].length;\n const bodyFrom = opener === -1 ? -1 : opener + 1;\n const bodyTo = opener === -1 ? -1 : stmtEnd - 1;\n const title = literalIn(arrowEnd, headEnd)?.value ?? keyedLiteral(\"title\", bodyFrom, bodyTo);\n const tags: string[] = [];\n for (const tm of code.slice(stmtStart, stmtEnd).matchAll(/#([\\w-]+)/g)) tags.push(tm[1]!);\n raw.push({\n srcLit: am[1],\n tgtLit: am[2]!,\n parent: parentId,\n start: stmtStart,\n end: stmtEnd,\n indent: indentOf(stmtStart),\n title,\n op: keyedLiteral(\"op\", bodyFrom, bodyTo),\n publishes: keyedLiteral(\"publishes\", bodyFrom, bodyTo),\n consumes: keyedLiteral(\"consumes\", bodyFrom, bodyTo),\n tags,\n });\n }\n i = Math.max(stmtEnd, headEnd);\n continue;\n }\n\n if (opener !== -1) {\n const bClose = matchBrace(code, opener);\n i = bClose === -1 ? close : bClose + 1;\n } else {\n i = headEnd;\n }\n }\n\n // Resolve relationship endpoints against everything declared anywhere in the\n // model — LikeC4 resolution is not order-dependent, so neither is this.\n const ids = new Set(elements.map((e) => e.id));\n const byLeaf = new Map<string, string[]>();\n for (const e of elements) {\n const leaf = e.id.slice(e.id.lastIndexOf(\".\") + 1);\n byLeaf.set(leaf, [...(byLeaf.get(leaf) ?? []), e.id]);\n }\n const resolve = (lit: string | undefined, enclosing: string): string => {\n if (lit === undefined || lit === \"it\" || lit === \"this\") return enclosing;\n const segs = lit.split(\".\");\n let base: string | undefined;\n for (let scope = enclosing; scope !== \"\" && base === undefined; ) {\n if (ids.has(`${scope}.${segs[0]!}`)) base = `${scope}.${segs[0]!}`;\n const dot = scope.lastIndexOf(\".\");\n scope = dot === -1 ? \"\" : scope.slice(0, dot);\n }\n if (base === undefined && ids.has(segs[0]!)) base = segs[0]!;\n if (base === undefined) {\n const leafed = byLeaf.get(segs[0]!);\n if (leafed !== undefined && leafed.length === 1) base = leafed[0]!;\n }\n return [base ?? segs[0]!, ...segs.slice(1)].join(\".\");\n };\n\n const rels: ScannedRel[] = raw.map((r) => ({\n source: resolve(r.srcLit, r.parent),\n target: resolve(r.tgtLit, r.parent),\n title: r.title,\n op: r.op,\n publishes: r.publishes,\n consumes: r.consumes,\n tags: r.tags,\n start: r.start,\n end: r.end,\n indent: r.indent,\n }));\n\n elements.sort((a, b) => a.start - b.start);\n return { open, close, elements, rels };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"source-scan.js","sourceRoot":"","sources":["../../../src/core/c4/source-scan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The text-level view of a LikeC4 document: which bytes each declaration owns.\n *\n * loam's archive merges the landscape by SPLICING authored text, not by\n * re-rendering a parsed model — a re-render would reformat every line somebody\n * wrote. So the merge needs both views of the same file: the parsed one\n * (`likec4.ts`) for what the model MEANS, and this one for where each\n * declaration physically is. A key only one of them reads is a key the merge\n * silently drops, which is why `metadata` handling is spelled out in both.\n */\nimport { maskSource, matchBrace, statementEnd, statementHead, topLevelBlocks, type SourceLiteral } from \"./source-mask.js\";\n\nexport interface ScannedElement {\n /** Full dotted id — `parent.child` for a nested declaration. */\n id: string;\n /** Span of the whole declaration: first head character to one past its end. */\n start: number;\n end: number;\n /** Its own body braces; -1 when the declaration has no body. */\n bodyOpen: number;\n bodyClose: number;\n /** Leading whitespace of the declaration's first line. */\n indent: string;\n /** Index into `ScannedModel.blocks` of the `model { }` block it is written in. */\n block: number;\n /**\n * The title the declaration's HEAD names — the first string literal before\n * its body, which is where both declaration forms write it (pinned against\n * the parser by `test/likec4-scan-parity.test.ts`).\n *\n * Absent when the head names none: LikeC4 then titles the element after its\n * own name, and a default title is one the archive's title join must not\n * match on — `splice/identity/declared.ts` says why, and why losing it costs\n * that join nothing.\n */\n title?: string;\n /**\n * True for an `extend <fqn> { … }` frame — a block that DECLARES nothing and\n * reopens an element another document owns. Its id is the fqn as written, and\n * its children hang off that, which is what lets the archive splice a\n * service's interior into the model that owns it. Placement must skip it: it\n * is not a top-level declaration of this document, so anchoring beside it\n * would group additions around a box that lives somewhere else.\n */\n extend?: true;\n}\n\n/** A relationship statement located in source, endpoints resolved to full ids (best effort). */\nexport interface ScannedRel {\n source: string;\n target: string;\n title?: string;\n op?: string;\n /** `metadata { publishes '...' }` — see `Rel.publishes`. */\n publishes?: string;\n /** `metadata { consumes '...' }` — see `Rel.consumes`. */\n consumes?: string;\n tags: string[];\n start: number;\n end: number;\n indent: string;\n /** Index into `ScannedModel.blocks` of the `model { }` block it is written in. */\n block: number;\n}\n\n/** A half-open `[from, to)` run of the masked code — a body, or the metadata block inside one. */\ninterface CodeRange {\n from: number;\n to: number;\n}\n\n/** One top-level `model { }` block: its own braces. */\nexport interface ScannedBlock {\n open: number;\n close: number;\n}\n\nexport interface ScannedModel {\n /**\n * Every top-level `model { }` block, in document order — never empty. LikeC4\n * merges them into one model, so an id or an endpoint resolves across all of\n * them; which block a NEW declaration is written into is placement's choice\n * (`splice/placement.ts`, `HOME_BLOCK`), never the scan's.\n */\n blocks: ScannedBlock[];\n /** In document order. A nested declaration's span lies inside its parent's. */\n elements: ScannedElement[];\n rels: ScannedRel[];\n}\n\n/**\n * Locate every element and relationship declaration inside the top-level\n * `model { ... }` blocks of a LikeC4 source, with the byte range each one\n * occupies. This is the splice map `loam archive` merges the landscape with:\n * the parsed model says WHAT exists, this says WHERE its authored text is —\n * verbatim, so nothing the parser does not model (technology, style, links)\n * can be lost by rebuilding it.\n *\n * Every block is read, in document order, and each declaration records which\n * one it sits in (`block`); ids, endpoints and nesting are one namespace\n * across all of them, because that is how LikeC4 merges them.\n *\n * Both declaration forms are recognised — `name = kind ...` always, and\n * `kind name ...` for any kind the document's own `specification` block\n * declares. Relationship endpoints are resolved the way LikeC4 reads them:\n * innermost enclosing scope outward, then the top level, then a unique leaf\n * name anywhere; `it`/`this` (and an omitted source) mean the enclosing\n * element. A name that resolves nowhere is left as written — the caller's\n * match against the parsed model then fails loudly instead of guessing.\n *\n * Returns null when there is no model block at all. Callers only hand in documents\n * LikeC4 has already parsed, so the scan can trust balanced braces.\n */\nexport function scanModel(text: string): ScannedModel | null {\n const masked = maskSource(text);\n const { code, literals } = masked;\n // EVERY top-level `model { }` block, and only those (`topLevelBlocks`): a\n // document may hold any number, and LikeC4 reads them as one model. The\n // scan used to stop at the FIRST match, so every declaration in a later\n // block was invisible — the landscape parsed, `validate --all` was green,\n // and archive refused with a message about two declarations sharing a line\n // (a fleet on 0.2.0-alpha.7, 2026-10). Depth zero is the other half of the\n // same fix: the bare first match also took a nested `model {` — a kind or a\n // view NAMED model (`element model { … }`), written above the real block —\n // for the model.\n const blocks: ScannedBlock[] = [];\n for (const { match } of topLevelBlocks(code, /\\bmodel\\s*\\{/g)) {\n const open = match.index + match[0].length - 1;\n const close = matchBrace(code, open);\n if (close === -1) break;\n blocks.push({ open, close });\n }\n if (blocks.length === 0) return null;\n\n // Element kinds from the specification block(s): the `<kind> <name>`\n // declaration form is recognisable only by its first token being a kind.\n // Relationship kinds likewise, for the `source .kind target` edge form.\n const kinds = new Set<string>();\n const relKinds = new Set<string>();\n for (const sm of code.matchAll(/\\bspecification\\s*\\{/g)) {\n const sClose = matchBrace(code, sm.index + sm[0].length - 1);\n if (sClose === -1) continue;\n for (const em of code.slice(sm.index, sClose).matchAll(/\\b(element|relationship)\\s+([A-Za-z_][\\w-]*)/g)) {\n (em[1] === \"element\" ? kinds : relKinds).add(em[2]!);\n }\n }\n\n const indentOf = (at: number): string => {\n const nl = text.lastIndexOf(\"\\n\", at - 1);\n const ws = text.slice(nl + 1, at);\n return /^[ \\t]*$/.test(ws) ? ws : \"\";\n };\n const literalIn = (from: number, to: number): SourceLiteral | undefined =>\n literals.find((l) => l.start >= from && l.end <= to);\n // A key is a whole identifier, and LikeC4's identifiers carry hyphens. `\\b`\n // took the `-` for a boundary, so `op-version 'v2'` above `op 'cancelOrdr'`\n // was read as op `'v2'`, a `#op-critical` tag as the key `op` naming the\n // literal after it — the next property's — and `validate --all --base`\n // graded neither op the branch wrote: the scanned edge matched no parsed one,\n // so the misspelt `cancelOrdr` went green where the plain run reports\n // `spine.op-undefined` (probed on main at 171555d; 57b33ad fixed the same\n // hyphen for ids and not here).\n const keyedLiteral = (key: string, range: CodeRange | null): string | undefined => {\n if (range === null) return undefined;\n const re = new RegExp(`(?<![\\\\w-])${key}(?![\\\\w-])`, \"g\");\n re.lastIndex = range.from;\n const km = re.exec(code);\n if (km === null || km.index >= range.to) return undefined;\n return literalIn(km.index, range.to)?.value;\n };\n // The spine keys are METADATA keys — the parsed `Rel` reads them out of\n // `metadata { }` and nowhere else (`likec4.ts`) — so the scan reads them only\n // there. Read from the whole body, a bare `#op` tag (a legal tag name) above a\n // `description` was the key `op` once more, whatever the boundary rule.\n const metadataOf = (body: CodeRange | null): CodeRange | null => {\n if (body === null) return null;\n const re = /(?<![\\w-])metadata\\s*\\{/g;\n re.lastIndex = body.from;\n const mm = re.exec(code);\n if (mm === null || mm.index >= body.to) return null;\n const open = mm.index + mm[0].length - 1;\n const shut = matchBrace(code, open);\n return shut === -1 || shut > body.to ? null : { from: open + 1, to: shut };\n };\n // A bodyless statement's end — its trailing comment included, unless that\n // comment runs on past the line (`statementEnd` says why).\n const bodylessEnd = (from: number, to: number): number => statementEnd(text, masked, { start: from, end: to });\n\n const elements: ScannedElement[] = [];\n interface RawRel {\n srcLit?: string;\n tgtLit: string;\n parent: string;\n start: number;\n end: number;\n indent: string;\n block: number;\n title?: string;\n op?: string;\n publishes?: string;\n consumes?: string;\n tags: string[];\n }\n const raw: RawRel[] = [];\n const stack: Array<{ id: string; el: ScannedElement }> = [];\n\n for (const [block, { open, close }] of blocks.entries()) {\n let i = open + 1;\n while (i < close) {\n const ch = code[i]!;\n if (/\\s/.test(ch)) {\n i += 1;\n continue;\n }\n if (ch === \"}\") {\n const frame = stack.pop();\n if (frame !== undefined) {\n frame.el.bodyClose = i;\n frame.el.end = i + 1;\n elements.push(frame.el);\n }\n i += 1;\n continue;\n }\n\n // A statement's head: up to its own `{`, the end of the line, or the\n // enclosing block's `}` on the same line — whichever comes first, unless\n // LikeC4 reads on past the newline (`statementHead` says when it does).\n const stmtStart = i;\n const { end: headEnd, opener } = statementHead(masked, i, close);\n const head = code.slice(stmtStart, headEnd);\n const parentId = stack.length > 0 ? stack[stack.length - 1]!.id : \"\";\n\n // `extend <fqn> { … }` — the extending model's one construct, and the only\n // frame here whose id is not minted from the enclosing scope: it names an\n // element the fleet map already declares, so its children are `<fqn>.<name>`\n // and a reference inside it resolves against that scope. Without this the\n // block fell through to the property-line arm and everything in it was\n // invisible, which is why the archive spliced a service's interior into the\n // map instead (verification 2026-09-04, E1).\n const extended = opener === -1 ? null : /^extend\\s+([A-Za-z_][\\w.-]*)\\s*$/.exec(head);\n if (extended !== null) {\n const id = parentId === \"\" ? extended[1]! : `${parentId}.${extended[1]!}`;\n const el: ScannedElement = {\n id,\n start: stmtStart,\n end: headEnd,\n bodyOpen: opener,\n bodyClose: -1,\n indent: indentOf(stmtStart),\n block,\n extend: true,\n };\n stack.push({ id, el });\n i = opener + 1;\n continue;\n }\n\n // Classify: `name = kind` first, then a relationship (the arrow cannot hide\n // in a string — the head is masked), then the `kind name` form, else a\n // property/tag line that is consumed whole, nested block included.\n let localName: string | null = null;\n const assign = /^([A-Za-z_][\\w-]*)\\s*=\\s*[A-Za-z_]/.exec(head);\n if (assign !== null) {\n localName = assign[1]!;\n } else if (!head.includes(\"->\")) {\n const toks = head.trim().split(/\\s+/);\n if (toks.length >= 2 && kinds.has(toks[0]!) && /^[A-Za-z_][\\w-]*$/.test(toks[1]!)) {\n localName = toks[1]!;\n }\n }\n\n if (localName !== null) {\n const id = parentId === \"\" ? localName : `${parentId}.${localName}`;\n const el: ScannedElement = {\n id,\n start: stmtStart,\n end: headEnd,\n bodyOpen: opener,\n bodyClose: -1,\n indent: indentOf(stmtStart),\n block,\n };\n const titled = literalIn(stmtStart, headEnd)?.value;\n if (titled !== undefined) el.title = titled;\n if (opener !== -1) {\n stack.push({ id, el });\n i = opener + 1;\n } else {\n el.end = bodylessEnd(stmtStart, headEnd);\n elements.push(el);\n i = headEnd;\n }\n continue;\n }\n\n const am = relationHead(head, relKinds);\n if (am !== null || head.includes(\"->\")) {\n const bClose = opener === -1 ? -1 : matchBrace(code, opener);\n const stmtEnd = opener === -1 ? bodylessEnd(stmtStart, headEnd) : bClose === -1 ? close : bClose + 1;\n if (am !== null) {\n const arrowEnd = stmtStart + am.length;\n const body = opener === -1 ? null : { from: opener + 1, to: stmtEnd - 1 };\n const meta = metadataOf(body);\n const title = literalIn(arrowEnd, headEnd)?.value ?? keyedLiteral(\"title\", body);\n const tags: string[] = [];\n for (const tm of code.slice(stmtStart, stmtEnd).matchAll(/#([\\w-]+)/g)) tags.push(tm[1]!);\n raw.push({\n srcLit: am.src,\n tgtLit: am.tgt,\n parent: parentId,\n start: stmtStart,\n end: stmtEnd,\n indent: indentOf(stmtStart),\n block,\n title,\n op: keyedLiteral(\"op\", meta),\n publishes: keyedLiteral(\"publishes\", meta),\n consumes: keyedLiteral(\"consumes\", meta),\n tags,\n });\n }\n i = Math.max(stmtEnd, headEnd);\n continue;\n }\n\n if (opener !== -1) {\n const bClose = matchBrace(code, opener);\n i = bClose === -1 ? close : bClose + 1;\n } else {\n i = headEnd;\n }\n }\n }\n\n // Resolve relationship endpoints against everything declared anywhere in the\n // model — LikeC4 resolution is not order-dependent, so neither is this.\n const ids = new Set(elements.map((e) => e.id));\n const byLeaf = new Map<string, string[]>();\n for (const e of elements) {\n const leaf = e.id.slice(e.id.lastIndexOf(\".\") + 1);\n byLeaf.set(leaf, [...(byLeaf.get(leaf) ?? []), e.id]);\n }\n const resolve = (lit: string | undefined, enclosing: string): string => {\n if (lit === undefined || lit === \"it\" || lit === \"this\") return enclosing;\n const segs = lit.split(\".\");\n let base: string | undefined;\n for (let scope = enclosing; scope !== \"\" && base === undefined; ) {\n if (ids.has(`${scope}.${segs[0]!}`)) base = `${scope}.${segs[0]!}`;\n const dot = scope.lastIndexOf(\".\");\n scope = dot === -1 ? \"\" : scope.slice(0, dot);\n }\n if (base === undefined && ids.has(segs[0]!)) base = segs[0]!;\n if (base === undefined) {\n const leafed = byLeaf.get(segs[0]!);\n if (leafed !== undefined && leafed.length === 1) base = leafed[0]!;\n }\n return [base ?? segs[0]!, ...segs.slice(1)].join(\".\");\n };\n\n const rels: ScannedRel[] = raw.map((r) => ({\n source: resolve(r.srcLit, r.parent),\n target: resolve(r.tgtLit, r.parent),\n title: r.title,\n op: r.op,\n publishes: r.publishes,\n consumes: r.consumes,\n tags: r.tags,\n start: r.start,\n end: r.end,\n indent: r.indent,\n block: r.block,\n }));\n\n elements.sort((a, b) => a.start - b.start);\n return { blocks, elements, rels };\n}\n\n/**\n * A relationship head's endpoints as written, and where its arrow form ends —\n * null for any other head. Three forms, each with the source omittable inside\n * an element: `a -> b`, `a -[kind]-> b`, and `a .kind b` for a relationship\n * kind the specification declares, which the scan used to skip as a property\n * line, so archive refused a valid map on a relationship count.\n *\n * Ids carry hyphens (`entity-service`): LikeC4's identifier is\n * `[a-zA-Z_][-\\w]*`, and the `\\w`-only spelling here made such an element, or\n * an edge naming one, invisible. The lexer's greed is why `a->b` without a\n * space is not a form worth reading — LikeC4 takes `a-` for the id and rejects\n * the document.\n */\nfunction relationHead(head: string, relKinds: ReadonlySet<string>): { src: string | undefined; tgt: string; length: number } | null {\n const arrow = /^([A-Za-z_][\\w.-]*)?\\s*(?:-\\[[^\\]]*\\])?->\\s*([A-Za-z_][\\w.-]*)/.exec(head);\n if (arrow !== null) return { src: arrow[1], tgt: arrow[2]!, length: arrow[0].length };\n const dotted = /^(?:([A-Za-z_][\\w.-]*)\\s+)?\\.([A-Za-z_][\\w-]*)\\s+([A-Za-z_][\\w.-]*)/.exec(head);\n if (dotted === null || !relKinds.has(dotted[2]!)) return null;\n return { src: dotted[1], tgt: dotted[3]!, length: dotted[0].length };\n}\n"]}
|
|
@@ -60,6 +60,25 @@ function stripFeatureTag(block, featureId, cuts) {
|
|
|
60
60
|
continue;
|
|
61
61
|
let s = m.index;
|
|
62
62
|
let e = s + m[0].length;
|
|
63
|
+
// A tag list's separators go with the tag they separate. LikeC4 reads a
|
|
64
|
+
// list as `#a #b, #c;` — one or more tags first, then `,` groups, then an
|
|
65
|
+
// optional `;` — so `#FEAT-1, #x` stripped to `, #x` and `#FEAT-1;` to a
|
|
66
|
+
// bare `;`, and the parse net refused a delta LikeC4 accepts. The comma
|
|
67
|
+
// after the tag goes with it, else the comma before it; the `;` only when
|
|
68
|
+
// no tag is left in front of it.
|
|
69
|
+
const commaAfter = /^[ \t]*,[ \t]*/.exec(code.slice(e));
|
|
70
|
+
const commaBefore = /,[ \t]*$/.exec(code.slice(0, s));
|
|
71
|
+
const semi = /^[ \t]*;/.exec(code.slice(e));
|
|
72
|
+
if (commaAfter !== null) {
|
|
73
|
+
removals.push([s, e + commaAfter[0].length]);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (commaBefore !== null) {
|
|
77
|
+
removals.push([commaBefore.index, e]);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (semi !== null && !/#[\w-]+\s*$/.test(code.slice(0, s)))
|
|
81
|
+
e += semi[0].length;
|
|
63
82
|
// Take the whitespace on ONE side with the token — trailing first, so
|
|
64
83
|
// `#FEAT-1 #critical` leaves `#critical` at its own indent, and a token at
|
|
65
84
|
// the end of a line does not leave a trailing space behind.
|