@lingjingai/scriptctl 0.49.15 → 0.50.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.49.16.md +15 -0
- package/changes/0.50.0.md +63 -0
- package/changes/unreleased.md +2 -1
- package/dist/cli.js +26 -5
- package/dist/cli.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 +47 -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/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 +145 -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 +317 -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 +92 -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 +165 -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 +211 -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 +180 -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 +100 -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 +63 -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 +67 -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 +18 -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 +139 -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 +379 -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 +125 -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/help-text.js +146 -114
- package/dist/help-text.js.map +1 -1
- package/dist/llm/config.js +2 -0
- 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/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/types.d.ts +1 -1
- package/dist/llm/types.js.map +1 -1
- package/dist/usecases/ingest/command.js +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/pipeline.js +62 -11
- 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 +11 -4
- package/dist/usecases/ingest/serial-govern.js.map +1 -1
- package/dist/usecases/ingest/video-pipeline.js +100 -14
- package/dist/usecases/ingest/video-pipeline.js.map +1 -1
- package/dist/usecases/ingest/view-server.js +2 -2
- package/dist/usecases/ingest/view-server.js.map +1 -1
- package/dist/usecases/script/actions.js +101 -5
- package/dist/usecases/script/actions.js.map +1 -1
- package/dist/usecases/script/actors.js +16 -7
- package/dist/usecases/script/actors.js.map +1 -1
- package/dist/usecases/script/alias.js +7 -6
- package/dist/usecases/script/alias.js.map +1 -1
- package/dist/usecases/script/assets.js +18 -2
- 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 +40 -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 +115 -0
- package/dist/usecases/script/command-constraints.js.map +1 -0
- package/dist/usecases/script/context.js +31 -4
- package/dist/usecases/script/context.js.map +1 -1
- package/dist/usecases/script/create.js +2 -2
- package/dist/usecases/script/create.js.map +1 -1
- package/dist/usecases/script/delete.js +6 -3
- package/dist/usecases/script/delete.js.map +1 -1
- package/dist/usecases/script/describe.js +7 -4
- package/dist/usecases/script/describe.js.map +1 -1
- package/dist/usecases/script/dialogue.js +15 -5
- 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.js +74 -11
- package/dist/usecases/script/do.js.map +1 -1
- package/dist/usecases/script/emotion.js +14 -3
- package/dist/usecases/script/emotion.js.map +1 -1
- package/dist/usecases/script/episodes.js +15 -4
- package/dist/usecases/script/episodes.js.map +1 -1
- package/dist/usecases/script/export-authoring.js +35 -11
- package/dist/usecases/script/export-authoring.js.map +1 -1
- package/dist/usecases/script/extend.js +23 -15
- package/dist/usecases/script/extend.js.map +1 -1
- package/dist/usecases/script/ids.js +53 -10
- package/dist/usecases/script/ids.js.map +1 -1
- package/dist/usecases/script/insert.js +74 -38
- package/dist/usecases/script/insert.js.map +1 -1
- package/dist/usecases/script/lib.d.ts +50 -1
- package/dist/usecases/script/lib.js +599 -61
- package/dist/usecases/script/lib.js.map +1 -1
- package/dist/usecases/script/locations.js +16 -7
- package/dist/usecases/script/locations.js.map +1 -1
- package/dist/usecases/script/merge.js +8 -5
- package/dist/usecases/script/merge.js.map +1 -1
- package/dist/usecases/script/move.js +24 -5
- package/dist/usecases/script/move.js.map +1 -1
- package/dist/usecases/script/parenthetical.d.ts +3 -0
- package/dist/usecases/script/parenthetical.js +55 -0
- package/dist/usecases/script/parenthetical.js.map +1 -0
- package/dist/usecases/script/props.js +16 -7
- package/dist/usecases/script/props.js.map +1 -1
- package/dist/usecases/script/refs.js +44 -0
- package/dist/usecases/script/refs.js.map +1 -1
- package/dist/usecases/script/rename.js +7 -4
- package/dist/usecases/script/rename.js.map +1 -1
- package/dist/usecases/script/scenes.js +32 -6
- package/dist/usecases/script/scenes.js.map +1 -1
- package/dist/usecases/script/script-patch.js +180 -16
- package/dist/usecases/script/script-patch.js.map +1 -1
- package/dist/usecases/script/session.d.ts +3 -0
- package/dist/usecases/script/session.js +25 -5
- package/dist/usecases/script/session.js.map +1 -1
- package/dist/usecases/script/split.js +12 -6
- package/dist/usecases/script/split.js.map +1 -1
- package/dist/usecases/script/states.js +45 -1
- package/dist/usecases/script/states.js.map +1 -1
- package/dist/usecases/script/synopsis.js +11 -4
- package/dist/usecases/script/synopsis.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 +14 -0
- package/dist/usecases/script/v4/queries.js +154 -0
- package/dist/usecases/script/v4/queries.js.map +1 -0
- package/dist/usecases/script/working-copy.js +3 -3
- package/dist/usecases/script/working-copy.js.map +1 -1
- package/dist/usecases/script/write-authoring.js +99 -5
- package/dist/usecases/script/write-authoring.js.map +1 -1
- package/package.json +3 -2
- package/skills/scriptctl/SKILL.md +126 -283
- package/skills/scriptctl/references/atomic-edit-workflow.md +45 -0
- 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/skills/scriptctl/references/atomic-write-workflow.md +0 -176
|
@@ -0,0 +1,729 @@
|
|
|
1
|
+
import { CliError, EXIT_INPUT } from "../../../common.js";
|
|
2
|
+
import { parseBracketRecord } from "../shared/bracket.js";
|
|
3
|
+
import { isV4Id } from "../../script/v4/ids.js";
|
|
4
|
+
function invalid(message, line, received) {
|
|
5
|
+
throw new CliError("AUTHORING BLOCKED: Script v4 source invalid", message, {
|
|
6
|
+
exitCode: EXIT_INPUT,
|
|
7
|
+
errorCode: "AUTHORING_SOURCE_INVALID",
|
|
8
|
+
received: [`line ${line}: ${received}`],
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
function parseTag(raw, line) {
|
|
12
|
+
const text = raw.trim();
|
|
13
|
+
const close = /^<\/([a-z-]+)>$/.exec(text);
|
|
14
|
+
if (close)
|
|
15
|
+
return { name: close[1], closing: true, attrs: new Map(), line };
|
|
16
|
+
const open = /^<([a-z-]+)(?: ([^>]+))?>$/.exec(text);
|
|
17
|
+
if (!open)
|
|
18
|
+
return null;
|
|
19
|
+
const attrs = new Map();
|
|
20
|
+
const attrText = open[2] ?? "";
|
|
21
|
+
const tokens = attrText === "" ? [] : attrText.split(" ");
|
|
22
|
+
if (tokens.some((token) => token === ""))
|
|
23
|
+
invalid("Tag attributes need one-space separators.", line, text);
|
|
24
|
+
for (const token of tokens) {
|
|
25
|
+
const match = /^([a-z]+)=([A-Za-z0-9_./#:-]+)$/.exec(token);
|
|
26
|
+
if (!match || attrs.has(match[1]))
|
|
27
|
+
invalid("Tag attributes are invalid.", line, token);
|
|
28
|
+
attrs.set(match[1], match[2]);
|
|
29
|
+
}
|
|
30
|
+
return { name: open[1], closing: false, attrs, line };
|
|
31
|
+
}
|
|
32
|
+
function assertAttrs(tag, required, optional = []) {
|
|
33
|
+
const allowed = new Set([...required, ...optional]);
|
|
34
|
+
const unknown = [...tag.attrs.keys()].filter((key) => !allowed.has(key));
|
|
35
|
+
const missing = required.filter((key) => !tag.attrs.has(key));
|
|
36
|
+
if (unknown.length > 0 || missing.length > 0) {
|
|
37
|
+
invalid("Tag attributes do not match the canonical grammar.", tag.line, [
|
|
38
|
+
...missing.map((key) => `missing:${key}`),
|
|
39
|
+
...unknown.map((key) => `unknown:${key}`),
|
|
40
|
+
].join(","));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
class Cursor {
|
|
44
|
+
lines;
|
|
45
|
+
index = 0;
|
|
46
|
+
constructor(text) {
|
|
47
|
+
this.lines = text.split(/\r?\n/)
|
|
48
|
+
.map((raw, index) => ({
|
|
49
|
+
raw: raw.replace(/^\s+/, ""),
|
|
50
|
+
line: index + 1,
|
|
51
|
+
}))
|
|
52
|
+
.filter((item) => item.raw.trim() !== "");
|
|
53
|
+
}
|
|
54
|
+
peek() {
|
|
55
|
+
const item = this.lines[this.index];
|
|
56
|
+
if (!item)
|
|
57
|
+
invalid("Unexpected end of authoring file.", this.lines.at(-1)?.line ?? 1, "<eof>");
|
|
58
|
+
return item;
|
|
59
|
+
}
|
|
60
|
+
take() {
|
|
61
|
+
const item = this.peek();
|
|
62
|
+
this.index++;
|
|
63
|
+
return item;
|
|
64
|
+
}
|
|
65
|
+
tag(name, closing) {
|
|
66
|
+
const item = this.take();
|
|
67
|
+
const tag = parseTag(item.raw, item.line);
|
|
68
|
+
if (!tag || tag.name !== name || tag.closing !== closing) {
|
|
69
|
+
invalid(`Expected ${closing ? "</" : "<"}${name}>.`, item.line, item.raw);
|
|
70
|
+
}
|
|
71
|
+
return tag;
|
|
72
|
+
}
|
|
73
|
+
record() {
|
|
74
|
+
const item = this.take();
|
|
75
|
+
return parseBracketRecord(item.raw, item.line);
|
|
76
|
+
}
|
|
77
|
+
nextTag() {
|
|
78
|
+
const item = this.peek();
|
|
79
|
+
return parseTag(item.raw, item.line);
|
|
80
|
+
}
|
|
81
|
+
nextRecord() {
|
|
82
|
+
const item = this.peek();
|
|
83
|
+
return item.raw.startsWith("[") ? parseBracketRecord(item.raw, item.line) : null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function jsonValue(value) {
|
|
87
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean")
|
|
88
|
+
return true;
|
|
89
|
+
if (Array.isArray(value))
|
|
90
|
+
return value.every(jsonValue);
|
|
91
|
+
return typeof value === "object" && Object.values(value).every(jsonValue);
|
|
92
|
+
}
|
|
93
|
+
function modifiers(cursor) {
|
|
94
|
+
const result = {};
|
|
95
|
+
let next = cursor.nextRecord();
|
|
96
|
+
if (next?.type === "extensions") {
|
|
97
|
+
cursor.record();
|
|
98
|
+
const extend = {};
|
|
99
|
+
let previousKey = null;
|
|
100
|
+
while ((next = cursor.nextRecord())?.type === "extend") {
|
|
101
|
+
const record = cursor.record();
|
|
102
|
+
if (record.slots.length !== 1 || Object.hasOwn(extend, record.slots[0])) {
|
|
103
|
+
invalid("extend record is invalid or duplicated.", record.source.line, record.type);
|
|
104
|
+
}
|
|
105
|
+
const key = record.slots[0];
|
|
106
|
+
if (previousKey !== null && previousKey >= key) {
|
|
107
|
+
invalid("extend keys must use ascending canonical order.", record.source.line, key);
|
|
108
|
+
}
|
|
109
|
+
let value;
|
|
110
|
+
try {
|
|
111
|
+
value = JSON.parse(record.content);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
invalid("extend content must be JSON.", record.source.line, record.content);
|
|
115
|
+
}
|
|
116
|
+
if (!jsonValue(value))
|
|
117
|
+
invalid("extend value must be JSON-compatible.", record.source.line, record.content);
|
|
118
|
+
extend[key] = value;
|
|
119
|
+
previousKey = key;
|
|
120
|
+
}
|
|
121
|
+
result.extend = extend;
|
|
122
|
+
}
|
|
123
|
+
next = cursor.nextRecord();
|
|
124
|
+
if (next?.type === "aliases") {
|
|
125
|
+
cursor.record();
|
|
126
|
+
const aliases = [];
|
|
127
|
+
while ((next = cursor.nextRecord())?.type === "alias") {
|
|
128
|
+
const record = cursor.record();
|
|
129
|
+
if (record.slots.length !== 0)
|
|
130
|
+
invalid("alias takes no slots.", record.source.line, record.type);
|
|
131
|
+
if (record.content === "")
|
|
132
|
+
invalid("alias must not be empty.", record.source.line, record.type);
|
|
133
|
+
if (aliases.includes(record.content))
|
|
134
|
+
invalid("alias must not be duplicated.", record.source.line, record.content);
|
|
135
|
+
aliases.push(record.content);
|
|
136
|
+
}
|
|
137
|
+
result.aliases = aliases;
|
|
138
|
+
}
|
|
139
|
+
next = cursor.nextRecord();
|
|
140
|
+
if (next?.type === "prompt") {
|
|
141
|
+
const record = cursor.record();
|
|
142
|
+
if (record.slots.length !== 3 || record.slots.some((slot) => slot === "")) {
|
|
143
|
+
invalid("prompt requires non-empty target, process, and contrast.", record.source.line, record.type);
|
|
144
|
+
}
|
|
145
|
+
const target = record.slots[0];
|
|
146
|
+
if (!isV4Id("actor", target) && !isV4Id("location", target) && !isV4Id("prop", target)) {
|
|
147
|
+
invalid("prompt target must be an asset ID.", record.source.line, target);
|
|
148
|
+
}
|
|
149
|
+
result.prompt = {
|
|
150
|
+
target,
|
|
151
|
+
process: record.slots[1],
|
|
152
|
+
contrast: record.slots[2],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
function importance(raw, line) {
|
|
158
|
+
if (raw !== "featured" && raw !== "background")
|
|
159
|
+
invalid("Importance is invalid.", line, raw);
|
|
160
|
+
return raw;
|
|
161
|
+
}
|
|
162
|
+
function role(raw, line) {
|
|
163
|
+
if (raw === undefined)
|
|
164
|
+
return undefined;
|
|
165
|
+
if (raw !== "主角" && raw !== "配角")
|
|
166
|
+
invalid("Role type is invalid.", line, raw);
|
|
167
|
+
return raw;
|
|
168
|
+
}
|
|
169
|
+
function stateId(raw, line) {
|
|
170
|
+
if (raw === "default" || isV4Id("state", raw))
|
|
171
|
+
return raw;
|
|
172
|
+
return invalid("State ID is invalid.", line, raw);
|
|
173
|
+
}
|
|
174
|
+
function parseCreate(cursor) {
|
|
175
|
+
const opening = cursor.tag("create", false);
|
|
176
|
+
assertAttrs(opening, []);
|
|
177
|
+
const declarations = [];
|
|
178
|
+
const declaredAssets = new Map();
|
|
179
|
+
let activeNewAssetId = null;
|
|
180
|
+
let declarationPhase = 0;
|
|
181
|
+
const finishActiveAsset = (line) => {
|
|
182
|
+
if (activeNewAssetId === null)
|
|
183
|
+
return;
|
|
184
|
+
const asset = declaredAssets.get(activeNewAssetId);
|
|
185
|
+
if (!asset || asset.states.length === 0 || asset.states[0].state_id !== "default") {
|
|
186
|
+
invalid("A new asset must be followed immediately by its default state.", line, activeNewAssetId);
|
|
187
|
+
}
|
|
188
|
+
activeNewAssetId = null;
|
|
189
|
+
};
|
|
190
|
+
while (cursor.nextTag()?.name !== "create" || cursor.nextTag()?.closing !== true) {
|
|
191
|
+
const mod = modifiers(cursor);
|
|
192
|
+
const record = cursor.record();
|
|
193
|
+
if (record.type === "actor") {
|
|
194
|
+
if (declarationPhase > 0)
|
|
195
|
+
invalid("Create declarations are not in canonical order.", record.source.line, record.type);
|
|
196
|
+
finishActiveAsset(record.source.line);
|
|
197
|
+
if (mod.prompt !== undefined)
|
|
198
|
+
invalid("prompt cannot modify an asset.", record.source.line, record.type);
|
|
199
|
+
if (record.slots.length < 3 || record.slots.length > 4 || !isV4Id("actor", record.slots[0])) {
|
|
200
|
+
invalid("actor declaration is invalid.", record.source.line, record.type);
|
|
201
|
+
}
|
|
202
|
+
const roleType = role(record.slots[3], record.source.line);
|
|
203
|
+
const value = {
|
|
204
|
+
actor_id: record.slots[0],
|
|
205
|
+
actor_name: record.slots[1],
|
|
206
|
+
importance: importance(record.slots[2], record.source.line),
|
|
207
|
+
description: record.content,
|
|
208
|
+
states: [],
|
|
209
|
+
...(roleType === undefined ? {} : { role_type: roleType }),
|
|
210
|
+
...(mod.aliases === undefined ? {} : { aliases: mod.aliases }),
|
|
211
|
+
...(mod.extend === undefined ? {} : { extend: mod.extend }),
|
|
212
|
+
};
|
|
213
|
+
if (value.aliases?.includes(value.actor_name)) {
|
|
214
|
+
invalid("An alias must differ from the asset name.", record.source.line, value.actor_name);
|
|
215
|
+
}
|
|
216
|
+
declarations.push({ kind: "actor", value });
|
|
217
|
+
declaredAssets.set(value.actor_id, value);
|
|
218
|
+
activeNewAssetId = value.actor_id;
|
|
219
|
+
}
|
|
220
|
+
else if (record.type === "location" || record.type === "prop") {
|
|
221
|
+
const nextPhase = record.type === "location" ? 1 : 2;
|
|
222
|
+
if (nextPhase < declarationPhase) {
|
|
223
|
+
invalid("Create declarations are not in canonical order.", record.source.line, record.type);
|
|
224
|
+
}
|
|
225
|
+
declarationPhase = nextPhase;
|
|
226
|
+
finishActiveAsset(record.source.line);
|
|
227
|
+
if (mod.prompt !== undefined)
|
|
228
|
+
invalid("prompt cannot modify an asset.", record.source.line, record.type);
|
|
229
|
+
const kind = record.type;
|
|
230
|
+
if (record.slots.length !== 3
|
|
231
|
+
|| (kind === "location"
|
|
232
|
+
? !isV4Id("location", record.slots[0])
|
|
233
|
+
: !isV4Id("prop", record.slots[0]))) {
|
|
234
|
+
invalid(`${kind} declaration is invalid.`, record.source.line, record.type);
|
|
235
|
+
}
|
|
236
|
+
if (kind === "location") {
|
|
237
|
+
const locationId = record.slots[0];
|
|
238
|
+
if (!isV4Id("location", locationId))
|
|
239
|
+
invalid("location ID is invalid.", record.source.line, locationId);
|
|
240
|
+
const value = {
|
|
241
|
+
location_id: locationId,
|
|
242
|
+
location_name: record.slots[1],
|
|
243
|
+
importance: importance(record.slots[2], record.source.line),
|
|
244
|
+
description: record.content,
|
|
245
|
+
states: [],
|
|
246
|
+
...(mod.aliases === undefined ? {} : { aliases: mod.aliases }),
|
|
247
|
+
...(mod.extend === undefined ? {} : { extend: mod.extend }),
|
|
248
|
+
};
|
|
249
|
+
if (value.aliases?.includes(value.location_name)) {
|
|
250
|
+
invalid("An alias must differ from the asset name.", record.source.line, value.location_name);
|
|
251
|
+
}
|
|
252
|
+
declarations.push({ kind, value });
|
|
253
|
+
declaredAssets.set(value.location_id, value);
|
|
254
|
+
activeNewAssetId = value.location_id;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
const propId = record.slots[0];
|
|
258
|
+
if (!isV4Id("prop", propId))
|
|
259
|
+
invalid("prop ID is invalid.", record.source.line, propId);
|
|
260
|
+
const value = {
|
|
261
|
+
prop_id: propId,
|
|
262
|
+
prop_name: record.slots[1],
|
|
263
|
+
importance: importance(record.slots[2], record.source.line),
|
|
264
|
+
description: record.content,
|
|
265
|
+
states: [],
|
|
266
|
+
...(mod.aliases === undefined ? {} : { aliases: mod.aliases }),
|
|
267
|
+
...(mod.extend === undefined ? {} : { extend: mod.extend }),
|
|
268
|
+
};
|
|
269
|
+
if (value.aliases?.includes(value.prop_name)) {
|
|
270
|
+
invalid("An alias must differ from the asset name.", record.source.line, value.prop_name);
|
|
271
|
+
}
|
|
272
|
+
declarations.push({ kind, value });
|
|
273
|
+
declaredAssets.set(value.prop_id, value);
|
|
274
|
+
activeNewAssetId = value.prop_id;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
else if (record.type === "state") {
|
|
278
|
+
if (record.slots.length !== 3 || mod.aliases !== undefined || mod.prompt !== undefined) {
|
|
279
|
+
invalid("state declaration is invalid.", record.source.line, record.type);
|
|
280
|
+
}
|
|
281
|
+
const ownerId = record.slots[0];
|
|
282
|
+
const owner = declaredAssets.get(ownerId);
|
|
283
|
+
if (owner && activeNewAssetId !== ownerId) {
|
|
284
|
+
invalid("States for a new asset must immediately follow that asset.", record.source.line, ownerId);
|
|
285
|
+
}
|
|
286
|
+
if (!owner) {
|
|
287
|
+
finishActiveAsset(record.source.line);
|
|
288
|
+
declarationPhase = 3;
|
|
289
|
+
}
|
|
290
|
+
const value = {
|
|
291
|
+
state_id: stateId(record.slots[1], record.source.line),
|
|
292
|
+
state_name: record.slots[2],
|
|
293
|
+
description: record.content,
|
|
294
|
+
...(mod.extend === undefined ? {} : { extend: mod.extend }),
|
|
295
|
+
};
|
|
296
|
+
if (owner) {
|
|
297
|
+
if (owner.states.length === 0 && value.state_id !== "default") {
|
|
298
|
+
invalid("The first state of a new asset must be default.", record.source.line, value.state_id);
|
|
299
|
+
}
|
|
300
|
+
owner.states.push(value);
|
|
301
|
+
}
|
|
302
|
+
else
|
|
303
|
+
declarations.push({ kind: "state", ownerId, value });
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
finishActiveAsset(record.source.line);
|
|
307
|
+
invalid("Unknown create declaration.", record.source.line, record.type);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
finishActiveAsset(cursor.peek().line);
|
|
311
|
+
const closing = cursor.tag("create", true);
|
|
312
|
+
assertAttrs(closing, []);
|
|
313
|
+
return declarations;
|
|
314
|
+
}
|
|
315
|
+
function speaker(raw, line) {
|
|
316
|
+
const slash = raw.indexOf("/");
|
|
317
|
+
const actor = slash < 0 ? raw : raw.slice(0, slash);
|
|
318
|
+
if (isV4Id("actor", actor)) {
|
|
319
|
+
return slash < 0
|
|
320
|
+
? { actor_id: actor }
|
|
321
|
+
: { actor_id: actor, state_id: stateId(raw.slice(slash + 1), line) };
|
|
322
|
+
}
|
|
323
|
+
const colon = raw.indexOf(":");
|
|
324
|
+
const kind = (colon < 0 ? raw : raw.slice(0, colon));
|
|
325
|
+
if (!["system", "broadcast", "offscreen", "group"].includes(kind)) {
|
|
326
|
+
return invalid("Speaker is invalid.", line, raw);
|
|
327
|
+
}
|
|
328
|
+
return colon < 0 ? { kind } : { kind, label: raw.slice(colon + 1) };
|
|
329
|
+
}
|
|
330
|
+
function parseAction(cursor) {
|
|
331
|
+
const mod = modifiers(cursor);
|
|
332
|
+
if (mod.aliases !== undefined)
|
|
333
|
+
invalid("aliases cannot modify an Action.", cursor.peek().line, "aliases");
|
|
334
|
+
const record = cursor.record();
|
|
335
|
+
if (record.type === "act" || record.type === "trans") {
|
|
336
|
+
if (record.slots.length !== 1 || !isV4Id("action", record.slots[0])) {
|
|
337
|
+
invalid("Narrative Action record is invalid.", record.source.line, record.type);
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
action_id: record.slots[0],
|
|
341
|
+
type: record.type === "act" ? "action" : "transition",
|
|
342
|
+
content: record.content,
|
|
343
|
+
...(mod.extend === undefined ? {} : { extend: mod.extend }),
|
|
344
|
+
...(mod.prompt === undefined ? {} : { transition_prompt: mod.prompt }),
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
if (record.type !== "dlg" && record.type !== "think") {
|
|
348
|
+
return invalid("Unknown Action record.", record.source.line, record.type);
|
|
349
|
+
}
|
|
350
|
+
if ((record.slots.length !== 2 && record.slots.length !== 3) || !isV4Id("action", record.slots[0])) {
|
|
351
|
+
invalid("Speaking Action record is invalid.", record.source.line, record.type);
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
action_id: record.slots[0],
|
|
355
|
+
type: record.type === "dlg" ? "dialogue" : "inner_thought",
|
|
356
|
+
speaker: speaker(record.slots[1], record.source.line),
|
|
357
|
+
content: record.content,
|
|
358
|
+
...(record.slots.length === 3 ? { parenthetical: record.slots[2] } : {}),
|
|
359
|
+
...(mod.extend === undefined ? {} : { extend: mod.extend }),
|
|
360
|
+
...(mod.prompt === undefined ? {} : { transition_prompt: mod.prompt }),
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
function stateSet(slots, line) {
|
|
364
|
+
if (slots.length === 0)
|
|
365
|
+
invalid("Scene reference needs at least one state.", line, "<empty>");
|
|
366
|
+
const values = slots.map((value) => stateId(value, line));
|
|
367
|
+
if (new Set(values).size !== values.length)
|
|
368
|
+
invalid("Scene reference repeats a state.", line, values.join(","));
|
|
369
|
+
return values.sort();
|
|
370
|
+
}
|
|
371
|
+
function parseScene(cursor, opening, outerParent, extend) {
|
|
372
|
+
assertAttrs(opening, outerParent === undefined ? ["id", "parent"] : ["id"]);
|
|
373
|
+
const id = opening.attrs.get("id") ?? "";
|
|
374
|
+
if (!isV4Id("scene", id))
|
|
375
|
+
invalid("Scene ID is invalid.", opening.line, id);
|
|
376
|
+
const parent = opening.attrs.get("parent") ?? outerParent;
|
|
377
|
+
if (parent !== undefined && !isV4Id("episode", parent)) {
|
|
378
|
+
invalid("Scene parent must be an Episode ID.", opening.line, parent);
|
|
379
|
+
}
|
|
380
|
+
let environment;
|
|
381
|
+
let location;
|
|
382
|
+
const actors = [];
|
|
383
|
+
const props = [];
|
|
384
|
+
const actorIds = new Set();
|
|
385
|
+
const propIds = new Set();
|
|
386
|
+
let phase = 0;
|
|
387
|
+
while (cursor.nextTag()?.name !== "body") {
|
|
388
|
+
const record = cursor.record();
|
|
389
|
+
const nextPhase = record.type === "environment" ? 0
|
|
390
|
+
: record.type === "location" ? 1
|
|
391
|
+
: record.type === "cast" ? 2
|
|
392
|
+
: record.type === "prop" ? 3
|
|
393
|
+
: -1;
|
|
394
|
+
if (nextPhase < phase) {
|
|
395
|
+
invalid("Scene records are not in canonical order.", record.source.line, record.type);
|
|
396
|
+
}
|
|
397
|
+
phase = nextPhase;
|
|
398
|
+
if (record.type === "environment") {
|
|
399
|
+
if (environment !== undefined)
|
|
400
|
+
invalid("Scene environment is duplicated.", record.source.line, record.type);
|
|
401
|
+
if (record.slots.length > 2)
|
|
402
|
+
invalid("environment has too many slots.", record.source.line, record.type);
|
|
403
|
+
environment = {
|
|
404
|
+
...(record.slots[0] === undefined ? {} : { space: record.slots[0] }),
|
|
405
|
+
...(record.slots[1] === undefined ? {} : { time: record.slots[1] }),
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
else if (record.type === "location") {
|
|
409
|
+
if (location !== undefined)
|
|
410
|
+
invalid("Scene location is duplicated.", record.source.line, record.type);
|
|
411
|
+
if (record.slots.length === 0)
|
|
412
|
+
location = null;
|
|
413
|
+
else {
|
|
414
|
+
if (!isV4Id("location", record.slots[0]))
|
|
415
|
+
invalid("Location ref ID is invalid.", record.source.line, record.slots[0]);
|
|
416
|
+
location = { location_id: record.slots[0], state_ids: stateSet(record.slots.slice(1), record.source.line) };
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
else if (record.type === "cast") {
|
|
420
|
+
if (!isV4Id("actor", record.slots[0]))
|
|
421
|
+
invalid("Cast ref ID is invalid.", record.source.line, record.slots[0] ?? "");
|
|
422
|
+
if (actorIds.has(record.slots[0]))
|
|
423
|
+
invalid("Scene repeats an actor reference.", record.source.line, record.slots[0]);
|
|
424
|
+
actorIds.add(record.slots[0]);
|
|
425
|
+
actors.push({ actor_id: record.slots[0], state_ids: stateSet(record.slots.slice(1), record.source.line) });
|
|
426
|
+
}
|
|
427
|
+
else if (record.type === "prop") {
|
|
428
|
+
if (!isV4Id("prop", record.slots[0]))
|
|
429
|
+
invalid("Prop ref ID is invalid.", record.source.line, record.slots[0] ?? "");
|
|
430
|
+
if (propIds.has(record.slots[0]))
|
|
431
|
+
invalid("Scene repeats a prop reference.", record.source.line, record.slots[0]);
|
|
432
|
+
propIds.add(record.slots[0]);
|
|
433
|
+
props.push({ prop_id: record.slots[0], state_ids: stateSet(record.slots.slice(1), record.source.line) });
|
|
434
|
+
}
|
|
435
|
+
else
|
|
436
|
+
invalid("Unknown scene header record.", record.source.line, record.type);
|
|
437
|
+
}
|
|
438
|
+
if (location === undefined)
|
|
439
|
+
invalid("Scene must declare location or [location].", cursor.peek().line, id);
|
|
440
|
+
const bodyOpening = cursor.tag("body", false);
|
|
441
|
+
assertAttrs(bodyOpening, []);
|
|
442
|
+
const actions = [];
|
|
443
|
+
while (cursor.nextTag()?.name !== "body" || cursor.nextTag()?.closing !== true)
|
|
444
|
+
actions.push(parseAction(cursor));
|
|
445
|
+
assertAttrs(cursor.tag("body", true), []);
|
|
446
|
+
assertAttrs(cursor.tag("scene", true), []);
|
|
447
|
+
return {
|
|
448
|
+
...(parent === undefined ? {} : { parent }),
|
|
449
|
+
value: {
|
|
450
|
+
scene_id: id,
|
|
451
|
+
...(environment === undefined ? {} : { environment }),
|
|
452
|
+
location,
|
|
453
|
+
actors,
|
|
454
|
+
props,
|
|
455
|
+
actions,
|
|
456
|
+
...(extend === undefined ? {} : { extend }),
|
|
457
|
+
},
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
function parseEpisode(cursor, opening, extend) {
|
|
461
|
+
assertAttrs(opening, ["id"]);
|
|
462
|
+
const id = opening.attrs.get("id") ?? "";
|
|
463
|
+
if (!isV4Id("episode", id))
|
|
464
|
+
invalid("Episode ID is invalid.", opening.line, id);
|
|
465
|
+
let title;
|
|
466
|
+
let synopsis;
|
|
467
|
+
const scenes = [];
|
|
468
|
+
let phase = 0;
|
|
469
|
+
while (cursor.nextTag()?.name !== "episode" || cursor.nextTag()?.closing !== true) {
|
|
470
|
+
const mod = modifiers(cursor);
|
|
471
|
+
if (mod.aliases !== undefined || mod.prompt !== undefined) {
|
|
472
|
+
invalid("Invalid episode child modifier.", cursor.peek().line, "modifier");
|
|
473
|
+
}
|
|
474
|
+
const next = cursor.nextTag();
|
|
475
|
+
if (next?.name === "scene" && !next.closing) {
|
|
476
|
+
phase = 2;
|
|
477
|
+
cursor.take();
|
|
478
|
+
scenes.push(parseScene(cursor, next, id, mod.extend).value);
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
if (mod.extend !== undefined)
|
|
482
|
+
invalid("extend must precede a scene here.", cursor.peek().line, "extend");
|
|
483
|
+
const record = cursor.record();
|
|
484
|
+
const nextPhase = record.type === "title" ? 0 : record.type === "synopsis" ? 1 : -1;
|
|
485
|
+
if (nextPhase < phase)
|
|
486
|
+
invalid("Episode records are not in canonical order.", record.source.line, record.type);
|
|
487
|
+
phase = nextPhase;
|
|
488
|
+
if (record.type === "title") {
|
|
489
|
+
if (title !== undefined)
|
|
490
|
+
invalid("Episode title is duplicated.", record.source.line, record.type);
|
|
491
|
+
if (record.slots.length !== 0)
|
|
492
|
+
invalid("Episode title takes no slots.", record.source.line, record.type);
|
|
493
|
+
title = record.content;
|
|
494
|
+
}
|
|
495
|
+
else if (record.type === "synopsis") {
|
|
496
|
+
if (synopsis !== undefined)
|
|
497
|
+
invalid("Episode synopsis is duplicated.", record.source.line, record.type);
|
|
498
|
+
if (record.slots.length !== 0)
|
|
499
|
+
invalid("Episode synopsis takes no slots.", record.source.line, record.type);
|
|
500
|
+
synopsis = record.content;
|
|
501
|
+
}
|
|
502
|
+
else
|
|
503
|
+
invalid("Unknown episode record.", record.source.line, record.type);
|
|
504
|
+
}
|
|
505
|
+
assertAttrs(cursor.tag("episode", true), []);
|
|
506
|
+
return {
|
|
507
|
+
episode_id: id,
|
|
508
|
+
...(title === undefined ? {} : { title }),
|
|
509
|
+
...(synopsis === undefined ? {} : { synopsis }),
|
|
510
|
+
scenes,
|
|
511
|
+
...(extend === undefined ? {} : { extend }),
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
function range(tag, kind) {
|
|
515
|
+
const value = tag.attrs.get("range") ?? "";
|
|
516
|
+
const pieces = value.split("..");
|
|
517
|
+
if (pieces.length !== 2
|
|
518
|
+
|| !pieces[0]
|
|
519
|
+
|| !pieces[1]
|
|
520
|
+
|| !isV4Id(kind, pieces[0])
|
|
521
|
+
|| !isV4Id(kind, pieces[1])) {
|
|
522
|
+
invalid(`Span range must contain two ${kind} IDs.`, tag.line, value);
|
|
523
|
+
}
|
|
524
|
+
return [pieces[0], pieces[1]];
|
|
525
|
+
}
|
|
526
|
+
function parseScriptTarget(cursor, opening, extend) {
|
|
527
|
+
assertAttrs(opening, []);
|
|
528
|
+
let title;
|
|
529
|
+
let worldview;
|
|
530
|
+
let worldview_raw;
|
|
531
|
+
let style;
|
|
532
|
+
let synopsis;
|
|
533
|
+
let logline;
|
|
534
|
+
let theme;
|
|
535
|
+
let main_characters;
|
|
536
|
+
const episodes = [];
|
|
537
|
+
let phase = 0;
|
|
538
|
+
while (cursor.nextTag()?.name !== "script" || cursor.nextTag()?.closing !== true) {
|
|
539
|
+
const mod = modifiers(cursor);
|
|
540
|
+
if (mod.aliases !== undefined || mod.prompt !== undefined) {
|
|
541
|
+
invalid("Invalid script child modifier.", cursor.peek().line, "modifier");
|
|
542
|
+
}
|
|
543
|
+
const next = cursor.nextTag();
|
|
544
|
+
if (next?.name === "episode" && !next.closing) {
|
|
545
|
+
phase = 8;
|
|
546
|
+
cursor.take();
|
|
547
|
+
episodes.push(parseEpisode(cursor, next, mod.extend));
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
if (mod.extend !== undefined)
|
|
551
|
+
invalid("extend must precede an episode here.", cursor.peek().line, "extend");
|
|
552
|
+
const record = cursor.record();
|
|
553
|
+
const nextPhase = record.type === "title" ? 0
|
|
554
|
+
: record.type === "worldview" ? 1
|
|
555
|
+
: record.type === "worldview-raw" ? 2
|
|
556
|
+
: record.type === "style" ? 3
|
|
557
|
+
: record.type === "synopsis" ? 4
|
|
558
|
+
: record.type === "logline" ? 5
|
|
559
|
+
: record.type === "theme" ? 6
|
|
560
|
+
: record.type === "main-characters" || record.type === "main-character" ? 7
|
|
561
|
+
: -1;
|
|
562
|
+
if (nextPhase < phase)
|
|
563
|
+
invalid("Script records are not in canonical order.", record.source.line, record.type);
|
|
564
|
+
phase = nextPhase;
|
|
565
|
+
if (record.type !== "main-character"
|
|
566
|
+
&& record.slots.length !== 0) {
|
|
567
|
+
invalid("Script metadata record takes no slots.", record.source.line, record.type);
|
|
568
|
+
}
|
|
569
|
+
if (record.type === "title") {
|
|
570
|
+
if (title !== undefined)
|
|
571
|
+
invalid("Script title is duplicated.", record.source.line, record.type);
|
|
572
|
+
title = record.content;
|
|
573
|
+
}
|
|
574
|
+
else if (record.type === "worldview") {
|
|
575
|
+
if (worldview !== undefined)
|
|
576
|
+
invalid("Script worldview is duplicated.", record.source.line, record.type);
|
|
577
|
+
worldview = record.content;
|
|
578
|
+
}
|
|
579
|
+
else if (record.type === "worldview-raw") {
|
|
580
|
+
if (worldview_raw !== undefined)
|
|
581
|
+
invalid("Script worldview-raw is duplicated.", record.source.line, record.type);
|
|
582
|
+
worldview_raw = record.content;
|
|
583
|
+
}
|
|
584
|
+
else if (record.type === "style") {
|
|
585
|
+
if (style !== undefined)
|
|
586
|
+
invalid("Script style is duplicated.", record.source.line, record.type);
|
|
587
|
+
style = record.content;
|
|
588
|
+
}
|
|
589
|
+
else if (record.type === "synopsis") {
|
|
590
|
+
if (synopsis !== undefined)
|
|
591
|
+
invalid("Script synopsis is duplicated.", record.source.line, record.type);
|
|
592
|
+
synopsis = record.content;
|
|
593
|
+
}
|
|
594
|
+
else if (record.type === "logline") {
|
|
595
|
+
if (logline !== undefined)
|
|
596
|
+
invalid("Script logline is duplicated.", record.source.line, record.type);
|
|
597
|
+
logline = record.content;
|
|
598
|
+
}
|
|
599
|
+
else if (record.type === "theme") {
|
|
600
|
+
if (theme !== undefined)
|
|
601
|
+
invalid("Script theme is duplicated.", record.source.line, record.type);
|
|
602
|
+
theme = record.content;
|
|
603
|
+
}
|
|
604
|
+
else if (record.type === "main-characters") {
|
|
605
|
+
if (main_characters !== undefined)
|
|
606
|
+
invalid("Script main-characters is duplicated.", record.source.line, record.type);
|
|
607
|
+
main_characters = [];
|
|
608
|
+
}
|
|
609
|
+
else if (record.type === "main-character"
|
|
610
|
+
&& main_characters !== undefined
|
|
611
|
+
&& record.slots.length === 2
|
|
612
|
+
&& record.content === "") {
|
|
613
|
+
main_characters.push({ name: record.slots[0], role: record.slots[1] });
|
|
614
|
+
}
|
|
615
|
+
else
|
|
616
|
+
invalid("Unknown script record.", record.source.line, record.type);
|
|
617
|
+
}
|
|
618
|
+
assertAttrs(cursor.tag("script", true), []);
|
|
619
|
+
if (title === undefined || worldview === undefined || style === undefined) {
|
|
620
|
+
invalid("Script target needs title, worldview, and style.", cursor.peek().line, "script");
|
|
621
|
+
}
|
|
622
|
+
return {
|
|
623
|
+
kind: "script",
|
|
624
|
+
value: {
|
|
625
|
+
title,
|
|
626
|
+
worldview,
|
|
627
|
+
style,
|
|
628
|
+
episodes,
|
|
629
|
+
...(worldview_raw === undefined ? {} : { worldview_raw }),
|
|
630
|
+
...(synopsis === undefined ? {} : { synopsis }),
|
|
631
|
+
...(logline === undefined ? {} : { logline }),
|
|
632
|
+
...(theme === undefined ? {} : { theme }),
|
|
633
|
+
...(main_characters === undefined ? {} : { main_characters }),
|
|
634
|
+
...(extend === undefined ? {} : { extend }),
|
|
635
|
+
},
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
export function parseAuthoringV4(text) {
|
|
639
|
+
const cursor = new Cursor(text);
|
|
640
|
+
const root = cursor.tag("authoring", false);
|
|
641
|
+
assertAttrs(root, ["version"]);
|
|
642
|
+
if (root.attrs.get("version") !== "1")
|
|
643
|
+
invalid("authoring version must be 1.", 1, root.attrs.get("version") ?? "<missing>");
|
|
644
|
+
const declarations = cursor.nextTag()?.name === "create" ? parseCreate(cursor) : [];
|
|
645
|
+
const targets = [];
|
|
646
|
+
while (cursor.nextTag()?.name !== "authoring" || cursor.nextTag()?.closing !== true) {
|
|
647
|
+
const mod = modifiers(cursor);
|
|
648
|
+
if (mod.aliases !== undefined || mod.prompt !== undefined) {
|
|
649
|
+
invalid("Invalid target modifier.", cursor.peek().line, "modifier");
|
|
650
|
+
}
|
|
651
|
+
const item = cursor.take();
|
|
652
|
+
const tag = parseTag(item.raw, item.line);
|
|
653
|
+
if (!tag || tag.closing)
|
|
654
|
+
invalid("Expected an authoring target.", item.line, item.raw);
|
|
655
|
+
if (tag.name === "script")
|
|
656
|
+
targets.push(parseScriptTarget(cursor, tag, mod.extend));
|
|
657
|
+
else if (tag.name === "episode")
|
|
658
|
+
targets.push({ kind: "episode", value: parseEpisode(cursor, tag, mod.extend) });
|
|
659
|
+
else if (tag.name === "scene") {
|
|
660
|
+
const parsed = parseScene(cursor, tag, undefined, mod.extend);
|
|
661
|
+
if (!parsed.parent)
|
|
662
|
+
invalid("Top-level scene needs parent.", item.line, item.raw);
|
|
663
|
+
targets.push({ kind: "scene", parent: parsed.parent, value: parsed.value });
|
|
664
|
+
}
|
|
665
|
+
else if (tag.name === "episode-span") {
|
|
666
|
+
if (mod.extend !== undefined)
|
|
667
|
+
invalid("A span cannot carry node extensions.", item.line, item.raw);
|
|
668
|
+
assertAttrs(tag, ["range"]);
|
|
669
|
+
const [from, through] = range(tag, "episode");
|
|
670
|
+
const values = [];
|
|
671
|
+
while (cursor.nextTag()?.name !== "episode-span" || cursor.nextTag()?.closing !== true) {
|
|
672
|
+
const childMod = modifiers(cursor);
|
|
673
|
+
if (childMod.aliases !== undefined || childMod.prompt !== undefined) {
|
|
674
|
+
invalid("Invalid episode child modifier.", cursor.peek().line, "modifier");
|
|
675
|
+
}
|
|
676
|
+
const open = cursor.tag("episode", false);
|
|
677
|
+
values.push(parseEpisode(cursor, open, childMod.extend));
|
|
678
|
+
}
|
|
679
|
+
assertAttrs(cursor.tag("episode-span", true), []);
|
|
680
|
+
targets.push({ kind: "episode-span", from, through, values });
|
|
681
|
+
}
|
|
682
|
+
else if (tag.name === "scene-span") {
|
|
683
|
+
if (mod.extend !== undefined)
|
|
684
|
+
invalid("A span cannot carry node extensions.", item.line, item.raw);
|
|
685
|
+
assertAttrs(tag, ["parent", "range"]);
|
|
686
|
+
const [from, through] = range(tag, "scene");
|
|
687
|
+
const parent = tag.attrs.get("parent") ?? invalid("scene-span needs parent.", item.line, item.raw);
|
|
688
|
+
if (!isV4Id("episode", parent))
|
|
689
|
+
invalid("scene-span parent must be an Episode ID.", item.line, parent);
|
|
690
|
+
const values = [];
|
|
691
|
+
while (cursor.nextTag()?.name !== "scene-span" || cursor.nextTag()?.closing !== true) {
|
|
692
|
+
const childMod = modifiers(cursor);
|
|
693
|
+
if (childMod.aliases !== undefined || childMod.prompt !== undefined) {
|
|
694
|
+
invalid("Invalid scene child modifier.", cursor.peek().line, "modifier");
|
|
695
|
+
}
|
|
696
|
+
const open = cursor.tag("scene", false);
|
|
697
|
+
values.push(parseScene(cursor, open, parent, childMod.extend).value);
|
|
698
|
+
}
|
|
699
|
+
assertAttrs(cursor.tag("scene-span", true), []);
|
|
700
|
+
targets.push({ kind: "scene-span", parent, from, through, values });
|
|
701
|
+
}
|
|
702
|
+
else if (tag.name === "action-span") {
|
|
703
|
+
if (mod.extend !== undefined)
|
|
704
|
+
invalid("A span cannot carry node extensions.", item.line, item.raw);
|
|
705
|
+
assertAttrs(tag, ["parent", "range"]);
|
|
706
|
+
const [from, through] = range(tag, "action");
|
|
707
|
+
const parent = tag.attrs.get("parent") ?? invalid("action-span needs parent.", item.line, item.raw);
|
|
708
|
+
if (!isV4Id("scene", parent))
|
|
709
|
+
invalid("action-span parent must be a Scene ID.", item.line, parent);
|
|
710
|
+
assertAttrs(cursor.tag("body", false), []);
|
|
711
|
+
const values = [];
|
|
712
|
+
while (cursor.nextTag()?.name !== "body" || cursor.nextTag()?.closing !== true)
|
|
713
|
+
values.push(parseAction(cursor));
|
|
714
|
+
assertAttrs(cursor.tag("body", true), []);
|
|
715
|
+
assertAttrs(cursor.tag("action-span", true), []);
|
|
716
|
+
targets.push({ kind: "action-span", parent, from, through, values });
|
|
717
|
+
}
|
|
718
|
+
else
|
|
719
|
+
invalid("Unknown authoring target.", item.line, tag.name);
|
|
720
|
+
}
|
|
721
|
+
assertAttrs(cursor.tag("authoring", true), []);
|
|
722
|
+
if (cursor.index !== cursor.lines.length || targets.length === 0)
|
|
723
|
+
invalid("Authoring file has trailing content or no targets.", cursor.peek().line, "<root>");
|
|
724
|
+
const targetKind = targets[0].kind;
|
|
725
|
+
if (!targets.every((target) => target.kind === targetKind))
|
|
726
|
+
invalid("All targets must have the same kind.", 1, targetKind);
|
|
727
|
+
return { declarations, targets, targetKind };
|
|
728
|
+
}
|
|
729
|
+
//# sourceMappingURL=parser.js.map
|