@lingjingai/scriptctl 0.49.16 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/changes/0.50.0.md +63 -0
- package/changes/0.51.0.md +24 -0
- package/dist/cli/register-batch.d.ts +3 -0
- package/dist/cli/register-batch.js +28 -0
- package/dist/cli/register-batch.js.map +1 -0
- package/dist/cli/register-edits.d.ts +4 -0
- package/dist/cli/register-edits.js +226 -0
- package/dist/cli/register-edits.js.map +1 -0
- package/dist/cli/register-query.d.ts +4 -0
- package/dist/cli/register-query.js +93 -0
- package/dist/cli/register-query.js.map +1 -0
- package/dist/cli/register-tools.d.ts +3 -0
- package/dist/cli/register-tools.js +23 -0
- package/dist/cli/register-tools.js.map +1 -0
- package/dist/cli/register-workflows.d.ts +4 -0
- package/dist/cli/register-workflows.js +71 -0
- package/dist/cli/register-workflows.js.map +1 -0
- package/dist/cli/registry.d.ts +14 -0
- package/dist/cli/registry.js +65 -0
- package/dist/cli/registry.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +146 -575
- package/dist/cli.js.map +1 -1
- package/dist/common.d.ts +12 -38
- package/dist/common.js +5 -11
- package/dist/common.js.map +1 -1
- package/dist/domain/authoring/apply.d.ts +1 -33
- package/dist/domain/authoring/apply.js +1 -783
- package/dist/domain/authoring/apply.js.map +1 -1
- package/dist/domain/authoring/export.d.ts +1 -7
- package/dist/domain/authoring/export.js +1 -84
- package/dist/domain/authoring/export.js.map +1 -1
- package/dist/domain/authoring/parser.d.ts +2 -3
- package/dist/domain/authoring/parser.js +2 -914
- package/dist/domain/authoring/parser.js.map +1 -1
- package/dist/domain/authoring/serializer.d.ts +1 -2
- package/dist/domain/authoring/serializer.js +1 -243
- package/dist/domain/authoring/serializer.js.map +1 -1
- package/dist/domain/authoring/shared/bracket.d.ts +4 -0
- package/dist/domain/authoring/shared/bracket.js +95 -0
- package/dist/domain/authoring/shared/bracket.js.map +1 -0
- package/dist/domain/authoring/shared/types.d.ts +12 -0
- package/dist/domain/authoring/shared/types.js +2 -0
- package/dist/domain/authoring/shared/types.js.map +1 -0
- package/dist/domain/authoring/types.d.ts +2 -87
- package/dist/domain/authoring/types.js +2 -1
- package/dist/domain/authoring/types.js.map +1 -1
- package/dist/domain/authoring/v3/apply.d.ts +33 -0
- package/dist/domain/authoring/v3/apply.js +784 -0
- package/dist/domain/authoring/v3/apply.js.map +1 -0
- package/dist/domain/authoring/v3/export.d.ts +7 -0
- package/dist/domain/authoring/v3/export.js +85 -0
- package/dist/domain/authoring/v3/export.js.map +1 -0
- package/dist/domain/authoring/v3/parser.d.ts +3 -0
- package/dist/domain/authoring/v3/parser.js +823 -0
- package/dist/domain/authoring/v3/parser.js.map +1 -0
- package/dist/domain/authoring/v3/serializer.d.ts +2 -0
- package/dist/domain/authoring/v3/serializer.js +244 -0
- package/dist/domain/authoring/v3/serializer.js.map +1 -0
- package/dist/domain/authoring/v3/types.d.ts +76 -0
- package/dist/domain/authoring/v3/types.js +2 -0
- package/dist/domain/authoring/v3/types.js.map +1 -0
- package/dist/domain/authoring/v4/apply.d.ts +40 -0
- package/dist/domain/authoring/v4/apply.js +451 -0
- package/dist/domain/authoring/v4/apply.js.map +1 -0
- package/dist/domain/authoring/v4/parser.d.ts +2 -0
- package/dist/domain/authoring/v4/parser.js +729 -0
- package/dist/domain/authoring/v4/parser.js.map +1 -0
- package/dist/domain/authoring/v4/serializer.d.ts +6 -0
- package/dist/domain/authoring/v4/serializer.js +280 -0
- package/dist/domain/authoring/v4/serializer.js.map +1 -0
- package/dist/domain/authoring/v4/types.d.ts +50 -0
- package/dist/domain/authoring/v4/types.js +2 -0
- package/dist/domain/authoring/v4/types.js.map +1 -0
- package/dist/domain/ingest/apply-plan.d.ts +1 -1
- package/dist/domain/ingest/assembler.d.ts +9 -0
- package/dist/domain/ingest/assembler.js +98 -36
- package/dist/domain/ingest/assembler.js.map +1 -1
- package/dist/domain/ingest/asset-audit.d.ts +50 -0
- package/dist/domain/ingest/asset-audit.js +196 -0
- package/dist/domain/ingest/asset-audit.js.map +1 -0
- package/dist/domain/ingest/production-validation.d.ts +5 -4
- package/dist/domain/ingest/production-validation.js +10 -25
- package/dist/domain/ingest/production-validation.js.map +1 -1
- package/dist/domain/ingest/records.d.ts +1 -1
- package/dist/domain/ingest/records.js +1 -1
- package/dist/domain/ingest/records.js.map +1 -1
- package/dist/domain/ingest/serial-context.d.ts +1 -1
- package/dist/domain/ingest/validation.d.ts +1 -11
- package/dist/domain/ingest/validation.js +1 -199
- package/dist/domain/ingest/validation.js.map +1 -1
- package/dist/domain/ingest/video-apply.js +68 -45
- package/dist/domain/ingest/video-apply.js.map +1 -1
- package/dist/domain/script/address.d.ts +1 -32
- package/dist/domain/script/address.js +1 -144
- package/dist/domain/script/address.js.map +1 -1
- package/dist/domain/script/dispatch.d.ts +14 -0
- package/dist/domain/script/dispatch.js +45 -0
- package/dist/domain/script/dispatch.js.map +1 -0
- package/dist/domain/script/lookups.d.ts +1 -33
- package/dist/domain/script/lookups.js +1 -316
- package/dist/domain/script/lookups.js.map +1 -1
- package/dist/domain/script/parse.d.ts +1 -3
- package/dist/domain/script/parse.js +1 -164
- package/dist/domain/script/parse.js.map +1 -1
- package/dist/domain/script/patch/apply.d.ts +1 -2
- package/dist/domain/script/patch/apply.js +1 -30
- package/dist/domain/script/patch/apply.js.map +1 -1
- package/dist/domain/script/patch/helpers.d.ts +1 -17
- package/dist/domain/script/patch/helpers.js +1 -210
- package/dist/domain/script/patch/helpers.js.map +1 -1
- package/dist/domain/script/patch/inline-speaker.d.ts +1 -2
- package/dist/domain/script/patch/inline-speaker.js +1 -49
- package/dist/domain/script/patch/inline-speaker.js.map +1 -1
- package/dist/domain/script/patch/ops-action.d.ts +1 -12
- package/dist/domain/script/patch/ops-action.js +1 -366
- package/dist/domain/script/patch/ops-action.js.map +1 -1
- package/dist/domain/script/patch/ops-asset.d.ts +1 -14
- package/dist/domain/script/patch/ops-asset.js +1 -364
- package/dist/domain/script/patch/ops-asset.js.map +1 -1
- package/dist/domain/script/patch/ops-dialogue.d.ts +1 -2
- package/dist/domain/script/patch/ops-dialogue.js +1 -25
- package/dist/domain/script/patch/ops-dialogue.js.map +1 -1
- package/dist/domain/script/patch/ops-extend.d.ts +1 -8
- package/dist/domain/script/patch/ops-extend.js +1 -110
- package/dist/domain/script/patch/ops-extend.js.map +1 -1
- package/dist/domain/script/patch/ops-meta.d.ts +1 -5
- package/dist/domain/script/patch/ops-meta.js +1 -81
- package/dist/domain/script/patch/ops-meta.js.map +1 -1
- package/dist/domain/script/patch/ops-scene.d.ts +1 -6
- package/dist/domain/script/patch/ops-scene.js +1 -350
- package/dist/domain/script/patch/ops-scene.js.map +1 -1
- package/dist/domain/script/patch/ops-state.d.ts +1 -8
- package/dist/domain/script/patch/ops-state.js +1 -164
- package/dist/domain/script/patch/ops-state.js.map +1 -1
- package/dist/domain/script/patch/registry.d.ts +1 -2
- package/dist/domain/script/patch/registry.js +1 -52
- package/dist/domain/script/patch/registry.js.map +1 -1
- package/dist/domain/script/patch/types.d.ts +1 -10
- package/dist/domain/script/patch/types.js +1 -1
- package/dist/domain/script/patch/types.js.map +1 -1
- package/dist/domain/script/refs.d.ts +1 -4
- package/dist/domain/script/refs.js +1 -63
- package/dist/domain/script/refs.js.map +1 -1
- package/dist/domain/script/scene-refs.d.ts +1 -3
- package/dist/domain/script/scene-refs.js +1 -34
- package/dist/domain/script/scene-refs.js.map +1 -1
- package/dist/domain/script/schema.d.ts +1 -6
- package/dist/domain/script/schema.js +1 -55
- package/dist/domain/script/schema.js.map +1 -1
- package/dist/domain/script/selector.d.ts +1 -45
- package/dist/domain/script/selector.js +1 -184
- package/dist/domain/script/selector.js.map +1 -1
- package/dist/domain/script/shared/regex.d.ts +2 -0
- package/dist/domain/script/shared/regex.js +7 -0
- package/dist/domain/script/shared/regex.js.map +1 -0
- package/dist/domain/script/shared/types.d.ts +18 -0
- package/dist/domain/script/shared/types.js +9 -0
- package/dist/domain/script/shared/types.js.map +1 -0
- package/dist/domain/script/shared/validation.d.ts +10 -0
- package/dist/domain/script/shared/validation.js +2 -0
- package/dist/domain/script/shared/validation.js.map +1 -0
- package/dist/domain/script/shared.js +4 -6
- package/dist/domain/script/shared.js.map +1 -1
- package/dist/domain/script/types.d.ts +1 -123
- package/dist/domain/script/types.js +1 -8
- package/dist/domain/script/types.js.map +1 -1
- package/dist/domain/script/v3/address.d.ts +32 -0
- package/dist/domain/script/v3/address.js +136 -0
- package/dist/domain/script/v3/address.js.map +1 -0
- package/dist/domain/script/v3/lookups.d.ts +33 -0
- package/dist/domain/script/v3/lookups.js +316 -0
- package/dist/domain/script/v3/lookups.js.map +1 -0
- package/dist/domain/script/v3/ordinal.d.ts +8 -0
- package/dist/domain/script/v3/ordinal.js +91 -0
- package/dist/domain/script/v3/ordinal.js.map +1 -0
- package/dist/domain/script/v3/parse.d.ts +3 -0
- package/dist/domain/script/v3/parse.js +164 -0
- package/dist/domain/script/v3/parse.js.map +1 -0
- package/dist/domain/script/v3/patch/apply.d.ts +2 -0
- package/dist/domain/script/v3/patch/apply.js +31 -0
- package/dist/domain/script/v3/patch/apply.js.map +1 -0
- package/dist/domain/script/v3/patch/helpers.d.ts +17 -0
- package/dist/domain/script/v3/patch/helpers.js +209 -0
- package/dist/domain/script/v3/patch/helpers.js.map +1 -0
- package/dist/domain/script/v3/patch/inline-speaker.d.ts +2 -0
- package/dist/domain/script/v3/patch/inline-speaker.js +50 -0
- package/dist/domain/script/v3/patch/inline-speaker.js.map +1 -0
- package/dist/domain/script/v3/patch/ops-action.d.ts +12 -0
- package/dist/domain/script/v3/patch/ops-action.js +367 -0
- package/dist/domain/script/v3/patch/ops-action.js.map +1 -0
- package/dist/domain/script/v3/patch/ops-asset.d.ts +14 -0
- package/dist/domain/script/v3/patch/ops-asset.js +365 -0
- package/dist/domain/script/v3/patch/ops-asset.js.map +1 -0
- package/dist/domain/script/v3/patch/ops-dialogue.d.ts +2 -0
- package/dist/domain/script/v3/patch/ops-dialogue.js +26 -0
- package/dist/domain/script/v3/patch/ops-dialogue.js.map +1 -0
- package/dist/domain/script/v3/patch/ops-extend.d.ts +8 -0
- package/dist/domain/script/v3/patch/ops-extend.js +111 -0
- package/dist/domain/script/v3/patch/ops-extend.js.map +1 -0
- package/dist/domain/script/v3/patch/ops-meta.d.ts +5 -0
- package/dist/domain/script/v3/patch/ops-meta.js +82 -0
- package/dist/domain/script/v3/patch/ops-meta.js.map +1 -0
- package/dist/domain/script/v3/patch/ops-scene.d.ts +6 -0
- package/dist/domain/script/v3/patch/ops-scene.js +351 -0
- package/dist/domain/script/v3/patch/ops-scene.js.map +1 -0
- package/dist/domain/script/v3/patch/ops-state.d.ts +8 -0
- package/dist/domain/script/v3/patch/ops-state.js +165 -0
- package/dist/domain/script/v3/patch/ops-state.js.map +1 -0
- package/dist/domain/script/v3/patch/registry.d.ts +2 -0
- package/dist/domain/script/v3/patch/registry.js +53 -0
- package/dist/domain/script/v3/patch/registry.js.map +1 -0
- package/dist/domain/script/v3/patch/types.d.ts +10 -0
- package/dist/domain/script/v3/patch/types.js +2 -0
- package/dist/domain/script/v3/patch/types.js.map +1 -0
- package/dist/domain/script/v3/refs.d.ts +4 -0
- package/dist/domain/script/v3/refs.js +64 -0
- package/dist/domain/script/v3/refs.js.map +1 -0
- package/dist/domain/script/v3/scene-refs.d.ts +3 -0
- package/dist/domain/script/v3/scene-refs.js +35 -0
- package/dist/domain/script/v3/scene-refs.js.map +1 -0
- package/dist/domain/script/v3/schema.d.ts +6 -0
- package/dist/domain/script/v3/schema.js +56 -0
- package/dist/domain/script/v3/schema.js.map +1 -0
- package/dist/domain/script/v3/selector.d.ts +44 -0
- package/dist/domain/script/v3/selector.js +178 -0
- package/dist/domain/script/v3/selector.js.map +1 -0
- package/dist/domain/script/v3/types.d.ts +106 -0
- package/dist/domain/script/v3/types.js +2 -0
- package/dist/domain/script/v3/types.js.map +1 -0
- package/dist/domain/script/v3/validation.d.ts +3 -0
- package/dist/domain/script/v3/validation.js +200 -0
- package/dist/domain/script/v3/validation.js.map +1 -0
- package/dist/domain/script/v4/address.d.ts +61 -0
- package/dist/domain/script/v4/address.js +99 -0
- package/dist/domain/script/v4/address.js.map +1 -0
- package/dist/domain/script/v4/factory.d.ts +2 -0
- package/dist/domain/script/v4/factory.js +13 -0
- package/dist/domain/script/v4/factory.js.map +1 -0
- package/dist/domain/script/v4/from-v3.d.ts +29 -0
- package/dist/domain/script/v4/from-v3.js +307 -0
- package/dist/domain/script/v4/from-v3.js.map +1 -0
- package/dist/domain/script/v4/ids.d.ts +27 -0
- package/dist/domain/script/v4/ids.js +62 -0
- package/dist/domain/script/v4/ids.js.map +1 -0
- package/dist/domain/script/v4/ordinal.d.ts +3 -0
- package/dist/domain/script/v4/ordinal.js +66 -0
- package/dist/domain/script/v4/ordinal.js.map +1 -0
- package/dist/domain/script/v4/parse.d.ts +3 -0
- package/dist/domain/script/v4/parse.js +17 -0
- package/dist/domain/script/v4/parse.js.map +1 -0
- package/dist/domain/script/v4/patch/apply.d.ts +3 -0
- package/dist/domain/script/v4/patch/apply.js +24 -0
- package/dist/domain/script/v4/patch/apply.js.map +1 -0
- package/dist/domain/script/v4/patch/helpers.d.ts +32 -0
- package/dist/domain/script/v4/patch/helpers.js +138 -0
- package/dist/domain/script/v4/patch/helpers.js.map +1 -0
- package/dist/domain/script/v4/patch/ops-action.d.ts +13 -0
- package/dist/domain/script/v4/patch/ops-action.js +376 -0
- package/dist/domain/script/v4/patch/ops-action.js.map +1 -0
- package/dist/domain/script/v4/patch/ops-asset.d.ts +17 -0
- package/dist/domain/script/v4/patch/ops-asset.js +617 -0
- package/dist/domain/script/v4/patch/ops-asset.js.map +1 -0
- package/dist/domain/script/v4/patch/ops-extend.d.ts +11 -0
- package/dist/domain/script/v4/patch/ops-extend.js +86 -0
- package/dist/domain/script/v4/patch/ops-extend.js.map +1 -0
- package/dist/domain/script/v4/patch/ops-meta.d.ts +5 -0
- package/dist/domain/script/v4/patch/ops-meta.js +49 -0
- package/dist/domain/script/v4/patch/ops-meta.js.map +1 -0
- package/dist/domain/script/v4/patch/ops-scene-ref.d.ts +3 -0
- package/dist/domain/script/v4/patch/ops-scene-ref.js +98 -0
- package/dist/domain/script/v4/patch/ops-scene-ref.js.map +1 -0
- package/dist/domain/script/v4/patch/ops-structure.d.ts +6 -0
- package/dist/domain/script/v4/patch/ops-structure.js +236 -0
- package/dist/domain/script/v4/patch/ops-structure.js.map +1 -0
- package/dist/domain/script/v4/patch/registry.d.ts +2 -0
- package/dist/domain/script/v4/patch/registry.js +50 -0
- package/dist/domain/script/v4/patch/registry.js.map +1 -0
- package/dist/domain/script/v4/patch/schema.d.ts +7 -0
- package/dist/domain/script/v4/patch/schema.js +75 -0
- package/dist/domain/script/v4/patch/schema.js.map +1 -0
- package/dist/domain/script/v4/patch/types.d.ts +10 -0
- package/dist/domain/script/v4/patch/types.js +2 -0
- package/dist/domain/script/v4/patch/types.js.map +1 -0
- package/dist/domain/script/v4/selector.d.ts +11 -0
- package/dist/domain/script/v4/selector.js +124 -0
- package/dist/domain/script/v4/selector.js.map +1 -0
- package/dist/domain/script/v4/types.d.ts +120 -0
- package/dist/domain/script/v4/types.js +2 -0
- package/dist/domain/script/v4/types.js.map +1 -0
- package/dist/domain/script/v4/validation.d.ts +2 -0
- package/dist/domain/script/v4/validation.js +378 -0
- package/dist/domain/script/v4/validation.js.map +1 -0
- package/dist/infra/ingest/video-discovery.js +7 -4
- package/dist/infra/ingest/video-discovery.js.map +1 -1
- package/dist/infra/script-output-store.js +6 -11
- package/dist/infra/script-output-store.js.map +1 -1
- package/dist/infra/script-working-copy.js +15 -16
- package/dist/infra/script-working-copy.js.map +1 -1
- package/dist/llm/config.js +5 -4
- package/dist/llm/config.js.map +1 -1
- package/dist/llm/registry.d.ts +1 -0
- package/dist/llm/registry.js +3 -0
- package/dist/llm/registry.js.map +1 -1
- package/dist/llm/router.js +6 -8
- package/dist/llm/router.js.map +1 -1
- package/dist/llm/tasks/ingest/asset-audit.d.ts +6 -0
- package/dist/llm/tasks/ingest/asset-audit.js +164 -0
- package/dist/llm/tasks/ingest/asset-audit.js.map +1 -0
- package/dist/llm/tasks/ingest/asset-curate.d.ts +1 -1
- package/dist/llm/tasks/ingest/text-normalize.js +3 -3
- package/dist/llm/tasks/ingest/text-normalize.js.map +1 -1
- package/dist/llm/tasks/ingest/video-serial.js +3 -3
- package/dist/llm/tasks/ingest/video-serial.js.map +1 -1
- package/dist/llm/types.d.ts +1 -1
- package/dist/llm/types.js.map +1 -1
- package/dist/output.d.ts +2 -3
- package/dist/output.js +72 -109
- package/dist/output.js.map +1 -1
- package/dist/usecases/changelog.d.ts +2 -2
- package/dist/usecases/changelog.js +28 -36
- package/dist/usecases/changelog.js.map +1 -1
- package/dist/usecases/doctor.d.ts +2 -2
- package/dist/usecases/doctor.js +3 -5
- package/dist/usecases/doctor.js.map +1 -1
- package/dist/usecases/ingest/command.d.ts +2 -2
- package/dist/usecases/ingest/command.js +23 -6
- package/dist/usecases/ingest/command.js.map +1 -1
- package/dist/usecases/ingest/final-asset-audit.d.ts +39 -0
- package/dist/usecases/ingest/final-asset-audit.js +88 -0
- package/dist/usecases/ingest/final-asset-audit.js.map +1 -0
- package/dist/usecases/ingest/pass5-extract.js +5 -4
- package/dist/usecases/ingest/pass5-extract.js.map +1 -1
- package/dist/usecases/ingest/pass5-govern.js +13 -11
- package/dist/usecases/ingest/pass5-govern.js.map +1 -1
- package/dist/usecases/ingest/pipeline.js +77 -23
- package/dist/usecases/ingest/pipeline.js.map +1 -1
- package/dist/usecases/ingest/serial-govern.d.ts +2 -1
- package/dist/usecases/ingest/serial-govern.js +16 -8
- package/dist/usecases/ingest/serial-govern.js.map +1 -1
- package/dist/usecases/ingest/status.d.ts +2 -2
- package/dist/usecases/ingest/status.js +1 -1
- package/dist/usecases/ingest/status.js.map +1 -1
- package/dist/usecases/ingest/video-pipeline.js +121 -29
- package/dist/usecases/ingest/video-pipeline.js.map +1 -1
- package/dist/usecases/ingest/view-command.d.ts +2 -2
- package/dist/usecases/ingest/view-command.js +7 -6
- package/dist/usecases/ingest/view-command.js.map +1 -1
- package/dist/usecases/ingest/view-server.d.ts +2 -2
- package/dist/usecases/ingest/view-server.js +9 -7
- package/dist/usecases/ingest/view-server.js.map +1 -1
- package/dist/usecases/script/actions.d.ts +2 -2
- package/dist/usecases/script/actions.js +106 -11
- package/dist/usecases/script/actions.js.map +1 -1
- package/dist/usecases/script/actor.d.ts +2 -2
- package/dist/usecases/script/actor.js +3 -4
- package/dist/usecases/script/actor.js.map +1 -1
- package/dist/usecases/script/actors.d.ts +2 -2
- package/dist/usecases/script/actors.js +18 -9
- package/dist/usecases/script/actors.js.map +1 -1
- package/dist/usecases/script/add-actor.d.ts +2 -2
- package/dist/usecases/script/add-episode.d.ts +2 -2
- package/dist/usecases/script/add-location.d.ts +2 -2
- package/dist/usecases/script/add-prop.d.ts +2 -2
- package/dist/usecases/script/alias.d.ts +2 -2
- package/dist/usecases/script/alias.js +13 -14
- package/dist/usecases/script/alias.js.map +1 -1
- package/dist/usecases/script/assets.d.ts +2 -2
- package/dist/usecases/script/assets.js +29 -5
- package/dist/usecases/script/assets.js.map +1 -1
- package/dist/usecases/script/audit-assets.d.ts +4 -0
- package/dist/usecases/script/audit-assets.js +37 -0
- package/dist/usecases/script/audit-assets.js.map +1 -0
- package/dist/usecases/script/command-constraints.d.ts +36 -0
- package/dist/usecases/script/command-constraints.js +114 -0
- package/dist/usecases/script/command-constraints.js.map +1 -0
- package/dist/usecases/script/context.d.ts +2 -2
- package/dist/usecases/script/context.js +34 -8
- package/dist/usecases/script/context.js.map +1 -1
- package/dist/usecases/script/create.d.ts +2 -2
- package/dist/usecases/script/create.js +5 -6
- package/dist/usecases/script/create.js.map +1 -1
- package/dist/usecases/script/delete.d.ts +2 -2
- package/dist/usecases/script/delete.js +15 -15
- package/dist/usecases/script/delete.js.map +1 -1
- package/dist/usecases/script/describe.d.ts +2 -2
- package/dist/usecases/script/describe.js +13 -12
- package/dist/usecases/script/describe.js.map +1 -1
- package/dist/usecases/script/dialogue.d.ts +2 -2
- package/dist/usecases/script/dialogue.js +18 -9
- package/dist/usecases/script/dialogue.js.map +1 -1
- package/dist/usecases/script/dispatch.d.ts +3 -0
- package/dist/usecases/script/dispatch.js +10 -0
- package/dist/usecases/script/dispatch.js.map +1 -0
- package/dist/usecases/script/do.d.ts +2 -2
- package/dist/usecases/script/do.js +105 -45
- package/dist/usecases/script/do.js.map +1 -1
- package/dist/usecases/script/emotion.d.ts +2 -2
- package/dist/usecases/script/emotion.js +14 -3
- package/dist/usecases/script/emotion.js.map +1 -1
- package/dist/usecases/script/episodes.d.ts +2 -2
- package/dist/usecases/script/episodes.js +19 -8
- package/dist/usecases/script/episodes.js.map +1 -1
- package/dist/usecases/script/export-authoring.d.ts +2 -2
- package/dist/usecases/script/export-authoring.js +47 -26
- package/dist/usecases/script/export-authoring.js.map +1 -1
- package/dist/usecases/script/extend.d.ts +2 -2
- package/dist/usecases/script/extend.js +43 -31
- package/dist/usecases/script/extend.js.map +1 -1
- package/dist/usecases/script/ids.d.ts +2 -2
- package/dist/usecases/script/ids.js +68 -21
- package/dist/usecases/script/ids.js.map +1 -1
- package/dist/usecases/script/importance.d.ts +2 -2
- package/dist/usecases/script/importance.js +3 -4
- package/dist/usecases/script/importance.js.map +1 -1
- package/dist/usecases/script/insert.d.ts +2 -2
- package/dist/usecases/script/insert.js +80 -46
- package/dist/usecases/script/insert.js.map +1 -1
- package/dist/usecases/script/issues.d.ts +2 -2
- package/dist/usecases/script/issues.js +10 -2
- package/dist/usecases/script/issues.js.map +1 -1
- package/dist/usecases/script/lib.d.ts +62 -7
- package/dist/usecases/script/lib.js +782 -184
- package/dist/usecases/script/lib.js.map +1 -1
- package/dist/usecases/script/locations.d.ts +2 -2
- package/dist/usecases/script/locations.js +18 -9
- package/dist/usecases/script/locations.js.map +1 -1
- package/dist/usecases/script/merge.d.ts +2 -2
- package/dist/usecases/script/merge.js +17 -17
- package/dist/usecases/script/merge.js.map +1 -1
- package/dist/usecases/script/move.d.ts +2 -2
- package/dist/usecases/script/move.js +30 -13
- package/dist/usecases/script/move.js.map +1 -1
- package/dist/usecases/script/parenthetical.d.ts +3 -0
- package/dist/usecases/script/parenthetical.js +52 -0
- package/dist/usecases/script/parenthetical.js.map +1 -0
- package/dist/usecases/script/props.d.ts +2 -2
- package/dist/usecases/script/props.js +18 -9
- package/dist/usecases/script/props.js.map +1 -1
- package/dist/usecases/script/refs.d.ts +2 -2
- package/dist/usecases/script/refs.js +61 -11
- package/dist/usecases/script/refs.js.map +1 -1
- package/dist/usecases/script/rename.d.ts +2 -2
- package/dist/usecases/script/rename.js +13 -12
- package/dist/usecases/script/rename.js.map +1 -1
- package/dist/usecases/script/replace.d.ts +2 -2
- package/dist/usecases/script/replace.js +6 -8
- package/dist/usecases/script/replace.js.map +1 -1
- package/dist/usecases/script/role.d.ts +2 -2
- package/dist/usecases/script/role.js +3 -4
- package/dist/usecases/script/role.js.map +1 -1
- package/dist/usecases/script/scenes.d.ts +2 -2
- package/dist/usecases/script/scenes.js +35 -7
- package/dist/usecases/script/scenes.js.map +1 -1
- package/dist/usecases/script/script-patch.d.ts +2 -2
- package/dist/usecases/script/script-patch.js +219 -72
- package/dist/usecases/script/script-patch.js.map +1 -1
- package/dist/usecases/script/script-validate.d.ts +2 -2
- package/dist/usecases/script/script-validate.js +11 -7
- package/dist/usecases/script/script-validate.js.map +1 -1
- package/dist/usecases/script/session.d.ts +3 -0
- package/dist/usecases/script/session.js +74 -65
- package/dist/usecases/script/session.js.map +1 -1
- package/dist/usecases/script/split.d.ts +2 -2
- package/dist/usecases/script/split.js +18 -14
- package/dist/usecases/script/split.js.map +1 -1
- package/dist/usecases/script/state-add.d.ts +2 -2
- package/dist/usecases/script/state-add.js +3 -4
- package/dist/usecases/script/state-add.js.map +1 -1
- package/dist/usecases/script/state-delete.d.ts +2 -2
- package/dist/usecases/script/state-delete.js +3 -4
- package/dist/usecases/script/state-delete.js.map +1 -1
- package/dist/usecases/script/state-rename.d.ts +2 -2
- package/dist/usecases/script/state-rename.js +3 -4
- package/dist/usecases/script/state-rename.js.map +1 -1
- package/dist/usecases/script/states.d.ts +2 -2
- package/dist/usecases/script/states.js +91 -20
- package/dist/usecases/script/states.js.map +1 -1
- package/dist/usecases/script/summary.d.ts +2 -2
- package/dist/usecases/script/summary.js +21 -2
- package/dist/usecases/script/summary.js.map +1 -1
- package/dist/usecases/script/synopsis-generate.d.ts +2 -2
- package/dist/usecases/script/synopsis-generate.js +38 -39
- package/dist/usecases/script/synopsis-generate.js.map +1 -1
- package/dist/usecases/script/synopsis.d.ts +2 -2
- package/dist/usecases/script/synopsis.js +20 -16
- package/dist/usecases/script/synopsis.js.map +1 -1
- package/dist/usecases/script/transition.d.ts +2 -2
- package/dist/usecases/script/transition.js +3 -4
- package/dist/usecases/script/transition.js.map +1 -1
- package/dist/usecases/script/type.d.ts +2 -2
- package/dist/usecases/script/type.js +3 -4
- package/dist/usecases/script/type.js.map +1 -1
- package/dist/usecases/script/v3/mutations.d.ts +2 -0
- package/dist/usecases/script/v3/mutations.js +5 -0
- package/dist/usecases/script/v3/mutations.js.map +1 -0
- package/dist/usecases/script/v4/mutations.d.ts +2 -0
- package/dist/usecases/script/v4/mutations.js +6 -0
- package/dist/usecases/script/v4/mutations.js.map +1 -0
- package/dist/usecases/script/v4/queries.d.ts +15 -0
- package/dist/usecases/script/v4/queries.js +191 -0
- package/dist/usecases/script/v4/queries.js.map +1 -0
- package/dist/usecases/script/working-copy.d.ts +4 -4
- package/dist/usecases/script/working-copy.js +98 -94
- package/dist/usecases/script/working-copy.js.map +1 -1
- package/dist/usecases/script/worldview.d.ts +2 -2
- package/dist/usecases/script/worldview.js +3 -4
- package/dist/usecases/script/worldview.js.map +1 -1
- package/dist/usecases/script/write-authoring.d.ts +2 -2
- package/dist/usecases/script/write-authoring.js +125 -50
- package/dist/usecases/script/write-authoring.js.map +1 -1
- package/dist/usecases/update.d.ts +2 -2
- package/dist/usecases/update.js +32 -47
- package/dist/usecases/update.js.map +1 -1
- package/package.json +3 -2
- package/skills/scriptctl/SKILL.md +128 -282
- package/skills/scriptctl/references/atomic-edit-workflow.md +23 -38
- package/skills/scriptctl/references/bulk-authoring.md +35 -154
- package/skills/scriptctl/references/ingest-workflow.md +12 -11
- package/skills/scriptctl/references/production-writing-standard.md +38 -67
- package/skills/scriptctl/references/state-reference-repair.md +19 -42
- package/dist/help-text.d.ts +0 -2
- package/dist/help-text.js +0 -1112
- package/dist/help-text.js.map +0 -1
|
@@ -0,0 +1,823 @@
|
|
|
1
|
+
import { ACTION_TYPE_SET, IMPORTANCE_TIER_SET, NON_ACTOR_SPEAKER_KIND_SET, ROLE_TYPE_SET, } from "../../script/v3/types.js";
|
|
2
|
+
import { authoringError, parseBracketRecord, } from "../shared/bracket.js";
|
|
3
|
+
export { parseBracketRecord } from "../shared/bracket.js";
|
|
4
|
+
function emptyModifiers() {
|
|
5
|
+
return { extend: {}, extendPresent: false, aliases: [], aliasesPresent: false, phase: "extend" };
|
|
6
|
+
}
|
|
7
|
+
function hasModifiers(modifiers) {
|
|
8
|
+
return modifiers.extendPresent
|
|
9
|
+
|| modifiers.aliasesPresent
|
|
10
|
+
|| modifiers.prompt !== undefined;
|
|
11
|
+
}
|
|
12
|
+
function extensionOrUndefined(modifiers) {
|
|
13
|
+
return modifiers.extendPresent ? modifiers.extend : undefined;
|
|
14
|
+
}
|
|
15
|
+
function isJsonValue(value) {
|
|
16
|
+
if (value === null)
|
|
17
|
+
return true;
|
|
18
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
|
|
19
|
+
return true;
|
|
20
|
+
if (Array.isArray(value))
|
|
21
|
+
return value.every(isJsonValue);
|
|
22
|
+
if (typeof value !== "object")
|
|
23
|
+
return false;
|
|
24
|
+
return Object.values(value).every(isJsonValue);
|
|
25
|
+
}
|
|
26
|
+
function canonicalJson(value) {
|
|
27
|
+
if (Array.isArray(value))
|
|
28
|
+
return value.map(canonicalJson);
|
|
29
|
+
if (value !== null && typeof value === "object") {
|
|
30
|
+
const result = {};
|
|
31
|
+
for (const key of Object.keys(value).sort())
|
|
32
|
+
result[key] = canonicalJson(value[key]);
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
function isImportance(value) {
|
|
38
|
+
return value === "featured" || value === "background";
|
|
39
|
+
}
|
|
40
|
+
function isRoleType(value) {
|
|
41
|
+
return value === "主角" || value === "配角";
|
|
42
|
+
}
|
|
43
|
+
function isNonActorSpeakerKind(value) {
|
|
44
|
+
return value === "system" || value === "broadcast" || value === "offscreen" || value === "group";
|
|
45
|
+
}
|
|
46
|
+
function isAssetKind(value) {
|
|
47
|
+
return value === "actor" || value === "location" || value === "prop";
|
|
48
|
+
}
|
|
49
|
+
function parsePositiveInteger(raw, source, label, allowZero) {
|
|
50
|
+
if (!/^\d+$/.test(raw)) {
|
|
51
|
+
throw authoringError(`${label} must be an integer.`, source, raw || "<empty>", `Use ${allowZero ? "a non-negative" : "a positive"} integer.`);
|
|
52
|
+
}
|
|
53
|
+
const value = Number(raw);
|
|
54
|
+
if (!Number.isSafeInteger(value) || (allowZero ? value < 0 : value < 1)) {
|
|
55
|
+
throw authoringError(`${label} is out of range.`, source, raw, `Use ${allowZero ? "a non-negative" : "a positive"} safe integer.`);
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
function parseTag(raw, line) {
|
|
60
|
+
const text = raw.trim();
|
|
61
|
+
if (!text.startsWith("<"))
|
|
62
|
+
return null;
|
|
63
|
+
const source = { line, column: raw.indexOf("<") + 1 };
|
|
64
|
+
const closingMatch = /^<\/([a-z-]+)>$/.exec(text);
|
|
65
|
+
if (closingMatch)
|
|
66
|
+
return { name: closingMatch[1], closing: true, attrs: new Map(), source };
|
|
67
|
+
const openMatch = /^<([a-z-]+)(?: ([^>]+))?>$/.exec(text);
|
|
68
|
+
if (!openMatch) {
|
|
69
|
+
throw authoringError("Block tag syntax is invalid.", source, raw, "Use <name key=value> or </name> on its own line.");
|
|
70
|
+
}
|
|
71
|
+
const attrs = new Map();
|
|
72
|
+
const attrText = openMatch[2] ?? "";
|
|
73
|
+
if (attrText) {
|
|
74
|
+
for (const token of attrText.split(" ")) {
|
|
75
|
+
if (!token) {
|
|
76
|
+
throw authoringError("Block attributes must use one space separators.", source, raw, "Use canonical key=value attributes separated by one space.");
|
|
77
|
+
}
|
|
78
|
+
const match = /^([a-z]+)=([A-Za-z0-9_./#:-]+)$/.exec(token);
|
|
79
|
+
if (!match) {
|
|
80
|
+
throw authoringError("Block attribute syntax is invalid.", source, token, "Use unquoted canonical key=value attributes.");
|
|
81
|
+
}
|
|
82
|
+
if (attrs.has(match[1])) {
|
|
83
|
+
throw authoringError("Block attribute is duplicated.", source, match[1], "Keep exactly one value for each attribute.");
|
|
84
|
+
}
|
|
85
|
+
attrs.set(match[1], match[2]);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { name: openMatch[1], closing: false, attrs, source };
|
|
89
|
+
}
|
|
90
|
+
function assertAttributes(tag, required, optional = []) {
|
|
91
|
+
const allowed = new Set([...required, ...optional]);
|
|
92
|
+
const unknown = [...tag.attrs.keys()].filter((key) => !allowed.has(key));
|
|
93
|
+
const missing = required.filter((key) => !tag.attrs.has(key));
|
|
94
|
+
if (unknown.length > 0 || missing.length > 0) {
|
|
95
|
+
throw authoringError(`Attributes for <${tag.name}> are invalid.`, tag.source, `missing=${missing.join(",") || "-"} unknown=${unknown.join(",") || "-"}`, `Use ${[...required, ...optional].map((key) => `${key}=...`).join(" ")}.`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function speakerFromSlot(raw, source) {
|
|
99
|
+
if (!raw) {
|
|
100
|
+
throw authoringError("Speaker is required.", source, "<empty>", "Use act_ID[/state_ID] or system|broadcast|offscreen|group[:label].");
|
|
101
|
+
}
|
|
102
|
+
const slash = raw.indexOf("/");
|
|
103
|
+
const actorId = slash >= 0 ? raw.slice(0, slash) : raw;
|
|
104
|
+
if (/^act_[A-Za-z0-9_-]+$/.test(actorId)) {
|
|
105
|
+
if (slash < 0)
|
|
106
|
+
return { actor_id: actorId };
|
|
107
|
+
const stateId = raw.slice(slash + 1);
|
|
108
|
+
if (!stateId || stateId.includes("/")) {
|
|
109
|
+
throw authoringError("Actor speaker state is invalid.", source, raw, "Use act_ID/state_ID.");
|
|
110
|
+
}
|
|
111
|
+
return { actor_id: actorId, state_id: stateId };
|
|
112
|
+
}
|
|
113
|
+
const colon = raw.indexOf(":");
|
|
114
|
+
const kind = colon >= 0 ? raw.slice(0, colon) : raw;
|
|
115
|
+
if (!NON_ACTOR_SPEAKER_KIND_SET.has(kind) || !isNonActorSpeakerKind(kind)) {
|
|
116
|
+
throw authoringError("Speaker kind is invalid.", source, raw, "Use an actor ID or system, broadcast, offscreen, or group.");
|
|
117
|
+
}
|
|
118
|
+
if (colon < 0)
|
|
119
|
+
return { kind };
|
|
120
|
+
return { kind, label: raw.slice(colon + 1) };
|
|
121
|
+
}
|
|
122
|
+
function actionFromRecord(record, modifiers) {
|
|
123
|
+
const map = {
|
|
124
|
+
act: "action",
|
|
125
|
+
dlg: "dialogue",
|
|
126
|
+
think: "inner_thought",
|
|
127
|
+
trans: "transition",
|
|
128
|
+
};
|
|
129
|
+
const type = map[record.type];
|
|
130
|
+
if (type === undefined || !ACTION_TYPE_SET.has(type)) {
|
|
131
|
+
throw authoringError("Body record type is invalid.", record.source, record.type, "Use [act], [dlg], [think], or [trans].");
|
|
132
|
+
}
|
|
133
|
+
const action = { type, content: record.content };
|
|
134
|
+
if (type === "dialogue" || type === "inner_thought") {
|
|
135
|
+
if (record.slots.length < 1 || record.slots.length > 2) {
|
|
136
|
+
throw authoringError("Speaker record slots are invalid.", record.source, record.slots.join("|"), `Use [${record.type}|speaker|emotion?].`);
|
|
137
|
+
}
|
|
138
|
+
action.speaker = speakerFromSlot(record.slots[0], record.source);
|
|
139
|
+
if (record.slots.length === 2)
|
|
140
|
+
action.emotion = record.slots[1];
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
if (record.slots.length > 1) {
|
|
144
|
+
throw authoringError("Body record slots are invalid.", record.source, record.slots.join("|"), `Use [${record.type}|emotion?].`);
|
|
145
|
+
}
|
|
146
|
+
if (record.slots.length === 1)
|
|
147
|
+
action.emotion = record.slots[0];
|
|
148
|
+
}
|
|
149
|
+
const extend = extensionOrUndefined(modifiers);
|
|
150
|
+
if (extend !== undefined)
|
|
151
|
+
action.extend = extend;
|
|
152
|
+
if (modifiers.aliasesPresent) {
|
|
153
|
+
throw authoringError("Alias cannot modify an action.", modifiers.source ?? record.source, modifiers.aliases.join(","), "Use [alias] only before an asset declaration.");
|
|
154
|
+
}
|
|
155
|
+
if (modifiers.prompt !== undefined)
|
|
156
|
+
action.transition_prompt = modifiers.prompt;
|
|
157
|
+
return action;
|
|
158
|
+
}
|
|
159
|
+
class Parser {
|
|
160
|
+
lines;
|
|
161
|
+
index = 0;
|
|
162
|
+
constructor(text) {
|
|
163
|
+
this.lines = text.replace(/\r\n?/g, "\n").split("\n");
|
|
164
|
+
}
|
|
165
|
+
parse() {
|
|
166
|
+
this.skipBlank();
|
|
167
|
+
const root = this.takeOpen("authoring");
|
|
168
|
+
assertAttributes(root, ["version"]);
|
|
169
|
+
if (root.attrs.get("version") !== "1") {
|
|
170
|
+
throw authoringError("Authoring version is unsupported.", root.source, root.attrs.get("version") ?? "<missing>", "Use <authoring version=1>.");
|
|
171
|
+
}
|
|
172
|
+
const declarations = [];
|
|
173
|
+
const targets = [];
|
|
174
|
+
let seenTarget = false;
|
|
175
|
+
let pending = emptyModifiers();
|
|
176
|
+
while (true) {
|
|
177
|
+
this.skipBlank();
|
|
178
|
+
if (this.peekClose("authoring")) {
|
|
179
|
+
if (hasModifiers(pending))
|
|
180
|
+
this.throwDangling(pending);
|
|
181
|
+
this.takeClose("authoring");
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
const next = this.peekSemantic();
|
|
185
|
+
if (next === null)
|
|
186
|
+
throw this.eofError("authoring");
|
|
187
|
+
if (next.record?.type === "extensions" || next.record?.type === "extend") {
|
|
188
|
+
pending = this.addModifier(pending, this.takeRecord());
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (next.tag?.name === "create" && !next.tag.closing) {
|
|
192
|
+
if (seenTarget)
|
|
193
|
+
throw authoringError("<create> must precede every target.", next.tag.source, "<create>", "Move the single <create> block before the targets.");
|
|
194
|
+
if (hasModifiers(pending))
|
|
195
|
+
this.throwUnsupportedModifiers(pending, "create");
|
|
196
|
+
declarations.push(...this.parseCreate());
|
|
197
|
+
seenTarget = true;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
seenTarget = true;
|
|
201
|
+
targets.push(this.parseTarget(pending));
|
|
202
|
+
pending = emptyModifiers();
|
|
203
|
+
}
|
|
204
|
+
this.skipBlank();
|
|
205
|
+
if (this.index < this.lines.length) {
|
|
206
|
+
const source = { line: this.index + 1, column: 1 };
|
|
207
|
+
throw authoringError("Content exists after </authoring>.", source, this.lines[this.index], "Remove content outside the root block.");
|
|
208
|
+
}
|
|
209
|
+
if (targets.length === 0) {
|
|
210
|
+
throw authoringError("Authoring file has no target.", root.source, "<authoring>", "Add one or more homogeneous target blocks.");
|
|
211
|
+
}
|
|
212
|
+
const targetKind = targets[0].kind;
|
|
213
|
+
const mixed = targets.find((target) => target.kind !== targetKind);
|
|
214
|
+
if (mixed !== undefined) {
|
|
215
|
+
throw authoringError("Authoring targets are not homogeneous.", mixed.source, mixed.kind, `Keep only ${targetKind} targets in this file.`);
|
|
216
|
+
}
|
|
217
|
+
if (targetKind === "script" && targets.length !== 1) {
|
|
218
|
+
throw authoringError("A script authoring file has exactly one target.", targets[1].source, "second <script>", "Keep one <script> target.");
|
|
219
|
+
}
|
|
220
|
+
return { version: 1, declarations, targets, targetKind };
|
|
221
|
+
}
|
|
222
|
+
parseCreate() {
|
|
223
|
+
const tag = this.takeOpen("create");
|
|
224
|
+
assertAttributes(tag, []);
|
|
225
|
+
const declarations = [];
|
|
226
|
+
let pending = emptyModifiers();
|
|
227
|
+
while (true) {
|
|
228
|
+
this.skipBlank();
|
|
229
|
+
if (this.peekClose("create")) {
|
|
230
|
+
if (hasModifiers(pending))
|
|
231
|
+
this.throwDangling(pending);
|
|
232
|
+
this.takeClose("create");
|
|
233
|
+
return declarations;
|
|
234
|
+
}
|
|
235
|
+
const record = this.takeRecord();
|
|
236
|
+
if (record.type === "extensions" || record.type === "extend" || record.type === "aliases" || record.type === "alias" || record.type === "prompt") {
|
|
237
|
+
pending = this.addModifier(pending, record);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
if (record.type === "actor") {
|
|
241
|
+
if (record.slots.length < 3 || record.slots.length > 4) {
|
|
242
|
+
throw authoringError("Actor declaration slots are invalid.", record.source, record.slots.join("|"), "Use [actor|id|name|importance|role?] description.");
|
|
243
|
+
}
|
|
244
|
+
const [actorId, actorName, importance, role] = record.slots;
|
|
245
|
+
if (!actorId || !actorName || !importance || !IMPORTANCE_TIER_SET.has(importance) || !isImportance(importance)) {
|
|
246
|
+
throw authoringError("Actor declaration is invalid.", record.source, record.slots.join("|"), "Provide id, name, and featured|background importance.");
|
|
247
|
+
}
|
|
248
|
+
if (role !== undefined && (!ROLE_TYPE_SET.has(role) || !isRoleType(role))) {
|
|
249
|
+
throw authoringError("Actor role is invalid.", record.source, role, "Use 主角 or 配角, or omit the slot.");
|
|
250
|
+
}
|
|
251
|
+
const value = {
|
|
252
|
+
actor_id: actorId,
|
|
253
|
+
actor_name: actorName,
|
|
254
|
+
importance,
|
|
255
|
+
description: record.content,
|
|
256
|
+
states: [],
|
|
257
|
+
};
|
|
258
|
+
if (role !== undefined)
|
|
259
|
+
value.role_type = role;
|
|
260
|
+
if (pending.aliasesPresent)
|
|
261
|
+
value.aliases = [...pending.aliases];
|
|
262
|
+
const extend = extensionOrUndefined(pending);
|
|
263
|
+
if (extend !== undefined)
|
|
264
|
+
value.extend = extend;
|
|
265
|
+
if (pending.prompt !== undefined)
|
|
266
|
+
this.throwUnsupportedModifiers(pending, "actor");
|
|
267
|
+
declarations.push({ declarationKind: "actor", value, source: record.source });
|
|
268
|
+
pending = emptyModifiers();
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
if (record.type === "location" || record.type === "prop") {
|
|
272
|
+
if (record.slots.length !== 3) {
|
|
273
|
+
throw authoringError(`${record.type} declaration slots are invalid.`, record.source, record.slots.join("|"), `Use [${record.type}|id|name|importance] description.`);
|
|
274
|
+
}
|
|
275
|
+
const [id, name, importance] = record.slots;
|
|
276
|
+
if (!id || !name || !importance || !IMPORTANCE_TIER_SET.has(importance) || !isImportance(importance)) {
|
|
277
|
+
throw authoringError(`${record.type} declaration is invalid.`, record.source, record.slots.join("|"), "Provide id, name, and featured|background importance.");
|
|
278
|
+
}
|
|
279
|
+
if (pending.prompt !== undefined)
|
|
280
|
+
this.throwUnsupportedModifiers(pending, record.type);
|
|
281
|
+
const extend = extensionOrUndefined(pending);
|
|
282
|
+
if (record.type === "location") {
|
|
283
|
+
const value = {
|
|
284
|
+
location_id: id,
|
|
285
|
+
location_name: name,
|
|
286
|
+
importance,
|
|
287
|
+
description: record.content,
|
|
288
|
+
states: [],
|
|
289
|
+
};
|
|
290
|
+
if (pending.aliasesPresent)
|
|
291
|
+
value.aliases = [...pending.aliases];
|
|
292
|
+
if (extend !== undefined)
|
|
293
|
+
value.extend = extend;
|
|
294
|
+
declarations.push({ declarationKind: "location", value, source: record.source });
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
const value = {
|
|
298
|
+
prop_id: id,
|
|
299
|
+
prop_name: name,
|
|
300
|
+
importance,
|
|
301
|
+
description: record.content,
|
|
302
|
+
states: [],
|
|
303
|
+
};
|
|
304
|
+
if (pending.aliasesPresent)
|
|
305
|
+
value.aliases = [...pending.aliases];
|
|
306
|
+
if (extend !== undefined)
|
|
307
|
+
value.extend = extend;
|
|
308
|
+
declarations.push({ declarationKind: "prop", value, source: record.source });
|
|
309
|
+
}
|
|
310
|
+
pending = emptyModifiers();
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (record.type === "state") {
|
|
314
|
+
if (record.slots.length !== 3) {
|
|
315
|
+
throw authoringError("State declaration slots are invalid.", record.source, record.slots.join("|"), "Use [state|kind:asset_id|state_id|state_name] description.");
|
|
316
|
+
}
|
|
317
|
+
if (pending.aliasesPresent || pending.prompt !== undefined)
|
|
318
|
+
this.throwUnsupportedModifiers(pending, "state");
|
|
319
|
+
const [owner, stateId, stateName] = record.slots;
|
|
320
|
+
const ownerMatch = /^(actor|location|prop):(.+)$/.exec(owner ?? "");
|
|
321
|
+
const ownerKind = ownerMatch?.[1] ?? "";
|
|
322
|
+
if (!ownerMatch || !isAssetKind(ownerKind) || !stateId || !stateName) {
|
|
323
|
+
throw authoringError("State declaration is invalid.", record.source, record.slots.join("|"), "Use a typed owner and non-empty state ID/name.");
|
|
324
|
+
}
|
|
325
|
+
const value = { state_id: stateId, state_name: stateName, description: record.content };
|
|
326
|
+
const extend = extensionOrUndefined(pending);
|
|
327
|
+
if (extend !== undefined)
|
|
328
|
+
value.extend = extend;
|
|
329
|
+
declarations.push({
|
|
330
|
+
declarationKind: "state",
|
|
331
|
+
ownerKind,
|
|
332
|
+
ownerId: ownerMatch[2],
|
|
333
|
+
value,
|
|
334
|
+
source: record.source,
|
|
335
|
+
});
|
|
336
|
+
pending = emptyModifiers();
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
throw authoringError("Record is not allowed in <create>.", record.source, record.type, "Use actor, location, prop, state, or a supported prefix modifier.");
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
parseTarget(modifiers) {
|
|
343
|
+
const tag = this.peekTag();
|
|
344
|
+
if (tag === null || tag.closing) {
|
|
345
|
+
const source = tag?.source ?? { line: this.index + 1, column: 1 };
|
|
346
|
+
throw authoringError("Expected a target block.", source, this.lines[this.index] ?? "<eof>", "Add a supported target block.");
|
|
347
|
+
}
|
|
348
|
+
if (modifiers.aliasesPresent || modifiers.prompt !== undefined)
|
|
349
|
+
this.throwUnsupportedModifiers(modifiers, tag.name);
|
|
350
|
+
switch (tag.name) {
|
|
351
|
+
case "script": return this.parseScript(modifiers);
|
|
352
|
+
case "episode": return { kind: "episode", value: this.parseEpisode(modifiers), source: tag.source, ...(extensionOrUndefined(modifiers) ? { extend: extensionOrUndefined(modifiers) } : {}) };
|
|
353
|
+
case "episode-span": return this.parseEpisodeSpan(modifiers);
|
|
354
|
+
case "scene": {
|
|
355
|
+
assertAttributes(tag, ["id", "parent"]);
|
|
356
|
+
const parent = tag.attrs.get("parent");
|
|
357
|
+
return { kind: "scene", parent, value: this.parseScene(modifiers, true), source: tag.source, ...(extensionOrUndefined(modifiers) ? { extend: extensionOrUndefined(modifiers) } : {}) };
|
|
358
|
+
}
|
|
359
|
+
case "scene-span": return this.parseSceneSpan(modifiers);
|
|
360
|
+
case "action-span": return this.parseActionSpan(modifiers);
|
|
361
|
+
default:
|
|
362
|
+
throw authoringError("Unknown target block.", tag.source, tag.name, "Use script, episode, episode-span, scene, scene-span, or action-span.");
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
parseScript(modifiers) {
|
|
366
|
+
const tag = this.takeOpen("script");
|
|
367
|
+
assertAttributes(tag, []);
|
|
368
|
+
const recordOrder = ["title", "worldview", "worldview-raw", "style", "synopsis", "logline", "theme", "main-characters", "main-character"];
|
|
369
|
+
const values = new Map();
|
|
370
|
+
const mainCharacters = [];
|
|
371
|
+
const episodes = [];
|
|
372
|
+
let lastRecord = -1;
|
|
373
|
+
let episodesStarted = false;
|
|
374
|
+
let pending = emptyModifiers();
|
|
375
|
+
while (true) {
|
|
376
|
+
this.skipBlank();
|
|
377
|
+
if (this.peekClose("script")) {
|
|
378
|
+
if (hasModifiers(pending))
|
|
379
|
+
this.throwDangling(pending);
|
|
380
|
+
this.takeClose("script");
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
const next = this.peekSemantic();
|
|
384
|
+
if (next?.record !== undefined) {
|
|
385
|
+
const record = this.takeRecord();
|
|
386
|
+
if (record.type === "extensions" || record.type === "extend" || record.type === "aliases" || record.type === "alias" || record.type === "prompt") {
|
|
387
|
+
pending = this.addModifier(pending, record);
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
if (hasModifiers(pending))
|
|
391
|
+
this.throwUnsupportedModifiers(pending, record.type);
|
|
392
|
+
const order = recordOrder.indexOf(record.type);
|
|
393
|
+
const repeatedMainCharacter = record.type === "main-character";
|
|
394
|
+
if (episodesStarted || order < 0 || order < lastRecord || (!repeatedMainCharacter && values.has(record.type))) {
|
|
395
|
+
throw authoringError("Metadata record in <script> is invalid or out of order.", record.source, record.type, `Use ${recordOrder.join(", ")} in canonical order before episode blocks.`);
|
|
396
|
+
}
|
|
397
|
+
lastRecord = order;
|
|
398
|
+
if (record.type === "main-characters") {
|
|
399
|
+
if (record.slots.length !== 0 || record.content !== "") {
|
|
400
|
+
throw authoringError("Main characters marker is invalid.", record.source, record.content, "Use [main-characters] with no slots or content.");
|
|
401
|
+
}
|
|
402
|
+
values.set(record.type, "");
|
|
403
|
+
}
|
|
404
|
+
else if (repeatedMainCharacter) {
|
|
405
|
+
if (record.slots.length !== 2 || !record.slots[0] || !record.slots[1] || record.content !== "") {
|
|
406
|
+
throw authoringError("Main character record is invalid.", record.source, record.slots.join("|"), "Use [main-character|name|role] with no content.");
|
|
407
|
+
}
|
|
408
|
+
mainCharacters.push({ name: record.slots[0], role: record.slots[1] });
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
if (record.slots.length !== 0) {
|
|
412
|
+
throw authoringError("Script metadata record has unexpected slots.", record.source, record.slots.join("|"), `Use [${record.type}] content.`);
|
|
413
|
+
}
|
|
414
|
+
values.set(record.type, record.content);
|
|
415
|
+
}
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
if (next?.tag === undefined || next.tag.closing || next.tag.name !== "episode") {
|
|
419
|
+
const source = next?.tag?.source ?? { line: this.index + 1, column: 1 };
|
|
420
|
+
throw authoringError("Unexpected member in <script>.", source, this.lines[this.index] ?? "<eof>", "Use metadata records followed by <episode> blocks.");
|
|
421
|
+
}
|
|
422
|
+
episodesStarted = true;
|
|
423
|
+
episodes.push(this.parseEpisode(pending));
|
|
424
|
+
pending = emptyModifiers();
|
|
425
|
+
}
|
|
426
|
+
const title = this.requiredMetadata(values, "title", tag.source);
|
|
427
|
+
const worldview = this.requiredMetadata(values, "worldview", tag.source);
|
|
428
|
+
const style = this.requiredMetadata(values, "style", tag.source);
|
|
429
|
+
const extend = extensionOrUndefined(modifiers);
|
|
430
|
+
return {
|
|
431
|
+
kind: "script",
|
|
432
|
+
title,
|
|
433
|
+
worldview,
|
|
434
|
+
style,
|
|
435
|
+
...(values.get("worldview-raw") !== undefined ? { worldviewRaw: values.get("worldview-raw") } : {}),
|
|
436
|
+
...(values.get("synopsis") !== undefined ? { synopsis: values.get("synopsis") } : {}),
|
|
437
|
+
...(values.get("logline") !== undefined ? { logline: values.get("logline") } : {}),
|
|
438
|
+
...(values.get("theme") !== undefined ? { theme: values.get("theme") } : {}),
|
|
439
|
+
...(values.has("main-characters") || mainCharacters.length > 0 ? { mainCharacters } : {}),
|
|
440
|
+
episodes,
|
|
441
|
+
source: tag.source,
|
|
442
|
+
...(extend !== undefined ? { extend } : {}),
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
parseEpisode(modifiers) {
|
|
446
|
+
const tag = this.takeOpen("episode");
|
|
447
|
+
assertAttributes(tag, ["id"]);
|
|
448
|
+
if (modifiers.aliasesPresent || modifiers.prompt !== undefined)
|
|
449
|
+
this.throwUnsupportedModifiers(modifiers, "episode");
|
|
450
|
+
const metadata = this.parseMetadataAndChildren("episode", ["title", "synopsis"], "scene", (childModifiers) => this.parseScene(childModifiers, false));
|
|
451
|
+
const episode = { episode_id: tag.attrs.get("id"), scenes: metadata.children };
|
|
452
|
+
if (metadata.values.has("title"))
|
|
453
|
+
episode.title = metadata.values.get("title");
|
|
454
|
+
if (metadata.values.has("synopsis"))
|
|
455
|
+
episode.synopsis = metadata.values.get("synopsis");
|
|
456
|
+
const extend = extensionOrUndefined(modifiers);
|
|
457
|
+
if (extend !== undefined)
|
|
458
|
+
episode.extend = extend;
|
|
459
|
+
return episode;
|
|
460
|
+
}
|
|
461
|
+
parseScene(modifiers, root) {
|
|
462
|
+
const tag = this.takeOpen("scene");
|
|
463
|
+
assertAttributes(tag, root ? ["id", "parent"] : ["id"]);
|
|
464
|
+
if (modifiers.aliasesPresent || modifiers.prompt !== undefined)
|
|
465
|
+
this.throwUnsupportedModifiers(modifiers, "scene");
|
|
466
|
+
let environment;
|
|
467
|
+
let location;
|
|
468
|
+
const actors = [];
|
|
469
|
+
const props = [];
|
|
470
|
+
let phase = "environment";
|
|
471
|
+
let actions;
|
|
472
|
+
while (true) {
|
|
473
|
+
this.skipBlank();
|
|
474
|
+
if (this.peekClose("scene")) {
|
|
475
|
+
this.takeClose("scene");
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
const next = this.peekSemantic();
|
|
479
|
+
if (next?.tag?.name === "body" && !next.tag.closing) {
|
|
480
|
+
if (phase === "body")
|
|
481
|
+
throw authoringError("Scene has more than one body.", next.tag.source, "<body>", "Keep exactly one <body>.");
|
|
482
|
+
phase = "body";
|
|
483
|
+
actions = this.parseBody();
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
if (next?.record === undefined) {
|
|
487
|
+
const source = next?.tag?.source ?? { line: this.index + 1, column: 1 };
|
|
488
|
+
throw authoringError("Only scene records and <body> are allowed here.", source, this.lines[this.index] ?? "<eof>", "Use environment, location, cast, prop, then body.");
|
|
489
|
+
}
|
|
490
|
+
const record = this.takeRecord();
|
|
491
|
+
if (record.type === "extensions" || record.type === "extend" || record.type === "aliases" || record.type === "alias" || record.type === "prompt") {
|
|
492
|
+
throw authoringError("Scene prefix modifier must directly precede <scene>.", record.source, record.type, "Move the modifier before the <scene> opening tag.");
|
|
493
|
+
}
|
|
494
|
+
if (record.type === "environment") {
|
|
495
|
+
if (phase !== "environment" || environment !== undefined || record.slots.length > 2) {
|
|
496
|
+
throw authoringError("Environment record is out of order or invalid.", record.source, record.slots.join("|"), "Place at most one [environment|space?|time?] first.");
|
|
497
|
+
}
|
|
498
|
+
environment = {};
|
|
499
|
+
if (record.slots.length >= 1 && record.slots[0] !== "")
|
|
500
|
+
environment.space = record.slots[0];
|
|
501
|
+
if (record.slots.length >= 2 && record.slots[1] !== "")
|
|
502
|
+
environment.time = record.slots[1];
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
if (record.type === "location") {
|
|
506
|
+
if (phase === "cast" || phase === "prop" || phase === "body" || location !== undefined || record.slots.length > 2) {
|
|
507
|
+
throw authoringError("Location record is out of order or invalid.", record.source, record.slots.join("|"), "Place exactly one [location|id?|state?] before cast.");
|
|
508
|
+
}
|
|
509
|
+
phase = "location";
|
|
510
|
+
const id = record.slots[0];
|
|
511
|
+
if (id === undefined || id === "")
|
|
512
|
+
location = null;
|
|
513
|
+
else
|
|
514
|
+
location = record.slots.length === 2 ? { location_id: id, state_id: record.slots[1] } : { location_id: id };
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
if (record.type === "cast") {
|
|
518
|
+
if (location === undefined || phase === "prop" || phase === "body" || record.slots.length < 1 || record.slots.length > 2 || !record.slots[0]) {
|
|
519
|
+
throw authoringError("Cast record is out of order or invalid.", record.source, record.slots.join("|"), "Place [cast|actor_id|state_id?] after location and before props.");
|
|
520
|
+
}
|
|
521
|
+
phase = "cast";
|
|
522
|
+
actors.push(record.slots.length === 2 ? { actor_id: record.slots[0], state_id: record.slots[1] } : { actor_id: record.slots[0] });
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
if (record.type === "prop") {
|
|
526
|
+
if (location === undefined || phase === "body" || record.slots.length < 1 || record.slots.length > 2 || !record.slots[0]) {
|
|
527
|
+
throw authoringError("Prop record is out of order or invalid.", record.source, record.slots.join("|"), "Place [prop|prop_id|state_id?] after cast and before body.");
|
|
528
|
+
}
|
|
529
|
+
phase = "prop";
|
|
530
|
+
props.push(record.slots.length === 2 ? { prop_id: record.slots[0], state_id: record.slots[1] } : { prop_id: record.slots[0] });
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
throw authoringError("Record is not allowed in a scene header.", record.source, record.type, "Use environment, location, cast, prop, or body records.");
|
|
534
|
+
}
|
|
535
|
+
if (location === undefined)
|
|
536
|
+
throw authoringError("Scene location record is missing.", tag.source, `<scene id=${tag.attrs.get("id")}>`, "Add [location] or [location|loc_ID|state_ID].");
|
|
537
|
+
if (actions === undefined)
|
|
538
|
+
throw authoringError("Scene body is missing.", tag.source, `<scene id=${tag.attrs.get("id")}>`, "Add one <body> block.");
|
|
539
|
+
const scene = { scene_id: tag.attrs.get("id"), location, actors, props, actions };
|
|
540
|
+
if (environment !== undefined)
|
|
541
|
+
scene.environment = environment;
|
|
542
|
+
const extend = extensionOrUndefined(modifiers);
|
|
543
|
+
if (extend !== undefined)
|
|
544
|
+
scene.extend = extend;
|
|
545
|
+
return scene;
|
|
546
|
+
}
|
|
547
|
+
parseBody() {
|
|
548
|
+
const tag = this.takeOpen("body");
|
|
549
|
+
assertAttributes(tag, []);
|
|
550
|
+
const actions = [];
|
|
551
|
+
let pending = emptyModifiers();
|
|
552
|
+
while (true) {
|
|
553
|
+
this.skipBlank();
|
|
554
|
+
if (this.peekClose("body")) {
|
|
555
|
+
if (hasModifiers(pending))
|
|
556
|
+
this.throwDangling(pending);
|
|
557
|
+
this.takeClose("body");
|
|
558
|
+
return actions;
|
|
559
|
+
}
|
|
560
|
+
const record = this.takeRecord();
|
|
561
|
+
if (record.type === "extensions" || record.type === "extend" || record.type === "aliases" || record.type === "prompt" || record.type === "alias") {
|
|
562
|
+
pending = this.addModifier(pending, record);
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
actions.push(actionFromRecord(record, pending));
|
|
566
|
+
pending = emptyModifiers();
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
parseEpisodeSpan(modifiers) {
|
|
570
|
+
const tag = this.takeOpen("episode-span");
|
|
571
|
+
assertAttributes(tag, ["from", "through"]);
|
|
572
|
+
const episodes = this.parseOnlyChildren("episode-span", "episode", (childModifiers) => this.parseEpisode(childModifiers));
|
|
573
|
+
const extend = extensionOrUndefined(modifiers);
|
|
574
|
+
return {
|
|
575
|
+
kind: "episode-span",
|
|
576
|
+
from: tag.attrs.get("from"),
|
|
577
|
+
through: tag.attrs.get("through"),
|
|
578
|
+
episodes,
|
|
579
|
+
source: tag.source,
|
|
580
|
+
...(extend !== undefined ? { extend } : {}),
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
parseSceneSpan(modifiers) {
|
|
584
|
+
const tag = this.takeOpen("scene-span");
|
|
585
|
+
assertAttributes(tag, ["parent", "from", "through"]);
|
|
586
|
+
const scenes = this.parseOnlyChildren("scene-span", "scene", (childModifiers) => this.parseScene(childModifiers, false));
|
|
587
|
+
const extend = extensionOrUndefined(modifiers);
|
|
588
|
+
return {
|
|
589
|
+
kind: "scene-span",
|
|
590
|
+
parent: tag.attrs.get("parent"),
|
|
591
|
+
from: tag.attrs.get("from"),
|
|
592
|
+
through: tag.attrs.get("through"),
|
|
593
|
+
scenes,
|
|
594
|
+
source: tag.source,
|
|
595
|
+
...(extend !== undefined ? { extend } : {}),
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
parseActionSpan(modifiers) {
|
|
599
|
+
const tag = this.takeOpen("action-span");
|
|
600
|
+
assertAttributes(tag, ["parent", "from", "through"]);
|
|
601
|
+
this.skipBlank();
|
|
602
|
+
const actions = this.parseBody();
|
|
603
|
+
this.skipBlank();
|
|
604
|
+
this.takeClose("action-span");
|
|
605
|
+
const extend = extensionOrUndefined(modifiers);
|
|
606
|
+
return {
|
|
607
|
+
kind: "action-span",
|
|
608
|
+
parent: tag.attrs.get("parent"),
|
|
609
|
+
from: parsePositiveInteger(tag.attrs.get("from"), tag.source, "action-span from", true),
|
|
610
|
+
through: parsePositiveInteger(tag.attrs.get("through"), tag.source, "action-span through", true),
|
|
611
|
+
actions,
|
|
612
|
+
source: tag.source,
|
|
613
|
+
...(extend !== undefined ? { extend } : {}),
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
parseMetadataAndChildren(block, recordOrder, childName, parseChild) {
|
|
617
|
+
const values = new Map();
|
|
618
|
+
const children = [];
|
|
619
|
+
let lastRecord = -1;
|
|
620
|
+
let childrenStarted = false;
|
|
621
|
+
let pending = emptyModifiers();
|
|
622
|
+
while (true) {
|
|
623
|
+
this.skipBlank();
|
|
624
|
+
if (this.peekClose(block)) {
|
|
625
|
+
if (hasModifiers(pending))
|
|
626
|
+
this.throwDangling(pending);
|
|
627
|
+
this.takeClose(block);
|
|
628
|
+
return { values, children };
|
|
629
|
+
}
|
|
630
|
+
const next = this.peekSemantic();
|
|
631
|
+
if (next?.record !== undefined) {
|
|
632
|
+
const record = this.takeRecord();
|
|
633
|
+
if (record.type === "extensions" || record.type === "extend" || record.type === "aliases" || record.type === "alias" || record.type === "prompt") {
|
|
634
|
+
pending = this.addModifier(pending, record);
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
if (hasModifiers(pending))
|
|
638
|
+
this.throwUnsupportedModifiers(pending, record.type);
|
|
639
|
+
const order = recordOrder.indexOf(record.type);
|
|
640
|
+
if (childrenStarted || order < 0 || order < lastRecord || values.has(record.type) || record.slots.length !== 0) {
|
|
641
|
+
throw authoringError(`Metadata record in <${block}> is invalid or out of order.`, record.source, record.type, `Use each of ${recordOrder.join(", ")} at most once in canonical order before child blocks.`);
|
|
642
|
+
}
|
|
643
|
+
lastRecord = order;
|
|
644
|
+
values.set(record.type, record.content);
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
const tag = next?.tag;
|
|
648
|
+
if (tag === undefined || tag.closing || tag.name !== childName) {
|
|
649
|
+
const source = tag?.source ?? { line: this.index + 1, column: 1 };
|
|
650
|
+
throw authoringError(`Unexpected member in <${block}>.`, source, this.lines[this.index] ?? "<eof>", `Use metadata records followed by <${childName}> blocks.`);
|
|
651
|
+
}
|
|
652
|
+
childrenStarted = true;
|
|
653
|
+
children.push(parseChild(pending));
|
|
654
|
+
pending = emptyModifiers();
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
parseOnlyChildren(block, childName, parseChild) {
|
|
658
|
+
const children = [];
|
|
659
|
+
let pending = emptyModifiers();
|
|
660
|
+
while (true) {
|
|
661
|
+
this.skipBlank();
|
|
662
|
+
if (this.peekClose(block)) {
|
|
663
|
+
if (hasModifiers(pending))
|
|
664
|
+
this.throwDangling(pending);
|
|
665
|
+
this.takeClose(block);
|
|
666
|
+
return children;
|
|
667
|
+
}
|
|
668
|
+
const next = this.peekSemantic();
|
|
669
|
+
if (next?.record?.type === "extensions" || next?.record?.type === "extend") {
|
|
670
|
+
pending = this.addModifier(pending, this.takeRecord());
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
if (next?.tag === undefined || next.tag.closing || next.tag.name !== childName) {
|
|
674
|
+
const source = next?.tag?.source ?? next?.record?.source ?? { line: this.index + 1, column: 1 };
|
|
675
|
+
throw authoringError(`Only <${childName}> children are allowed in <${block}>.`, source, this.lines[this.index] ?? "<eof>", `Add complete <${childName}> blocks.`);
|
|
676
|
+
}
|
|
677
|
+
children.push(parseChild(pending));
|
|
678
|
+
pending = emptyModifiers();
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
addModifier(modifiers, record) {
|
|
682
|
+
const next = {
|
|
683
|
+
extend: { ...modifiers.extend },
|
|
684
|
+
extendPresent: modifiers.extendPresent,
|
|
685
|
+
aliases: [...modifiers.aliases],
|
|
686
|
+
aliasesPresent: modifiers.aliasesPresent,
|
|
687
|
+
phase: modifiers.phase,
|
|
688
|
+
...(modifiers.prompt !== undefined ? { prompt: modifiers.prompt } : {}),
|
|
689
|
+
source: modifiers.source ?? record.source,
|
|
690
|
+
};
|
|
691
|
+
if (record.type === "extensions") {
|
|
692
|
+
if (next.phase !== "extend" || next.extendPresent || record.slots.length !== 0 || record.content !== "") {
|
|
693
|
+
throw authoringError("Extensions marker is invalid or out of order.", record.source, record.content || "<empty>", "Use one [extensions] marker before extension records.");
|
|
694
|
+
}
|
|
695
|
+
next.extendPresent = true;
|
|
696
|
+
return next;
|
|
697
|
+
}
|
|
698
|
+
if (record.type === "extend") {
|
|
699
|
+
if (next.phase !== "extend" || record.slots.length !== 1 || !record.slots[0]) {
|
|
700
|
+
throw authoringError("Extend modifier is invalid or out of order.", record.source, record.slots.join("|"), "Place unique [extend|key] records first.");
|
|
701
|
+
}
|
|
702
|
+
const key = record.slots[0];
|
|
703
|
+
if (Object.hasOwn(next.extend, key)) {
|
|
704
|
+
throw authoringError("Extend key is duplicated.", record.source, key, "Keep one value for each extension key.");
|
|
705
|
+
}
|
|
706
|
+
let parsed;
|
|
707
|
+
try {
|
|
708
|
+
parsed = JSON.parse(record.content);
|
|
709
|
+
}
|
|
710
|
+
catch {
|
|
711
|
+
throw authoringError("Extension value is not valid JSON.", record.source, record.content, "Use one canonical JSON value.");
|
|
712
|
+
}
|
|
713
|
+
if (!isJsonValue(parsed)) {
|
|
714
|
+
throw authoringError("Extension value is not JSON-compatible.", record.source, record.content, "Use string, number, boolean, null, array, or object.");
|
|
715
|
+
}
|
|
716
|
+
next.extendPresent = true;
|
|
717
|
+
next.extend[key] = canonicalJson(parsed);
|
|
718
|
+
return next;
|
|
719
|
+
}
|
|
720
|
+
if (record.type === "aliases") {
|
|
721
|
+
if (next.phase !== "extend" || next.aliasesPresent || record.slots.length !== 0 || record.content !== "") {
|
|
722
|
+
throw authoringError("Aliases marker is invalid or out of order.", record.source, record.content || "<empty>", "Use one [aliases] marker after extensions and before alias records.");
|
|
723
|
+
}
|
|
724
|
+
next.phase = "alias";
|
|
725
|
+
next.aliasesPresent = true;
|
|
726
|
+
return next;
|
|
727
|
+
}
|
|
728
|
+
if (record.type === "alias") {
|
|
729
|
+
if (next.phase === "prompt" || record.slots.length !== 0 || !record.content) {
|
|
730
|
+
throw authoringError("Alias modifier is invalid or out of order.", record.source, record.content || "<empty>", "Place non-empty [alias] records after extensions and before prompt.");
|
|
731
|
+
}
|
|
732
|
+
next.phase = "alias";
|
|
733
|
+
next.aliasesPresent = true;
|
|
734
|
+
if (next.aliases.includes(record.content)) {
|
|
735
|
+
throw authoringError("Alias is duplicated.", record.source, record.content, "Keep each alias once.");
|
|
736
|
+
}
|
|
737
|
+
next.aliases.push(record.content);
|
|
738
|
+
return next;
|
|
739
|
+
}
|
|
740
|
+
if (record.type === "prompt") {
|
|
741
|
+
if (next.prompt !== undefined || record.slots.length !== 3 || record.slots.some((slot) => !slot)) {
|
|
742
|
+
throw authoringError("Prompt modifier is invalid.", record.source, record.slots.join("|"), "Use one [prompt|target|process|contrast] after extensions and aliases.");
|
|
743
|
+
}
|
|
744
|
+
if (!/^(?:actor:act_|location:loc_|prop:prp_)[A-Za-z0-9_-]+$/.test(record.slots[0])) {
|
|
745
|
+
throw authoringError("Prompt target is invalid.", record.source, record.slots[0], "Use actor:act_ID, location:loc_ID, or prop:prp_ID.");
|
|
746
|
+
}
|
|
747
|
+
next.phase = "prompt";
|
|
748
|
+
next.prompt = { target: record.slots[0], process: record.slots[1], contrast: record.slots[2] };
|
|
749
|
+
return next;
|
|
750
|
+
}
|
|
751
|
+
throw authoringError("Unknown prefix modifier.", record.source, record.type, "Use extend, alias, or prompt.");
|
|
752
|
+
}
|
|
753
|
+
requiredMetadata(values, key, source) {
|
|
754
|
+
const value = values.get(key);
|
|
755
|
+
if (value === undefined)
|
|
756
|
+
throw authoringError(`Script ${key} record is missing.`, source, `<script>`, `Add [${key}] in canonical metadata order.`);
|
|
757
|
+
return value;
|
|
758
|
+
}
|
|
759
|
+
peekSemantic() {
|
|
760
|
+
this.skipBlank();
|
|
761
|
+
if (this.index >= this.lines.length)
|
|
762
|
+
return null;
|
|
763
|
+
const raw = this.lines[this.index];
|
|
764
|
+
const tag = parseTag(raw, this.index + 1);
|
|
765
|
+
if (tag !== null)
|
|
766
|
+
return { tag };
|
|
767
|
+
if (raw.trimStart().startsWith("["))
|
|
768
|
+
return { record: parseBracketRecord(raw, this.index + 1) };
|
|
769
|
+
const source = { line: this.index + 1, column: Math.max(1, raw.search(/\S/) + 1) };
|
|
770
|
+
throw authoringError("Semantic line is neither a tag nor a bracket record.", source, raw, "Use only known tags, bracket records, or blank lines.");
|
|
771
|
+
}
|
|
772
|
+
peekTag() {
|
|
773
|
+
return this.peekSemantic()?.tag ?? null;
|
|
774
|
+
}
|
|
775
|
+
takeRecord() {
|
|
776
|
+
const item = this.peekSemantic();
|
|
777
|
+
if (item?.record === undefined) {
|
|
778
|
+
const source = item?.tag?.source ?? { line: this.index + 1, column: 1 };
|
|
779
|
+
throw authoringError("Expected a bracket record.", source, this.lines[this.index] ?? "<eof>", "Use the record required at this position.");
|
|
780
|
+
}
|
|
781
|
+
this.index += 1;
|
|
782
|
+
return item.record;
|
|
783
|
+
}
|
|
784
|
+
takeOpen(name) {
|
|
785
|
+
const tag = this.peekTag();
|
|
786
|
+
if (tag === null || tag.closing || tag.name !== name) {
|
|
787
|
+
const source = tag?.source ?? { line: this.index + 1, column: 1 };
|
|
788
|
+
throw authoringError(`Expected <${name}>.`, source, this.lines[this.index] ?? "<eof>", `Open <${name}> here.`);
|
|
789
|
+
}
|
|
790
|
+
this.index += 1;
|
|
791
|
+
return tag;
|
|
792
|
+
}
|
|
793
|
+
takeClose(name) {
|
|
794
|
+
const tag = this.peekTag();
|
|
795
|
+
if (tag === null || !tag.closing || tag.name !== name) {
|
|
796
|
+
const source = tag?.source ?? { line: this.index + 1, column: 1 };
|
|
797
|
+
throw authoringError(`Expected </${name}>.`, source, this.lines[this.index] ?? "<eof>", `Close the current <${name}> block.`);
|
|
798
|
+
}
|
|
799
|
+
this.index += 1;
|
|
800
|
+
return tag;
|
|
801
|
+
}
|
|
802
|
+
peekClose(name) {
|
|
803
|
+
const tag = this.peekTag();
|
|
804
|
+
return tag !== null && tag.closing && tag.name === name;
|
|
805
|
+
}
|
|
806
|
+
skipBlank() {
|
|
807
|
+
while (this.index < this.lines.length && this.lines[this.index].trim() === "")
|
|
808
|
+
this.index += 1;
|
|
809
|
+
}
|
|
810
|
+
eofError(block) {
|
|
811
|
+
return authoringError(`Unexpected end of file inside <${block}>.`, { line: this.lines.length, column: 1 }, "<eof>", `Add </${block}>.`);
|
|
812
|
+
}
|
|
813
|
+
throwDangling(modifiers) {
|
|
814
|
+
throw authoringError("Prefix modifier has no following node.", modifiers.source ?? { line: this.index + 1, column: 1 }, "dangling modifier", "Move it directly before a supported node.");
|
|
815
|
+
}
|
|
816
|
+
throwUnsupportedModifiers(modifiers, node) {
|
|
817
|
+
throw authoringError("Prefix modifier does not apply to this node.", modifiers.source ?? { line: this.index + 1, column: 1 }, node, "Remove the unsupported modifier or move it before a supported node.");
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
export function parseAuthoring(text) {
|
|
821
|
+
return new Parser(text).parse();
|
|
822
|
+
}
|
|
823
|
+
//# sourceMappingURL=parser.js.map
|