@asrunjs/asrun 0.14.0 → 0.15.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/.claude/commands/explore-case.md +8 -3
- package/.claude/skills/exploring-cases/SKILL.md +47 -4
- package/.claude/skills/exploring-cases/references/notes.md +42 -4
- package/.claude/skills/generating-specs/SKILL.md +10 -3
- package/AGENTS.md +9 -2
- package/README.md +13 -1
- package/dist/lib/explore-notes.d.ts +15 -0
- package/dist/lib/explore-notes.js +34 -1
- package/dist/lib/migrations.d.ts +43 -4
- package/dist/lib/migrations.js +39 -7
- package/dist/lib/scaffold.d.ts +87 -0
- package/dist/lib/scaffold.js +220 -0
- package/dist/lib/term.d.ts +36 -0
- package/dist/lib/term.js +77 -0
- package/dist/lib/update-check.d.ts +1 -7
- package/dist/lib/update-check.js +3 -15
- package/dist/lib/upgrade-prompt.d.ts +84 -0
- package/dist/lib/upgrade-prompt.js +233 -0
- package/dist/migrations/index.d.ts +12 -4
- package/dist/migrations/index.js +40 -5
- package/dist/migrations/manifest.json +27 -1
- package/dist/scripts/build.js +4 -1
- package/dist/scripts/cli.js +2 -1
- package/dist/scripts/doctor.js +34 -3
- package/dist/scripts/explore-notes.js +19 -2
- package/dist/scripts/init.d.ts +6 -26
- package/dist/scripts/init.js +82 -101
- package/dist/scripts/migrate.js +84 -21
- package/dist/scripts/migrations-check.d.ts +1 -0
- package/dist/scripts/migrations-check.js +272 -0
- package/dist/scripts/migrations-freeze.d.ts +1 -0
- package/dist/scripts/migrations-freeze.js +126 -0
- package/dist/scripts/upgrade.js +53 -10
- package/dist/ui/server/app.js +4 -0
- package/dist/ui/shared/types.d.ts +6 -0
- package/docs/agents/case-format.md +6 -0
- package/docs/agents/framework-dev.md +44 -5
- package/docs/ai-workflow.md +16 -3
- package/docs/commands.md +53 -14
- package/docs/install.md +17 -4
- package/docs/web-ui.md +16 -4
- package/package.json +4 -1
- package/templates/.claude/commands/explore-case.md +6 -1
- package/templates/.claude/commands/upgrade-workspace.md +21 -0
- package/templates/AGENTS.md +1 -1
- package/ui/dist/assets/{dist-BlFnpAOk.js → dist-B4pM62Hc.js} +1 -1
- package/ui/dist/assets/{dist-BzDmxZ9V.js → dist-BFADGd4p.js} +1 -1
- package/ui/dist/assets/{dist-DxlXH2E-.js → dist-Bd-TmWTD.js} +1 -1
- package/ui/dist/assets/{dist-CjFzi6xl.js → dist-Bt053MSo.js} +1 -1
- package/ui/dist/assets/{dist-BwXTr_k4.js → dist-CD9RixNE.js} +1 -1
- package/ui/dist/assets/{dist-C1uAVsF-.js → dist-ChACtLiA.js} +1 -1
- package/ui/dist/assets/{dist-D7YBl9nc.js → dist-CiW9sEPF.js} +1 -1
- package/ui/dist/assets/{dist-jGvx4PBr.js → dist-CxEpzoZU.js} +1 -1
- package/ui/dist/assets/{dist-DxeJFPaO.js → dist-Dh7um7By.js} +1 -1
- package/ui/dist/assets/{dist-fpvlcqX7.js → dist-gHwKkZ6g.js} +1 -1
- package/ui/dist/assets/{index-Djsj43vv.js → index-Ckax27uf.js} +157 -157
- package/ui/dist/index.html +1 -1
|
@@ -124,16 +124,55 @@ A release can require an *existing* workspace to change; `docs/commands.md` has
|
|
|
124
124
|
- `version` is the release that introduces the change. `pnpm asrun migrate` runs an entry when
|
|
125
125
|
`migrations.since < version <= installed`, in version order, and moves `since` only after every entry of that
|
|
126
126
|
release has been processed, so a failed run repeats the release instead of skipping its other entries.
|
|
127
|
+
- **Never write a version by hand.** Release Please names the version in its release pull request, after the change is
|
|
128
|
+
merged, so an author cannot know it (and a guessed version that is too high never runs: `since` moves past it and the
|
|
129
|
+
workspace is silently skipped for a release). Write `id: 'unreleased-<slug>'` and `version: 'unreleased'`.
|
|
130
|
+
`resolveMigrations()` turns the sentinel into the installed release's own version — the release that carries the
|
|
131
|
+
code — so the runtime and the built manifest are always right; `pnpm migrations:freeze` rewrites the sentinel into a
|
|
132
|
+
real version and id, and `.github/workflows/release-freeze.yml` runs it on the release pull request so the id a
|
|
133
|
+
workspace sees in `doctor` names a release. That frozen version has no tag yet (the tag comes with the merge), so
|
|
134
|
+
`migrations:check` accepts the version `package.json` declares as the release being prepared — see below.
|
|
127
135
|
- `auto: true` with an `apply` runs after the install, when `detect` says the workspace is not migrated yet. Keep it
|
|
128
136
|
idempotent: a run that failed repeats the entry.
|
|
129
137
|
- Anything a person has to do is `manual: string[]`. The id is remembered in `.asrun.json` (`migrations.manual`) and
|
|
130
|
-
`doctor` keeps reminding until `pnpm asrun migrate --ack <id
|
|
131
|
-
- `
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
138
|
+
`doctor` keeps reminding until `pnpm asrun migrate --ack <id>`; every output prints that command with the real id.
|
|
139
|
+
- `files: string[]` names the project files the change touches. A once-only scaffold file there (`AGENTS.md`,
|
|
140
|
+
`.mcp.json`, ...) also has its template baseline advanced when the migration is acknowledged, so one `migrate --ack`
|
|
141
|
+
clears both the manual step and the file from the upgrade's `NEXT` block.
|
|
142
|
+
- `advisory: true` is for a release that touched a surface but asks nothing of an existing workspace (documentation, a
|
|
143
|
+
clarified contract, a new optional flag). It makes `pnpm migrations:check` pass without inventing manual steps, and
|
|
144
|
+
`migrate` reports it and moves on.
|
|
145
|
+
- `breaking: true` makes `pnpm asrun upgrade` ask before installing anything (`Proceed? [y/N]`; `--yes`/`-y` for an
|
|
146
|
+
unattended run). The pre-install check reads `dist/migrations/manifest.json` out of the target tarball, so
|
|
147
|
+
`pnpm build` has to write it (`scripts/build.ts` serialises `MIGRATIONS` with `toManifest`) and `verify:pack` asserts
|
|
148
|
+
the packed manifest carries real versions.
|
|
135
149
|
- Append only: never delete or renumber an entry, because a workspace on an older release may still need it. A change
|
|
136
150
|
that only concerns brand-new workspaces belongs in `templates/`, not in a migration.
|
|
151
|
+
|
|
152
|
+
**`pnpm migrations:check` is the gate.** It compares the working tree with the newest release tag and fails when a
|
|
153
|
+
change touched a surface that needs an entry (`templates/**` of a once-only file, the case document format, the rule
|
|
154
|
+
ids, the peer dependency range) and no entry names it, or when an entry is malformed (a duplicate id, an id that does
|
|
155
|
+
not start with the version it declares, neither `manual` nor `auto` nor `advisory`). It runs in `verify.yml`, so a
|
|
156
|
+
forgotten entry stops the pull request. `/check-migrations` in Claude Code walks the same steps and writes the entry.
|
|
157
|
+
|
|
158
|
+
An entry's version must be `unreleased` or a release that already has a tag. The single exception is the version
|
|
159
|
+
`package.json` declares: on the release pull request release-please has bumped it and `release-freeze.yml` has frozen
|
|
160
|
+
the entries to it, while the tag only appears when that pull request is merged. So `migrations:check` reads
|
|
161
|
+
`package.json` as the release being prepared — that version needs no tag and every entry has to stay at or below it,
|
|
162
|
+
which is exactly the "a guess that is too high never runs" rule. `doctor` warns about an entry above the installed
|
|
163
|
+
release for the same reason: `migrate` filters at the installed version and would silently skip it.
|
|
164
|
+
|
|
165
|
+
A command this repository uses itself lives in **both** `.claude/commands/` and `.opencode/commands/`: Claude Code reads
|
|
166
|
+
only the first, OpenCode only the second (it reloads them without a restart). The two files are identical and neither is
|
|
167
|
+
shipped for a workspace's own commands — those come from `templates/.claude/commands/` through `GENERATED`, which writes
|
|
168
|
+
each one into both folders of the workspace.
|
|
169
|
+
|
|
170
|
+
**The scaffold baseline** (`lib/scaffold.ts`, `.asrun.json` → `scaffold`) is what tells "the template changed and nobody
|
|
171
|
+
edited the file" (`replace`) from "both changed" (`merge`) and "no baseline yet" (`unknown-base`). `init` records it
|
|
172
|
+
when it writes a once-only file; `init --ack <file>` records it after a merge; nothing else writes it. A release that
|
|
173
|
+
changes a `templates/**` file a workspace owns therefore needs an entry with `files`, or the change reaches the user as
|
|
174
|
+
silent drift that only the baseline comparison reports.
|
|
175
|
+
|
|
137
176
|
- `scripts/migrate.ts` applies the *installed* package's registry, so it never runs an entry from a release that is not
|
|
138
177
|
installed. `scripts/upgrade.ts` installs first, then runs `init --update`, `migrate` and `doctor` through the newly
|
|
139
178
|
installed bin (`bin/asrun.mjs`), never through the process that started the upgrade.
|
package/docs/ai-workflow.md
CHANGED
|
@@ -3,16 +3,19 @@
|
|
|
3
3
|
Four commands carry a test case from rough notes to a Playwright spec, and repair it when the product changes. They
|
|
4
4
|
work the same in Claude Code and OpenCode: each command is a thin shell that loads a skill from the framework package,
|
|
5
5
|
so the procedure lives in one place and a project can refine it (see
|
|
6
|
-
[Customizing the prompts](#customizing-the-prompts)).
|
|
6
|
+
[Customizing the prompts](#customizing-the-prompts)). A fifth, `/upgrade-workspace`, keeps the workspace itself in step
|
|
7
|
+
with the release it runs; it needs no environment and never touches what a test case means.
|
|
7
8
|
|
|
8
9
|
| Command | What it does |
|
|
9
10
|
|---|---|
|
|
10
11
|
| `/make-case <notes-or-path>` | Turn raw notes into case documents. Optional step. |
|
|
11
|
-
| `/explore-case <case-id> <env> [--attended] [--profiles a,b] [--hints <file>]` | Open the real pages and write what they show into the case. |
|
|
12
|
+
| `/explore-case <case-id> <env> [--attended] [--profiles a,b] [--lead <profile-id>] [--hints <file>]` | Open the real pages and write what they show into the case. |
|
|
12
13
|
| `/gen-spec <case-id> <env> [--force] [--hints <file>]` | Write `tests/<case-id>.spec.ts` and fill the case's `## Values`. |
|
|
13
14
|
| `/heal-spec <case-id> <env> [--profiles a,b] [--report <run-id>] [--hints <file>]` | Repair a failing spec, or refine a case and its spec on request, from the last report and what you asked for. |
|
|
15
|
+
| `/upgrade-workspace` | Run `pnpm asrun upgrade --prompt` and follow it: merge the scaffold text of a project-owned file, fix case structure, run the checks. It never writes data, runs tests or acknowledges a migration step. |
|
|
14
16
|
|
|
15
|
-
The environment is **required** by every command except `/make-case`, which
|
|
17
|
+
The environment is **required** by every command except `/make-case` and `/upgrade-workspace`, which do not open
|
|
18
|
+
pages. There is no default.
|
|
16
19
|
|
|
17
20
|
`--profiles` exists on `/explore-case` and `/heal-spec`, not on `/gen-spec`: a spec runs once per profile in the
|
|
18
21
|
environment, so it is generated from every profile the case holds information for, never from a chosen subset.
|
|
@@ -96,6 +99,16 @@ the case keeps what the earlier runs recorded. In the web UI the profile picker
|
|
|
96
99
|
profile that is logged in in that environment is ticked, and the list you tick is passed to the run and remembered for
|
|
97
100
|
the next one there.
|
|
98
101
|
|
|
102
|
+
`--lead <profile-id>` stops paying for the same flow on every profile. The lead profile is explored in full — every
|
|
103
|
+
step, every handoff, the recipe lines, an exploration note with every step — and each other selected profile only
|
|
104
|
+
where it can differ: its own `## Values` entries, its target screenshots and the steps that reach them. A case states
|
|
105
|
+
the same behaviour for every profile, so values and target screenshots are the only place a difference can live. A
|
|
106
|
+
profile whose page structure or flow turns out to differ from the lead's is explored in full instead, and the report
|
|
107
|
+
says so; a differing check that cannot be reached is a blocking question, never "same as the lead". A write step that a
|
|
108
|
+
differing check needs is still a handoff on that profile (test data is usually private to its account), so the person
|
|
109
|
+
still creates it — the saving is the pages and steps around it, not the write. Keep lead and diff profiles in one run:
|
|
110
|
+
the notes are written at its end and share one `caseSha256`, so a split run makes the earlier notes stale.
|
|
111
|
+
|
|
99
112
|
**To keep what the case says, delete the whole block.** **To answer, write after `Answer:`.** Then run the command
|
|
100
113
|
again. In the web UI the panel calls the first action **Keep what the case says**. The run's **What to do next** bar
|
|
101
114
|
offers **Answer**: the question list, an answer box, **Use the suggested defaults** and **Generate spec**. A continued
|
package/docs/commands.md
CHANGED
|
@@ -8,7 +8,8 @@ thin wrappers, so `pnpm asrun`, `pnpm signin` and the rest work as below. The sa
|
|
|
8
8
|
| I want to... | Command |
|
|
9
9
|
|---|---|
|
|
10
10
|
| Install the framework in a project | `pnpm dlx @asrunjs/asrun init --install` |
|
|
11
|
-
| Upgrade the framework and migrate the workspace | `pnpm asrun upgrade [--version <v>] [--dry-run]` |
|
|
11
|
+
| Upgrade the framework and migrate the workspace | `pnpm asrun upgrade [--version <v>] [--dry-run] [--yes]` |
|
|
12
|
+
| Let an AI finish what an upgrade left to the project | `pnpm asrun upgrade --prompt`, or `/upgrade-workspace` |
|
|
12
13
|
| Prepare or check the workspace | `pnpm asrun init [--update]`, `pnpm asrun doctor` |
|
|
13
14
|
| See the effective rules and project settings | `pnpm asrun rules [--json] [--case <case-id>]` |
|
|
14
15
|
| See or apply the workspace migrations after a manual install | `pnpm asrun migrate [--list] [--dry-run]` |
|
|
@@ -173,10 +174,12 @@ step, error, call log and screenshots for a case, and whether the report is stal
|
|
|
173
174
|
first.
|
|
174
175
|
|
|
175
176
|
`explore:notes` reads the **exploration note** that `/explore-case` writes for a case under
|
|
176
|
-
`.explore/notes/<case-id>/<profile-id>.json`. It prints one line per profile (fresh or stale,
|
|
177
|
-
covers) and `--json` prints the parsed notes for a run that reads
|
|
177
|
+
`.explore/notes/<case-id>/<profile-id>.json`. It prints one line per profile (fresh or stale, `full` or `diff` with the
|
|
178
|
+
lead profile it leans on, and the steps and targets it covers) and `--json` prints the parsed notes for a run that reads
|
|
179
|
+
them. A note is local, git-ignored and optional:
|
|
178
180
|
`/gen-spec` uses a fresh one to verify the locators and request patterns instead of rediscovering them, and replays the
|
|
179
|
-
case when it is missing or stale. `--check` fails on a malformed note and warns about a stale one
|
|
181
|
+
case when it is missing or stale. `--check` fails on a malformed note and warns about a stale one or a `diff` note whose
|
|
182
|
+
lead has no note (it prints the current
|
|
180
183
|
`caseSha256`); `--hash` prints that hash. Deleting `.explore/notes/` is always safe.
|
|
181
184
|
|
|
182
185
|
## Rules
|
|
@@ -242,15 +245,47 @@ pnpm asrun upgrade --version 0.9.0
|
|
|
242
245
|
`installed -> target`;
|
|
243
246
|
2. reads the **migration manifest of the target release out of its tarball, before installing anything**, and prints
|
|
244
247
|
the migrations and breaking changes between the workspace's baseline (`.asrun.json` → `migrations.since`) and that
|
|
245
|
-
release. A breaking change needs a person's confirmation (
|
|
246
|
-
release that ships no manifest (it predates the manifest) cannot be checked in
|
|
247
|
-
before it installs;
|
|
248
|
+
release. A breaking change needs a person's confirmation (`Proceed? [y/N]`, an empty line means no); an unattended
|
|
249
|
+
run passes `--yes` (or `-y`). A release that ships no manifest (it predates the manifest) cannot be checked in
|
|
250
|
+
advance: `upgrade` says so and asks before it installs;
|
|
248
251
|
3. installs `@asrunjs/asrun@<target>` (it first exempts a fresh release from pnpm's release age, or pnpm would install
|
|
249
252
|
the previous one);
|
|
250
253
|
4. runs `init --update`, `migrate` and `doctor` through the package that was just installed.
|
|
251
254
|
|
|
252
255
|
`--dry-run` stops after step 2. `--version` pins a release; `upgrade` never downgrades.
|
|
253
256
|
|
|
257
|
+
### What an upgrade leaves to a person or an AI
|
|
258
|
+
|
|
259
|
+
`init --update` refreshes only the files the framework generates. A release can also change a file the *project* owns
|
|
260
|
+
(`AGENTS.md`, `CLAUDE.md`, `.mcp.json`, `opencode.jsonc`, `tsconfig.json`, `pnpm-workspace.yaml`, `profiles.yaml`,
|
|
261
|
+
`.claude/settings.json`, `cases/_template.md`) or ask for a manual migration step. Both are recorded, and `upgrade` ends
|
|
262
|
+
with a framed `NEXT` block that lists them with the exact command for each. When there is nothing to do it prints one
|
|
263
|
+
quiet line instead.
|
|
264
|
+
|
|
265
|
+
`pnpm asrun upgrade --prompt` prints that work as a task for an AI agent, and changes nothing (it reads the workspace
|
|
266
|
+
and the installed package only, so it works offline):
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
pnpm asrun upgrade --prompt # the task, as Markdown
|
|
270
|
+
pnpm asrun upgrade --prompt --json # the same answer as JSON (the web UI uses this)
|
|
271
|
+
pnpm asrun migrate --prompt # the same, after a manual "pnpm add" + "init --update"
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
In Claude Code or OpenCode, `/upgrade-workspace` does the same: it runs the command above and follows its output.
|
|
275
|
+
|
|
276
|
+
The prompt is the same for every release; the release-specific part is data — which migrations are outstanding, and
|
|
277
|
+
which project files the templates moved under. For each project file it says how to resolve it:
|
|
278
|
+
|
|
279
|
+
| File state | Meaning | Command |
|
|
280
|
+
|---|---|---|
|
|
281
|
+
| `replace` | the template changed and nobody edited the file | `pnpm asrun init --force <file>` |
|
|
282
|
+
| `merge` | the template and the project both changed it | merge the template's part, then `pnpm asrun init --ack <file>` |
|
|
283
|
+
| `unknown-base` | the workspace has no recorded template for the file | compare and report, then `pnpm asrun init --ack <file>` |
|
|
284
|
+
| `missing` | the template has the file and the workspace does not | `pnpm asrun init` |
|
|
285
|
+
|
|
286
|
+
`init --ack <file>` only records that the file is aligned with the installed templates; it never edits the file. The
|
|
287
|
+
baseline lives in `.asrun.json` (`scaffold`) and is committed, so the whole team sees the same state after a `git pull`.
|
|
288
|
+
|
|
254
289
|
Every `asrun` command also checks the registry for a newer release, at most once a day (the answer is cached in `.tmp/`
|
|
255
290
|
and shared with the web UI), and prints one line on stderr before it starts:
|
|
256
291
|
`@asrunjs/asrun 0.8.0 is available (installed 0.7.0). Upgrade: pnpm asrun upgrade`. On a terminal the line carries an
|
|
@@ -275,11 +310,14 @@ can simply be repeated. A migration marked `auto` runs by itself; one with `manu
|
|
|
275
310
|
until a person does it and acknowledges it. `init --update` never advances the baseline, which is why a manual
|
|
276
311
|
`pnpm add -D @asrunjs/asrun@latest` followed by `pnpm asrun init --update` still leaves its migrations pending.
|
|
277
312
|
|
|
313
|
+
A migration that names project files (`files: ['AGENTS.md']`) also advances those files' template baseline when it is
|
|
314
|
+
acknowledged, so one command clears both the manual step and the `NEXT` block reminder about the file.
|
|
315
|
+
|
|
278
316
|
```bash
|
|
279
317
|
pnpm asrun migrate # apply what the installed release brings
|
|
280
318
|
pnpm asrun migrate --dry-run # show it, change nothing
|
|
281
319
|
pnpm asrun migrate --list # every migration of the installed release, and its state
|
|
282
|
-
pnpm asrun migrate --ack <id> # a manual step is done (--ack-all for every one)
|
|
320
|
+
pnpm asrun migrate --ack <id> # a manual step is done (--ack-all for every one); no file is touched
|
|
283
321
|
pnpm asrun migrate --to <v> # stop at that release
|
|
284
322
|
```
|
|
285
323
|
|
|
@@ -289,18 +327,19 @@ migration is the installed package. `doctor` warns while migrations or manual st
|
|
|
289
327
|
## Workspace
|
|
290
328
|
|
|
291
329
|
```bash
|
|
292
|
-
pnpm asrun init [--update] [--force] [--force <file>] [--reset-rules] [--root <dir>] [--no-env] [--no-extras] [--install [spec]]
|
|
330
|
+
pnpm asrun init [--update] [--force] [--force <file>] [--reset-rules] [--ack <file>] [--root <dir>] [--no-env] [--no-extras] [--install [spec]]
|
|
293
331
|
pnpm asrun doctor
|
|
294
|
-
pnpm asrun upgrade [--version <v>] [--dry-run] [--yes]
|
|
295
|
-
pnpm asrun migrate [--list] [--dry-run] [--yes] [--ack <id>|--ack-all]
|
|
332
|
+
pnpm asrun upgrade [--version <v>] [--dry-run] [--yes|-y] [--prompt [--json]]
|
|
333
|
+
pnpm asrun migrate [--list] [--dry-run] [--yes|-y] [--ack <id>|--ack-all] [--prompt [--json]]
|
|
296
334
|
pnpm asrun reset [--root <dir>] [--dry-run] [--yes] [--state] [--lockfile]
|
|
297
335
|
```
|
|
298
336
|
|
|
299
337
|
`init` writes the workspace files; `--update` refreshes only the generated ones, and `--force` rewrites every file
|
|
300
338
|
init writes (a single file with `--force <file>`). `--force` still keeps `profiles.yaml` and `package.json`; name
|
|
301
|
-
`--force profiles.yaml` to replace profiles, and add `--reset-rules` to replace `AGENTS.md` or `CLAUDE.md`.
|
|
302
|
-
|
|
303
|
-
|
|
339
|
+
`--force profiles.yaml` to replace profiles, and add `--reset-rules` to replace `AGENTS.md` or `CLAUDE.md`. `--ack
|
|
340
|
+
<file>` records that a project-owned file is aligned with the installed templates without editing it (after a merge).
|
|
341
|
+
It also adds the `allowBuilds` entries `pnpm-workspace.yaml` lacks, and installs the optional packages this machine
|
|
342
|
+
lacks (`ffmpeg-static`; `--no-extras` skips them).
|
|
304
343
|
`doctor` checks profiles, `tsconfig.json`, `playwright.config.ts`, the generated files, the installed version, the
|
|
305
344
|
project rule table, the skill overrides, the workspace migrations and the PDF renderer (a missing or unloadable
|
|
306
345
|
`pdfjs-dist` fails every PDF check). `upgrade` and `migrate` are described above.
|
package/docs/install.md
CHANGED
|
@@ -123,10 +123,22 @@ pnpm asrun upgrade
|
|
|
123
123
|
One command installs the newest release, refreshes the generated files to its templates, applies the workspace
|
|
124
124
|
migrations and runs `doctor`. Before it installs anything it reads the migration manifest of the target release and
|
|
125
125
|
prints the breaking changes and migrations between the workspace's baseline and that release; a breaking change needs
|
|
126
|
-
a person's confirmation (
|
|
127
|
-
changes nothing; `--version <v>` pins a release; it never downgrades.
|
|
126
|
+
a person's confirmation (`Proceed? [y/N]`, an empty line cancels), and an unattended run passes `--yes` (or `-y`).
|
|
127
|
+
`--dry-run` shows the same plan and changes nothing; `--version <v>` pins a release; it never downgrades.
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
The upgrade ends with a `NEXT` block when the release changed something the project owns (`AGENTS.md`, `.mcp.json`,
|
|
130
|
+
`cases/_template.md`, ...) or recorded manual migration steps. Each line carries the exact command; an AI can do the
|
|
131
|
+
whole block:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
pnpm asrun upgrade --prompt
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
That prints the task as Markdown and changes nothing. Paste it into any agent, or — in Claude Code or OpenCode — run
|
|
138
|
+
`/upgrade-workspace`, which does the same. The prompt is the same for every release: the release-specific part (which
|
|
139
|
+
files moved, which steps are open) is read from the workspace and the installed package.
|
|
140
|
+
|
|
141
|
+
`upgrade` arrives with this release, so a workspace that predates `upgrade` updates once by hand:
|
|
130
142
|
|
|
131
143
|
```bash
|
|
132
144
|
pnpm add -D @asrunjs/asrun@latest
|
|
@@ -142,7 +154,8 @@ you when the workspace is behind the installed version, and what is still to mig
|
|
|
142
154
|
|
|
143
155
|
An upgrade never replaces what belongs to the project: `cases/`, `tests/` with their baselines, `profiles.yaml`,
|
|
144
156
|
`AGENTS.md`, `CLAUDE.md`, the skill overrides and `.claude/settings.json` stay as they are. A release that needs a
|
|
145
|
-
project-owned file to change says so as a migration with manual steps
|
|
157
|
+
project-owned file to change says so as a migration with manual steps, and the `NEXT` block (or
|
|
158
|
+
`pnpm asrun upgrade --prompt`) tells a person or an agent what to merge.
|
|
146
159
|
|
|
147
160
|
To go back to an older release, install it yourself and refresh:
|
|
148
161
|
|
package/docs/web-ui.md
CHANGED
|
@@ -31,6 +31,11 @@ runs the AI tool you selected (Claude Code or OpenCode) with the same commands a
|
|
|
31
31
|
or not this page is open, focused or allowed to notify (macOS, Linux and Windows; `pnpm asrun notify-test` shows one
|
|
32
32
|
and prints the command behind it). The tab title shows the section and, in front, how many things wait for you:
|
|
33
33
|
`(1) AsRun | Cases`, and the job page says what to do.
|
|
34
|
+
- **Release badge:** when the registry has a newer release, a small amber version badge sits next to the title. Clicking
|
|
35
|
+
it opens the two steps: the upgrade command (with a **Copy**), then the work the upgrade leaves behind — run
|
|
36
|
+
`/upgrade-workspace` in Claude Code or OpenCode, or copy the prompt `pnpm asrun upgrade --prompt` prints. When this
|
|
37
|
+
workspace is already behind the release it runs (a file the project owns, a manual migration step), the dialog shows
|
|
38
|
+
that prompt itself, so the agent can be started from here.
|
|
34
39
|
|
|
35
40
|
The UI's look is the **Inkstone** theme; the palette, buttons, badges and icons are documented in
|
|
36
41
|
`theme-guide.html` in the framework package (also linked from the top bar).
|
|
@@ -93,7 +98,9 @@ right (drag the divider to resize, double-click to reset).
|
|
|
93
98
|
- **New case** takes an optional folder and runs `pnpm case:new`.
|
|
94
99
|
- **The Panel** shows the case as a form, with the open questions first: each one shows the sentence it is about,
|
|
95
100
|
then the question, and offers **Keep what the case says** (the question block disappears, that text stays) or
|
|
96
|
-
**Write your answer** (the AI folds it in). Only the two texts jump to the source; the rest of the row does not.
|
|
101
|
+
**Write your answer** (the AI folds it in). Only the two texts jump to the source; the rest of the row does not. A
|
|
102
|
+
`[T1]` in any text of the panel (the sentence, the question, its evidence, a recipe, a prose block) is a chip that
|
|
103
|
+
opens its card, so a reference never sends you looking for Targets.
|
|
97
104
|
Then the front matter (title, login, suites, writes and its note, environments), the `## Rules` bullets, the steps
|
|
98
105
|
(sentence, `[writes]` / `[input]` / `[email]` tags, `- Ready when:` lines,
|
|
99
106
|
`- Recipe:` lines), the `## Expected` and `## Visual checks` bullets (drag to reorder), the `## Values` table (one
|
|
@@ -102,15 +109,16 @@ right (drag the divider to resize, double-click to reset).
|
|
|
102
109
|
profiles the Values section offers a **Rows: Keys / Profiles** switch, and from four profiles on it also adds a
|
|
103
110
|
search and environment chips. With more profiles than keys it starts as one row per profile, so every name and
|
|
104
111
|
environment stays readable instead of being squeezed into a narrow column. Both the header and the profile/key
|
|
105
|
-
column stay in place while the table scrolls. `[T1]` chips open
|
|
112
|
+
column stay in place while the table scrolls. `[T1]` chips anywhere open
|
|
106
113
|
the card: what it is, where, how it is identified, what it must not be, and its reference screenshots. Every section
|
|
107
114
|
collapses and has a **?** with a short help card. Panel edits land in the same draft as the source editor, so one
|
|
108
115
|
save covers both, and **Discard** throws them away together.
|
|
109
116
|
- **The To confirm section** lists every line the AI marked: the sentence, where it is (`## Values · line 42`), **why it
|
|
110
117
|
needs you** (the reason the AI wrote after the marker's colon), **what it feeds** (an assertion or only a note) and,
|
|
111
118
|
when it saved one, the **screenshot** from the exploration, so you look at the image instead of opening the page
|
|
112
|
-
again.
|
|
113
|
-
list in one undo step. None of this blocks
|
|
119
|
+
again. A `[T1]` in the sentence or in the reason is a chip that opens its card. Rows that change an assertion are
|
|
120
|
+
highlighted; **Confirm** settles one line and **Confirm all** settles the list in one undo step. None of this blocks
|
|
121
|
+
generating a spec; healing stops until the case is settled.
|
|
114
122
|
- **Spec view** is editable too (`Ctrl/Cmd+S`; refused when the file changed on disk meanwhile), and its tab links back
|
|
115
123
|
to the case it was generated from. **Open in editor** opens it in the default application for `.spec.ts`, **Copy
|
|
116
124
|
path** copies its absolute path.
|
|
@@ -158,6 +166,10 @@ One entry per run, with a PRODUCTION or STAGING badge (runs from before environm
|
|
|
158
166
|
The bottom bar shows every command started from the UI with live stdout/stderr and the exit code; a job can be
|
|
159
167
|
cancelled there. Opening it shrinks the page instead of covering it.
|
|
160
168
|
|
|
169
|
+
- The job list shows when each job started and how long it ran (`2 m 13 s`); a running job counts up every second. The
|
|
170
|
+
job itself repeats this at the top, in bold, with the exact start and end times on hover. A job interrupted by a UI
|
|
171
|
+
server restart stops counting when that server stopped, not when its process did.
|
|
172
|
+
|
|
161
173
|
- Jobs are recorded under `.tmp/ui-jobs/<id>/` (`record.json`, `chunks.jsonl`, `output.log`), kept for 7 days and the
|
|
162
174
|
newest 50. A UI server restart does not forget them. A job that was running is shown as **Interrupted**: its output
|
|
163
175
|
stops at the last line the server received (the UI replays the last 4 MB of structured output; `output.log` keeps the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asrunjs/asrun",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Multi-profile end-to-end test suite: plain-language cases, AI-written Playwright specs, evidence for every run.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "Zoro Chen",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"docs/",
|
|
27
27
|
".claude/",
|
|
28
28
|
"!.claude/settings.local.json",
|
|
29
|
+
"!.claude/commands/check-migrations.md",
|
|
29
30
|
"ui/dist/",
|
|
30
31
|
"AGENTS.md",
|
|
31
32
|
"CLAUDE.md",
|
|
@@ -58,6 +59,8 @@
|
|
|
58
59
|
"case:new": "tsx scripts/new-case.ts",
|
|
59
60
|
"case:check": "tsx scripts/check-cases.ts",
|
|
60
61
|
"markers:confirm": "tsx scripts/markers-confirm.ts",
|
|
62
|
+
"migrations:check": "tsx scripts/migrations-check.ts",
|
|
63
|
+
"migrations:freeze": "tsx scripts/migrations-freeze.ts",
|
|
61
64
|
"spec:lint": "tsx scripts/lint-specs.ts",
|
|
62
65
|
"baselines:review": "tsx scripts/review-baselines.ts",
|
|
63
66
|
"pdf:render": "tsx scripts/render-pdf.ts",
|
|
@@ -10,7 +10,7 @@ Rules combine in this order, and a later one wins where they conflict: the frame
|
|
|
10
10
|
applied as written and is never turned into a question (a difference from a framework default is not a conflict).
|
|
11
11
|
Project facts are in `AGENTS.md` §3.
|
|
12
12
|
|
|
13
|
-
Arguments: `<case-id> <env> [--attended] [--profiles a,b] [--hints <file>]`. The case id is the path below `cases/` without `.md` (it may include a
|
|
13
|
+
Arguments: `<case-id> <env> [--attended] [--profiles a,b] [--lead <profile-id>] [--hints <file>]`. The case id is the path below `cases/` without `.md` (it may include a
|
|
14
14
|
group folder, e.g. `documents/landing-page`) and is required. `<env>` is `staging` or `production`; it is required and there
|
|
15
15
|
is no default (without one, stop and say so). With `--attended` I am at the machine and the browser window is
|
|
16
16
|
visible: when a step writes data or needs a choice, hand it to me as the skill describes, wait for me, and record
|
|
@@ -19,6 +19,11 @@ what I did as a general recipe under the step it belongs to (`- Recipe:` lines).
|
|
|
19
19
|
logged-in profile per domain. Every id in that list is opened in its own session (`generator_setup_page` with
|
|
20
20
|
`project=<id>`); two different hosts are two domains, even for the same product. A profile the list leaves out is not
|
|
21
21
|
opened and nothing is written about it: runs add up, so a later run covers the rest.
|
|
22
|
+
`--lead <profile-id>` explores that selection asymmetrically: the lead profile in full (every step, every handoff, the
|
|
23
|
+
recipe lines, a note with every step) and every other selected profile only where it can differ (its own `## Values`
|
|
24
|
+
entries, its target screenshots and the steps that reach them), as the skill's "Profile passes" says. A profile whose
|
|
25
|
+
page or flow differs from the lead's is explored in full instead, and the report says so. Lead and diff profiles belong
|
|
26
|
+
in one run: the notes are written at its end, and splitting them makes the earlier ones stale.
|
|
22
27
|
`--hints <file>` (or free text after the arguments) is what I know or want checked; read it first. After the work, a
|
|
23
28
|
reusable instruction goes into `## Rules` by the gate in
|
|
24
29
|
`{{framework}}/.claude/skills/exploring-cases/references/case-rules.md`; a one-off clue stays in the report.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Align this workspace with the asrun release it now runs (the files an upgrade leaves to a person or an AI)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
This workspace was just upgraded. The framework knows which project-owned files the new release changed and which
|
|
6
|
+
manual migration steps are still open; it prints that as a task for you.
|
|
7
|
+
|
|
8
|
+
1. Run `pnpm asrun upgrade --prompt` and read the whole output. It is the specification of this command.
|
|
9
|
+
If it cannot run (an older install, or "upgrade" refuses in the framework's own checkout), run
|
|
10
|
+
`pnpm asrun migrate --prompt` instead.
|
|
11
|
+
2. Follow it exactly. Read `pnpm asrun rules` and the framework baseline it names before you change a file, and copy
|
|
12
|
+
the commands it gives verbatim: `pnpm asrun init --force <file>` only for a file it says nobody edited,
|
|
13
|
+
`pnpm asrun init --ack <file>` after a merge, `pnpm asrun migrate --ack <id>` never (the person does that).
|
|
14
|
+
3. When it says nothing needs updating, say so and stop: run the checks it lists, report them, and change no files.
|
|
15
|
+
4. End with its report format, and put `RESULT: ready` or `RESULT: needs-input` on the last line as plain text —
|
|
16
|
+
never in a code fence or in emphasis.
|
|
17
|
+
|
|
18
|
+
Rules combine in this order, and a later one wins where they conflict: the framework baseline
|
|
19
|
+
`{{framework}}/AGENTS.md`, the framework skill, `.claude/skills/<skill>.md` if it exists, then the workspace
|
|
20
|
+
`AGENTS.md` §2 (Project rules). An upgrade never changes what a project rule says: §2 is applied as written, and a
|
|
21
|
+
difference from a framework default is not a conflict.
|
package/templates/AGENTS.md
CHANGED
|
@@ -69,7 +69,7 @@ and the front-matter keys. See "Fixed tokens" in the framework baseline.
|
|
|
69
69
|
- `profiles.yaml` one entry per environment, connection settings only (committed)
|
|
70
70
|
- `package.json` npm scripts and the framework dependency; its `"asrun"` object holds project settings
|
|
71
71
|
(`testDataPrefix`, committed)
|
|
72
|
-
- `.claude/commands/` `/make-case`, `/explore-case`, `/gen-spec`, `/heal-spec` for Claude Code
|
|
72
|
+
- `.claude/commands/` `/make-case`, `/explore-case`, `/gen-spec`, `/heal-spec`, `/upgrade-workspace` for Claude Code
|
|
73
73
|
- `.opencode/commands/` the same commands for OpenCode (it does not read `.claude/commands`)
|
|
74
74
|
- `.claude/skills/` optional overrides of a framework skill: `<skill>.md`
|
|
75
75
|
- `.auth/` saved logins: never read, never commit
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{C as e,D as t,F as n,L as r,X as i,i as a,n as o,q as s,r as c,s as l,u,v as d,wt as f,z as p}from"./dist-Dr9crbBz.js";import{t as m}from"./index-Djsj43vv.js";var h=1,g=2,_=3,v=155,y=4,b=156;function x(e){return e>=65&&e<=90||e>=97&&e<=122}var S=new o(e=>{let t=e.pos;for(;;){let{next:n}=e;if(n<0)break;if(n==123){let n=e.peek(1);if(n==123){if(e.pos>t)break;e.acceptToken(h,2);return}if(n==35){if(e.pos>t)break;e.acceptToken(g,2);return}if(n==37){if(e.pos>t)break;let n=2,r=2;for(;;){let t=e.peek(n);if(t==32||t==10)++n;else if(t==35)for(++n;;){let t=e.peek(n);if(t<0||t==10)break;n++}else if(t==45&&r==2)r=++n;else{e.acceptToken(_,r);return}}}}if(e.advance(),n==10)break}e.pos>t&&e.acceptToken(v)});function C(e,t,n){return new o(r=>{let i=r.pos;for(;;){let{next:t}=r;if(t==123&&r.peek(1)==37){let t=2;for(;;t++){let e=r.peek(t);if(e!=32&&e!=10)break}let a=``;for(;;t++){let e=r.peek(t);if(!x(e))break;a+=String.fromCharCode(e)}if(a==e){if(r.pos>i)break;r.acceptToken(n,2);break}}else if(t<0)break;if(r.advance(),t==10)break}r.pos>i&&r.acceptToken(t)})}var w=C(`endraw`,b,y),T={__proto__:null,in:38,is:40,and:46,or:48,not:52,if:78,else:80,true:98,false:98,self:100,super:102,loop:104,recursive:136,scoped:160,required:162,as:256,import:260,ignore:268,missing:270,with:272,without:274,context:276},E={__proto__:null,if:112,elif:118,else:122,endif:126,for:132,endfor:140,raw:146,endraw:152,block:158,endblock:166,macro:172,endmacro:182,call:188,endcall:192,filter:198,endfilter:202,set:208,endset:212,trans:218,pluralize:222,endtrans:226,with:232,endwith:236,autoescape:242,endautoescape:246,import:254,from:258,include:266},D=c.deserialize({version:14,states:"!*dQVOPOOOOOP'#F`'#F`OeOTO'#CbOvQSO'#CdO!kOPO'#DcO!yOPO'#DnO#XOQO'#DuO#^OPO'#D{O#lOPO'#ESO#zOPO'#E[O$YOPO'#EaO$hOPO'#EfO$vOPO'#EkO%UOPO'#ErO%dOPO'#EwOOOP'#F|'#F|O%rQWO'#E|O&sO#tO'#F]OOOP'#Fq'#FqOOOP'#F_'#F_QVOPOOOOOP-E9^-E9^OOQO'#Ce'#CeO'sQSO,59OO'zQSO'#DWO(RQSO'#DXO(YQ`O'#DZOOQO'#Fr'#FrOvQSO'#CuO(aOPO'#CbOOOP'#Fd'#FdO!kOPO,59}OOOP,59},59}O(oOPO,59}O(}QWO'#E|OOOP,5:Y,5:YO)[OPO,5:YO!yOPO,5:YO)jQWO'#E|OOOQ'#Ff'#FfO)tOQO'#DxO)|OQO,5:aOOOP,5:g,5:gO#^OPO,5:gO*RQWO'#E|OOOP,5:n,5:nO#lOPO,5:nO*YQWO'#E|OOOP,5:v,5:vO#zOPO,5:vO*aQWO'#E|OOOP,5:{,5:{O$YOPO,5:{O*hQWO'#E|OOOP,5;Q,5;QO$hOPO,5;QO*oQWO'#E|OOOP,5;V,5;VO*vOPO,5;VO$vOPO,5;VO+UQWO'#E|OOOP,5;^,5;^O%UOPO,5;^O+`QWO'#E|OOOP,5;c,5;cO%dOPO,5;cO+gQWO'#E|O+nQSO,5;hOvQSO,5:OO+uQSO,5:ZO+zQSO,5:bO+uQSO,5:hO+uQSO,5:oO,PQSO,5:wO,XQpO,5:|O+uQSO,5;RO,^QSO,5;WO,fQSO,5;_OvQSO,5;dOvQSO,5;jOvQSO,5;jOvQSO,5;pOOOO'#Fk'#FkO,nO#tO,5;wOOOP-E9]-E9]O,vQ!bO,59QOvQSO,59TOvQSO,59UOvQSO,59UOvQSO,59UOvQSO,59UO,{QSO'#C}O,XQpO,59cOOQO,59q,59qOOOP1G.j1G.jOvQSO,59UO-SQSO,59UOvQSO,59UOvQSO,59UOvQSO,59nO-wQSO'#FxO.RQSO,59rO.WQSO,59tOOQO,59s,59sO.bQSO'#D[O.iQWO'#F{O.qQWO,59uO0WQSO,59aOOOP-E9b-E9bOOOP1G/i1G/iO(oOPO1G/iO(oOPO1G/iO)TQWO'#E|OvQSO,5:SO0nQSO,5:UO0sQSO,5:WOOOP1G/t1G/tO)[OPO1G/tO)mQWO'#E|O)[OPO1G/tO0xQSO,5:_OOOQ-E9d-E9dOOOP1G/{1G/{O0}QWO'#DyOOOP1G0R1G0RO1SQSO,5:lOOOP1G0Y1G0YO1[QSO,5:tOOOP1G0b1G0bO1aQSO,5:yOOOP1G0g1G0gO1fQSO,5;OOOOP1G0l1G0lO1kQSO,5;TOOOP1G0q1G0qO*vOPO1G0qO+XQWO'#E|O*vOPO1G0qOvQSO,5;YO1pQSO,5;[OOOP1G0x1G0xO1uQSO,5;aOOOP1G0}1G0}O1zQSO,5;fO2PQSO1G1SOOOP1G1S1G1SO2WQSO1G/jOOQO'#Dq'#DqO2_QSO1G/uOOOQ1G/|1G/|O2gQSO1G0SO2rQSO1G0ZO2zQSO'#EVO3SQSO1G0cO,SQSO1G0cO4fQSO'#FvOOQO'#Fv'#FvO5]QSO1G0hO5bQSO1G0mOOOP1G0r1G0rO5mQSO1G0rO5rQSO'#GOO5zQSO1G0yO6PQSO1G1OO6WQSO1G1UO6_QSO1G1UO6fQSO1G1[OOOO-E9i-E9iOOOP1G1c1G1cOOQO1G.l1G.lO6vQSO1G.oO8wQSO1G.pO:oQSO1G.pO:vQSO1G.pO<nQSO1G.pO<uQSO'#FwO>QQSO'#FrO>XQSO'#FwO>aQSO,59iOOQO1G.}1G.}O>fQSO1G.pO@aQSO1G.pOB_QSO1G.pOBfQSO1G.pOD^QSO1G/YOvQSO'#FbODeQSO,5<dOOQO1G/^1G/^ODmQSO1G/_OOQO1G/`1G/`ODuQSO,59vOvQSO'#FcOEjQWO,5<gOOQO1G/a1G/aPErQWO'#E|OOOP7+%T7+%TO(oOPO7+%TOEyQSO1G/nOOOP1G/p1G/pOOOP1G/r1G/rOOOP7+%`7+%`O)[OPO7+%`OOOP1G/y1G/yOFQQSO,5:eOOOP1G0W1G0WOFVQSO1G0WOOOP1G0`1G0`OOOP1G0e1G0eOOOP1G0j1G0jOOOP1G0o1G0oOOOP7+&]7+&]O*vOPO7+&]OF[QSO1G0tOOOP1G0v1G0vOOOP1G0{1G0{OOOP1G1Q1G1QOOOP7+&n7+&nOOOP7+%U7+%UO+uQSO'#FeOFcQSO7+%aOvQSO7+%aOOOP7+%n7+%nOFkQSO7+%nOFpQSO7+%nOOOP7+%u7+%uOFxQSO7+%uOF}QSO'#F}OGQQSO'#F}OGYQSO,5:qOOOP7+%}7+%}OG_QSO7+%}OGdQSO7+%}OOQO,59f,59fOOOP7+&S7+&SOGlQSO7+&oOOOP7+&X7+&XOvQSO7+&oOvQSO7+&^OGtQSO,5<jOvQSO,5<jOOOP7+&e7+&eOOOP7+&j7+&jO+uQSO7+&pOG|QSO7+&pOOOP7+&v7+&vOHRQSO7+&vOHWQSO7+&vOOQO7+$Z7+$ZOvQSO'#FaOH]QSO,5<cOvQSO,59jOOQO1G/T1G/TOOQO7+$[7+$[OvQSO7+$tOHeQSO,5;|OOQO-E9`-E9`OOQO7+$y7+$yOImQ`O1G/bOIwQSO'#D^OOQO,5;},5;}OOQO-E9a-E9aOOOP<<Ho<<HoOOOP7+%Y7+%YOOOP<<Hz<<HzOOOP1G0P1G0POOOP7+%r7+%rOOOP<<Iw<<IwOOOP7+&`7+&`OOQO,5<P,5<POOQO-E9c-E9cOvQSO<<H{OJOQSO<<H{OOOP<<IY<<IYOJYQSO<<IYOOOP<<Ia<<IaOvQSO,5:rO+uQSO'#FgOJ_QSO,5<iOOQO1G0]1G0]OOOP<<Ii<<IiOJgQSO<<IiOvQSO<<JZOJlQSO<<JZOJsQSO<<IxOvQSO1G2UOJ}QSO1G2UOKXQSO<<J[OK^QSO'#CeOOQO'#FT'#FTOKiQSO'#FTOKnQSO<<J[OKvQSO<<JbOK{QSO<<JbOLWQSO,5;{OLbQSO'#FrOOQO,5;{,5;{OOQO-E9_-E9_OLiQSO1G/UOM}QSO<<H`O! ]Q`O,59aODuQSO,59xO! sQSOAN>gOOOPAN>gAN>gO! }QSOAN>gOOOPAN>tAN>tO!!SQSO1G0^O!!^QSO,5<ROOQO,5<R,5<ROOQO-E9e-E9eOOOPAN?TAN?TO!!iQSOAN?uOOOPAN?uAN?uO+uQSO'#FhO!!pQSOAN?dOOOPAN?dAN?dO!!xQSO7+'pO+uQSO'#FiO!#SQSO7+'pOOOPAN?vAN?vO+uQSO,5;oOG|QSO'#FjO!#[QSOAN?vOOOPAN?|AN?|O!#dQSOAN?|OvQSO,59mO!$sQ`O1G.pO!%{Q`O1G.pO!&SQ`O1G.pO!'[Q`O1G.pO!'cQ`O'#FvO!'jQ`O1G.pO!(uQ`O1G.pO!*TQ`O1G.pO!*[Q`O1G.pO!+dQ`O1G/YO!+kQ`O1G/dOOOPG24RG24RO!+uQSOG24ROvQSO,5:sOOOPG25aG25aO!+zQSO,5<SOOQO-E9f-E9fOOOPG25OG25OO!,PQSO<<K[O!,XQSO,5<TOOQO-E9g-E9gOOQO1G1Z1G1ZOOQO,5<U,5<UOOQO-E9h-E9hOOOPG25bG25bO!,aQSOG25hO!,fQSO1G/XOOOPLD)mLD)mO!,pQSO1G0_OvQSO1G1nO!,zQSO1G1oOvQSO1G1oOOOPLD+SLD+SO!-wQ`O<<H`O!.[QSO7+'YOvQSO7+'ZO!.fQSO7+'ZO!.pQSO<<JuODuQSO'#CuODuQSO,59UODuQSO,59UODuQSO,59UODuQSO,59UO!.zQpO,59cODuQSO,59UO!/PQSO,59UODuQSO,59UODuQSO,59UODuQSO,59nO!/tQSO1G.pP!0RQSO1G/YODuQSO7+$tO!0YQ`O1G.pP!0gQ`O1G/YO-SQSO,59UPvQSO,59nO!0nQSO,59aP!3XQSO1G.pP!3`QSO1G.pP!5aQSO1G/YP!5hQSO<<H`O!/PQSO,59UPDuQSO,59nP!6_QSO1G/YP!7pQ`O1G/YO-SQSO'#CuO-SQSO,59UO-SQSO,59UO-SQSO,59UO-SQSO,59UO-SQSO,59UP-SQSO,59UP-SQSO,59UP-SQSO,59nO!7wQSO1G.pO!9xQSO1G.pO!:PQSO1G.pO!;UQSO1G.pP-SQSO7+$tO!<XQ`O,59aP!>SQ`O1G.pP!>ZQ`O1G.pP!>bQ`O1G/YP!?QQ`O<<H`O!/PQSO'#CuO!/PQSO,59UO!/PQSO,59UO!/PQSO,59UO!/PQSO,59UO!/PQSO,59UP!/PQSO,59UP!/PQSO,59UP!/PQSO,59nP!/PQSO7+$tP-SQSO,59nP!/PQSO,59nO!?zQ`O1G.pO!@RQ`O1G.pO!@fQ`O1G.pO!@yQ`O1G.p",stateData:"!Ac~O$dOS~OPROQaOR`O$aPO~O$aPOPUXQUXRUX$`UX~OekOfkOjlOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~OPROQaORrO$aPO~OPROQaORvO$aPO~O$bwO~OPROQaOR|O$aPO~OPROQaOR!PO$aPO~OPROQaOR!SO$aPO~OPROQaOR!VO$aPO~OPROQaOR!YO$aPO~OPROQaOR!^O$aPO~OPROQaOR!aO$aPO~OPROQaOR!dO$aPO~O!X!eO!Y!fO!d!gO!k!hO!q!iO!x!jO#Q!kO#V!lO#[!mO#a!nO#h!oO#m!pO#s!qO#u!rO#y!sO~O$s!tO~OZ!wO_!yO`!zOa!{Ob!|Oc#ROd#SOg#TOh#UOl#OOp!}Ow#VO$i!xO~OV#QO~P&xO$h$lP~PvOo#ZO~PvO$m$oP~PvO$aPOPUXQUXRUX~OPROQaOR#dO$aPO~O!]#eO!_#fO!a#gO~P%rOPROQaOR#jO$aPO~O!_#fO!h#lO~P%rO$bwOS!lX~OS#oO~O!u#qO~P%rO!}#sO~P%rO#S#uO~P%rO#X#wO~P%rO#^#yO~P%rOPROQaOR#|O$aPO~O#c$OO#e$PO~P%rO#j$RO~P%rO#o$TO~P%rO!Z$VO~PvO$g$XO~O!Z$ZO~Op$^O$gfO~Om$aO~O!Z$eO$g$XO~O$g$XO!Z$rP~O$Q$nO$s!tO~O[$oO~Oo$kP~PvOekOfkOj)fOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~Ot%PO$h$lX~P&xO$h%RO~Oo%TOt%PO~P&xO!P%UO~P&xOt%VO$m$oX~O$m%XO~OZ!wOp!}O$i!xOViagiahialiawiatia$hiaoia!Pia!Zia#tia#via#zia#|ia#}iaxia!fia~O_!yO`!zOa!{Ob!|Oc#ROd#SO~P.vO!Z%^O~O!Z%_O~O!Z%bO~O!n%cO~O!Z%dO$g$XO~O!Z%fO~O!Z%gO~O!Z%hO~O!Z%iO~O!Z%mO~O!Z%nO~O!Z%oO~O!Z%pO~P&xO!Z%qO~P&xOc%tOt%rO~O!Z%uO!r%wO!s%vO~Op$^O!Z%xO~O$g$XOo$qP~Op!}O!Z%}O~Op!}OZ$jX_$jX`$jXa$jXb$jXc$jXd$jXg$jXh$jXl$jXw$jX$i$jXt$jXe$jXf$jX$g$jXx$jX~O!Z$jXV$jX$h$jXo$jX!P$jX#t$jX#v$jX#z$jX#|$jX#}$jX!f$jX~P3[O!Z&RO~Os&UOt%rO!Z&TO~Os&VO~Os&XOt%rO~O!Z&YO~O!Z&ZO~P&xO#t&[O~P&xO#v&]O~P&xO!Z&^O#z&`O#|&_O#}&_O~P&xO$h&aO~P&xOZ!wOp!}O$i!xOV^i`^ia^ib^ic^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ie^if^i$g^ix^i!f^i~O_^i~P6}OZ!wO_!yOp!}O$i!xOV^ia^ib^ic^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~O`^i~P9OO`!zO~P9OOZ!wO_!yO`!zOa!{Op!}O$i!xOV^ic^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Ob^i~P:}Ot&bOo$kX~P&xOZ$fX_$fX`$fXa$fXb$fXc$fXd$fXg$fXh$fXl$fXo$fXp$fXt$fXw$fX$i$fX~Os&dO~P=POt&bOo$kX~Oo&eO~Ob!|O~P:}OZ!wO_)gO`)hOa)iOb)jOc)kOp!}O$i!xOV^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Oe&fOf&fO$gfO~P>mOZ!wO_!yO`!zOa!{Ob!|Oc#ROd#SOp!}O$i!xOV^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Og^i~P@nOg#TO~P@nOZ!wO_!yO`!zOa!{Ob!|Oc#ROd#SOg#TOh#UOp!}O$i!xOVvilviwvitvi$hviovi!Pvi!Zvi#tvi#vvi#zvi#|vi#}vi!fvi~Ox&gO~PBmOt%PO$h$la~Oo&jOt%PO~OekOfkOj(yOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~Ot%VO$m$oa~O!]#eO~P%rO!Z&pO~P&xO!Z&rO~O!Z&sO~O!Z&uO~P&xOc&xOt%rO~O!Z&zO~O!Z&zO!s&{O~O!Z&|O~Os&}Ot'OOo$qX~Oo'QO~O!Z'RO~Op!}O!Z'RO~Os'TOt%rO~Os'WOt%rO~O$g'ZO~O$O'_O~O#{'`O~Ot&bOo$ka~Ot$Ua$h$Uao$Ua~P&xOZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOg)ROh)SOl)OOp!}Ow)TO$i!xO~Ot!Oi$m!Oi~PHrO!P'hO~P&xO!Z'jO!f'kO~P&xO!Z'lO~Ot'OOo$qa~O!Z'qO~O!Z'sO~P&xOt'tO!Z'vO~P&xOt'xO!Z$ri~P&xO!Z'zO~Ot!eX!Z!eX#tXX~O#t'{O~Ot'|O!Z'zO~O!Z(OO~O!Z(OO#|(PO#}(PO~Oo$Tat$Ta~P&xOs(QO~P=POoritri~P&xOZ!wOp!}O$i!xOVvylvywvytvy$hvyovy!Pvy!Zvy#tvy#vvy#zvy#|vy#}vyxvy!fvy~O_!yO`!zOa!{Ob!|Oc#ROd#SOg#TOh#UO~PLsOZ!wOp!}O$i!xOgiahialiatiawia$miaxia~O_(zO`({Oa(|Ob(}Oc)POd)QO~PNkO!Z(^O!f(_O~P&xO!Z(^O~Oo!zit!zi~P&xOs(`Oo$Zat$Za~O!Z(aO~P&xOt'tO!Z(dO~Ot'xO!Z$rq~P&xOt'xO!Z$rq~Ot'|O!Z(kO~O$O(lO~OZ!wOp!}O$i!xO`^ia^ib^ic^id^ig^ih^il^it^iw^i$m^ie^if^i$g^ix^i~O_^i~P!#iOZ!wO_(zOp!}O$i!xOa^ib^ic^id^ig^ih^il^it^iw^i$m^ix^i~O`^i~P!$zO`({O~P!$zOZ!wO_(zO`({Oa(|Op!}O$i!xOc^id^ig^ih^il^it^iw^i$m^ix^i~Ob^i~P!&ZO$m$jX~P3[Ob(}O~P!&ZOZ!wO_)zO`){Oa)|Ob)}Oc*OOp!}O$i!xOd^ig^ih^il^it^iw^i$m^ix^i~Oe&fOf&fO$gfO~P!'qOZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOp!}O$i!xOh^il^it^iw^i$m^ix^i~Og^i~P!)SOg)RO~P!)SOZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOg)ROh)SOp!}O$i!xOlvitviwvi$mvi~Ox)WO~P!*cOt!Qi$m!Qi~PHrO!Z(nO~Os(pO~Ot'xO!Z$ry~Os(rOt%rO~O!Z(sO~Oouitui~P&xOo!{it!{i~P&xOs(vOt%rO~OZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOg)ROh)SOp!}O$i!xO~Olvytvywvy$mvyxvy~P!-SOt$[q!Z$[q~P&xOt$]q!Z$]q~P&xOt$]y!Z$]y~P&xOm(VO~OekOfkOj)yOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~Oe^if^i$g^i~P>mOxvi~PBmOe^if^i$g^i~P!'qOxvi~P!*cO_)gO`)hOa)iOb)jOc)kOd)ZOeiafia$gia~P.vOZ!wO_)gO`)hOa)iOb)jOc)kOd)ZOp!}O$i!xOV^ie^if^ih^il^iw^i$g^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Og^i~P!1_Og)lO~P!1_OZ!wO_)gO`)hOa)iOb)jOc)kOd)ZOg)lOh)mOp!}O$i!xOVvievifvilviwvi$gvitvi$hviovi!Pvi!Zvi#tvi#vvi#zvi#|vi#}vi!fvi~Ox)sO~P!3gO_)gO`)hOa)iOb)jOc)kOd)ZOg)lOh)mOevyfvy$gvy~PLsOxvi~P!3gOZ!wO_)zO`){Oa)|Ob)}Oc*OOd)bOg*POh*QOp!}O$i!xOevifvilvitviwvi$gvi$mvi~Oxvi~P!6fO_)gO~P6}OZ!wO_)gO`)hOp!}O$i!xOV^ib^ic^id^ie^if^ig^ih^il^iw^i$g^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Oa^i~P!8OOa)iO~P!8OOZ!wOp!}O$i!xOc^id^ie^if^ig^ih^il^iw^i$g^it^ix^i~O_)gO`)hOa)iOb)jOV^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^i!f^i~P!:WO_)zO`){Oa)|Ob)}Oc*OOd)bOeiafia$gia~PNkOZ!wO_)zO`){Oa)|Ob)}Oc*OOd)bOp!}O$i!xOe^if^ih^il^it^iw^i$g^i$m^ix^i~Og^i~P!<xOg*PO~P!<xOx*SO~P!6fOZ!wO_)zO`){Oa)|Ob)}Op!}O$i!xO~Oc*OOd)bOg*POh*QOevyfvylvytvywvy$gvy$mvyxvy~P!>iO_)zO~P!#iO_)zO`){Oa^ib^i$m^i~P!:WO_)zO`){Oa)|Ob^i$m^i~P!:WO_)zO`){Oa)|Ob)}O$m^i~P!:WOfaZa~",goto:"Cy$sPPPPPP$tP$t%j'sPP's'sPPPPPPPPPP'sP'sPP)jPP)o+nPP+q'sPP's's's's's+tP+wPPPP+z,pPPP-fP-jP-vP+z.UP.zP/zP+z0YP1O1RP+z1UPPP1zP+z2QP2v2|3P3SP+z3YP4OP+z4UP4zP+z5QP5vP+z5|P6rP6xP+z7WP7|P+z8SP8xP$t$t$tPPPP9O$tPPPPPP$tP9U:j;f;m;w;}<T<g<m<t<z=U=[PPPPP=b>YPPPCcCjCmPPCp$tCsCv!gbOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%k$dkRhijl!e!f!p!q!r!s!x!y!z!{!|#R#S#T#U#V#e$O%P%U%V%t&U&V&X&d&g&x&}'T'W'h(Q(`(p(r(v(y(z({(|(})P)Q)R)S)T)W)Z)[)b)c)f)g)h)i)j)k)l)m)n)s)y)z){)|)}*O*P*Q*R*S*T*UQ$_!kQ$v!}Q&P$`S&f${(XS']&]'|R'b&b$ikRhijl!e!f!p!q!r!s!x!y!z!{!|!}#R#S#T#U#V#e$O%P%U%V%t&U&V&X&b&d&g&x&}'T'W'h(Q(`(p(r(v(y(z({(|(})P)Q)R)S)T)W)Z)[)b)c)f)g)h)i)j)k)l)m)n)s)y)z){)|)}*O*P*Q*R*S*T*UV$b!l#O)O$d#Pg#W#Y#[#_$U$W$i$j$k$l$p$q$r$s$t$u$z${$|$}%O%]%l&h&k&l&y'U'V'X'a'e'f'g'i'm'r'w(R(S(T(U(W(X(Y(Z([(](m(o(t(u(w(x)U)V)X)Y)])^)_)`)a)d)e)o)p)q)r)t)u)v)w)x*V*W*X*YQ&O$_S&Q$a(VR'S&PR$w!}R'c&bR#]jR&m%V!g_OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%k!gSOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kTnSoQqSQtTQ#boR#kuQpSS#aoqS%Z#b#cR&o%[!gTOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ$Y!gQ$[!iQ$]!jQ$d!mQ$f!nQ$g!oQ%e#qQ%z$^Q&v%rQ'Y&[S'[&]'|Q'n'OQ(b'tQ(f'xR(h'{QsTS#htuS%`#i#kR&q%a!gUOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kRyUR#ny!gVOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQzVR#p{!gWOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ$`!kR%y$]R%{$^R'o'OQ}WR#r!O!gXOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!QXR#t!R!gYOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!TYR#v!U!gZOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!WZR#x!X!g[OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ![[R#}!]Q!Z[S#z![!]S%j#{#}R&t%k!g]OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!_]R$Q!`!g^OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!b^R$S!cQ'^&]R(i'|QdOQuTQ{VQ!OWQ!RXQ!UYQ!XZQ!][Q!`]Q!c^p!vdu{!O!R!U!X!]!`!c#c#i#{%[%a%kQ#cqQ#itQ#{![Q%[#bQ%a#kR%k#}SQOdSeQm!cmSTVWXYZ[]^oqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kS&c$u$wR'd&cQ%Q#WQ%S#YT&i%Q%SQ%W#]R&n%WQoSR#`oQ%s$YQ&S$dQ&W$gW&w%s&S&W(qR(q(fQxUR#mxS'P%z%{R'p'PQ'u'VR(c'uQ'y'XQ(e'wT(g'y(eQ'}'^R(j'}Q!uaR$m!u!bcOTVWXYZ[]^dqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kTnSoQgRQ#WhQ#YiQ#[jQ#_lQ$U!eQ$W!fQ$i!pQ$j!qQ$k!rQ$l!sQ$p!xS$q!y)gQ$r!zQ$s!{Q$t!|Q$u!}Q$z#RQ${#SQ$|#TQ$}#UQ%O#VQ%]#eQ%l$OQ&h%PQ&k%UQ&l%VQ&y%tQ'U&UQ'V&VQ'X&XQ'a&bQ'e&dQ'f&gQ'g(yQ'i&xQ'm&}Q'r'TQ'w'WS(R(z)zQ(S({Q(T(|Q(U(}Q(W)PQ(X)QQ(Y)RQ(Z)SQ([)TQ(]'hQ(m(QQ(o(`Q(t)WQ(u(pQ(w(rQ(x(vQ)U)ZQ)V)[Q)X)bQ)Y)cQ)])fQ)^)lQ)_)mQ)`)nQ)a)sQ)d*TQ)e*UQ)o)hQ)p)iQ)q)jQ)r)kQ)t)yQ)u*PQ)v*QQ)w*RQ)x*SQ*V){Q*W)|Q*X)}R*Y*OQ$c!lT$y#O)OR$x!}R#XhR#^jR%|$^R$h!o",nodeNames:`⚠ {{ {# {% {% Template Text }} Interpolation VariableName MemberExpression . PropertyName SubscriptExpression BinaryExpression ConcatOp ArithOp ArithOp CompareOp in is StringLiteral NumberLiteral and or NotExpression not FilterExpression FilterOp FilterName FilterCall ) ( ArgumentList NamedArgument AssignOp , NamedArgument ConditionalExpression if else CallExpression ArrayExpression TupleExpression ParenthesizedExpression DictExpression Entry : Entry BooleanLiteral self super loop IfStatement Tag TagName if %} Tag elif Tag else EndTag endif ForStatement Tag for Definition recursive EndTag endfor RawStatement Tag raw RawText EndTag endraw BlockStatement Tag block scoped required EndTag endblock MacroStatement Tag macro ParamList OptionalParameter OptionalParameter EndTag endmacro CallStatement Tag call EndTag endcall FilterStatement Tag filter EndTag endfilter SetStatement Tag set EndTag endset TransStatement Tag trans Tag pluralize EndTag endtrans WithStatement Tag with EndTag endwith AutoescapeStatement Tag autoescape EndTag endautoescape Tag Tag Tag import as from import ImportItem Tag include ignore missing with without context Comment #}`,maxTerm:173,nodeProps:[[`closedBy`,1,`}}`,2,`#}`,-2,3,4,`%}`,32,`)`],[`openedBy`,7,`{{`,31,`(`,57,`{%`,140,`{#`],[`group`,-18,9,10,13,14,21,22,25,27,38,41,42,43,44,45,49,50,51,52,`Expression`,-11,53,64,71,77,84,92,97,102,107,114,119,`Statement`]],skippedNodes:[0],repeatNodeCount:13,tokenData:".|~RqXY#YYZ#Y]^#Ypq#Yqr#krs#vuv&nwx&{xy)nyz)sz{)x{|*V|}+|}!O,R!O!P,g!P!Q,o!Q![+h![!],w!^!_,|!_!`-U!`!a,|!c!}-^!}#O.U#P#Q.Z#R#S-^#T#o-^#o#p.`#p#q.e#q#r.j#r#s.w%W;'S-^;'S;:j.O<%lO-^~#_S$d~XY#YYZ#Y]^#Ypq#Y~#nP!_!`#q~#vOb~~#yWOY#vZr#vrs$cs#O#v#O#P$h#P;'S#v;'S;=`%x<%lO#v~$hOe~~$kYOY#vYZ#vZr#vrs%Zs#O#v#O#P$h#P;'S#v;'S;=`&O;=`<%l#v<%lO#v~%`We~OY#vZr#vrs$cs#O#v#O#P$h#P;'S#v;'S;=`%x<%lO#v~%{P;=`<%l#v~&RXOY#vZr#vrs$cs#O#v#O#P$h#P;'S#v;'S;=`%x;=`<%l#v<%lO#v~&sP`~#q#r&v~&{O!Z~~'OWOY&{Zw&{wx$cx#O&{#O#P'h#P;'S&{;'S;=`(x<%lO&{~'kYOY&{YZ&{Zw&{wx(Zx#O&{#O#P'h#P;'S&{;'S;=`)O;=`<%l&{<%lO&{~(`We~OY&{Zw&{wx$cx#O&{#O#P'h#P;'S&{;'S;=`(x<%lO&{~({P;=`<%l&{~)RXOY&{Zw&{wx$cx#O&{#O#P'h#P;'S&{;'S;=`(x;=`<%l&{<%lO&{~)sOp~~)xOo~~)}P`~z{*Q~*VO`~~*[Qa~!O!P*b!Q![+h~*eP!Q![*h~*mSf~!Q![*h!g!h*y#R#S*h#X#Y*y~*|R{|+V}!O+V!Q![+]~+YP!Q![+]~+bQf~!Q![+]#R#S+]~+mTf~!O!P*b!Q![+h!g!h*y#R#S+h#X#Y*y~,ROt~~,WRa~uv,a!O!P*b!Q![+h~,dP#q#r&v~,lPZ~!Q![*h~,tP`~!P!Q*Q~,|O!P~~-RPb~!_!`#q~-ZPs~!_!`#q!`-iVm`[p!XS$gY!Q![-^!c!}-^#R#S-^#T#o-^%W;'S-^;'S;:j.O<%lO-^!`.RP;=`<%l-^~.ZO$i~~.`O$h~~.eO$n~~.jOl~^.oP$m[#q#r.rQ.wOVQ~.|O_~",tokenizers:[S,w,1,2,3,4,5,new a(`b~RPstU~XP#q#r[~aO$Q~~`,17,173)],topRules:{Template:[0,5]},specialized:[{term:161,get:e=>T[e]||-1},{term:55,get:e=>E[e]||-1}],tokenPrec:3602});function O(e,t){return e.split(` `).map(e=>({label:e,type:t}))}var k=O(`abs attr batch capitalize center default dictsort escape filesizeformat first float forceescape format groupby indent int items join last length list lower map max min pprint random reject rejectattr replace reverse round safe select selectattr slice sort string striptags sum title tojson trim truncate unique upper urlencode urlize wordcount wordwrap xmlattr`,`function`),A=O(`boolean callable defined divisibleby eq escaped even filter float ge gt in integer iterable le lower lt mapping ne none number odd sameas sequence string test undefined upper range lipsum dict joiner namespace`,`function`),j=O(`loop super self true false varargs kwargs caller name arguments catch_kwargs catch_varargs caller`,`keyword`),M=A.concat(j),N=O(`raw endraw filter endfilter trans pluralize endtrans with endwith autoescape endautoescape if elif else endif for endfor call endcall block endblock set endset macro endmacro import include break continue debug do extends`,`keyword`);function P(e){let{state:t,pos:r}=e,i=n(t).resolveInner(r,-1).enterUnfinishedNodesBefore(r),a=i.childBefore(r)?.name||i.name;if(i.name==`FilterName`)return{type:`filter`,node:i};if(e.explicit&&(a==`FilterOp`||a==`filter`))return{type:`filter`};if(i.name==`TagName`)return{type:`tag`,node:i};if(e.explicit&&a==`{%`)return{type:`tag`};if(i.name==`PropertyName`&&i.parent.name==`MemberExpression`)return{type:`prop`,node:i,target:i.parent};if(i.name==`.`&&i.parent.name==`MemberExpression`)return{type:`prop`,target:i.parent};if(i.name==`MemberExpression`&&a==`.`)return{type:`prop`,target:i};if(i.name==`VariableName`)return{type:`expr`,from:i.from};if(i.name==`Comment`||i.name==`StringLiteral`||i.name==`NumberLiteral`)return null;let o=e.matchBefore(/[\w\u00c0-\uffff]+$/);return o?{type:`expr`,from:o.from}:e.explicit?{type:`expr`}:null}function F(e,t,n,r){let i=[];for(;;){let n=t.getChild(`Expression`);if(!n)return[];if(n.name==`VariableName`){i.unshift(e.sliceDoc(n.from,n.to));break}if(n.name==`MemberExpression`){let r=n.getChild(`PropertyName`);r&&i.unshift(e.sliceDoc(r.from,r.to)),t=n}else return[]}return r(i,e,n)}function I(e={}){let t=e.tags?e.tags.concat(N):N,n=e.variables?e.variables.concat(M):M,{properties:r}=e;return e=>{let i=P(e);if(!i)return null;let a=i.from??(i.node?i.node.from:e.pos),o;return o=i.type==`filter`?k:i.type==`tag`?t:i.type==`expr`?n:r?F(e.state,i.target,e,r):[],o.length?{options:o,from:a,validFor:/^[\w\u00c0-\uffff]*$/}:null}}var L=i.inputHandler.of((e,t,n,r)=>r!=`%`||t!=n||e.state.doc.sliceString(t-1,n+1)!=`{}`?!1:(e.dispatch(e.state.changeByRange(e=>({changes:{from:e.from,to:e.to,insert:`%%`},range:f.cursor(e.from+1)})),{scrollIntoView:!0,userEvent:`input.type`}),!0));function R(e){return t=>{let n=e.test(t.textAfter);return t.lineIndent(t.node.from)+(n?0:t.unit)}}var z=l.define({name:`jinja`,parser:D.configure({props:[r({"TagName raw endraw filter endfilter as trans pluralize endtrans with endwith autoescape endautoescape":p.keyword,"required scoped recursive with without context ignore missing":p.modifier,self:p.self,"loop super":p.standard(p.variableName),"if elif else endif for endfor call endcall":p.controlKeyword,"block endblock set endset macro endmacro import from include":p.definitionKeyword,"Comment/...":p.blockComment,VariableName:p.variableName,Definition:p.definition(p.variableName),PropertyName:p.propertyName,FilterName:p.special(p.variableName),ArithOp:p.arithmeticOperator,AssignOp:p.definitionOperator,"not and or":p.logicOperator,CompareOp:p.compareOperator,"in is":p.operatorKeyword,"FilterOp ConcatOp":p.operator,StringLiteral:p.string,NumberLiteral:p.number,BooleanLiteral:p.bool,"{% %} {# #} {{ }} { }":p.brace,"( )":p.paren,".":p.derefOperator,": , .":p.punctuation}),t.add({Tag:d({closing:`%}`}),"IfStatement ForStatement":R(/^\s*(\{%-?\s*)?(endif|endfor|else|elif)\b/),Statement:R(/^\s*(\{%-?\s*)?end\w/)}),e.add({"Statement Comment"(e){let t=e.firstChild,n=e.lastChild;return!t||t.name!=`Tag`&&t.name!=`{#`?null:{from:t.to,to:n.name==`EndTag`||n.name==`#}`?n.from:e.to}}})]}),languageData:{indentOnInput:/^\s*{%-?\s*(?:end|elif|else)$/}}),B=m();function V(e){return z.configure({wrap:s(t=>t.type.isTop?{parser:e.parser,overlay:e=>e.name==`Text`||e.name==`RawText`}:null)},`jinja`)}var H=V(B.language);function U(e={}){let t=e.base||B,n=t.language==B.language?H:V(t.language);return new u(n,[t.support,n.data.of({autocomplete:I(e)}),t.language.data.of({closeBrackets:{brackets:[`{`]}}),L])}export{U as jinja};
|
|
1
|
+
import{C as e,D as t,F as n,L as r,X as i,i as a,n as o,q as s,r as c,s as l,u,v as d,wt as f,z as p}from"./dist-Dr9crbBz.js";import{t as m}from"./index-Ckax27uf.js";var h=1,g=2,_=3,v=155,y=4,b=156;function x(e){return e>=65&&e<=90||e>=97&&e<=122}var S=new o(e=>{let t=e.pos;for(;;){let{next:n}=e;if(n<0)break;if(n==123){let n=e.peek(1);if(n==123){if(e.pos>t)break;e.acceptToken(h,2);return}if(n==35){if(e.pos>t)break;e.acceptToken(g,2);return}if(n==37){if(e.pos>t)break;let n=2,r=2;for(;;){let t=e.peek(n);if(t==32||t==10)++n;else if(t==35)for(++n;;){let t=e.peek(n);if(t<0||t==10)break;n++}else if(t==45&&r==2)r=++n;else{e.acceptToken(_,r);return}}}}if(e.advance(),n==10)break}e.pos>t&&e.acceptToken(v)});function C(e,t,n){return new o(r=>{let i=r.pos;for(;;){let{next:t}=r;if(t==123&&r.peek(1)==37){let t=2;for(;;t++){let e=r.peek(t);if(e!=32&&e!=10)break}let a=``;for(;;t++){let e=r.peek(t);if(!x(e))break;a+=String.fromCharCode(e)}if(a==e){if(r.pos>i)break;r.acceptToken(n,2);break}}else if(t<0)break;if(r.advance(),t==10)break}r.pos>i&&r.acceptToken(t)})}var w=C(`endraw`,b,y),T={__proto__:null,in:38,is:40,and:46,or:48,not:52,if:78,else:80,true:98,false:98,self:100,super:102,loop:104,recursive:136,scoped:160,required:162,as:256,import:260,ignore:268,missing:270,with:272,without:274,context:276},E={__proto__:null,if:112,elif:118,else:122,endif:126,for:132,endfor:140,raw:146,endraw:152,block:158,endblock:166,macro:172,endmacro:182,call:188,endcall:192,filter:198,endfilter:202,set:208,endset:212,trans:218,pluralize:222,endtrans:226,with:232,endwith:236,autoescape:242,endautoescape:246,import:254,from:258,include:266},D=c.deserialize({version:14,states:"!*dQVOPOOOOOP'#F`'#F`OeOTO'#CbOvQSO'#CdO!kOPO'#DcO!yOPO'#DnO#XOQO'#DuO#^OPO'#D{O#lOPO'#ESO#zOPO'#E[O$YOPO'#EaO$hOPO'#EfO$vOPO'#EkO%UOPO'#ErO%dOPO'#EwOOOP'#F|'#F|O%rQWO'#E|O&sO#tO'#F]OOOP'#Fq'#FqOOOP'#F_'#F_QVOPOOOOOP-E9^-E9^OOQO'#Ce'#CeO'sQSO,59OO'zQSO'#DWO(RQSO'#DXO(YQ`O'#DZOOQO'#Fr'#FrOvQSO'#CuO(aOPO'#CbOOOP'#Fd'#FdO!kOPO,59}OOOP,59},59}O(oOPO,59}O(}QWO'#E|OOOP,5:Y,5:YO)[OPO,5:YO!yOPO,5:YO)jQWO'#E|OOOQ'#Ff'#FfO)tOQO'#DxO)|OQO,5:aOOOP,5:g,5:gO#^OPO,5:gO*RQWO'#E|OOOP,5:n,5:nO#lOPO,5:nO*YQWO'#E|OOOP,5:v,5:vO#zOPO,5:vO*aQWO'#E|OOOP,5:{,5:{O$YOPO,5:{O*hQWO'#E|OOOP,5;Q,5;QO$hOPO,5;QO*oQWO'#E|OOOP,5;V,5;VO*vOPO,5;VO$vOPO,5;VO+UQWO'#E|OOOP,5;^,5;^O%UOPO,5;^O+`QWO'#E|OOOP,5;c,5;cO%dOPO,5;cO+gQWO'#E|O+nQSO,5;hOvQSO,5:OO+uQSO,5:ZO+zQSO,5:bO+uQSO,5:hO+uQSO,5:oO,PQSO,5:wO,XQpO,5:|O+uQSO,5;RO,^QSO,5;WO,fQSO,5;_OvQSO,5;dOvQSO,5;jOvQSO,5;jOvQSO,5;pOOOO'#Fk'#FkO,nO#tO,5;wOOOP-E9]-E9]O,vQ!bO,59QOvQSO,59TOvQSO,59UOvQSO,59UOvQSO,59UOvQSO,59UO,{QSO'#C}O,XQpO,59cOOQO,59q,59qOOOP1G.j1G.jOvQSO,59UO-SQSO,59UOvQSO,59UOvQSO,59UOvQSO,59nO-wQSO'#FxO.RQSO,59rO.WQSO,59tOOQO,59s,59sO.bQSO'#D[O.iQWO'#F{O.qQWO,59uO0WQSO,59aOOOP-E9b-E9bOOOP1G/i1G/iO(oOPO1G/iO(oOPO1G/iO)TQWO'#E|OvQSO,5:SO0nQSO,5:UO0sQSO,5:WOOOP1G/t1G/tO)[OPO1G/tO)mQWO'#E|O)[OPO1G/tO0xQSO,5:_OOOQ-E9d-E9dOOOP1G/{1G/{O0}QWO'#DyOOOP1G0R1G0RO1SQSO,5:lOOOP1G0Y1G0YO1[QSO,5:tOOOP1G0b1G0bO1aQSO,5:yOOOP1G0g1G0gO1fQSO,5;OOOOP1G0l1G0lO1kQSO,5;TOOOP1G0q1G0qO*vOPO1G0qO+XQWO'#E|O*vOPO1G0qOvQSO,5;YO1pQSO,5;[OOOP1G0x1G0xO1uQSO,5;aOOOP1G0}1G0}O1zQSO,5;fO2PQSO1G1SOOOP1G1S1G1SO2WQSO1G/jOOQO'#Dq'#DqO2_QSO1G/uOOOQ1G/|1G/|O2gQSO1G0SO2rQSO1G0ZO2zQSO'#EVO3SQSO1G0cO,SQSO1G0cO4fQSO'#FvOOQO'#Fv'#FvO5]QSO1G0hO5bQSO1G0mOOOP1G0r1G0rO5mQSO1G0rO5rQSO'#GOO5zQSO1G0yO6PQSO1G1OO6WQSO1G1UO6_QSO1G1UO6fQSO1G1[OOOO-E9i-E9iOOOP1G1c1G1cOOQO1G.l1G.lO6vQSO1G.oO8wQSO1G.pO:oQSO1G.pO:vQSO1G.pO<nQSO1G.pO<uQSO'#FwO>QQSO'#FrO>XQSO'#FwO>aQSO,59iOOQO1G.}1G.}O>fQSO1G.pO@aQSO1G.pOB_QSO1G.pOBfQSO1G.pOD^QSO1G/YOvQSO'#FbODeQSO,5<dOOQO1G/^1G/^ODmQSO1G/_OOQO1G/`1G/`ODuQSO,59vOvQSO'#FcOEjQWO,5<gOOQO1G/a1G/aPErQWO'#E|OOOP7+%T7+%TO(oOPO7+%TOEyQSO1G/nOOOP1G/p1G/pOOOP1G/r1G/rOOOP7+%`7+%`O)[OPO7+%`OOOP1G/y1G/yOFQQSO,5:eOOOP1G0W1G0WOFVQSO1G0WOOOP1G0`1G0`OOOP1G0e1G0eOOOP1G0j1G0jOOOP1G0o1G0oOOOP7+&]7+&]O*vOPO7+&]OF[QSO1G0tOOOP1G0v1G0vOOOP1G0{1G0{OOOP1G1Q1G1QOOOP7+&n7+&nOOOP7+%U7+%UO+uQSO'#FeOFcQSO7+%aOvQSO7+%aOOOP7+%n7+%nOFkQSO7+%nOFpQSO7+%nOOOP7+%u7+%uOFxQSO7+%uOF}QSO'#F}OGQQSO'#F}OGYQSO,5:qOOOP7+%}7+%}OG_QSO7+%}OGdQSO7+%}OOQO,59f,59fOOOP7+&S7+&SOGlQSO7+&oOOOP7+&X7+&XOvQSO7+&oOvQSO7+&^OGtQSO,5<jOvQSO,5<jOOOP7+&e7+&eOOOP7+&j7+&jO+uQSO7+&pOG|QSO7+&pOOOP7+&v7+&vOHRQSO7+&vOHWQSO7+&vOOQO7+$Z7+$ZOvQSO'#FaOH]QSO,5<cOvQSO,59jOOQO1G/T1G/TOOQO7+$[7+$[OvQSO7+$tOHeQSO,5;|OOQO-E9`-E9`OOQO7+$y7+$yOImQ`O1G/bOIwQSO'#D^OOQO,5;},5;}OOQO-E9a-E9aOOOP<<Ho<<HoOOOP7+%Y7+%YOOOP<<Hz<<HzOOOP1G0P1G0POOOP7+%r7+%rOOOP<<Iw<<IwOOOP7+&`7+&`OOQO,5<P,5<POOQO-E9c-E9cOvQSO<<H{OJOQSO<<H{OOOP<<IY<<IYOJYQSO<<IYOOOP<<Ia<<IaOvQSO,5:rO+uQSO'#FgOJ_QSO,5<iOOQO1G0]1G0]OOOP<<Ii<<IiOJgQSO<<IiOvQSO<<JZOJlQSO<<JZOJsQSO<<IxOvQSO1G2UOJ}QSO1G2UOKXQSO<<J[OK^QSO'#CeOOQO'#FT'#FTOKiQSO'#FTOKnQSO<<J[OKvQSO<<JbOK{QSO<<JbOLWQSO,5;{OLbQSO'#FrOOQO,5;{,5;{OOQO-E9_-E9_OLiQSO1G/UOM}QSO<<H`O! ]Q`O,59aODuQSO,59xO! sQSOAN>gOOOPAN>gAN>gO! }QSOAN>gOOOPAN>tAN>tO!!SQSO1G0^O!!^QSO,5<ROOQO,5<R,5<ROOQO-E9e-E9eOOOPAN?TAN?TO!!iQSOAN?uOOOPAN?uAN?uO+uQSO'#FhO!!pQSOAN?dOOOPAN?dAN?dO!!xQSO7+'pO+uQSO'#FiO!#SQSO7+'pOOOPAN?vAN?vO+uQSO,5;oOG|QSO'#FjO!#[QSOAN?vOOOPAN?|AN?|O!#dQSOAN?|OvQSO,59mO!$sQ`O1G.pO!%{Q`O1G.pO!&SQ`O1G.pO!'[Q`O1G.pO!'cQ`O'#FvO!'jQ`O1G.pO!(uQ`O1G.pO!*TQ`O1G.pO!*[Q`O1G.pO!+dQ`O1G/YO!+kQ`O1G/dOOOPG24RG24RO!+uQSOG24ROvQSO,5:sOOOPG25aG25aO!+zQSO,5<SOOQO-E9f-E9fOOOPG25OG25OO!,PQSO<<K[O!,XQSO,5<TOOQO-E9g-E9gOOQO1G1Z1G1ZOOQO,5<U,5<UOOQO-E9h-E9hOOOPG25bG25bO!,aQSOG25hO!,fQSO1G/XOOOPLD)mLD)mO!,pQSO1G0_OvQSO1G1nO!,zQSO1G1oOvQSO1G1oOOOPLD+SLD+SO!-wQ`O<<H`O!.[QSO7+'YOvQSO7+'ZO!.fQSO7+'ZO!.pQSO<<JuODuQSO'#CuODuQSO,59UODuQSO,59UODuQSO,59UODuQSO,59UO!.zQpO,59cODuQSO,59UO!/PQSO,59UODuQSO,59UODuQSO,59UODuQSO,59nO!/tQSO1G.pP!0RQSO1G/YODuQSO7+$tO!0YQ`O1G.pP!0gQ`O1G/YO-SQSO,59UPvQSO,59nO!0nQSO,59aP!3XQSO1G.pP!3`QSO1G.pP!5aQSO1G/YP!5hQSO<<H`O!/PQSO,59UPDuQSO,59nP!6_QSO1G/YP!7pQ`O1G/YO-SQSO'#CuO-SQSO,59UO-SQSO,59UO-SQSO,59UO-SQSO,59UO-SQSO,59UP-SQSO,59UP-SQSO,59UP-SQSO,59nO!7wQSO1G.pO!9xQSO1G.pO!:PQSO1G.pO!;UQSO1G.pP-SQSO7+$tO!<XQ`O,59aP!>SQ`O1G.pP!>ZQ`O1G.pP!>bQ`O1G/YP!?QQ`O<<H`O!/PQSO'#CuO!/PQSO,59UO!/PQSO,59UO!/PQSO,59UO!/PQSO,59UO!/PQSO,59UP!/PQSO,59UP!/PQSO,59UP!/PQSO,59nP!/PQSO7+$tP-SQSO,59nP!/PQSO,59nO!?zQ`O1G.pO!@RQ`O1G.pO!@fQ`O1G.pO!@yQ`O1G.p",stateData:"!Ac~O$dOS~OPROQaOR`O$aPO~O$aPOPUXQUXRUX$`UX~OekOfkOjlOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~OPROQaORrO$aPO~OPROQaORvO$aPO~O$bwO~OPROQaOR|O$aPO~OPROQaOR!PO$aPO~OPROQaOR!SO$aPO~OPROQaOR!VO$aPO~OPROQaOR!YO$aPO~OPROQaOR!^O$aPO~OPROQaOR!aO$aPO~OPROQaOR!dO$aPO~O!X!eO!Y!fO!d!gO!k!hO!q!iO!x!jO#Q!kO#V!lO#[!mO#a!nO#h!oO#m!pO#s!qO#u!rO#y!sO~O$s!tO~OZ!wO_!yO`!zOa!{Ob!|Oc#ROd#SOg#TOh#UOl#OOp!}Ow#VO$i!xO~OV#QO~P&xO$h$lP~PvOo#ZO~PvO$m$oP~PvO$aPOPUXQUXRUX~OPROQaOR#dO$aPO~O!]#eO!_#fO!a#gO~P%rOPROQaOR#jO$aPO~O!_#fO!h#lO~P%rO$bwOS!lX~OS#oO~O!u#qO~P%rO!}#sO~P%rO#S#uO~P%rO#X#wO~P%rO#^#yO~P%rOPROQaOR#|O$aPO~O#c$OO#e$PO~P%rO#j$RO~P%rO#o$TO~P%rO!Z$VO~PvO$g$XO~O!Z$ZO~Op$^O$gfO~Om$aO~O!Z$eO$g$XO~O$g$XO!Z$rP~O$Q$nO$s!tO~O[$oO~Oo$kP~PvOekOfkOj)fOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~Ot%PO$h$lX~P&xO$h%RO~Oo%TOt%PO~P&xO!P%UO~P&xOt%VO$m$oX~O$m%XO~OZ!wOp!}O$i!xOViagiahialiawiatia$hiaoia!Pia!Zia#tia#via#zia#|ia#}iaxia!fia~O_!yO`!zOa!{Ob!|Oc#ROd#SO~P.vO!Z%^O~O!Z%_O~O!Z%bO~O!n%cO~O!Z%dO$g$XO~O!Z%fO~O!Z%gO~O!Z%hO~O!Z%iO~O!Z%mO~O!Z%nO~O!Z%oO~O!Z%pO~P&xO!Z%qO~P&xOc%tOt%rO~O!Z%uO!r%wO!s%vO~Op$^O!Z%xO~O$g$XOo$qP~Op!}O!Z%}O~Op!}OZ$jX_$jX`$jXa$jXb$jXc$jXd$jXg$jXh$jXl$jXw$jX$i$jXt$jXe$jXf$jX$g$jXx$jX~O!Z$jXV$jX$h$jXo$jX!P$jX#t$jX#v$jX#z$jX#|$jX#}$jX!f$jX~P3[O!Z&RO~Os&UOt%rO!Z&TO~Os&VO~Os&XOt%rO~O!Z&YO~O!Z&ZO~P&xO#t&[O~P&xO#v&]O~P&xO!Z&^O#z&`O#|&_O#}&_O~P&xO$h&aO~P&xOZ!wOp!}O$i!xOV^i`^ia^ib^ic^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ie^if^i$g^ix^i!f^i~O_^i~P6}OZ!wO_!yOp!}O$i!xOV^ia^ib^ic^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~O`^i~P9OO`!zO~P9OOZ!wO_!yO`!zOa!{Op!}O$i!xOV^ic^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Ob^i~P:}Ot&bOo$kX~P&xOZ$fX_$fX`$fXa$fXb$fXc$fXd$fXg$fXh$fXl$fXo$fXp$fXt$fXw$fX$i$fX~Os&dO~P=POt&bOo$kX~Oo&eO~Ob!|O~P:}OZ!wO_)gO`)hOa)iOb)jOc)kOp!}O$i!xOV^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Oe&fOf&fO$gfO~P>mOZ!wO_!yO`!zOa!{Ob!|Oc#ROd#SOp!}O$i!xOV^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Og^i~P@nOg#TO~P@nOZ!wO_!yO`!zOa!{Ob!|Oc#ROd#SOg#TOh#UOp!}O$i!xOVvilviwvitvi$hviovi!Pvi!Zvi#tvi#vvi#zvi#|vi#}vi!fvi~Ox&gO~PBmOt%PO$h$la~Oo&jOt%PO~OekOfkOj(yOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~Ot%VO$m$oa~O!]#eO~P%rO!Z&pO~P&xO!Z&rO~O!Z&sO~O!Z&uO~P&xOc&xOt%rO~O!Z&zO~O!Z&zO!s&{O~O!Z&|O~Os&}Ot'OOo$qX~Oo'QO~O!Z'RO~Op!}O!Z'RO~Os'TOt%rO~Os'WOt%rO~O$g'ZO~O$O'_O~O#{'`O~Ot&bOo$ka~Ot$Ua$h$Uao$Ua~P&xOZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOg)ROh)SOl)OOp!}Ow)TO$i!xO~Ot!Oi$m!Oi~PHrO!P'hO~P&xO!Z'jO!f'kO~P&xO!Z'lO~Ot'OOo$qa~O!Z'qO~O!Z'sO~P&xOt'tO!Z'vO~P&xOt'xO!Z$ri~P&xO!Z'zO~Ot!eX!Z!eX#tXX~O#t'{O~Ot'|O!Z'zO~O!Z(OO~O!Z(OO#|(PO#}(PO~Oo$Tat$Ta~P&xOs(QO~P=POoritri~P&xOZ!wOp!}O$i!xOVvylvywvytvy$hvyovy!Pvy!Zvy#tvy#vvy#zvy#|vy#}vyxvy!fvy~O_!yO`!zOa!{Ob!|Oc#ROd#SOg#TOh#UO~PLsOZ!wOp!}O$i!xOgiahialiatiawia$miaxia~O_(zO`({Oa(|Ob(}Oc)POd)QO~PNkO!Z(^O!f(_O~P&xO!Z(^O~Oo!zit!zi~P&xOs(`Oo$Zat$Za~O!Z(aO~P&xOt'tO!Z(dO~Ot'xO!Z$rq~P&xOt'xO!Z$rq~Ot'|O!Z(kO~O$O(lO~OZ!wOp!}O$i!xO`^ia^ib^ic^id^ig^ih^il^it^iw^i$m^ie^if^i$g^ix^i~O_^i~P!#iOZ!wO_(zOp!}O$i!xOa^ib^ic^id^ig^ih^il^it^iw^i$m^ix^i~O`^i~P!$zO`({O~P!$zOZ!wO_(zO`({Oa(|Op!}O$i!xOc^id^ig^ih^il^it^iw^i$m^ix^i~Ob^i~P!&ZO$m$jX~P3[Ob(}O~P!&ZOZ!wO_)zO`){Oa)|Ob)}Oc*OOp!}O$i!xOd^ig^ih^il^it^iw^i$m^ix^i~Oe&fOf&fO$gfO~P!'qOZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOp!}O$i!xOh^il^it^iw^i$m^ix^i~Og^i~P!)SOg)RO~P!)SOZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOg)ROh)SOp!}O$i!xOlvitviwvi$mvi~Ox)WO~P!*cOt!Qi$m!Qi~PHrO!Z(nO~Os(pO~Ot'xO!Z$ry~Os(rOt%rO~O!Z(sO~Oouitui~P&xOo!{it!{i~P&xOs(vOt%rO~OZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOg)ROh)SOp!}O$i!xO~Olvytvywvy$mvyxvy~P!-SOt$[q!Z$[q~P&xOt$]q!Z$]q~P&xOt$]y!Z$]y~P&xOm(VO~OekOfkOj)yOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~Oe^if^i$g^i~P>mOxvi~PBmOe^if^i$g^i~P!'qOxvi~P!*cO_)gO`)hOa)iOb)jOc)kOd)ZOeiafia$gia~P.vOZ!wO_)gO`)hOa)iOb)jOc)kOd)ZOp!}O$i!xOV^ie^if^ih^il^iw^i$g^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Og^i~P!1_Og)lO~P!1_OZ!wO_)gO`)hOa)iOb)jOc)kOd)ZOg)lOh)mOp!}O$i!xOVvievifvilviwvi$gvitvi$hviovi!Pvi!Zvi#tvi#vvi#zvi#|vi#}vi!fvi~Ox)sO~P!3gO_)gO`)hOa)iOb)jOc)kOd)ZOg)lOh)mOevyfvy$gvy~PLsOxvi~P!3gOZ!wO_)zO`){Oa)|Ob)}Oc*OOd)bOg*POh*QOp!}O$i!xOevifvilvitviwvi$gvi$mvi~Oxvi~P!6fO_)gO~P6}OZ!wO_)gO`)hOp!}O$i!xOV^ib^ic^id^ie^if^ig^ih^il^iw^i$g^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Oa^i~P!8OOa)iO~P!8OOZ!wOp!}O$i!xOc^id^ie^if^ig^ih^il^iw^i$g^it^ix^i~O_)gO`)hOa)iOb)jOV^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^i!f^i~P!:WO_)zO`){Oa)|Ob)}Oc*OOd)bOeiafia$gia~PNkOZ!wO_)zO`){Oa)|Ob)}Oc*OOd)bOp!}O$i!xOe^if^ih^il^it^iw^i$g^i$m^ix^i~Og^i~P!<xOg*PO~P!<xOx*SO~P!6fOZ!wO_)zO`){Oa)|Ob)}Op!}O$i!xO~Oc*OOd)bOg*POh*QOevyfvylvytvywvy$gvy$mvyxvy~P!>iO_)zO~P!#iO_)zO`){Oa^ib^i$m^i~P!:WO_)zO`){Oa)|Ob^i$m^i~P!:WO_)zO`){Oa)|Ob)}O$m^i~P!:WOfaZa~",goto:"Cy$sPPPPPP$tP$t%j'sPP's'sPPPPPPPPPP'sP'sPP)jPP)o+nPP+q'sPP's's's's's+tP+wPPPP+z,pPPP-fP-jP-vP+z.UP.zP/zP+z0YP1O1RP+z1UPPP1zP+z2QP2v2|3P3SP+z3YP4OP+z4UP4zP+z5QP5vP+z5|P6rP6xP+z7WP7|P+z8SP8xP$t$t$tPPPP9O$tPPPPPP$tP9U:j;f;m;w;}<T<g<m<t<z=U=[PPPPP=b>YPPPCcCjCmPPCp$tCsCv!gbOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%k$dkRhijl!e!f!p!q!r!s!x!y!z!{!|#R#S#T#U#V#e$O%P%U%V%t&U&V&X&d&g&x&}'T'W'h(Q(`(p(r(v(y(z({(|(})P)Q)R)S)T)W)Z)[)b)c)f)g)h)i)j)k)l)m)n)s)y)z){)|)}*O*P*Q*R*S*T*UQ$_!kQ$v!}Q&P$`S&f${(XS']&]'|R'b&b$ikRhijl!e!f!p!q!r!s!x!y!z!{!|!}#R#S#T#U#V#e$O%P%U%V%t&U&V&X&b&d&g&x&}'T'W'h(Q(`(p(r(v(y(z({(|(})P)Q)R)S)T)W)Z)[)b)c)f)g)h)i)j)k)l)m)n)s)y)z){)|)}*O*P*Q*R*S*T*UV$b!l#O)O$d#Pg#W#Y#[#_$U$W$i$j$k$l$p$q$r$s$t$u$z${$|$}%O%]%l&h&k&l&y'U'V'X'a'e'f'g'i'm'r'w(R(S(T(U(W(X(Y(Z([(](m(o(t(u(w(x)U)V)X)Y)])^)_)`)a)d)e)o)p)q)r)t)u)v)w)x*V*W*X*YQ&O$_S&Q$a(VR'S&PR$w!}R'c&bR#]jR&m%V!g_OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%k!gSOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kTnSoQqSQtTQ#boR#kuQpSS#aoqS%Z#b#cR&o%[!gTOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ$Y!gQ$[!iQ$]!jQ$d!mQ$f!nQ$g!oQ%e#qQ%z$^Q&v%rQ'Y&[S'[&]'|Q'n'OQ(b'tQ(f'xR(h'{QsTS#htuS%`#i#kR&q%a!gUOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kRyUR#ny!gVOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQzVR#p{!gWOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ$`!kR%y$]R%{$^R'o'OQ}WR#r!O!gXOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!QXR#t!R!gYOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!TYR#v!U!gZOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!WZR#x!X!g[OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ![[R#}!]Q!Z[S#z![!]S%j#{#}R&t%k!g]OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!_]R$Q!`!g^OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!b^R$S!cQ'^&]R(i'|QdOQuTQ{VQ!OWQ!RXQ!UYQ!XZQ!][Q!`]Q!c^p!vdu{!O!R!U!X!]!`!c#c#i#{%[%a%kQ#cqQ#itQ#{![Q%[#bQ%a#kR%k#}SQOdSeQm!cmSTVWXYZ[]^oqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kS&c$u$wR'd&cQ%Q#WQ%S#YT&i%Q%SQ%W#]R&n%WQoSR#`oQ%s$YQ&S$dQ&W$gW&w%s&S&W(qR(q(fQxUR#mxS'P%z%{R'p'PQ'u'VR(c'uQ'y'XQ(e'wT(g'y(eQ'}'^R(j'}Q!uaR$m!u!bcOTVWXYZ[]^dqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kTnSoQgRQ#WhQ#YiQ#[jQ#_lQ$U!eQ$W!fQ$i!pQ$j!qQ$k!rQ$l!sQ$p!xS$q!y)gQ$r!zQ$s!{Q$t!|Q$u!}Q$z#RQ${#SQ$|#TQ$}#UQ%O#VQ%]#eQ%l$OQ&h%PQ&k%UQ&l%VQ&y%tQ'U&UQ'V&VQ'X&XQ'a&bQ'e&dQ'f&gQ'g(yQ'i&xQ'm&}Q'r'TQ'w'WS(R(z)zQ(S({Q(T(|Q(U(}Q(W)PQ(X)QQ(Y)RQ(Z)SQ([)TQ(]'hQ(m(QQ(o(`Q(t)WQ(u(pQ(w(rQ(x(vQ)U)ZQ)V)[Q)X)bQ)Y)cQ)])fQ)^)lQ)_)mQ)`)nQ)a)sQ)d*TQ)e*UQ)o)hQ)p)iQ)q)jQ)r)kQ)t)yQ)u*PQ)v*QQ)w*RQ)x*SQ*V){Q*W)|Q*X)}R*Y*OQ$c!lT$y#O)OR$x!}R#XhR#^jR%|$^R$h!o",nodeNames:`⚠ {{ {# {% {% Template Text }} Interpolation VariableName MemberExpression . PropertyName SubscriptExpression BinaryExpression ConcatOp ArithOp ArithOp CompareOp in is StringLiteral NumberLiteral and or NotExpression not FilterExpression FilterOp FilterName FilterCall ) ( ArgumentList NamedArgument AssignOp , NamedArgument ConditionalExpression if else CallExpression ArrayExpression TupleExpression ParenthesizedExpression DictExpression Entry : Entry BooleanLiteral self super loop IfStatement Tag TagName if %} Tag elif Tag else EndTag endif ForStatement Tag for Definition recursive EndTag endfor RawStatement Tag raw RawText EndTag endraw BlockStatement Tag block scoped required EndTag endblock MacroStatement Tag macro ParamList OptionalParameter OptionalParameter EndTag endmacro CallStatement Tag call EndTag endcall FilterStatement Tag filter EndTag endfilter SetStatement Tag set EndTag endset TransStatement Tag trans Tag pluralize EndTag endtrans WithStatement Tag with EndTag endwith AutoescapeStatement Tag autoescape EndTag endautoescape Tag Tag Tag import as from import ImportItem Tag include ignore missing with without context Comment #}`,maxTerm:173,nodeProps:[[`closedBy`,1,`}}`,2,`#}`,-2,3,4,`%}`,32,`)`],[`openedBy`,7,`{{`,31,`(`,57,`{%`,140,`{#`],[`group`,-18,9,10,13,14,21,22,25,27,38,41,42,43,44,45,49,50,51,52,`Expression`,-11,53,64,71,77,84,92,97,102,107,114,119,`Statement`]],skippedNodes:[0],repeatNodeCount:13,tokenData:".|~RqXY#YYZ#Y]^#Ypq#Yqr#krs#vuv&nwx&{xy)nyz)sz{)x{|*V|}+|}!O,R!O!P,g!P!Q,o!Q![+h![!],w!^!_,|!_!`-U!`!a,|!c!}-^!}#O.U#P#Q.Z#R#S-^#T#o-^#o#p.`#p#q.e#q#r.j#r#s.w%W;'S-^;'S;:j.O<%lO-^~#_S$d~XY#YYZ#Y]^#Ypq#Y~#nP!_!`#q~#vOb~~#yWOY#vZr#vrs$cs#O#v#O#P$h#P;'S#v;'S;=`%x<%lO#v~$hOe~~$kYOY#vYZ#vZr#vrs%Zs#O#v#O#P$h#P;'S#v;'S;=`&O;=`<%l#v<%lO#v~%`We~OY#vZr#vrs$cs#O#v#O#P$h#P;'S#v;'S;=`%x<%lO#v~%{P;=`<%l#v~&RXOY#vZr#vrs$cs#O#v#O#P$h#P;'S#v;'S;=`%x;=`<%l#v<%lO#v~&sP`~#q#r&v~&{O!Z~~'OWOY&{Zw&{wx$cx#O&{#O#P'h#P;'S&{;'S;=`(x<%lO&{~'kYOY&{YZ&{Zw&{wx(Zx#O&{#O#P'h#P;'S&{;'S;=`)O;=`<%l&{<%lO&{~(`We~OY&{Zw&{wx$cx#O&{#O#P'h#P;'S&{;'S;=`(x<%lO&{~({P;=`<%l&{~)RXOY&{Zw&{wx$cx#O&{#O#P'h#P;'S&{;'S;=`(x;=`<%l&{<%lO&{~)sOp~~)xOo~~)}P`~z{*Q~*VO`~~*[Qa~!O!P*b!Q![+h~*eP!Q![*h~*mSf~!Q![*h!g!h*y#R#S*h#X#Y*y~*|R{|+V}!O+V!Q![+]~+YP!Q![+]~+bQf~!Q![+]#R#S+]~+mTf~!O!P*b!Q![+h!g!h*y#R#S+h#X#Y*y~,ROt~~,WRa~uv,a!O!P*b!Q![+h~,dP#q#r&v~,lPZ~!Q![*h~,tP`~!P!Q*Q~,|O!P~~-RPb~!_!`#q~-ZPs~!_!`#q!`-iVm`[p!XS$gY!Q![-^!c!}-^#R#S-^#T#o-^%W;'S-^;'S;:j.O<%lO-^!`.RP;=`<%l-^~.ZO$i~~.`O$h~~.eO$n~~.jOl~^.oP$m[#q#r.rQ.wOVQ~.|O_~",tokenizers:[S,w,1,2,3,4,5,new a(`b~RPstU~XP#q#r[~aO$Q~~`,17,173)],topRules:{Template:[0,5]},specialized:[{term:161,get:e=>T[e]||-1},{term:55,get:e=>E[e]||-1}],tokenPrec:3602});function O(e,t){return e.split(` `).map(e=>({label:e,type:t}))}var k=O(`abs attr batch capitalize center default dictsort escape filesizeformat first float forceescape format groupby indent int items join last length list lower map max min pprint random reject rejectattr replace reverse round safe select selectattr slice sort string striptags sum title tojson trim truncate unique upper urlencode urlize wordcount wordwrap xmlattr`,`function`),A=O(`boolean callable defined divisibleby eq escaped even filter float ge gt in integer iterable le lower lt mapping ne none number odd sameas sequence string test undefined upper range lipsum dict joiner namespace`,`function`),j=O(`loop super self true false varargs kwargs caller name arguments catch_kwargs catch_varargs caller`,`keyword`),M=A.concat(j),N=O(`raw endraw filter endfilter trans pluralize endtrans with endwith autoescape endautoescape if elif else endif for endfor call endcall block endblock set endset macro endmacro import include break continue debug do extends`,`keyword`);function P(e){let{state:t,pos:r}=e,i=n(t).resolveInner(r,-1).enterUnfinishedNodesBefore(r),a=i.childBefore(r)?.name||i.name;if(i.name==`FilterName`)return{type:`filter`,node:i};if(e.explicit&&(a==`FilterOp`||a==`filter`))return{type:`filter`};if(i.name==`TagName`)return{type:`tag`,node:i};if(e.explicit&&a==`{%`)return{type:`tag`};if(i.name==`PropertyName`&&i.parent.name==`MemberExpression`)return{type:`prop`,node:i,target:i.parent};if(i.name==`.`&&i.parent.name==`MemberExpression`)return{type:`prop`,target:i.parent};if(i.name==`MemberExpression`&&a==`.`)return{type:`prop`,target:i};if(i.name==`VariableName`)return{type:`expr`,from:i.from};if(i.name==`Comment`||i.name==`StringLiteral`||i.name==`NumberLiteral`)return null;let o=e.matchBefore(/[\w\u00c0-\uffff]+$/);return o?{type:`expr`,from:o.from}:e.explicit?{type:`expr`}:null}function F(e,t,n,r){let i=[];for(;;){let n=t.getChild(`Expression`);if(!n)return[];if(n.name==`VariableName`){i.unshift(e.sliceDoc(n.from,n.to));break}if(n.name==`MemberExpression`){let r=n.getChild(`PropertyName`);r&&i.unshift(e.sliceDoc(r.from,r.to)),t=n}else return[]}return r(i,e,n)}function I(e={}){let t=e.tags?e.tags.concat(N):N,n=e.variables?e.variables.concat(M):M,{properties:r}=e;return e=>{let i=P(e);if(!i)return null;let a=i.from??(i.node?i.node.from:e.pos),o;return o=i.type==`filter`?k:i.type==`tag`?t:i.type==`expr`?n:r?F(e.state,i.target,e,r):[],o.length?{options:o,from:a,validFor:/^[\w\u00c0-\uffff]*$/}:null}}var L=i.inputHandler.of((e,t,n,r)=>r!=`%`||t!=n||e.state.doc.sliceString(t-1,n+1)!=`{}`?!1:(e.dispatch(e.state.changeByRange(e=>({changes:{from:e.from,to:e.to,insert:`%%`},range:f.cursor(e.from+1)})),{scrollIntoView:!0,userEvent:`input.type`}),!0));function R(e){return t=>{let n=e.test(t.textAfter);return t.lineIndent(t.node.from)+(n?0:t.unit)}}var z=l.define({name:`jinja`,parser:D.configure({props:[r({"TagName raw endraw filter endfilter as trans pluralize endtrans with endwith autoescape endautoescape":p.keyword,"required scoped recursive with without context ignore missing":p.modifier,self:p.self,"loop super":p.standard(p.variableName),"if elif else endif for endfor call endcall":p.controlKeyword,"block endblock set endset macro endmacro import from include":p.definitionKeyword,"Comment/...":p.blockComment,VariableName:p.variableName,Definition:p.definition(p.variableName),PropertyName:p.propertyName,FilterName:p.special(p.variableName),ArithOp:p.arithmeticOperator,AssignOp:p.definitionOperator,"not and or":p.logicOperator,CompareOp:p.compareOperator,"in is":p.operatorKeyword,"FilterOp ConcatOp":p.operator,StringLiteral:p.string,NumberLiteral:p.number,BooleanLiteral:p.bool,"{% %} {# #} {{ }} { }":p.brace,"( )":p.paren,".":p.derefOperator,": , .":p.punctuation}),t.add({Tag:d({closing:`%}`}),"IfStatement ForStatement":R(/^\s*(\{%-?\s*)?(endif|endfor|else|elif)\b/),Statement:R(/^\s*(\{%-?\s*)?end\w/)}),e.add({"Statement Comment"(e){let t=e.firstChild,n=e.lastChild;return!t||t.name!=`Tag`&&t.name!=`{#`?null:{from:t.to,to:n.name==`EndTag`||n.name==`#}`?n.from:e.to}}})]}),languageData:{indentOnInput:/^\s*{%-?\s*(?:end|elif|else)$/}}),B=m();function V(e){return z.configure({wrap:s(t=>t.type.isTop?{parser:e.parser,overlay:e=>e.name==`Text`||e.name==`RawText`}:null)},`jinja`)}var H=V(B.language);function U(e={}){let t=e.base||B,n=t.language==B.language?H:V(t.language);return new u(n,[t.support,n.data.of({autocomplete:I(e)}),t.language.data.of({closeBrackets:{brackets:[`{`]}}),L])}export{U as jinja};
|