@lucidkiln/core 1.1.0 → 1.2.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/CHANGELOG.md +5 -0
- package/dist/{ast-1akLiy-A.d.ts → ast-DDhHuwaY.d.ts} +15 -22
- package/dist/ast-DDhHuwaY.d.ts.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/{environment-DkfrPazl.d.ts → environment-DBvRrOn0.d.ts} +15 -8
- package/dist/environment-DBvRrOn0.d.ts.map +1 -0
- package/dist/{format-CLCViAPn.js → format-Di6-GUtH.js} +4 -4
- package/dist/{format-CLCViAPn.js.map → format-Di6-GUtH.js.map} +1 -1
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +50 -147
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/{parser-BU5dThuk.js → parser-isboTef0.js} +59 -99
- package/dist/parser-isboTef0.js.map +1 -0
- package/dist/{source-BHcxowQp.js → source-BbikGqIb.js} +25 -97
- package/dist/source-BbikGqIb.js.map +1 -0
- package/dist/syntax.d.ts +1 -1
- package/dist/syntax.js +1 -1
- package/package.json +1 -1
- package/dist/ast-1akLiy-A.d.ts.map +0 -1
- package/dist/environment-DkfrPazl.d.ts.map +0 -1
- package/dist/parser-BU5dThuk.js.map +0 -1
- package/dist/source-BHcxowQp.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
- Inserted content is no longer re-indented to line up with its tag. ([46e6cae](https://github.com/buildlucid/kiln/commit/46e6cae3afbbc88ded8a19dcd9018f8559d4e7ce))
|
|
6
|
+
- `withRender` now keeps your function's type parameters, and `RenderAware` takes the whole function type. ([08f192c](https://github.com/buildlucid/kiln/commit/08f192cd0fcf7913039bd065d9ced29d5453a73a))
|
|
7
|
+
|
|
3
8
|
## 1.1.0
|
|
4
9
|
|
|
5
10
|
- New `KilnFunctions`, `KilnFilters`, `KilnTests` and `KilnGlobals` interfaces. Add your own to them so your editor can show their types. See [Types from TypeScript](https://kilnlang.com/docs/tooling/editors/#types-from-typescript). ([d55ef63](https://github.com/buildlucid/kiln/commit/d55ef63677df3b34ea247f3b9f25562b201a18b0))
|
|
@@ -184,18 +184,9 @@ type FilterCall = {
|
|
|
184
184
|
args: Argument[];
|
|
185
185
|
span: Span;
|
|
186
186
|
};
|
|
187
|
-
/**
|
|
188
|
-
* On a tag that inserts content, when it stands on a line of its own: the line's indentation in the output, which
|
|
189
|
-
* every inserted line gets on top of the indentation around it. See `indent.ts`.
|
|
190
|
-
*/
|
|
191
|
-
type Placement = {
|
|
192
|
-
indent?: string;
|
|
193
|
-
};
|
|
194
187
|
type Statement = {
|
|
195
188
|
type: "Text";
|
|
196
189
|
value: string;
|
|
197
|
-
/** Where lines start in `value`, which get the indentation of the content they are inserted into. */
|
|
198
|
-
lines?: number[];
|
|
199
190
|
span: Span;
|
|
200
191
|
} | {
|
|
201
192
|
type: "Output";
|
|
@@ -238,18 +229,18 @@ type Statement = {
|
|
|
238
229
|
type: "Extends";
|
|
239
230
|
template: Expression;
|
|
240
231
|
span: Span;
|
|
241
|
-
} |
|
|
232
|
+
} | {
|
|
242
233
|
type: "Block";
|
|
243
234
|
name: string;
|
|
244
235
|
body: Statement[];
|
|
245
236
|
span: Span;
|
|
246
|
-
}
|
|
237
|
+
} | {
|
|
247
238
|
type: "Include";
|
|
248
239
|
template: Expression;
|
|
249
240
|
with: Expression | null;
|
|
250
241
|
ignoreMissing: boolean;
|
|
251
242
|
span: Span;
|
|
252
|
-
}
|
|
243
|
+
} | {
|
|
253
244
|
type: "Component";
|
|
254
245
|
template: Expression;
|
|
255
246
|
with: Expression | null;
|
|
@@ -261,28 +252,30 @@ type Statement = {
|
|
|
261
252
|
/** Content outside any `fill`, which fills the default slot. */
|
|
262
253
|
body: Statement[];
|
|
263
254
|
span: Span;
|
|
264
|
-
}
|
|
255
|
+
} | {
|
|
265
256
|
type: "Slot";
|
|
266
257
|
name: string;
|
|
267
258
|
body: Statement[];
|
|
268
259
|
span: Span;
|
|
269
|
-
}
|
|
260
|
+
} |
|
|
270
261
|
/**
|
|
271
|
-
* A component that can load after the page. `body` is the fallback, shown until a deferred island loads.
|
|
272
|
-
*
|
|
273
|
-
* `island` tag
|
|
262
|
+
* A component that can load after the page. `body` is the fallback, shown until a deferred island loads. A deferred
|
|
263
|
+
* island writes its tags back as `<kiln-island>` lines where they stand on lines of their own. `indent` is set when
|
|
264
|
+
* the `island` tag does: its line's indentation. `closing` is set when `endisland` does: its indentation, or null
|
|
265
|
+
* when it shares that line with the `island` tag, and whether a line break followed it.
|
|
274
266
|
*/
|
|
275
|
-
|
|
267
|
+
{
|
|
276
268
|
type: "Island";
|
|
277
269
|
template: Expression;
|
|
278
270
|
with: Expression | null;
|
|
279
271
|
body: Statement[];
|
|
272
|
+
indent?: string;
|
|
280
273
|
closing?: {
|
|
281
274
|
indent: string | null;
|
|
282
275
|
newline: boolean;
|
|
283
276
|
};
|
|
284
277
|
span: Span;
|
|
285
|
-
}
|
|
278
|
+
} | {
|
|
286
279
|
type: "Macro";
|
|
287
280
|
name: string;
|
|
288
281
|
params: Param[];
|
|
@@ -309,11 +302,11 @@ type Statement = {
|
|
|
309
302
|
span: Span;
|
|
310
303
|
} |
|
|
311
304
|
/** A place other templates add content to with `add to`, filled when the render ends. */
|
|
312
|
-
|
|
305
|
+
{
|
|
313
306
|
type: "Outlet";
|
|
314
307
|
name: string;
|
|
315
308
|
span: Span;
|
|
316
|
-
}
|
|
309
|
+
} |
|
|
317
310
|
/** Closes the outlets reached so far, so a streamed render can send its output up to here. */
|
|
318
311
|
{
|
|
319
312
|
type: "Flush";
|
|
@@ -354,4 +347,4 @@ type TemplateNode = {
|
|
|
354
347
|
declare const TYPE_NAMES: readonly ["null", "boolean", "number", "string", "array", "hash", "set", "date", "markup", "object"];
|
|
355
348
|
//#endregion
|
|
356
349
|
export { HashEntry as a, PropType as c, Statement as d, TemplateNode as f, Span as g, Source as h, Expression as i, ShapeKey as l, Position as m, BinaryOperator as n, Param as o, TypeName as p, EscapeStrategy as r, PropParam as s, Argument as t, Spread as u };
|
|
357
|
-
//# sourceMappingURL=ast-
|
|
350
|
+
//# sourceMappingURL=ast-DDhHuwaY.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast-DDhHuwaY.d.ts","names":[],"sources":["../src/source.ts","../src/parser/ast.ts"],"mappings":";;KAGY;EAAS;EAAe;;KAExB;;EAEX;;EAEA;;EAEA;;;;;;;;cASY;;WAIF;WACA;EAFV,YACU,cACA;;EAIV,SAAS,iBAAiB;;;;;;;;;;EA0B1B,MAAM,MAAM,MAAM;;;;KCrDP;KAEA;KAyBA;EAAW;EAAgB,OAAO;EAAY,MAAM;;KAEpD;EACP;EAAoB,OAAO;EAAY,MAAM;;EAC7C;EAAe;EAAc,OAAO;EAAY,MAAM;IACxD;KAES;EACP;EAAkB,KAAK;EAAY,OAAO;EAAY,MAAM;IAC9D;KAES;EAET;EACA;EACA,MAAM;;EAEJ;EAAc;EAAc,MAAM;;;;EAElC;EAAuB,OAAO;EAAc,MAAM;;EAClD;EAAe,WAAW,aAAa;EAAW,MAAM;;EACxD;EAAc,SAAS;EAAa,MAAM;;EAE5C;EACA;EACA,SAAS;EACT,MAAM;;EAGN;EACA,UAAU;EACV,MAAM;EACN,OAAO;EACP,MAAM;;EAGN;EACA,MAAM;EACN,YAAY;EACZ,WAAW;EACX,MAAM;;EAGN;EACA,QAAQ;EACR,UAAU;;EAEV;EACA,MAAM;;EAEJ;EAAc,QAAQ;EAAY,MAAM;EAAY,MAAM;;EAE5D;EACA;EACA,UAAU;EACV,OAAO;EACP,MAAM;EACN,MAAM;;EAGN;EACA;EACA,UAAU;EACV,OAAO;EACP,MAAM;EACN;EACA,MAAM;;EAEJ;EAAe;EAAkB,MAAM;EAAY,MAAM;;;;EAEzD;EAAuB,YAAY;EAAY,MAAM;;;;EAErD;EAAiB,MAAM;;KAEhB;EAAU;EAAc,SAAS;EAAmB,MAAM;;;KAG1D,mBAAmB;;;;;;;;;;KAWnB,WACT;EACE;;EACA,MAAM;;EACN,OAAO;;EACP;;;KAGO;EAAa;EAAc;EAAmB,MAAM;;;KAGpD,YAAY;EAAU,MAAM;;KAE5B;EACX;EACA,MAAM;EACN,MAAM;;KAGK;EACP;EAAc;EAAe,MAAM;;EACnC;EAAgB,YAAY;EAAY,MAAM;;EAEhD;EACA;IAAY,MAAM;IAAY,MAAM;;EACpC,WAAW;EACX,MAAM;;EAGN;EACA;EACA;EACA,UAAU;EACV,MAAM;EACN,WAAW;EACX,MAAM;;EAEJ;EAAa;EAAc,OAAO;EAAY,MAAM;;EACpD;EAAkB;EAAc,MAAM;EAAa,MAAM;;;;EAEzD;EAAe,OAAO;EAAa;EAAqB,MAAM;;EAC9D;EAAiB,UAAU;EAAY,MAAM;;EAC7C;EAAe;EAAc,MAAM;EAAa,MAAM;;EAExD;EACA,UAAU;EACV,MAAM;EACN;EACA,MAAM;;EAGN;EACA,UAAU;EACV,MAAM;EACN;IAAS;IAAc,MAAM;IAAa,MAAM;;;EAEhD,MAAM;EACN,MAAM;;EAEJ;EAAc;EAAc,MAAM;EAAa,MAAM;;;;;;;;;EAQvD;EACA,UAAU;EACV,MAAM;EACN,MAAM;EACN;EACA;IAAY;IAAuB;;EACnC,MAAM;;EAGN;EACA;EACA,QAAQ;EACR,MAAM;EACN,MAAM;;EAEJ;EAAgB;EAAkB;EAAe,MAAM;;EAEzD;EACA;EACA;IAAS;IAAc;IAAe,MAAM;;EAC5C,MAAM;;EAEJ;EAAc,OAAO;EAAY,MAAM;EAAa,MAAM;;;;EAE1D;EAAgB;EAAc,MAAM;;;;EAEpC;EAAe,MAAM;;;;EAGvB;EACA;EACA;EACA,MAAM;EACN,MAAM;;;;EAIN;EACA,KAAK;EACL,SAAS;EACT,MAAM;EACN,MAAM;;EAEJ;EAAe,SAAS;EAAc,MAAM;EAAa,MAAM;;EAEjE;EACA,UAAU;EACV,MAAM;EACN,MAAM;;KAGG;EAAiB;EAAkB,MAAM;EAAa,MAAM;;;cAgB3D"}
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { n as format, t as KilnFormatError } from "./format-
|
|
2
|
+
import { an as KilnSyntaxError } from "./source-BbikGqIb.js";
|
|
3
|
+
import { n as format, t as KilnFormatError } from "./format-Di6-GUtH.js";
|
|
4
4
|
import { readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
5
5
|
import { join, relative, resolve } from "node:path";
|
|
6
6
|
import process from "node:process";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as PropType, g as Span, h as Source, m as Position, r as EscapeStrategy } from "./ast-
|
|
1
|
+
import { c as PropType, g as Span, h as Source, m as Position, r as EscapeStrategy } from "./ast-DDhHuwaY.js";
|
|
2
2
|
//#region src/errors.d.ts
|
|
3
3
|
type Diagnostic = {
|
|
4
4
|
/** A stable kebab-case code, such as `unknown-filter`. */
|
|
@@ -288,15 +288,22 @@ type TemplateBlock<Name extends string, Templates extends object = KilnTemplates
|
|
|
288
288
|
} ? Block : string;
|
|
289
289
|
declare const renderAware: unique symbol;
|
|
290
290
|
/**
|
|
291
|
-
*
|
|
292
|
-
*
|
|
291
|
+
* Any function that takes `RenderInfo` first. Written as a method so `render` can declare any state, while a `render`
|
|
292
|
+
* without a type gets `RenderInfo<unknown>`, or the environment's state inside `createKiln`.
|
|
293
293
|
*/
|
|
294
|
-
type
|
|
294
|
+
type RenderCall = {
|
|
295
|
+
call(render: RenderInfo<unknown>, ...args: never): unknown;
|
|
296
|
+
}["call"];
|
|
297
|
+
/**
|
|
298
|
+
* A host function that receives `RenderInfo` before its arguments. Create it with `withRender`. `Call` is the function's
|
|
299
|
+
* own type, type parameters included, so editors can show it and work out what each call returns.
|
|
300
|
+
*/
|
|
301
|
+
type RenderAware<Call extends RenderCall = RenderCall> = {
|
|
295
302
|
readonly [renderAware]: true;
|
|
296
|
-
readonly call:
|
|
303
|
+
readonly call: Call;
|
|
297
304
|
};
|
|
298
305
|
/** A function, filter or test a host registers. Parameter types are the host's to declare. */
|
|
299
|
-
type KilnCallable<State = undefined> = ((...args: never) => unknown) | RenderAware<State>;
|
|
306
|
+
type KilnCallable<State = undefined> = ((...args: never) => unknown) | RenderAware<(render: RenderInfo<State>, ...args: never) => unknown>;
|
|
300
307
|
type Limits = {
|
|
301
308
|
/** Characters of output, counted as string length. */
|
|
302
309
|
maxOutputLength: number;
|
|
@@ -383,7 +390,7 @@ type Kiln<State = undefined, Schema extends KilnSchema = DefaultSchema> = {
|
|
|
383
390
|
* document: withRender((render, collection: string) => fetchDocument(collection, render.state.locale))
|
|
384
391
|
* ```
|
|
385
392
|
*/
|
|
386
|
-
declare const withRender: <
|
|
393
|
+
declare const withRender: <Call extends RenderCall>(fn: Call) => RenderAware<Call>;
|
|
387
394
|
/**
|
|
388
395
|
* Creates a Kiln environment: the loader, functions, filters, tests, globals and options every render uses.
|
|
389
396
|
*
|
|
@@ -429,4 +436,4 @@ declare const memoryCache: ({ max }?: {
|
|
|
429
436
|
};
|
|
430
437
|
//#endregion
|
|
431
438
|
export { AbortSignalLike as A, islandScript as B, HtmlCheck as C, AnalysedProp as D, PrecompiledTemplate as E, IslandManifest as F, TemplateLocation as G, Diagnostic as H, IslandMode as I, JsonValue as L, RenderInfo as M, DeferredIslands as N, Analysis as O, IslandEntry as P, StreamedIslands as R, withRender as S, HtmlChecks as T, KilnRenderError as U, streamIslands as V, KilnSyntaxError as W, TemplateName as _, KilnGlobals as a, memoryCache as b, KilnTemplates as c, Limits as d, Loader as f, TemplateContext as g, TemplateBlock as h, KilnFunctions as i, KilnCache as j, TemplateReference as k, KilnTests as l, RenderOptions as m, KilnCallable as n, KilnOptions as o, RenderAware as p, KilnFilters as r, KilnSchema as s, Kiln as t, KilnTypes as u, TypeChecks as v, HtmlCheckLevel as w, memoryLoader as x, createKiln as y, deferIslands as z };
|
|
432
|
-
//# sourceMappingURL=environment-
|
|
439
|
+
//# sourceMappingURL=environment-DBvRrOn0.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-DBvRrOn0.d.ts","names":[],"sources":["../src/errors.ts","../src/runtime/islands.ts","../src/runtime/types.ts","../src/analyzer.ts","../src/compiler/precompiled.ts","../src/html/options.ts","../src/environment.ts"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { r as scanParts, t as parse } from "./parser-
|
|
1
|
+
import { an as KilnSyntaxError, on as createDiagnostic, r as builtinTests, t as Source } from "./source-BbikGqIb.js";
|
|
2
|
+
import { r as scanParts, t as parse } from "./parser-isboTef0.js";
|
|
3
3
|
//#region src/formatter/delimiters.ts
|
|
4
4
|
const KEYWORDS = /* @__PURE__ */ new Set([
|
|
5
5
|
"and",
|
|
@@ -652,7 +652,7 @@ const normaliseTree = (value) => {
|
|
|
652
652
|
if (typeof value !== "object" || value === null) return value;
|
|
653
653
|
const copy = {};
|
|
654
654
|
for (const [key, item] of Object.entries(value)) {
|
|
655
|
-
if (key === "span" || key === "nameSpan" || key === "
|
|
655
|
+
if (key === "span" || key === "nameSpan" || key === "indent") continue;
|
|
656
656
|
copy[key] = key === "value" && value.type === "Text" ? normaliseText(item) : normaliseTree(item);
|
|
657
657
|
}
|
|
658
658
|
return copy;
|
|
@@ -694,4 +694,4 @@ const format = (text, options = {}) => applyEdits(text, formatEdits(text, option
|
|
|
694
694
|
//#endregion
|
|
695
695
|
export { format as n, formatEdits as r, KilnFormatError as t };
|
|
696
696
|
|
|
697
|
-
//# sourceMappingURL=format-
|
|
697
|
+
//# sourceMappingURL=format-Di6-GUtH.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-CLCViAPn.js","names":[],"sources":["../src/formatter/delimiters.ts","../src/formatter/format.ts"],"sourcesContent":["import type { DelimitedPart, Token } from \"../lexer/lexer.js\";\n\n/** A token as the formatter prints it: its source text, unchanged. An interpolated string is one piece. */\ntype Piece = {\n\ttype: Token[\"type\"];\n\ttext: string;\n\tstart: number;\n\tend: number;\n};\n\n/**\n * What a piece does, where that changes its spacing.\n *\n * - `word`: a name, number or string.\n * - `keyword`: a tag's name, or a name such as `and` or `in`. A bracket after it groups rather than calls.\n * - `unary`: a sign that makes a number negative or positive, written against its operand.\n * - `tight`: `.`, `?.`, `..` and a filter's `|`, with no space either side.\n * - `key`: the colon after a key or named argument, or `?` and `?:` marking an optional key in `props`.\n * - `call`: a bracket that calls or indexes the piece before it.\n * - `open`, `close`: other brackets.\n * - `spaced`: operators with a space either side.\n */\ntype Role =\n\t| \"word\"\n\t| \"keyword\"\n\t| \"unary\"\n\t| \"tight\"\n\t| \"key\"\n\t| \"call\"\n\t| \"open\"\n\t| \"close\"\n\t| \"comma\"\n\t| \"spread\"\n\t| \"spaced\";\n\nconst KEYWORDS = new Set([\n\t\"and\",\n\t\"or\",\n\t\"not\",\n\t\"in\",\n\t\"is\",\n\t\"starts\",\n\t\"ends\",\n\t\"with\",\n\t\"as\",\n\t\"import\",\n\t\"ignore\",\n\t\"missing\",\n]);\n\n/** Joins each interpolated string's tokens, from `stringStart` to its matching `stringEnd`, into one piece. */\nconst toPieces = (source: string, tokens: readonly Token[]): Piece[] => {\n\tconst pieces: Piece[] = [];\n\tfor (let index = 0; index < tokens.length; index++) {\n\t\tconst token = tokens[index] as Token;\n\t\tlet end = token.end;\n\t\tif (token.type === \"stringStart\") {\n\t\t\tlet depth = 0;\n\t\t\tfor (; index < tokens.length; index++) {\n\t\t\t\tconst inner = tokens[index] as Token;\n\t\t\t\tif (inner.type === \"stringStart\") depth++;\n\t\t\t\telse if (inner.type === \"stringEnd\" && --depth === 0) break;\n\t\t\t}\n\t\t\tend = (tokens[Math.min(index, tokens.length - 1)] as Token).end;\n\t\t}\n\t\tpieces.push({\n\t\t\ttype: token.type === \"stringStart\" ? \"string\" : token.type,\n\t\t\ttext: source.slice(token.start, end),\n\t\t\tstart: token.start,\n\t\t\tend,\n\t\t});\n\t}\n\treturn pieces;\n};\n\n/** Works out each piece's role. `isTag` means the first piece is a tag's name. */\nconst rolesOf = (pieces: readonly Piece[], isTag: boolean): Role[] => {\n\tconst roles: Role[] = [];\n\t// In `props`, `|` joins types and `?:` marks an optional key, until `=` starts a default value.\n\tconst props = isTag && pieces[0]?.text === \"props\";\n\tlet inDefault = false;\n\t// Open `?`s at each bracket depth, so a conditional's `:` can be told from a key's.\n\tconst conditionals: number[] = [0];\n\n\tfor (const [index, piece] of pieces.entries()) {\n\t\tconst previous = roles[index - 1];\n\t\tconst depth = conditionals.length - 1;\n\t\tconst types = props && !inDefault;\n\t\tlet role: Role;\n\n\t\tif (piece.type !== \"punct\") {\n\t\t\trole =\n\t\t\t\t(isTag && index === 0) ||\n\t\t\t\t(piece.type === \"name\" && KEYWORDS.has(piece.text))\n\t\t\t\t\t? \"keyword\"\n\t\t\t\t\t: \"word\";\n\t\t} else {\n\t\t\tswitch (piece.text) {\n\t\t\t\tcase \"(\":\n\t\t\t\tcase \"[\":\n\t\t\t\t\trole = previous === \"word\" || previous === \"close\" ? \"call\" : \"open\";\n\t\t\t\t\tconditionals.push(0);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"{\":\n\t\t\t\t\trole = \"open\";\n\t\t\t\t\tconditionals.push(0);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \")\":\n\t\t\t\tcase \"]\":\n\t\t\t\tcase \"}\":\n\t\t\t\t\trole = \"close\";\n\t\t\t\t\tif (conditionals.length > 1) conditionals.pop();\n\t\t\t\t\tbreak;\n\t\t\t\tcase \",\":\n\t\t\t\t\trole = \"comma\";\n\t\t\t\t\tif (props && depth === 0) inDefault = false;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"...\":\n\t\t\t\t\trole = \"spread\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \".\":\n\t\t\t\tcase \"?.\":\n\t\t\t\tcase \"..\":\n\t\t\t\t\trole = \"tight\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"|\":\n\t\t\t\t\trole = types ? \"spaced\" : \"tight\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"-\":\n\t\t\t\tcase \"+\":\n\t\t\t\t\trole =\n\t\t\t\t\t\tprevious === undefined ||\n\t\t\t\t\t\t(previous !== \"word\" && previous !== \"close\")\n\t\t\t\t\t\t\t? \"unary\"\n\t\t\t\t\t\t\t: \"spaced\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"?\":\n\t\t\t\tcase \"?:\":\n\t\t\t\t\trole = types ? \"key\" : \"spaced\";\n\t\t\t\t\tif (piece.text === \"?\" && !types) {\n\t\t\t\t\t\tconditionals[depth] = (conditionals[depth] ?? 0) + 1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \":\":\n\t\t\t\t\tif ((conditionals[depth] ?? 0) > 0) {\n\t\t\t\t\t\tconditionals[depth] = (conditionals[depth] ?? 0) - 1;\n\t\t\t\t\t\trole = \"spaced\";\n\t\t\t\t\t} else role = \"key\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\trole = \"spaced\";\n\t\t\t\t\tif (props && depth === 0 && piece.text === \"=\") inDefault = true;\n\t\t\t}\n\t\t}\n\t\troles.push(role);\n\t}\n\treturn roles;\n};\n\n/** The gap between two pieces: a space or nothing. */\nconst gapBetween = (\n\tprevious: Piece,\n\tpreviousRole: Role,\n\tpiece: Piece,\n\trole: Role,\n): string => {\n\tif (role === \"comma\" || role === \"tight\" || role === \"key\" || role === \"call\")\n\t\treturn \"\";\n\tif (role === \"close\") {\n\t\treturn piece.text === \"}\" && previous.text !== \"{\" ? \" \" : \"\";\n\t}\n\tif (previousRole === \"tight\" || previousRole === \"unary\") return \"\";\n\tif (previousRole === \"spread\") return \"\";\n\tif (previousRole === \"open\" || previousRole === \"call\") {\n\t\treturn previous.text === \"{\" ? \" \" : \"\";\n\t}\n\treturn \" \";\n};\n\n/**\n * Prints one output or tag with normalised spacing. Line breaks between tokens stay; each line after one is indented from `indent`, one step further or to match the brackets it sits inside, using `unit` per step.\n *\n * Returns null for a delimiter that never closed, which the formatter leaves as it is.\n */\nexport const printDelimiter = (\n\tsource: string,\n\tpart: DelimitedPart,\n\tindent: string,\n\tunit: string,\n): string | null => {\n\tconst tokens = part.tokens;\n\tconst open = tokens[0];\n\tconst close = tokens[tokens.length - 1];\n\tif (!open || !close || close.value === \"\" || tokens.length < 3) return null;\n\n\tconst pieces = toPieces(source, tokens.slice(1, -1));\n\tconst roles = rolesOf(pieces, part.kind === \"tag\");\n\tlet out = open.value;\n\tlet previousEnd = part.start + open.value.length;\n\t// The line each open bracket started on. Brackets opened on the same line add one step between them.\n\tconst openedOn: number[] = [];\n\tlet line = 0;\n\t/** Steps of indentation for a new line, once `closers` brackets at its start have closed. */\n\tconst steps = (closers: number) =>\n\t\tnew Set(openedOn.slice(0, openedOn.length - closers)).size;\n\n\tfor (const [index, piece] of pieces.entries()) {\n\t\tconst role = roles[index] as Role;\n\t\tconst gap = source.slice(previousEnd, piece.start);\n\t\tif (gap.includes(\"\\n\")) {\n\t\t\tline++;\n\t\t\t// Closing brackets at the start of a line line up with the line that opened them. Only those on this line count.\n\t\t\tlet closers = 0;\n\t\t\twhile (\n\t\t\t\troles[index + closers] === \"close\" &&\n\t\t\t\t(closers === 0 ||\n\t\t\t\t\t!source\n\t\t\t\t\t\t.slice(\n\t\t\t\t\t\t\t(pieces[index + closers - 1] as Piece).end,\n\t\t\t\t\t\t\t(pieces[index + closers] as Piece).start,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.includes(\"\\n\"))\n\t\t\t) {\n\t\t\t\tclosers++;\n\t\t\t}\n\t\t\tout += `\\n${indent}${unit.repeat(closers > 0 ? steps(closers) : Math.max(steps(0), 1))}`;\n\t\t} else if (index === 0) out += \" \";\n\t\telse {\n\t\t\tout += gapBetween(\n\t\t\t\tpieces[index - 1] as Piece,\n\t\t\t\troles[index - 1] as Role,\n\t\t\t\tpiece,\n\t\t\t\trole,\n\t\t\t);\n\t\t}\n\t\tout += piece.text;\n\t\tif (role === \"open\" || role === \"call\") openedOn.push(line);\n\t\telse if (role === \"close\") openedOn.pop();\n\t\tpreviousEnd = piece.end;\n\t}\n\n\tconst closeStart = part.end - close.value.length;\n\tout += source.slice(previousEnd, closeStart).includes(\"\\n\")\n\t\t? `\\n${indent}`\n\t\t: \" \";\n\treturn out + close.value;\n};\n","import { builtinTests } from \"../builtins/functions.js\";\nimport { KilnSyntaxError } from \"../errors.js\";\nimport { createDiagnostic } from \"../errors.js\";\nimport { type DelimitedPart, type Part, scanParts } from \"../lexer/lexer.js\";\nimport { parse } from \"../parser/parser.js\";\nimport { Source } from \"../source.js\";\nimport { printDelimiter } from \"./delimiters.js\";\n\nexport type FormatOptions = {\n\t/** Indent with tabs. Default `true`. */\n\tuseTabs?: boolean;\n\t/** Spaces per step without tabs, and the width of a tab when moving lines. A whole number of at least 1. Default `4`. */\n\ttabWidth?: number;\n\t/** Only format lines that overlap this range of offsets. */\n\trange?: { start: number; end: number };\n};\n\n/** Replace `start` to `end` of the original source with `text`. */\nexport type FormatEdit = { start: number; end: number; text: string };\n\n/** Thrown when formatting would have changed what a template renders. That is a bug in the formatter. */\nexport class KilnFormatError extends Error {\n\toverride name = \"KilnFormatError\";\n}\n\n/**\n * How the formatter treats one line.\n *\n * - `indent`: set its indentation to `level` steps.\n * - `shift`: move it by as much as line `anchor` moved, keeping its own indentation relative to it. For scripts, styles and comments.\n * - `keep`: leave it alone, for `<pre>`, `<textarea>`, `verbatim`, text inside attribute values, and the body of a `set` or `apply` whose tag shares its line.\n * - `inside`: it starts inside an output or tag, which `printDelimiter` indents.\n */\ntype Line =\n\t| { kind: \"indent\"; start: number; level: number }\n\t| { kind: \"shift\"; start: number; anchor: number }\n\t| { kind: \"keep\" | \"inside\"; start: number };\n\ntype Frame = { kind: \"kiln\" | \"html\"; name: string };\n\n/**\n * Where the scanner is in the HTML.\n *\n * - `tag`: inside `<name ...>` or `</name>`, which started on line `line`. `inner` counts block tags open inside it.\n * - `raw`: inside `<script>` or `<style>`, or kept as written inside `<pre>`, `<textarea>` and the like.\n * - `kept`: inside the body of block tag `name`, output as written: `verbatim`, or a `set` or `apply` whose tag shares\n * its line, where Kiln doesn't remove the body's indentation. `depth` counts the tags of that name open.\n */\ntype Mode =\n\t| { kind: \"data\" }\n\t| {\n\t\t\tkind: \"tag\";\n\t\t\tname: string;\n\t\t\tclosing: boolean;\n\t\t\tquote: string | null;\n\t\t\tline: number;\n\t\t\tatLineStart: boolean;\n\t\t\tinner: number;\n\t }\n\t| { kind: \"comment\"; anchor: number; level: number }\n\t| { kind: \"raw\"; name: string; keep: boolean; anchor: number; level: number }\n\t| { kind: \"kept\"; name: string; depth: number; level: number };\n\nconst VOID_ELEMENTS = new Set([\n\t\"area\",\n\t\"base\",\n\t\"br\",\n\t\"col\",\n\t\"embed\",\n\t\"hr\",\n\t\"img\",\n\t\"input\",\n\t\"link\",\n\t\"meta\",\n\t\"source\",\n\t\"track\",\n\t\"wbr\",\n]);\n\n/** Elements written in `<script>` or `<style>`'s own language, whose lines move together. */\nconst RAW_ELEMENTS = new Set([\"script\", \"style\"]);\n/** Elements whose whitespace shows on the page. Nothing closes `<plaintext>`. */\nconst KEPT_ELEMENTS = new Set([\n\t\"pre\",\n\t\"textarea\",\n\t\"xmp\",\n\t\"listing\",\n\t\"plaintext\",\n]);\n\n/** Whether `</name` starts at `index`, as a whole tag name. */\nconst closesElement = (text: string, index: number, name: string): boolean => {\n\tif (name === \"plaintext\") return false;\n\tconst end = index + 2 + name.length;\n\treturn (\n\t\ttext.slice(index, end).toLowerCase() === `</${name}` &&\n\t\t(end === text.length || /[\\s/>]/.test(text[end] as string))\n\t);\n};\n\n/**\n * Whether a line starting with `trimmed` begins with the tag that ends the outermost `kept` body, and the formatter\n * may indent it. It may when Kiln removes the whitespace before the tag: a `-` trim marker, or a tag alone on its line.\n */\nconst endsKept = (\n\ttrimmed: string,\n\tmode: Extract<Mode, { kind: \"kept\" }>,\n): boolean => {\n\tconst match = /^\\{%(-?)\\s*end([A-Za-z]+)\\s*-?%\\}([^\\n]*)/.exec(trimmed);\n\treturn (\n\t\tmatch !== null &&\n\t\tmatch[2] === mode.name &&\n\t\tmode.depth === 1 &&\n\t\t(match[1] === \"-\" || /^[ \\t\\r]*$/.test(match[3] as string))\n\t);\n};\n\n/** Elements that the next of these siblings closes, such as a `<li>` without `</li>`. */\nconst CLOSED_BY: Record<string, readonly string[]> = {\n\tli: [\"li\"],\n\tdt: [\"dt\", \"dd\"],\n\tdd: [\"dt\", \"dd\"],\n\tp: [\"p\"],\n\toption: [\"option\"],\n\ttr: [\"tr\"],\n\ttd: [\"td\", \"th\"],\n\tth: [\"td\", \"th\"],\n\tthead: [\"tbody\", \"tfoot\"],\n\ttbody: [\"tbody\", \"tfoot\"],\n};\n\n/** Block tags that hold a body, and so indent what follows. */\nconst BLOCK_TAGS = new Set([\n\t\"if\",\n\t\"for\",\n\t\"set\",\n\t\"block\",\n\t\"component\",\n\t\"fill\",\n\t\"slot\",\n\t\"macro\",\n\t\"with\",\n\t\"cache\",\n\t\"island\",\n\t\"add\",\n\t\"apply\",\n\t\"autoescape\",\n\t\"verbatim\",\n]);\n\n/** What a tag does to indentation: opens a body, starts another branch of one, closes one, or nothing. */\nconst roleOf = (\n\tpart: DelimitedPart,\n): { kind: \"open\" | \"close\"; name: string } | { kind: \"branch\" } | null => {\n\tconst name = part.tokens[1];\n\tif (name?.type !== \"name\") return null;\n\tif (BLOCK_TAGS.has(name.value)) {\n\t\tif (\n\t\t\tname.value === \"set\" &&\n\t\t\tpart.tokens.some((token) => token.type === \"punct\" && token.value === \"=\")\n\t\t) {\n\t\t\treturn null;\n\t\t}\n\t\t// `{% block title page.title %}` is the short form, with no body.\n\t\tif (name.value === \"block\" && part.tokens.length > 4) return null;\n\t\treturn { kind: \"open\", name: name.value };\n\t}\n\tif (name.value === \"else\" || name.value === \"elseif\")\n\t\treturn { kind: \"branch\" };\n\tif (name.value.startsWith(\"end\")) {\n\t\treturn { kind: \"close\", name: name.value.slice(3) };\n\t}\n\treturn null;\n};\n\nconst isLetter = (char: string | undefined) =>\n\tchar !== undefined && /[A-Za-z]/.test(char);\n\nconst isTest = (name: string) => Object.hasOwn(builtinTests, name);\n\n/** The start offset of every line. */\nconst lineStarts = (text: string): number[] => {\n\tconst starts = [0];\n\tfor (let index = text.indexOf(\"\\n\"); index !== -1;) {\n\t\tstarts.push(index + 1);\n\t\tindex = text.indexOf(\"\\n\", index + 1);\n\t}\n\treturn starts;\n};\n\n/**\n * Walks the template once, tracking open block tags and HTML elements, and decides how to treat each line.\n *\n * Returns the lines, which lines may lose trailing whitespace, and the outputs and tags to print.\n */\nconst planLines = (text: string, parts: readonly Part[]) => {\n\tconst starts = lineStarts(text);\n\tconst lines: Line[] = [];\n\tconst trimEnd: boolean[] = [];\n\tconst stack: Frame[] = [];\n\tlet mode: Mode = { kind: \"data\" };\n\tlet atLineStart = true;\n\t// A line that starts where the next part does, recorded when that part begins.\n\tlet pendingLine = -1;\n\n\tconst lineText = (index: number) =>\n\t\ttext.slice(starts[index], starts[index + 1] ?? text.length);\n\t/** Whether only spaces and tabs come between `offset` and the end of its line. */\n\tconst endsLine = (offset: number) => {\n\t\tlet index = offset;\n\t\twhile (index < text.length && \" \\t\\r\".includes(text[index] as string)) {\n\t\t\tindex++;\n\t\t}\n\t\treturn index === text.length || text[index] === \"\\n\";\n\t};\n\tconst current = () => lines.length - 1;\n\n\t/** Lowers the current line's level when a closing tag comes before anything else on it. */\n\tconst outdent = (line: number, level: number, first: boolean) => {\n\t\tconst info = lines[line];\n\t\tif (first && info?.kind === \"indent\") {\n\t\t\tinfo.level = Math.min(info.level, level);\n\t\t}\n\t};\n\n\tconst levelOf = (line: number): number => {\n\t\tconst info = lines[line];\n\t\treturn info?.kind === \"indent\" ? info.level : stack.length;\n\t};\n\n\t/** Records how to treat the line that starts at `start`, from the current state. */\n\tconst beginLine = (start: number) => {\n\t\tconst index = lines.length;\n\t\tconst trimmed = lineText(index).trimStart();\n\t\tatLineStart = true;\n\t\tswitch (mode.kind) {\n\t\t\tcase \"data\":\n\t\t\t\tlines.push({ kind: \"indent\", start, level: stack.length });\n\t\t\t\treturn;\n\t\t\tcase \"tag\": {\n\t\t\t\tif (mode.quote !== null) {\n\t\t\t\t\tlines.push({ kind: \"keep\", start });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst base = levelOf(mode.line);\n\t\t\t\tconst level =\n\t\t\t\t\ttrimmed.startsWith(\">\") || trimmed.startsWith(\"/>\")\n\t\t\t\t\t\t? base\n\t\t\t\t\t\t: base + 1 + mode.inner;\n\t\t\t\tlines.push({ kind: \"indent\", start, level });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"comment\":\n\t\t\t\tlines.push(\n\t\t\t\t\ttrimmed.startsWith(\"-->\")\n\t\t\t\t\t\t? { kind: \"indent\", start, level: mode.level }\n\t\t\t\t\t\t: { kind: \"shift\", start, anchor: mode.anchor },\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\tcase \"raw\":\n\t\t\t\tif (mode.keep) lines.push({ kind: \"keep\", start });\n\t\t\t\telse if (closesElement(trimmed, 0, mode.name)) {\n\t\t\t\t\tlines.push({ kind: \"indent\", start, level: mode.level });\n\t\t\t\t} else lines.push({ kind: \"shift\", start, anchor: mode.anchor });\n\t\t\t\treturn;\n\t\t\tcase \"kept\":\n\t\t\t\tlines.push(\n\t\t\t\t\tendsKept(trimmed, mode)\n\t\t\t\t\t\t? { kind: \"indent\", start, level: mode.level }\n\t\t\t\t\t\t: { kind: \"keep\", start },\n\t\t\t\t);\n\t\t}\n\t};\n\n\t/** Whether trailing whitespace on a line ending here can go. Not inside attribute values or kept elements. */\n\tconst canTrimHere = () =>\n\t\t!(mode.kind === \"tag\" && mode.quote !== null) &&\n\t\t!(mode.kind === \"raw\" && mode.keep) &&\n\t\tmode.kind !== \"kept\";\n\n\tconst finishTag = (\n\t\ttag: Extract<Mode, { kind: \"tag\" }>,\n\t\tselfClosing: boolean,\n\t) => {\n\t\tmode = { kind: \"data\" };\n\t\tconst name = tag.name;\n\t\tif (tag.closing) {\n\t\t\t// Close the nearest open element of this name, without crossing a block tag.\n\t\t\tfor (let index = stack.length - 1; index >= 0; index--) {\n\t\t\t\tconst frame = stack[index] as Frame;\n\t\t\t\tif (frame.kind === \"kiln\") break;\n\t\t\t\tif (frame.name === name) {\n\t\t\t\t\tstack.length = index;\n\t\t\t\t\toutdent(tag.line, index, tag.atLineStart);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (name.startsWith(\"!\") || selfClosing || VOID_ELEMENTS.has(name)) return;\n\t\tif (RAW_ELEMENTS.has(name) || KEPT_ELEMENTS.has(name)) {\n\t\t\tmode = {\n\t\t\t\tkind: \"raw\",\n\t\t\t\tname,\n\t\t\t\tkeep: KEPT_ELEMENTS.has(name),\n\t\t\t\tanchor: tag.line,\n\t\t\t\tlevel: stack.length,\n\t\t\t};\n\t\t\treturn;\n\t\t}\n\t\tconst top = stack[stack.length - 1];\n\t\tif (top?.kind === \"html\" && CLOSED_BY[top.name]?.includes(name)) {\n\t\t\tstack.pop();\n\t\t\toutdent(tag.line, stack.length, tag.atLineStart);\n\t\t}\n\t\tstack.push({ kind: \"html\", name });\n\t};\n\n\t/** Starts a tag at `index` if one starts there, and returns where scanning continues. */\n\tconst startTag = (index: number, closing: boolean): number => {\n\t\tconst nameStart = index + (closing ? 2 : 1);\n\t\tlet nameEnd = nameStart;\n\t\twhile (\n\t\t\tnameEnd < text.length &&\n\t\t\t/[A-Za-z0-9:!_-]/.test(text[nameEnd] as string)\n\t\t) {\n\t\t\tnameEnd++;\n\t\t}\n\t\tmode = {\n\t\t\tkind: \"tag\",\n\t\t\tname: text.slice(nameStart, nameEnd).toLowerCase(),\n\t\t\tclosing,\n\t\t\tquote: null,\n\t\t\tline: current(),\n\t\t\tatLineStart,\n\t\t\tinner: 0,\n\t\t};\n\t\tatLineStart = false;\n\t\treturn nameEnd;\n\t};\n\n\t/** Moves through a text part one character at a time. */\n\tconst scanText = (start: number, end: number) => {\n\t\tfor (let index = start; index < end; index++) {\n\t\t\tconst char = text[index] as string;\n\t\t\tif (char === \"\\n\") {\n\t\t\t\ttrimEnd[current()] = canTrimHere();\n\t\t\t\tif (index + 1 < end) beginLine(index + 1);\n\t\t\t\telse if (index + 1 === text.length) {\n\t\t\t\t\t// The file ends with a line break: there is no further line.\n\t\t\t\t} else pendingLine = index + 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tswitch (mode.kind) {\n\t\t\t\tcase \"data\":\n\t\t\t\t\tif (char === \" \" || char === \"\\t\" || char === \"\\r\") break;\n\t\t\t\t\tif (char === \"<\") {\n\t\t\t\t\t\tif (text.startsWith(\"<!--\", index)) {\n\t\t\t\t\t\t\tmode = {\n\t\t\t\t\t\t\t\tkind: \"comment\",\n\t\t\t\t\t\t\t\tanchor: current(),\n\t\t\t\t\t\t\t\tlevel: levelOf(current()),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tatLineStart = false;\n\t\t\t\t\t\t\tindex += 3;\n\t\t\t\t\t\t} else if (text[index + 1] === \"/\" && isLetter(text[index + 2])) {\n\t\t\t\t\t\t\tindex = startTag(index, true) - 1;\n\t\t\t\t\t\t} else if (isLetter(text[index + 1]) || text[index + 1] === \"!\") {\n\t\t\t\t\t\t\tindex = startTag(index, false) - 1;\n\t\t\t\t\t\t} else atLineStart = false;\n\t\t\t\t\t} else atLineStart = false;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"tag\":\n\t\t\t\t\tif (mode.quote !== null) {\n\t\t\t\t\t\tif (char === mode.quote) mode.quote = null;\n\t\t\t\t\t} else if (char === '\"' || char === \"'\") mode.quote = char;\n\t\t\t\t\telse if (char === \">\") finishTag(mode, text[index - 1] === \"/\");\n\t\t\t\t\telse if (char !== \" \" && char !== \"\\t\" && char !== \"\\r\") {\n\t\t\t\t\t\tatLineStart = false;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"comment\":\n\t\t\t\t\tif (text.startsWith(\"-->\", index)) {\n\t\t\t\t\t\tmode = { kind: \"data\" };\n\t\t\t\t\t\tindex += 2;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"raw\":\n\t\t\t\t\tif (char === \"<\" && closesElement(text, index, mode.name)) {\n\t\t\t\t\t\tindex = startTag(index, true) - 1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"kept\":\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t};\n\n\t/** Applies a block tag to the stack, or to the count of block tags open inside an HTML tag. */\n\tconst applyTag = (part: DelimitedPart) => {\n\t\tconst role = roleOf(part);\n\t\tconst first = atLineStart;\n\t\tatLineStart = false;\n\t\tif (!role) return;\n\t\tif (mode.kind === \"tag\") {\n\t\t\tconst base = levelOf(mode.line) + 1;\n\t\t\tif (role.kind === \"open\") mode.inner++;\n\t\t\telse if (role.kind === \"close\") {\n\t\t\t\tmode.inner = Math.max(0, mode.inner - 1);\n\t\t\t\toutdent(current(), base + mode.inner, first);\n\t\t\t} else outdent(current(), base + mode.inner - 1, first);\n\t\t\treturn;\n\t\t}\n\t\tif (mode.kind === \"kept\") {\n\t\t\tif (role.kind === \"open\" && role.name === mode.name) mode.depth++;\n\t\t\telse if (\n\t\t\t\trole.kind === \"close\" &&\n\t\t\t\trole.name === mode.name &&\n\t\t\t\t--mode.depth === 0\n\t\t\t) {\n\t\t\t\tconst index = stack.findLastIndex((frame) => frame.kind === \"kiln\");\n\t\t\t\tif (index !== -1) stack.length = index;\n\t\t\t\tmode = { kind: \"data\" };\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (mode.kind !== \"data\") return;\n\t\tif (role.kind === \"open\") {\n\t\t\tstack.push({ kind: \"kiln\", name: role.name });\n\t\t\tif (\n\t\t\t\trole.name === \"verbatim\" ||\n\t\t\t\t((role.name === \"set\" || role.name === \"apply\") &&\n\t\t\t\t\t!(first && endsLine(part.end)))\n\t\t\t) {\n\t\t\t\tmode = {\n\t\t\t\t\tkind: \"kept\",\n\t\t\t\t\tname: role.name,\n\t\t\t\t\tdepth: 1,\n\t\t\t\t\tlevel: stack.length - 1,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tconst index =\n\t\t\trole.kind === \"branch\"\n\t\t\t\t? stack.findLastIndex((frame) => frame.kind === \"kiln\")\n\t\t\t\t: stack.findLastIndex(\n\t\t\t\t\t\t(frame) => frame.kind === \"kiln\" && frame.name === role.name,\n\t\t\t\t\t);\n\t\tif (index === -1) return;\n\t\t// Elements opened in this body or branch end with it.\n\t\tstack.length = role.kind === \"branch\" ? index + 1 : index;\n\t\toutdent(current(), index, first);\n\t};\n\n\tbeginLine(0);\n\tconst delimiters: { part: DelimitedPart; line: number }[] = [];\n\n\tfor (const part of parts) {\n\t\tif (pendingLine !== -1) {\n\t\t\tbeginLine(pendingLine);\n\t\t\tpendingLine = -1;\n\t\t}\n\t\tif (part.kind === \"text\") {\n\t\t\tscanText(part.start, part.end);\n\t\t\tcontinue;\n\t\t}\n\t\tconst line = current();\n\t\tif (part.kind === \"comment\") atLineStart = false;\n\t\telse {\n\t\t\tdelimiters.push({ part, line });\n\t\t\tif (part.kind === \"tag\") applyTag(part);\n\t\t\telse atLineStart = false;\n\t\t}\n\t\t// Lines that start inside this delimiter.\n\t\tfor (\n\t\t\tlet index = text.indexOf(\"\\n\", part.start);\n\t\t\tindex !== -1 && index < part.end;\n\t\t\tindex = text.indexOf(\"\\n\", index + 1)\n\t\t) {\n\t\t\ttrimEnd[current()] = part.kind === \"comment\";\n\t\t\tlines.push(\n\t\t\t\tpart.kind === \"comment\"\n\t\t\t\t\t? { kind: \"shift\", start: index + 1, anchor: line }\n\t\t\t\t\t: { kind: \"inside\", start: index + 1 },\n\t\t\t);\n\t\t}\n\t}\n\ttrimEnd[current()] ??= canTrimHere();\n\treturn { lines, trimEnd, delimiters };\n};\n\nconst widthOf = (whitespace: string, tabWidth: number): number => {\n\tlet width = 0;\n\tfor (const char of whitespace) width += char === \"\\t\" ? tabWidth : 1;\n\treturn width;\n};\n\n/**\n * Works out the edits that format a template, without checking them. See `formatEdits`.\n */\nconst planEdits = (\n\ttext: string,\n\tparts: readonly Part[],\n\toptions: Required<Omit<FormatOptions, \"range\">>,\n): FormatEdit[] => {\n\tconst { useTabs, tabWidth } = options;\n\tconst unit = useTabs ? \"\\t\" : \" \".repeat(tabWidth);\n\tconst indentOfWidth = (width: number) =>\n\t\tuseTabs\n\t\t\t? \"\\t\".repeat(Math.floor(width / tabWidth)) + \" \".repeat(width % tabWidth)\n\t\t\t: \" \".repeat(width);\n\tconst { lines, trimEnd, delimiters } = planLines(text, parts);\n\n\tconst oldIndent = (line: number) => {\n\t\tconst start = lines[line]?.start ?? 0;\n\t\tlet end = start;\n\t\twhile (text[end] === \" \" || text[end] === \"\\t\") end++;\n\t\treturn text.slice(start, end);\n\t};\n\t/** Where a line's content ends: at its line break, or the end of the file. */\n\tconst lineEnd = (line: number) => {\n\t\tconst next = lines[line + 1]?.start;\n\t\tif (next !== undefined) return next - 1;\n\t\treturn text.endsWith(\"\\n\") ? text.length - 1 : text.length;\n\t};\n\tconst isBlank = (line: number) => {\n\t\tconst info = lines[line] as Line;\n\t\treturn (\n\t\t\tinfo.kind !== \"keep\" &&\n\t\t\tinfo.kind !== \"inside\" &&\n\t\t\ttext.slice(info.start, lineEnd(line)).trim() === \"\"\n\t\t);\n\t};\n\n\t// Whitespace before the first content and after the last is output as written wherever the template is placed, so\n\t// it stays as it is, as does a file of only whitespace.\n\tlet firstContent = 0;\n\twhile (firstContent < lines.length && isBlank(firstContent)) firstContent++;\n\tlet lastContent = lines.length - 1;\n\twhile (lastContent >= 0 && isBlank(lastContent)) lastContent--;\n\n\tconst newIndents = new Map<number, string | null>();\n\tconst newIndent = (line: number): string | null => {\n\t\tif (newIndents.has(line)) return newIndents.get(line) ?? null;\n\t\tconst info = lines[line];\n\t\tlet indent: string | null = null;\n\t\tif (info?.kind === \"indent\") {\n\t\t\t// The first content line keeps its indentation. See `firstContent`.\n\t\t\tindent =\n\t\t\t\tline === firstContent ? oldIndent(line) : unit.repeat(info.level);\n\t\t} else if (info?.kind === \"shift\") {\n\t\t\tconst anchor = newIndent(info.anchor);\n\t\t\tconst moved =\n\t\t\t\tanchor === null\n\t\t\t\t\t? 0\n\t\t\t\t\t: widthOf(anchor, tabWidth) -\n\t\t\t\t\t\twidthOf(oldIndent(info.anchor), tabWidth);\n\t\t\tindent = indentOfWidth(\n\t\t\t\tMath.max(0, widthOf(oldIndent(line), tabWidth) + moved),\n\t\t\t);\n\t\t}\n\t\tnewIndents.set(line, indent);\n\t\treturn indent;\n\t};\n\n\tconst edits: FormatEdit[] = [];\n\t// Blank lines go where the line before is blank too, so runs become one.\n\tlet previousBlank = false;\n\n\tfor (const [index, info] of lines.entries()) {\n\t\tif (index > lastContent) break;\n\t\tif (index < firstContent) continue;\n\t\tconst start = info.start;\n\t\tconst end = lineEnd(index);\n\t\tif (isBlank(index)) {\n\t\t\tif (info.kind === \"indent\" && previousBlank) {\n\t\t\t\tedits.push({ start, end: end + 1, text: \"\" });\n\t\t\t} else if (end > start) edits.push({ start, end, text: \"\" });\n\t\t\tpreviousBlank = true;\n\t\t\tcontinue;\n\t\t}\n\t\tpreviousBlank = false;\n\n\t\tconst indent = newIndent(index);\n\t\tif (indent !== null) {\n\t\t\tconst current = oldIndent(index);\n\t\t\tif (current !== indent) {\n\t\t\t\tedits.push({ start, end: start + current.length, text: indent });\n\t\t\t}\n\t\t}\n\t\tif (trimEnd[index] && info.kind !== \"keep\" && index !== lastContent) {\n\t\t\tlet from = end;\n\t\t\twhile (from > start && /[ \\t\\r]/.test(text[from - 1] as string)) from--;\n\t\t\tif (from < end && !insideDelimiter(delimiters, from)) {\n\t\t\t\tedits.push({ start: from, end, text: \"\" });\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const { part, line } of delimiters) {\n\t\tconst indent = newIndent(line) ?? oldIndent(line);\n\t\tconst printed = printDelimiter(text, part, indent, unit);\n\t\tif (printed !== null && printed !== text.slice(part.start, part.end)) {\n\t\t\tedits.push({ start: part.start, end: part.end, text: printed });\n\t\t}\n\t}\n\n\treturn edits.sort((a, b) => a.start - b.start || a.end - b.end);\n};\n\nconst insideDelimiter = (\n\tdelimiters: readonly { part: DelimitedPart }[],\n\toffset: number,\n) => delimiters.some(({ part }) => offset > part.start && offset < part.end);\n\nconst applyEdits = (text: string, edits: readonly FormatEdit[]): string => {\n\tlet out = \"\";\n\tlet position = 0;\n\tfor (const edit of edits) {\n\t\tout += text.slice(position, edit.start) + edit.text;\n\t\tposition = edit.end;\n\t}\n\treturn out + text.slice(position);\n};\n\n/** Removes whitespace at the start and end of lines, and blank lines, which the formatter may change. */\nconst normaliseText = (value: string) =>\n\tvalue\n\t\t.replace(/[ \\t\\r\\f\\v]+$/gm, \"\")\n\t\t.replace(/^[ \\t\\f\\v]+/gm, \"\")\n\t\t.replace(/\\n{2,}/g, \"\\n\");\n\n/** A copy of a syntax tree without positions or layout, with text normalised and text left empty by that removed. */\nconst normaliseTree = (value: unknown): unknown => {\n\tif (Array.isArray(value)) {\n\t\treturn value\n\t\t\t.map(normaliseTree)\n\t\t\t.filter(\n\t\t\t\t(item) =>\n\t\t\t\t\t!(\n\t\t\t\t\t\ttypeof item === \"object\" &&\n\t\t\t\t\t\titem !== null &&\n\t\t\t\t\t\t(item as { type?: unknown }).type === \"Text\" &&\n\t\t\t\t\t\t(item as { value?: unknown }).value === \"\"\n\t\t\t\t\t),\n\t\t\t);\n\t}\n\tif (typeof value !== \"object\" || value === null) return value;\n\tconst copy: Record<string, unknown> = {};\n\tfor (const [key, item] of Object.entries(value)) {\n\t\tif (\n\t\t\tkey === \"span\" ||\n\t\t\tkey === \"nameSpan\" ||\n\t\t\tkey === \"lines\" ||\n\t\t\tkey === \"indent\"\n\t\t)\n\t\t\tcontinue;\n\t\tcopy[key] =\n\t\t\tkey === \"value\" && (value as { type?: unknown }).type === \"Text\"\n\t\t\t\t? normaliseText(item as string)\n\t\t\t\t: normaliseTree(item);\n\t}\n\treturn copy;\n};\n\n/** The syntax tree as JSON, without the whitespace the formatter may change, so two trees can be compared. */\nconst shape = (text: string): string =>\n\tJSON.stringify(normaliseTree(parse(text, { isTest }).ast));\n\n/**\n * Works out the edits that format a template, in source order and never overlapping. Editors apply these so the cursor and undo history stay put. See `format` for what it throws.\n */\nexport const formatEdits = (\n\ttext: string,\n\toptions: FormatOptions = {},\n): FormatEdit[] => {\n\tconst parsed = parse(text, { isTest });\n\tif (parsed.problems.length > 0) {\n\t\tconst source = new Source(\"template.kiln\", text);\n\t\tthrow new KilnSyntaxError(\n\t\t\tparsed.problems.map((problem) =>\n\t\t\t\tcreateDiagnostic(source, problem.code, problem.message, problem.span),\n\t\t\t),\n\t\t\tsource,\n\t\t);\n\t}\n\n\tconst tabWidth = options.tabWidth ?? 4;\n\tif (!Number.isInteger(tabWidth) || tabWidth < 1) {\n\t\tthrow new RangeError(\n\t\t\t`tabWidth must be a whole number of at least 1, but got ${tabWidth}`,\n\t\t);\n\t}\n\tlet edits = planEdits(text, scanParts(text).parts, {\n\t\tuseTabs: options.useTabs ?? true,\n\t\ttabWidth,\n\t});\n\tconst range = options.range;\n\tif (range) {\n\t\tedits = edits.filter(\n\t\t\t(edit) => edit.end >= range.start && edit.start <= range.end,\n\t\t);\n\t}\n\n\tconst formatted = applyEdits(text, edits);\n\tconst changed = parse(formatted, { isTest });\n\tif (changed.problems.length > 0 || shape(formatted) !== shape(text)) {\n\t\tthrow new KilnFormatError(\n\t\t\t\"Formatting would have changed what this template renders, so nothing was changed. This is a bug in Kiln's formatter.\",\n\t\t);\n\t}\n\treturn edits;\n};\n\n/**\n * Formats a template: indents it to match its structure, and tidies spacing inside outputs and tags. Never changes what it renders.\n *\n * Throws `KilnSyntaxError` when the template has syntax errors, `KilnFormatError` if the safety check fails, and\n * `RangeError` for a `tabWidth` that isn't a whole number of at least 1.\n *\n * ```ts\n * const formatted = format(source, { useTabs: false, tabWidth: 2 });\n * ```\n */\nexport const format = (text: string, options: FormatOptions = {}): string =>\n\tapplyEdits(text, formatEdits(text, options));\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"format-Di6-GUtH.js","names":[],"sources":["../src/formatter/delimiters.ts","../src/formatter/format.ts"],"sourcesContent":["import type { DelimitedPart, Token } from \"../lexer/lexer.js\";\n\n/** A token as the formatter prints it: its source text, unchanged. An interpolated string is one piece. */\ntype Piece = {\n\ttype: Token[\"type\"];\n\ttext: string;\n\tstart: number;\n\tend: number;\n};\n\n/**\n * What a piece does, where that changes its spacing.\n *\n * - `word`: a name, number or string.\n * - `keyword`: a tag's name, or a name such as `and` or `in`. A bracket after it groups rather than calls.\n * - `unary`: a sign that makes a number negative or positive, written against its operand.\n * - `tight`: `.`, `?.`, `..` and a filter's `|`, with no space either side.\n * - `key`: the colon after a key or named argument, or `?` and `?:` marking an optional key in `props`.\n * - `call`: a bracket that calls or indexes the piece before it.\n * - `open`, `close`: other brackets.\n * - `spaced`: operators with a space either side.\n */\ntype Role =\n\t| \"word\"\n\t| \"keyword\"\n\t| \"unary\"\n\t| \"tight\"\n\t| \"key\"\n\t| \"call\"\n\t| \"open\"\n\t| \"close\"\n\t| \"comma\"\n\t| \"spread\"\n\t| \"spaced\";\n\nconst KEYWORDS = new Set([\n\t\"and\",\n\t\"or\",\n\t\"not\",\n\t\"in\",\n\t\"is\",\n\t\"starts\",\n\t\"ends\",\n\t\"with\",\n\t\"as\",\n\t\"import\",\n\t\"ignore\",\n\t\"missing\",\n]);\n\n/** Joins each interpolated string's tokens, from `stringStart` to its matching `stringEnd`, into one piece. */\nconst toPieces = (source: string, tokens: readonly Token[]): Piece[] => {\n\tconst pieces: Piece[] = [];\n\tfor (let index = 0; index < tokens.length; index++) {\n\t\tconst token = tokens[index] as Token;\n\t\tlet end = token.end;\n\t\tif (token.type === \"stringStart\") {\n\t\t\tlet depth = 0;\n\t\t\tfor (; index < tokens.length; index++) {\n\t\t\t\tconst inner = tokens[index] as Token;\n\t\t\t\tif (inner.type === \"stringStart\") depth++;\n\t\t\t\telse if (inner.type === \"stringEnd\" && --depth === 0) break;\n\t\t\t}\n\t\t\tend = (tokens[Math.min(index, tokens.length - 1)] as Token).end;\n\t\t}\n\t\tpieces.push({\n\t\t\ttype: token.type === \"stringStart\" ? \"string\" : token.type,\n\t\t\ttext: source.slice(token.start, end),\n\t\t\tstart: token.start,\n\t\t\tend,\n\t\t});\n\t}\n\treturn pieces;\n};\n\n/** Works out each piece's role. `isTag` means the first piece is a tag's name. */\nconst rolesOf = (pieces: readonly Piece[], isTag: boolean): Role[] => {\n\tconst roles: Role[] = [];\n\t// In `props`, `|` joins types and `?:` marks an optional key, until `=` starts a default value.\n\tconst props = isTag && pieces[0]?.text === \"props\";\n\tlet inDefault = false;\n\t// Open `?`s at each bracket depth, so a conditional's `:` can be told from a key's.\n\tconst conditionals: number[] = [0];\n\n\tfor (const [index, piece] of pieces.entries()) {\n\t\tconst previous = roles[index - 1];\n\t\tconst depth = conditionals.length - 1;\n\t\tconst types = props && !inDefault;\n\t\tlet role: Role;\n\n\t\tif (piece.type !== \"punct\") {\n\t\t\trole =\n\t\t\t\t(isTag && index === 0) ||\n\t\t\t\t(piece.type === \"name\" && KEYWORDS.has(piece.text))\n\t\t\t\t\t? \"keyword\"\n\t\t\t\t\t: \"word\";\n\t\t} else {\n\t\t\tswitch (piece.text) {\n\t\t\t\tcase \"(\":\n\t\t\t\tcase \"[\":\n\t\t\t\t\trole = previous === \"word\" || previous === \"close\" ? \"call\" : \"open\";\n\t\t\t\t\tconditionals.push(0);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"{\":\n\t\t\t\t\trole = \"open\";\n\t\t\t\t\tconditionals.push(0);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \")\":\n\t\t\t\tcase \"]\":\n\t\t\t\tcase \"}\":\n\t\t\t\t\trole = \"close\";\n\t\t\t\t\tif (conditionals.length > 1) conditionals.pop();\n\t\t\t\t\tbreak;\n\t\t\t\tcase \",\":\n\t\t\t\t\trole = \"comma\";\n\t\t\t\t\tif (props && depth === 0) inDefault = false;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"...\":\n\t\t\t\t\trole = \"spread\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \".\":\n\t\t\t\tcase \"?.\":\n\t\t\t\tcase \"..\":\n\t\t\t\t\trole = \"tight\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"|\":\n\t\t\t\t\trole = types ? \"spaced\" : \"tight\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"-\":\n\t\t\t\tcase \"+\":\n\t\t\t\t\trole =\n\t\t\t\t\t\tprevious === undefined ||\n\t\t\t\t\t\t(previous !== \"word\" && previous !== \"close\")\n\t\t\t\t\t\t\t? \"unary\"\n\t\t\t\t\t\t\t: \"spaced\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"?\":\n\t\t\t\tcase \"?:\":\n\t\t\t\t\trole = types ? \"key\" : \"spaced\";\n\t\t\t\t\tif (piece.text === \"?\" && !types) {\n\t\t\t\t\t\tconditionals[depth] = (conditionals[depth] ?? 0) + 1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \":\":\n\t\t\t\t\tif ((conditionals[depth] ?? 0) > 0) {\n\t\t\t\t\t\tconditionals[depth] = (conditionals[depth] ?? 0) - 1;\n\t\t\t\t\t\trole = \"spaced\";\n\t\t\t\t\t} else role = \"key\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\trole = \"spaced\";\n\t\t\t\t\tif (props && depth === 0 && piece.text === \"=\") inDefault = true;\n\t\t\t}\n\t\t}\n\t\troles.push(role);\n\t}\n\treturn roles;\n};\n\n/** The gap between two pieces: a space or nothing. */\nconst gapBetween = (\n\tprevious: Piece,\n\tpreviousRole: Role,\n\tpiece: Piece,\n\trole: Role,\n): string => {\n\tif (role === \"comma\" || role === \"tight\" || role === \"key\" || role === \"call\")\n\t\treturn \"\";\n\tif (role === \"close\") {\n\t\treturn piece.text === \"}\" && previous.text !== \"{\" ? \" \" : \"\";\n\t}\n\tif (previousRole === \"tight\" || previousRole === \"unary\") return \"\";\n\tif (previousRole === \"spread\") return \"\";\n\tif (previousRole === \"open\" || previousRole === \"call\") {\n\t\treturn previous.text === \"{\" ? \" \" : \"\";\n\t}\n\treturn \" \";\n};\n\n/**\n * Prints one output or tag with normalised spacing. Line breaks between tokens stay; each line after one is indented from `indent`, one step further or to match the brackets it sits inside, using `unit` per step.\n *\n * Returns null for a delimiter that never closed, which the formatter leaves as it is.\n */\nexport const printDelimiter = (\n\tsource: string,\n\tpart: DelimitedPart,\n\tindent: string,\n\tunit: string,\n): string | null => {\n\tconst tokens = part.tokens;\n\tconst open = tokens[0];\n\tconst close = tokens[tokens.length - 1];\n\tif (!open || !close || close.value === \"\" || tokens.length < 3) return null;\n\n\tconst pieces = toPieces(source, tokens.slice(1, -1));\n\tconst roles = rolesOf(pieces, part.kind === \"tag\");\n\tlet out = open.value;\n\tlet previousEnd = part.start + open.value.length;\n\t// The line each open bracket started on. Brackets opened on the same line add one step between them.\n\tconst openedOn: number[] = [];\n\tlet line = 0;\n\t/** Steps of indentation for a new line, once `closers` brackets at its start have closed. */\n\tconst steps = (closers: number) =>\n\t\tnew Set(openedOn.slice(0, openedOn.length - closers)).size;\n\n\tfor (const [index, piece] of pieces.entries()) {\n\t\tconst role = roles[index] as Role;\n\t\tconst gap = source.slice(previousEnd, piece.start);\n\t\tif (gap.includes(\"\\n\")) {\n\t\t\tline++;\n\t\t\t// Closing brackets at the start of a line line up with the line that opened them. Only those on this line count.\n\t\t\tlet closers = 0;\n\t\t\twhile (\n\t\t\t\troles[index + closers] === \"close\" &&\n\t\t\t\t(closers === 0 ||\n\t\t\t\t\t!source\n\t\t\t\t\t\t.slice(\n\t\t\t\t\t\t\t(pieces[index + closers - 1] as Piece).end,\n\t\t\t\t\t\t\t(pieces[index + closers] as Piece).start,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.includes(\"\\n\"))\n\t\t\t) {\n\t\t\t\tclosers++;\n\t\t\t}\n\t\t\tout += `\\n${indent}${unit.repeat(closers > 0 ? steps(closers) : Math.max(steps(0), 1))}`;\n\t\t} else if (index === 0) out += \" \";\n\t\telse {\n\t\t\tout += gapBetween(\n\t\t\t\tpieces[index - 1] as Piece,\n\t\t\t\troles[index - 1] as Role,\n\t\t\t\tpiece,\n\t\t\t\trole,\n\t\t\t);\n\t\t}\n\t\tout += piece.text;\n\t\tif (role === \"open\" || role === \"call\") openedOn.push(line);\n\t\telse if (role === \"close\") openedOn.pop();\n\t\tpreviousEnd = piece.end;\n\t}\n\n\tconst closeStart = part.end - close.value.length;\n\tout += source.slice(previousEnd, closeStart).includes(\"\\n\")\n\t\t? `\\n${indent}`\n\t\t: \" \";\n\treturn out + close.value;\n};\n","import { builtinTests } from \"../builtins/functions.js\";\nimport { KilnSyntaxError } from \"../errors.js\";\nimport { createDiagnostic } from \"../errors.js\";\nimport { type DelimitedPart, type Part, scanParts } from \"../lexer/lexer.js\";\nimport { parse } from \"../parser/parser.js\";\nimport { Source } from \"../source.js\";\nimport { printDelimiter } from \"./delimiters.js\";\n\nexport type FormatOptions = {\n\t/** Indent with tabs. Default `true`. */\n\tuseTabs?: boolean;\n\t/** Spaces per step without tabs, and the width of a tab when moving lines. A whole number of at least 1. Default `4`. */\n\ttabWidth?: number;\n\t/** Only format lines that overlap this range of offsets. */\n\trange?: { start: number; end: number };\n};\n\n/** Replace `start` to `end` of the original source with `text`. */\nexport type FormatEdit = { start: number; end: number; text: string };\n\n/** Thrown when formatting would have changed what a template renders. That is a bug in the formatter. */\nexport class KilnFormatError extends Error {\n\toverride name = \"KilnFormatError\";\n}\n\n/**\n * How the formatter treats one line.\n *\n * - `indent`: set its indentation to `level` steps.\n * - `shift`: move it by as much as line `anchor` moved, keeping its own indentation relative to it. For scripts, styles and comments.\n * - `keep`: leave it alone, for `<pre>`, `<textarea>`, `verbatim`, text inside attribute values, and the body of a `set` or `apply` whose tag shares its line.\n * - `inside`: it starts inside an output or tag, which `printDelimiter` indents.\n */\ntype Line =\n\t| { kind: \"indent\"; start: number; level: number }\n\t| { kind: \"shift\"; start: number; anchor: number }\n\t| { kind: \"keep\" | \"inside\"; start: number };\n\ntype Frame = { kind: \"kiln\" | \"html\"; name: string };\n\n/**\n * Where the scanner is in the HTML.\n *\n * - `tag`: inside `<name ...>` or `</name>`, which started on line `line`. `inner` counts block tags open inside it.\n * - `raw`: inside `<script>` or `<style>`, or kept as written inside `<pre>`, `<textarea>` and the like.\n * - `kept`: inside the body of block tag `name`, output as written: `verbatim`, or a `set` or `apply` whose tag shares\n * its line, where Kiln doesn't remove the body's indentation. `depth` counts the tags of that name open.\n */\ntype Mode =\n\t| { kind: \"data\" }\n\t| {\n\t\t\tkind: \"tag\";\n\t\t\tname: string;\n\t\t\tclosing: boolean;\n\t\t\tquote: string | null;\n\t\t\tline: number;\n\t\t\tatLineStart: boolean;\n\t\t\tinner: number;\n\t }\n\t| { kind: \"comment\"; anchor: number; level: number }\n\t| { kind: \"raw\"; name: string; keep: boolean; anchor: number; level: number }\n\t| { kind: \"kept\"; name: string; depth: number; level: number };\n\nconst VOID_ELEMENTS = new Set([\n\t\"area\",\n\t\"base\",\n\t\"br\",\n\t\"col\",\n\t\"embed\",\n\t\"hr\",\n\t\"img\",\n\t\"input\",\n\t\"link\",\n\t\"meta\",\n\t\"source\",\n\t\"track\",\n\t\"wbr\",\n]);\n\n/** Elements written in `<script>` or `<style>`'s own language, whose lines move together. */\nconst RAW_ELEMENTS = new Set([\"script\", \"style\"]);\n/** Elements whose whitespace shows on the page. Nothing closes `<plaintext>`. */\nconst KEPT_ELEMENTS = new Set([\n\t\"pre\",\n\t\"textarea\",\n\t\"xmp\",\n\t\"listing\",\n\t\"plaintext\",\n]);\n\n/** Whether `</name` starts at `index`, as a whole tag name. */\nconst closesElement = (text: string, index: number, name: string): boolean => {\n\tif (name === \"plaintext\") return false;\n\tconst end = index + 2 + name.length;\n\treturn (\n\t\ttext.slice(index, end).toLowerCase() === `</${name}` &&\n\t\t(end === text.length || /[\\s/>]/.test(text[end] as string))\n\t);\n};\n\n/**\n * Whether a line starting with `trimmed` begins with the tag that ends the outermost `kept` body, and the formatter\n * may indent it. It may when Kiln removes the whitespace before the tag: a `-` trim marker, or a tag alone on its line.\n */\nconst endsKept = (\n\ttrimmed: string,\n\tmode: Extract<Mode, { kind: \"kept\" }>,\n): boolean => {\n\tconst match = /^\\{%(-?)\\s*end([A-Za-z]+)\\s*-?%\\}([^\\n]*)/.exec(trimmed);\n\treturn (\n\t\tmatch !== null &&\n\t\tmatch[2] === mode.name &&\n\t\tmode.depth === 1 &&\n\t\t(match[1] === \"-\" || /^[ \\t\\r]*$/.test(match[3] as string))\n\t);\n};\n\n/** Elements that the next of these siblings closes, such as a `<li>` without `</li>`. */\nconst CLOSED_BY: Record<string, readonly string[]> = {\n\tli: [\"li\"],\n\tdt: [\"dt\", \"dd\"],\n\tdd: [\"dt\", \"dd\"],\n\tp: [\"p\"],\n\toption: [\"option\"],\n\ttr: [\"tr\"],\n\ttd: [\"td\", \"th\"],\n\tth: [\"td\", \"th\"],\n\tthead: [\"tbody\", \"tfoot\"],\n\ttbody: [\"tbody\", \"tfoot\"],\n};\n\n/** Block tags that hold a body, and so indent what follows. */\nconst BLOCK_TAGS = new Set([\n\t\"if\",\n\t\"for\",\n\t\"set\",\n\t\"block\",\n\t\"component\",\n\t\"fill\",\n\t\"slot\",\n\t\"macro\",\n\t\"with\",\n\t\"cache\",\n\t\"island\",\n\t\"add\",\n\t\"apply\",\n\t\"autoescape\",\n\t\"verbatim\",\n]);\n\n/** What a tag does to indentation: opens a body, starts another branch of one, closes one, or nothing. */\nconst roleOf = (\n\tpart: DelimitedPart,\n): { kind: \"open\" | \"close\"; name: string } | { kind: \"branch\" } | null => {\n\tconst name = part.tokens[1];\n\tif (name?.type !== \"name\") return null;\n\tif (BLOCK_TAGS.has(name.value)) {\n\t\tif (\n\t\t\tname.value === \"set\" &&\n\t\t\tpart.tokens.some((token) => token.type === \"punct\" && token.value === \"=\")\n\t\t) {\n\t\t\treturn null;\n\t\t}\n\t\t// `{% block title page.title %}` is the short form, with no body.\n\t\tif (name.value === \"block\" && part.tokens.length > 4) return null;\n\t\treturn { kind: \"open\", name: name.value };\n\t}\n\tif (name.value === \"else\" || name.value === \"elseif\")\n\t\treturn { kind: \"branch\" };\n\tif (name.value.startsWith(\"end\")) {\n\t\treturn { kind: \"close\", name: name.value.slice(3) };\n\t}\n\treturn null;\n};\n\nconst isLetter = (char: string | undefined) =>\n\tchar !== undefined && /[A-Za-z]/.test(char);\n\nconst isTest = (name: string) => Object.hasOwn(builtinTests, name);\n\n/** The start offset of every line. */\nconst lineStarts = (text: string): number[] => {\n\tconst starts = [0];\n\tfor (let index = text.indexOf(\"\\n\"); index !== -1;) {\n\t\tstarts.push(index + 1);\n\t\tindex = text.indexOf(\"\\n\", index + 1);\n\t}\n\treturn starts;\n};\n\n/**\n * Walks the template once, tracking open block tags and HTML elements, and decides how to treat each line.\n *\n * Returns the lines, which lines may lose trailing whitespace, and the outputs and tags to print.\n */\nconst planLines = (text: string, parts: readonly Part[]) => {\n\tconst starts = lineStarts(text);\n\tconst lines: Line[] = [];\n\tconst trimEnd: boolean[] = [];\n\tconst stack: Frame[] = [];\n\tlet mode: Mode = { kind: \"data\" };\n\tlet atLineStart = true;\n\t// A line that starts where the next part does, recorded when that part begins.\n\tlet pendingLine = -1;\n\n\tconst lineText = (index: number) =>\n\t\ttext.slice(starts[index], starts[index + 1] ?? text.length);\n\t/** Whether only spaces and tabs come between `offset` and the end of its line. */\n\tconst endsLine = (offset: number) => {\n\t\tlet index = offset;\n\t\twhile (index < text.length && \" \\t\\r\".includes(text[index] as string)) {\n\t\t\tindex++;\n\t\t}\n\t\treturn index === text.length || text[index] === \"\\n\";\n\t};\n\tconst current = () => lines.length - 1;\n\n\t/** Lowers the current line's level when a closing tag comes before anything else on it. */\n\tconst outdent = (line: number, level: number, first: boolean) => {\n\t\tconst info = lines[line];\n\t\tif (first && info?.kind === \"indent\") {\n\t\t\tinfo.level = Math.min(info.level, level);\n\t\t}\n\t};\n\n\tconst levelOf = (line: number): number => {\n\t\tconst info = lines[line];\n\t\treturn info?.kind === \"indent\" ? info.level : stack.length;\n\t};\n\n\t/** Records how to treat the line that starts at `start`, from the current state. */\n\tconst beginLine = (start: number) => {\n\t\tconst index = lines.length;\n\t\tconst trimmed = lineText(index).trimStart();\n\t\tatLineStart = true;\n\t\tswitch (mode.kind) {\n\t\t\tcase \"data\":\n\t\t\t\tlines.push({ kind: \"indent\", start, level: stack.length });\n\t\t\t\treturn;\n\t\t\tcase \"tag\": {\n\t\t\t\tif (mode.quote !== null) {\n\t\t\t\t\tlines.push({ kind: \"keep\", start });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst base = levelOf(mode.line);\n\t\t\t\tconst level =\n\t\t\t\t\ttrimmed.startsWith(\">\") || trimmed.startsWith(\"/>\")\n\t\t\t\t\t\t? base\n\t\t\t\t\t\t: base + 1 + mode.inner;\n\t\t\t\tlines.push({ kind: \"indent\", start, level });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"comment\":\n\t\t\t\tlines.push(\n\t\t\t\t\ttrimmed.startsWith(\"-->\")\n\t\t\t\t\t\t? { kind: \"indent\", start, level: mode.level }\n\t\t\t\t\t\t: { kind: \"shift\", start, anchor: mode.anchor },\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\tcase \"raw\":\n\t\t\t\tif (mode.keep) lines.push({ kind: \"keep\", start });\n\t\t\t\telse if (closesElement(trimmed, 0, mode.name)) {\n\t\t\t\t\tlines.push({ kind: \"indent\", start, level: mode.level });\n\t\t\t\t} else lines.push({ kind: \"shift\", start, anchor: mode.anchor });\n\t\t\t\treturn;\n\t\t\tcase \"kept\":\n\t\t\t\tlines.push(\n\t\t\t\t\tendsKept(trimmed, mode)\n\t\t\t\t\t\t? { kind: \"indent\", start, level: mode.level }\n\t\t\t\t\t\t: { kind: \"keep\", start },\n\t\t\t\t);\n\t\t}\n\t};\n\n\t/** Whether trailing whitespace on a line ending here can go. Not inside attribute values or kept elements. */\n\tconst canTrimHere = () =>\n\t\t!(mode.kind === \"tag\" && mode.quote !== null) &&\n\t\t!(mode.kind === \"raw\" && mode.keep) &&\n\t\tmode.kind !== \"kept\";\n\n\tconst finishTag = (\n\t\ttag: Extract<Mode, { kind: \"tag\" }>,\n\t\tselfClosing: boolean,\n\t) => {\n\t\tmode = { kind: \"data\" };\n\t\tconst name = tag.name;\n\t\tif (tag.closing) {\n\t\t\t// Close the nearest open element of this name, without crossing a block tag.\n\t\t\tfor (let index = stack.length - 1; index >= 0; index--) {\n\t\t\t\tconst frame = stack[index] as Frame;\n\t\t\t\tif (frame.kind === \"kiln\") break;\n\t\t\t\tif (frame.name === name) {\n\t\t\t\t\tstack.length = index;\n\t\t\t\t\toutdent(tag.line, index, tag.atLineStart);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (name.startsWith(\"!\") || selfClosing || VOID_ELEMENTS.has(name)) return;\n\t\tif (RAW_ELEMENTS.has(name) || KEPT_ELEMENTS.has(name)) {\n\t\t\tmode = {\n\t\t\t\tkind: \"raw\",\n\t\t\t\tname,\n\t\t\t\tkeep: KEPT_ELEMENTS.has(name),\n\t\t\t\tanchor: tag.line,\n\t\t\t\tlevel: stack.length,\n\t\t\t};\n\t\t\treturn;\n\t\t}\n\t\tconst top = stack[stack.length - 1];\n\t\tif (top?.kind === \"html\" && CLOSED_BY[top.name]?.includes(name)) {\n\t\t\tstack.pop();\n\t\t\toutdent(tag.line, stack.length, tag.atLineStart);\n\t\t}\n\t\tstack.push({ kind: \"html\", name });\n\t};\n\n\t/** Starts a tag at `index` if one starts there, and returns where scanning continues. */\n\tconst startTag = (index: number, closing: boolean): number => {\n\t\tconst nameStart = index + (closing ? 2 : 1);\n\t\tlet nameEnd = nameStart;\n\t\twhile (\n\t\t\tnameEnd < text.length &&\n\t\t\t/[A-Za-z0-9:!_-]/.test(text[nameEnd] as string)\n\t\t) {\n\t\t\tnameEnd++;\n\t\t}\n\t\tmode = {\n\t\t\tkind: \"tag\",\n\t\t\tname: text.slice(nameStart, nameEnd).toLowerCase(),\n\t\t\tclosing,\n\t\t\tquote: null,\n\t\t\tline: current(),\n\t\t\tatLineStart,\n\t\t\tinner: 0,\n\t\t};\n\t\tatLineStart = false;\n\t\treturn nameEnd;\n\t};\n\n\t/** Moves through a text part one character at a time. */\n\tconst scanText = (start: number, end: number) => {\n\t\tfor (let index = start; index < end; index++) {\n\t\t\tconst char = text[index] as string;\n\t\t\tif (char === \"\\n\") {\n\t\t\t\ttrimEnd[current()] = canTrimHere();\n\t\t\t\tif (index + 1 < end) beginLine(index + 1);\n\t\t\t\telse if (index + 1 === text.length) {\n\t\t\t\t\t// The file ends with a line break: there is no further line.\n\t\t\t\t} else pendingLine = index + 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tswitch (mode.kind) {\n\t\t\t\tcase \"data\":\n\t\t\t\t\tif (char === \" \" || char === \"\\t\" || char === \"\\r\") break;\n\t\t\t\t\tif (char === \"<\") {\n\t\t\t\t\t\tif (text.startsWith(\"<!--\", index)) {\n\t\t\t\t\t\t\tmode = {\n\t\t\t\t\t\t\t\tkind: \"comment\",\n\t\t\t\t\t\t\t\tanchor: current(),\n\t\t\t\t\t\t\t\tlevel: levelOf(current()),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tatLineStart = false;\n\t\t\t\t\t\t\tindex += 3;\n\t\t\t\t\t\t} else if (text[index + 1] === \"/\" && isLetter(text[index + 2])) {\n\t\t\t\t\t\t\tindex = startTag(index, true) - 1;\n\t\t\t\t\t\t} else if (isLetter(text[index + 1]) || text[index + 1] === \"!\") {\n\t\t\t\t\t\t\tindex = startTag(index, false) - 1;\n\t\t\t\t\t\t} else atLineStart = false;\n\t\t\t\t\t} else atLineStart = false;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"tag\":\n\t\t\t\t\tif (mode.quote !== null) {\n\t\t\t\t\t\tif (char === mode.quote) mode.quote = null;\n\t\t\t\t\t} else if (char === '\"' || char === \"'\") mode.quote = char;\n\t\t\t\t\telse if (char === \">\") finishTag(mode, text[index - 1] === \"/\");\n\t\t\t\t\telse if (char !== \" \" && char !== \"\\t\" && char !== \"\\r\") {\n\t\t\t\t\t\tatLineStart = false;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"comment\":\n\t\t\t\t\tif (text.startsWith(\"-->\", index)) {\n\t\t\t\t\t\tmode = { kind: \"data\" };\n\t\t\t\t\t\tindex += 2;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"raw\":\n\t\t\t\t\tif (char === \"<\" && closesElement(text, index, mode.name)) {\n\t\t\t\t\t\tindex = startTag(index, true) - 1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"kept\":\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t};\n\n\t/** Applies a block tag to the stack, or to the count of block tags open inside an HTML tag. */\n\tconst applyTag = (part: DelimitedPart) => {\n\t\tconst role = roleOf(part);\n\t\tconst first = atLineStart;\n\t\tatLineStart = false;\n\t\tif (!role) return;\n\t\tif (mode.kind === \"tag\") {\n\t\t\tconst base = levelOf(mode.line) + 1;\n\t\t\tif (role.kind === \"open\") mode.inner++;\n\t\t\telse if (role.kind === \"close\") {\n\t\t\t\tmode.inner = Math.max(0, mode.inner - 1);\n\t\t\t\toutdent(current(), base + mode.inner, first);\n\t\t\t} else outdent(current(), base + mode.inner - 1, first);\n\t\t\treturn;\n\t\t}\n\t\tif (mode.kind === \"kept\") {\n\t\t\tif (role.kind === \"open\" && role.name === mode.name) mode.depth++;\n\t\t\telse if (\n\t\t\t\trole.kind === \"close\" &&\n\t\t\t\trole.name === mode.name &&\n\t\t\t\t--mode.depth === 0\n\t\t\t) {\n\t\t\t\tconst index = stack.findLastIndex((frame) => frame.kind === \"kiln\");\n\t\t\t\tif (index !== -1) stack.length = index;\n\t\t\t\tmode = { kind: \"data\" };\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (mode.kind !== \"data\") return;\n\t\tif (role.kind === \"open\") {\n\t\t\tstack.push({ kind: \"kiln\", name: role.name });\n\t\t\tif (\n\t\t\t\trole.name === \"verbatim\" ||\n\t\t\t\t((role.name === \"set\" || role.name === \"apply\") &&\n\t\t\t\t\t!(first && endsLine(part.end)))\n\t\t\t) {\n\t\t\t\tmode = {\n\t\t\t\t\tkind: \"kept\",\n\t\t\t\t\tname: role.name,\n\t\t\t\t\tdepth: 1,\n\t\t\t\t\tlevel: stack.length - 1,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tconst index =\n\t\t\trole.kind === \"branch\"\n\t\t\t\t? stack.findLastIndex((frame) => frame.kind === \"kiln\")\n\t\t\t\t: stack.findLastIndex(\n\t\t\t\t\t\t(frame) => frame.kind === \"kiln\" && frame.name === role.name,\n\t\t\t\t\t);\n\t\tif (index === -1) return;\n\t\t// Elements opened in this body or branch end with it.\n\t\tstack.length = role.kind === \"branch\" ? index + 1 : index;\n\t\toutdent(current(), index, first);\n\t};\n\n\tbeginLine(0);\n\tconst delimiters: { part: DelimitedPart; line: number }[] = [];\n\n\tfor (const part of parts) {\n\t\tif (pendingLine !== -1) {\n\t\t\tbeginLine(pendingLine);\n\t\t\tpendingLine = -1;\n\t\t}\n\t\tif (part.kind === \"text\") {\n\t\t\tscanText(part.start, part.end);\n\t\t\tcontinue;\n\t\t}\n\t\tconst line = current();\n\t\tif (part.kind === \"comment\") atLineStart = false;\n\t\telse {\n\t\t\tdelimiters.push({ part, line });\n\t\t\tif (part.kind === \"tag\") applyTag(part);\n\t\t\telse atLineStart = false;\n\t\t}\n\t\t// Lines that start inside this delimiter.\n\t\tfor (\n\t\t\tlet index = text.indexOf(\"\\n\", part.start);\n\t\t\tindex !== -1 && index < part.end;\n\t\t\tindex = text.indexOf(\"\\n\", index + 1)\n\t\t) {\n\t\t\ttrimEnd[current()] = part.kind === \"comment\";\n\t\t\tlines.push(\n\t\t\t\tpart.kind === \"comment\"\n\t\t\t\t\t? { kind: \"shift\", start: index + 1, anchor: line }\n\t\t\t\t\t: { kind: \"inside\", start: index + 1 },\n\t\t\t);\n\t\t}\n\t}\n\ttrimEnd[current()] ??= canTrimHere();\n\treturn { lines, trimEnd, delimiters };\n};\n\nconst widthOf = (whitespace: string, tabWidth: number): number => {\n\tlet width = 0;\n\tfor (const char of whitespace) width += char === \"\\t\" ? tabWidth : 1;\n\treturn width;\n};\n\n/**\n * Works out the edits that format a template, without checking them. See `formatEdits`.\n */\nconst planEdits = (\n\ttext: string,\n\tparts: readonly Part[],\n\toptions: Required<Omit<FormatOptions, \"range\">>,\n): FormatEdit[] => {\n\tconst { useTabs, tabWidth } = options;\n\tconst unit = useTabs ? \"\\t\" : \" \".repeat(tabWidth);\n\tconst indentOfWidth = (width: number) =>\n\t\tuseTabs\n\t\t\t? \"\\t\".repeat(Math.floor(width / tabWidth)) + \" \".repeat(width % tabWidth)\n\t\t\t: \" \".repeat(width);\n\tconst { lines, trimEnd, delimiters } = planLines(text, parts);\n\n\tconst oldIndent = (line: number) => {\n\t\tconst start = lines[line]?.start ?? 0;\n\t\tlet end = start;\n\t\twhile (text[end] === \" \" || text[end] === \"\\t\") end++;\n\t\treturn text.slice(start, end);\n\t};\n\t/** Where a line's content ends: at its line break, or the end of the file. */\n\tconst lineEnd = (line: number) => {\n\t\tconst next = lines[line + 1]?.start;\n\t\tif (next !== undefined) return next - 1;\n\t\treturn text.endsWith(\"\\n\") ? text.length - 1 : text.length;\n\t};\n\tconst isBlank = (line: number) => {\n\t\tconst info = lines[line] as Line;\n\t\treturn (\n\t\t\tinfo.kind !== \"keep\" &&\n\t\t\tinfo.kind !== \"inside\" &&\n\t\t\ttext.slice(info.start, lineEnd(line)).trim() === \"\"\n\t\t);\n\t};\n\n\t// Whitespace before the first content and after the last is output as written wherever the template is placed, so\n\t// it stays as it is, as does a file of only whitespace.\n\tlet firstContent = 0;\n\twhile (firstContent < lines.length && isBlank(firstContent)) firstContent++;\n\tlet lastContent = lines.length - 1;\n\twhile (lastContent >= 0 && isBlank(lastContent)) lastContent--;\n\n\tconst newIndents = new Map<number, string | null>();\n\tconst newIndent = (line: number): string | null => {\n\t\tif (newIndents.has(line)) return newIndents.get(line) ?? null;\n\t\tconst info = lines[line];\n\t\tlet indent: string | null = null;\n\t\tif (info?.kind === \"indent\") {\n\t\t\t// The first content line keeps its indentation. See `firstContent`.\n\t\t\tindent =\n\t\t\t\tline === firstContent ? oldIndent(line) : unit.repeat(info.level);\n\t\t} else if (info?.kind === \"shift\") {\n\t\t\tconst anchor = newIndent(info.anchor);\n\t\t\tconst moved =\n\t\t\t\tanchor === null\n\t\t\t\t\t? 0\n\t\t\t\t\t: widthOf(anchor, tabWidth) -\n\t\t\t\t\t\twidthOf(oldIndent(info.anchor), tabWidth);\n\t\t\tindent = indentOfWidth(\n\t\t\t\tMath.max(0, widthOf(oldIndent(line), tabWidth) + moved),\n\t\t\t);\n\t\t}\n\t\tnewIndents.set(line, indent);\n\t\treturn indent;\n\t};\n\n\tconst edits: FormatEdit[] = [];\n\t// Blank lines go where the line before is blank too, so runs become one.\n\tlet previousBlank = false;\n\n\tfor (const [index, info] of lines.entries()) {\n\t\tif (index > lastContent) break;\n\t\tif (index < firstContent) continue;\n\t\tconst start = info.start;\n\t\tconst end = lineEnd(index);\n\t\tif (isBlank(index)) {\n\t\t\tif (info.kind === \"indent\" && previousBlank) {\n\t\t\t\tedits.push({ start, end: end + 1, text: \"\" });\n\t\t\t} else if (end > start) edits.push({ start, end, text: \"\" });\n\t\t\tpreviousBlank = true;\n\t\t\tcontinue;\n\t\t}\n\t\tpreviousBlank = false;\n\n\t\tconst indent = newIndent(index);\n\t\tif (indent !== null) {\n\t\t\tconst current = oldIndent(index);\n\t\t\tif (current !== indent) {\n\t\t\t\tedits.push({ start, end: start + current.length, text: indent });\n\t\t\t}\n\t\t}\n\t\tif (trimEnd[index] && info.kind !== \"keep\" && index !== lastContent) {\n\t\t\tlet from = end;\n\t\t\twhile (from > start && /[ \\t\\r]/.test(text[from - 1] as string)) from--;\n\t\t\tif (from < end && !insideDelimiter(delimiters, from)) {\n\t\t\t\tedits.push({ start: from, end, text: \"\" });\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const { part, line } of delimiters) {\n\t\tconst indent = newIndent(line) ?? oldIndent(line);\n\t\tconst printed = printDelimiter(text, part, indent, unit);\n\t\tif (printed !== null && printed !== text.slice(part.start, part.end)) {\n\t\t\tedits.push({ start: part.start, end: part.end, text: printed });\n\t\t}\n\t}\n\n\treturn edits.sort((a, b) => a.start - b.start || a.end - b.end);\n};\n\nconst insideDelimiter = (\n\tdelimiters: readonly { part: DelimitedPart }[],\n\toffset: number,\n) => delimiters.some(({ part }) => offset > part.start && offset < part.end);\n\nconst applyEdits = (text: string, edits: readonly FormatEdit[]): string => {\n\tlet out = \"\";\n\tlet position = 0;\n\tfor (const edit of edits) {\n\t\tout += text.slice(position, edit.start) + edit.text;\n\t\tposition = edit.end;\n\t}\n\treturn out + text.slice(position);\n};\n\n/** Removes whitespace at the start and end of lines, and blank lines, which the formatter may change. */\nconst normaliseText = (value: string) =>\n\tvalue\n\t\t.replace(/[ \\t\\r\\f\\v]+$/gm, \"\")\n\t\t.replace(/^[ \\t\\f\\v]+/gm, \"\")\n\t\t.replace(/\\n{2,}/g, \"\\n\");\n\n/** A copy of a syntax tree without positions or layout, with text normalised and text left empty by that removed. */\nconst normaliseTree = (value: unknown): unknown => {\n\tif (Array.isArray(value)) {\n\t\treturn value\n\t\t\t.map(normaliseTree)\n\t\t\t.filter(\n\t\t\t\t(item) =>\n\t\t\t\t\t!(\n\t\t\t\t\t\ttypeof item === \"object\" &&\n\t\t\t\t\t\titem !== null &&\n\t\t\t\t\t\t(item as { type?: unknown }).type === \"Text\" &&\n\t\t\t\t\t\t(item as { value?: unknown }).value === \"\"\n\t\t\t\t\t),\n\t\t\t);\n\t}\n\tif (typeof value !== \"object\" || value === null) return value;\n\tconst copy: Record<string, unknown> = {};\n\tfor (const [key, item] of Object.entries(value)) {\n\t\tif (key === \"span\" || key === \"nameSpan\" || key === \"indent\") continue;\n\t\tcopy[key] =\n\t\t\tkey === \"value\" && (value as { type?: unknown }).type === \"Text\"\n\t\t\t\t? normaliseText(item as string)\n\t\t\t\t: normaliseTree(item);\n\t}\n\treturn copy;\n};\n\n/** The syntax tree as JSON, without the whitespace the formatter may change, so two trees can be compared. */\nconst shape = (text: string): string =>\n\tJSON.stringify(normaliseTree(parse(text, { isTest }).ast));\n\n/**\n * Works out the edits that format a template, in source order and never overlapping. Editors apply these so the cursor and undo history stay put. See `format` for what it throws.\n */\nexport const formatEdits = (\n\ttext: string,\n\toptions: FormatOptions = {},\n): FormatEdit[] => {\n\tconst parsed = parse(text, { isTest });\n\tif (parsed.problems.length > 0) {\n\t\tconst source = new Source(\"template.kiln\", text);\n\t\tthrow new KilnSyntaxError(\n\t\t\tparsed.problems.map((problem) =>\n\t\t\t\tcreateDiagnostic(source, problem.code, problem.message, problem.span),\n\t\t\t),\n\t\t\tsource,\n\t\t);\n\t}\n\n\tconst tabWidth = options.tabWidth ?? 4;\n\tif (!Number.isInteger(tabWidth) || tabWidth < 1) {\n\t\tthrow new RangeError(\n\t\t\t`tabWidth must be a whole number of at least 1, but got ${tabWidth}`,\n\t\t);\n\t}\n\tlet edits = planEdits(text, scanParts(text).parts, {\n\t\tuseTabs: options.useTabs ?? true,\n\t\ttabWidth,\n\t});\n\tconst range = options.range;\n\tif (range) {\n\t\tedits = edits.filter(\n\t\t\t(edit) => edit.end >= range.start && edit.start <= range.end,\n\t\t);\n\t}\n\n\tconst formatted = applyEdits(text, edits);\n\tconst changed = parse(formatted, { isTest });\n\tif (changed.problems.length > 0 || shape(formatted) !== shape(text)) {\n\t\tthrow new KilnFormatError(\n\t\t\t\"Formatting would have changed what this template renders, so nothing was changed. This is a bug in Kiln's formatter.\",\n\t\t);\n\t}\n\treturn edits;\n};\n\n/**\n * Formats a template: indents it to match its structure, and tidies spacing inside outputs and tags. Never changes what it renders.\n *\n * Throws `KilnSyntaxError` when the template has syntax errors, `KilnFormatError` if the safety check fails, and\n * `RangeError` for a `tabWidth` that isn't a whole number of at least 1.\n *\n * ```ts\n * const formatted = format(source, { useTabs: false, tabWidth: 2 });\n * ```\n */\nexport const format = (text: string, options: FormatOptions = {}): string =>\n\tapplyEdits(text, formatEdits(text, options));\n"],"mappings":";;;AAmCA,MAAM,2BAAW,IAAI,IAAI;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;;AAGD,MAAM,YAAY,QAAgB,WAAsC;CACvE,MAAM,SAAkB,CAAC;CACzB,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS;EACnD,MAAM,QAAQ,OAAO;EACrB,IAAI,MAAM,MAAM;EAChB,IAAI,MAAM,SAAS,eAAe;GACjC,IAAI,QAAQ;GACZ,OAAO,QAAQ,OAAO,QAAQ,SAAS;IACtC,MAAM,QAAQ,OAAO;IACrB,IAAI,MAAM,SAAS,eAAe;SAC7B,IAAI,MAAM,SAAS,eAAe,EAAE,UAAU,GAAG;GACvD;GACA,MAAO,OAAO,KAAK,IAAI,OAAO,OAAO,SAAS,CAAC,EAAE,CAAW;EAC7D;EACA,OAAO,KAAK;GACX,MAAM,MAAM,SAAS,gBAAgB,WAAW,MAAM;GACtD,MAAM,OAAO,MAAM,MAAM,OAAO,GAAG;GACnC,OAAO,MAAM;GACb;EACD,CAAC;CACF;CACA,OAAO;AACR;;AAGA,MAAM,WAAW,QAA0B,UAA2B;CACrE,MAAM,QAAgB,CAAC;CAEvB,MAAM,QAAQ,SAAS,OAAO,EAAE,EAAE,SAAS;CAC3C,IAAI,YAAY;CAEhB,MAAM,eAAyB,CAAC,CAAC;CAEjC,KAAK,MAAM,CAAC,OAAO,UAAU,OAAO,QAAQ,GAAG;EAC9C,MAAM,WAAW,MAAM,QAAQ;EAC/B,MAAM,QAAQ,aAAa,SAAS;EACpC,MAAM,QAAQ,SAAS,CAAC;EACxB,IAAI;EAEJ,IAAI,MAAM,SAAS,SAClB,OACE,SAAS,UAAU,KACnB,MAAM,SAAS,UAAU,SAAS,IAAI,MAAM,IAAI,IAC9C,YACA;OAEJ,QAAQ,MAAM,MAAd;GACC,KAAK;GACL,KAAK;IACJ,OAAO,aAAa,UAAU,aAAa,UAAU,SAAS;IAC9D,aAAa,KAAK,CAAC;IACnB;GACD,KAAK;IACJ,OAAO;IACP,aAAa,KAAK,CAAC;IACnB;GACD,KAAK;GACL,KAAK;GACL,KAAK;IACJ,OAAO;IACP,IAAI,aAAa,SAAS,GAAG,aAAa,IAAI;IAC9C;GACD,KAAK;IACJ,OAAO;IACP,IAAI,SAAS,UAAU,GAAG,YAAY;IACtC;GACD,KAAK;IACJ,OAAO;IACP;GACD,KAAK;GACL,KAAK;GACL,KAAK;IACJ,OAAO;IACP;GACD,KAAK;IACJ,OAAO,QAAQ,WAAW;IAC1B;GACD,KAAK;GACL,KAAK;IACJ,OACC,aAAa,KAAA,KACZ,aAAa,UAAU,aAAa,UAClC,UACA;IACJ;GACD,KAAK;GACL,KAAK;IACJ,OAAO,QAAQ,QAAQ;IACvB,IAAI,MAAM,SAAS,OAAO,CAAC,OAC1B,aAAa,UAAU,aAAa,UAAU,KAAK;IAEpD;GACD,KAAK;IACJ,KAAK,aAAa,UAAU,KAAK,GAAG;KACnC,aAAa,UAAU,aAAa,UAAU,KAAK;KACnD,OAAO;IACR,OAAO,OAAO;IACd;GACD;IACC,OAAO;IACP,IAAI,SAAS,UAAU,KAAK,MAAM,SAAS,KAAK,YAAY;EAC9D;EAED,MAAM,KAAK,IAAI;CAChB;CACA,OAAO;AACR;;AAGA,MAAM,cACL,UACA,cACA,OACA,SACY;CACZ,IAAI,SAAS,WAAW,SAAS,WAAW,SAAS,SAAS,SAAS,QACtE,OAAO;CACR,IAAI,SAAS,SACZ,OAAO,MAAM,SAAS,OAAO,SAAS,SAAS,MAAM,MAAM;CAE5D,IAAI,iBAAiB,WAAW,iBAAiB,SAAS,OAAO;CACjE,IAAI,iBAAiB,UAAU,OAAO;CACtC,IAAI,iBAAiB,UAAU,iBAAiB,QAC/C,OAAO,SAAS,SAAS,MAAM,MAAM;CAEtC,OAAO;AACR;;;;;;AAOA,MAAa,kBACZ,QACA,MACA,QACA,SACmB;CACnB,MAAM,SAAS,KAAK;CACpB,MAAM,OAAO,OAAO;CACpB,MAAM,QAAQ,OAAO,OAAO,SAAS;CACrC,IAAI,CAAC,QAAQ,CAAC,SAAS,MAAM,UAAU,MAAM,OAAO,SAAS,GAAG,OAAO;CAEvE,MAAM,SAAS,SAAS,QAAQ,OAAO,MAAM,GAAG,EAAE,CAAC;CACnD,MAAM,QAAQ,QAAQ,QAAQ,KAAK,SAAS,KAAK;CACjD,IAAI,MAAM,KAAK;CACf,IAAI,cAAc,KAAK,QAAQ,KAAK,MAAM;CAE1C,MAAM,WAAqB,CAAC;CAC5B,IAAI,OAAO;;CAEX,MAAM,SAAS,YACd,IAAI,IAAI,SAAS,MAAM,GAAG,SAAS,SAAS,OAAO,CAAC,CAAC,CAAC;CAEvD,KAAK,MAAM,CAAC,OAAO,UAAU,OAAO,QAAQ,GAAG;EAC9C,MAAM,OAAO,MAAM;EAEnB,IADY,OAAO,MAAM,aAAa,MAAM,KACtC,CAAC,CAAC,SAAS,IAAI,GAAG;GACvB;GAEA,IAAI,UAAU;GACd,OACC,MAAM,QAAQ,aAAa,YAC1B,YAAY,KACZ,CAAC,OACC,MACC,OAAO,QAAQ,UAAU,EAAE,CAAW,KACtC,OAAO,QAAQ,QAAQ,CAAW,KACpC,CAAC,CACA,SAAS,IAAI,IAEhB;GAED,OAAO,KAAK,SAAS,KAAK,OAAO,UAAU,IAAI,MAAM,OAAO,IAAI,KAAK,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;EACtF,OAAO,IAAI,UAAU,GAAG,OAAO;OAE9B,OAAO,WACN,OAAO,QAAQ,IACf,MAAM,QAAQ,IACd,OACA,IACD;EAED,OAAO,MAAM;EACb,IAAI,SAAS,UAAU,SAAS,QAAQ,SAAS,KAAK,IAAI;OACrD,IAAI,SAAS,SAAS,SAAS,IAAI;EACxC,cAAc,MAAM;CACrB;CAEA,MAAM,aAAa,KAAK,MAAM,MAAM,MAAM;CAC1C,OAAO,OAAO,MAAM,aAAa,UAAU,CAAC,CAAC,SAAS,IAAI,IACvD,KAAK,WACL;CACH,OAAO,MAAM,MAAM;AACpB;;;;ACjOA,IAAa,kBAAb,cAAqC,MAAM;CAC1C,OAAgB;AACjB;AAwCA,MAAM,gCAAgB,IAAI,IAAI;CAC7B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;;AAGD,MAAM,+BAAe,IAAI,IAAI,CAAC,UAAU,OAAO,CAAC;;AAEhD,MAAM,gCAAgB,IAAI,IAAI;CAC7B;CACA;CACA;CACA;CACA;AACD,CAAC;;AAGD,MAAM,iBAAiB,MAAc,OAAe,SAA0B;CAC7E,IAAI,SAAS,aAAa,OAAO;CACjC,MAAM,MAAM,QAAQ,IAAI,KAAK;CAC7B,OACC,KAAK,MAAM,OAAO,GAAG,CAAC,CAAC,YAAY,MAAM,KAAK,WAC7C,QAAQ,KAAK,UAAU,SAAS,KAAK,KAAK,IAAc;AAE3D;;;;;AAMA,MAAM,YACL,SACA,SACa;CACb,MAAM,QAAQ,4CAA4C,KAAK,OAAO;CACtE,OACC,UAAU,QACV,MAAM,OAAO,KAAK,QAClB,KAAK,UAAU,MACd,MAAM,OAAO,OAAO,aAAa,KAAK,MAAM,EAAY;AAE3D;;AAGA,MAAM,YAA+C;CACpD,IAAI,CAAC,IAAI;CACT,IAAI,CAAC,MAAM,IAAI;CACf,IAAI,CAAC,MAAM,IAAI;CACf,GAAG,CAAC,GAAG;CACP,QAAQ,CAAC,QAAQ;CACjB,IAAI,CAAC,IAAI;CACT,IAAI,CAAC,MAAM,IAAI;CACf,IAAI,CAAC,MAAM,IAAI;CACf,OAAO,CAAC,SAAS,OAAO;CACxB,OAAO,CAAC,SAAS,OAAO;AACzB;;AAGA,MAAM,6BAAa,IAAI,IAAI;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;;AAGD,MAAM,UACL,SAC0E;CAC1E,MAAM,OAAO,KAAK,OAAO;CACzB,IAAI,MAAM,SAAS,QAAQ,OAAO;CAClC,IAAI,WAAW,IAAI,KAAK,KAAK,GAAG;EAC/B,IACC,KAAK,UAAU,SACf,KAAK,OAAO,MAAM,UAAU,MAAM,SAAS,WAAW,MAAM,UAAU,GAAG,GAEzE,OAAO;EAGR,IAAI,KAAK,UAAU,WAAW,KAAK,OAAO,SAAS,GAAG,OAAO;EAC7D,OAAO;GAAE,MAAM;GAAQ,MAAM,KAAK;EAAM;CACzC;CACA,IAAI,KAAK,UAAU,UAAU,KAAK,UAAU,UAC3C,OAAO,EAAE,MAAM,SAAS;CACzB,IAAI,KAAK,MAAM,WAAW,KAAK,GAC9B,OAAO;EAAE,MAAM;EAAS,MAAM,KAAK,MAAM,MAAM,CAAC;CAAE;CAEnD,OAAO;AACR;AAEA,MAAM,YAAY,SACjB,SAAS,KAAA,KAAa,WAAW,KAAK,IAAI;AAE3C,MAAM,UAAU,SAAiB,OAAO,OAAO,cAAc,IAAI;;AAGjE,MAAM,cAAc,SAA2B;CAC9C,MAAM,SAAS,CAAC,CAAC;CACjB,KAAK,IAAI,QAAQ,KAAK,QAAQ,IAAI,GAAG,UAAU,KAAK;EACnD,OAAO,KAAK,QAAQ,CAAC;EACrB,QAAQ,KAAK,QAAQ,MAAM,QAAQ,CAAC;CACrC;CACA,OAAO;AACR;;;;;;AAOA,MAAM,aAAa,MAAc,UAA2B;CAC3D,MAAM,SAAS,WAAW,IAAI;CAC9B,MAAM,QAAgB,CAAC;CACvB,MAAM,UAAqB,CAAC;CAC5B,MAAM,QAAiB,CAAC;CACxB,IAAI,OAAa,EAAE,MAAM,OAAO;CAChC,IAAI,cAAc;CAElB,IAAI,cAAc;CAElB,MAAM,YAAY,UACjB,KAAK,MAAM,OAAO,QAAQ,OAAO,QAAQ,MAAM,KAAK,MAAM;;CAE3D,MAAM,YAAY,WAAmB;EACpC,IAAI,QAAQ;EACZ,OAAO,QAAQ,KAAK,UAAU,OAAQ,SAAS,KAAK,MAAgB,GACnE;EAED,OAAO,UAAU,KAAK,UAAU,KAAK,WAAW;CACjD;CACA,MAAM,gBAAgB,MAAM,SAAS;;CAGrC,MAAM,WAAW,MAAc,OAAe,UAAmB;EAChE,MAAM,OAAO,MAAM;EACnB,IAAI,SAAS,MAAM,SAAS,UAC3B,KAAK,QAAQ,KAAK,IAAI,KAAK,OAAO,KAAK;CAEzC;CAEA,MAAM,WAAW,SAAyB;EACzC,MAAM,OAAO,MAAM;EACnB,OAAO,MAAM,SAAS,WAAW,KAAK,QAAQ,MAAM;CACrD;;CAGA,MAAM,aAAa,UAAkB;EACpC,MAAM,QAAQ,MAAM;EACpB,MAAM,UAAU,SAAS,KAAK,CAAC,CAAC,UAAU;EAC1C,cAAc;EACd,QAAQ,KAAK,MAAb;GACC,KAAK;IACJ,MAAM,KAAK;KAAE,MAAM;KAAU;KAAO,OAAO,MAAM;IAAO,CAAC;IACzD;GACD,KAAK,OAAO;IACX,IAAI,KAAK,UAAU,MAAM;KACxB,MAAM,KAAK;MAAE,MAAM;MAAQ;KAAM,CAAC;KAClC;IACD;IACA,MAAM,OAAO,QAAQ,KAAK,IAAI;IAC9B,MAAM,QACL,QAAQ,WAAW,GAAG,KAAK,QAAQ,WAAW,IAAI,IAC/C,OACA,OAAO,IAAI,KAAK;IACpB,MAAM,KAAK;KAAE,MAAM;KAAU;KAAO;IAAM,CAAC;IAC3C;GACD;GACA,KAAK;IACJ,MAAM,KACL,QAAQ,WAAW,KAAK,IACrB;KAAE,MAAM;KAAU;KAAO,OAAO,KAAK;IAAM,IAC3C;KAAE,MAAM;KAAS;KAAO,QAAQ,KAAK;IAAO,CAChD;IACA;GACD,KAAK;IACJ,IAAI,KAAK,MAAM,MAAM,KAAK;KAAE,MAAM;KAAQ;IAAM,CAAC;SAC5C,IAAI,cAAc,SAAS,GAAG,KAAK,IAAI,GAC3C,MAAM,KAAK;KAAE,MAAM;KAAU;KAAO,OAAO,KAAK;IAAM,CAAC;SACjD,MAAM,KAAK;KAAE,MAAM;KAAS;KAAO,QAAQ,KAAK;IAAO,CAAC;IAC/D;GACD,KAAK,QACJ,MAAM,KACL,SAAS,SAAS,IAAI,IACnB;IAAE,MAAM;IAAU;IAAO,OAAO,KAAK;GAAM,IAC3C;IAAE,MAAM;IAAQ;GAAM,CAC1B;EACF;CACD;;CAGA,MAAM,oBACL,EAAE,KAAK,SAAS,SAAS,KAAK,UAAU,SACxC,EAAE,KAAK,SAAS,SAAS,KAAK,SAC9B,KAAK,SAAS;CAEf,MAAM,aACL,KACA,gBACI;EACJ,OAAO,EAAE,MAAM,OAAO;EACtB,MAAM,OAAO,IAAI;EACjB,IAAI,IAAI,SAAS;GAEhB,KAAK,IAAI,QAAQ,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS;IACvD,MAAM,QAAQ,MAAM;IACpB,IAAI,MAAM,SAAS,QAAQ;IAC3B,IAAI,MAAM,SAAS,MAAM;KACxB,MAAM,SAAS;KACf,QAAQ,IAAI,MAAM,OAAO,IAAI,WAAW;KACxC;IACD;GACD;GACA;EACD;EACA,IAAI,KAAK,WAAW,GAAG,KAAK,eAAe,cAAc,IAAI,IAAI,GAAG;EACpE,IAAI,aAAa,IAAI,IAAI,KAAK,cAAc,IAAI,IAAI,GAAG;GACtD,OAAO;IACN,MAAM;IACN;IACA,MAAM,cAAc,IAAI,IAAI;IAC5B,QAAQ,IAAI;IACZ,OAAO,MAAM;GACd;GACA;EACD;EACA,MAAM,MAAM,MAAM,MAAM,SAAS;EACjC,IAAI,KAAK,SAAS,UAAU,UAAU,IAAI,KAAK,EAAE,SAAS,IAAI,GAAG;GAChE,MAAM,IAAI;GACV,QAAQ,IAAI,MAAM,MAAM,QAAQ,IAAI,WAAW;EAChD;EACA,MAAM,KAAK;GAAE,MAAM;GAAQ;EAAK,CAAC;CAClC;;CAGA,MAAM,YAAY,OAAe,YAA6B;EAC7D,MAAM,YAAY,SAAS,UAAU,IAAI;EACzC,IAAI,UAAU;EACd,OACC,UAAU,KAAK,UACf,kBAAkB,KAAK,KAAK,QAAkB,GAE9C;EAED,OAAO;GACN,MAAM;GACN,MAAM,KAAK,MAAM,WAAW,OAAO,CAAC,CAAC,YAAY;GACjD;GACA,OAAO;GACP,MAAM,QAAQ;GACd;GACA,OAAO;EACR;EACA,cAAc;EACd,OAAO;CACR;;CAGA,MAAM,YAAY,OAAe,QAAgB;EAChD,KAAK,IAAI,QAAQ,OAAO,QAAQ,KAAK,SAAS;GAC7C,MAAM,OAAO,KAAK;GAClB,IAAI,SAAS,MAAM;IAClB,QAAQ,QAAQ,KAAK,YAAY;IACjC,IAAI,QAAQ,IAAI,KAAK,UAAU,QAAQ,CAAC;SACnC,IAAI,QAAQ,MAAM,KAAK,QAAQ,CAEpC,OAAO,cAAc,QAAQ;IAC7B;GACD;GACA,QAAQ,KAAK,MAAb;IACC,KAAK;KACJ,IAAI,SAAS,OAAO,SAAS,OAAQ,SAAS,MAAM;KACpD,IAAI,SAAS,KAAK;MACjB,IAAI,KAAK,WAAW,QAAQ,KAAK,GAAG;OACnC,OAAO;QACN,MAAM;QACN,QAAQ,QAAQ;QAChB,OAAO,QAAQ,QAAQ,CAAC;OACzB;OACA,cAAc;OACd,SAAS;MACV,OAAO,IAAI,KAAK,QAAQ,OAAO,OAAO,SAAS,KAAK,QAAQ,EAAE,GAC7D,QAAQ,SAAS,OAAO,IAAI,IAAI;WAC1B,IAAI,SAAS,KAAK,QAAQ,EAAE,KAAK,KAAK,QAAQ,OAAO,KAC3D,QAAQ,SAAS,OAAO,KAAK,IAAI;WAC3B,cAAc;KACtB,OAAO,cAAc;KACrB;IACD,KAAK;KACJ,IAAI,KAAK,UAAU,MACd;UAAA,SAAS,KAAK,OAAO,KAAK,QAAQ;KAAA,OAChC,IAAI,SAAS,QAAO,SAAS,KAAK,KAAK,QAAQ;UACjD,IAAI,SAAS,KAAK,UAAU,MAAM,KAAK,QAAQ,OAAO,GAAG;UACzD,IAAI,SAAS,OAAO,SAAS,OAAQ,SAAS,MAClD,cAAc;KAEf;IACD,KAAK;KACJ,IAAI,KAAK,WAAW,OAAO,KAAK,GAAG;MAClC,OAAO,EAAE,MAAM,OAAO;MACtB,SAAS;KACV;KACA;IACD,KAAK,OACJ,IAAI,SAAS,OAAO,cAAc,MAAM,OAAO,KAAK,IAAI,GACvD,QAAQ,SAAS,OAAO,IAAI,IAAI;GAKnC;EACD;CACD;;CAGA,MAAM,YAAY,SAAwB;EACzC,MAAM,OAAO,OAAO,IAAI;EACxB,MAAM,QAAQ;EACd,cAAc;EACd,IAAI,CAAC,MAAM;EACX,IAAI,KAAK,SAAS,OAAO;GACxB,MAAM,OAAO,QAAQ,KAAK,IAAI,IAAI;GAClC,IAAI,KAAK,SAAS,QAAQ,KAAK;QAC1B,IAAI,KAAK,SAAS,SAAS;IAC/B,KAAK,QAAQ,KAAK,IAAI,GAAG,KAAK,QAAQ,CAAC;IACvC,QAAQ,QAAQ,GAAG,OAAO,KAAK,OAAO,KAAK;GAC5C,OAAO,QAAQ,QAAQ,GAAG,OAAO,KAAK,QAAQ,GAAG,KAAK;GACtD;EACD;EACA,IAAI,KAAK,SAAS,QAAQ;GACzB,IAAI,KAAK,SAAS,UAAU,KAAK,SAAS,KAAK,MAAM,KAAK;QACrD,IACJ,KAAK,SAAS,WACd,KAAK,SAAS,KAAK,QACnB,EAAE,KAAK,UAAU,GAChB;IACD,MAAM,QAAQ,MAAM,eAAe,UAAU,MAAM,SAAS,MAAM;IAClE,IAAI,UAAU,IAAI,MAAM,SAAS;IACjC,OAAO,EAAE,MAAM,OAAO;GACvB;GACA;EACD;EACA,IAAI,KAAK,SAAS,QAAQ;EAC1B,IAAI,KAAK,SAAS,QAAQ;GACzB,MAAM,KAAK;IAAE,MAAM;IAAQ,MAAM,KAAK;GAAK,CAAC;GAC5C,IACC,KAAK,SAAS,eACZ,KAAK,SAAS,SAAS,KAAK,SAAS,YACtC,EAAE,SAAS,SAAS,KAAK,GAAG,IAE7B,OAAO;IACN,MAAM;IACN,MAAM,KAAK;IACX,OAAO;IACP,OAAO,MAAM,SAAS;GACvB;GAED;EACD;EACA,MAAM,QACL,KAAK,SAAS,WACX,MAAM,eAAe,UAAU,MAAM,SAAS,MAAM,IACpD,MAAM,eACL,UAAU,MAAM,SAAS,UAAU,MAAM,SAAS,KAAK,IACzD;EACH,IAAI,UAAU,IAAI;EAElB,MAAM,SAAS,KAAK,SAAS,WAAW,QAAQ,IAAI;EACpD,QAAQ,QAAQ,GAAG,OAAO,KAAK;CAChC;CAEA,UAAU,CAAC;CACX,MAAM,aAAsD,CAAC;CAE7D,KAAK,MAAM,QAAQ,OAAO;EACzB,IAAI,gBAAgB,IAAI;GACvB,UAAU,WAAW;GACrB,cAAc;EACf;EACA,IAAI,KAAK,SAAS,QAAQ;GACzB,SAAS,KAAK,OAAO,KAAK,GAAG;GAC7B;EACD;EACA,MAAM,OAAO,QAAQ;EACrB,IAAI,KAAK,SAAS,WAAW,cAAc;OACtC;GACJ,WAAW,KAAK;IAAE;IAAM;GAAK,CAAC;GAC9B,IAAI,KAAK,SAAS,OAAO,SAAS,IAAI;QACjC,cAAc;EACpB;EAEA,KACC,IAAI,QAAQ,KAAK,QAAQ,MAAM,KAAK,KAAK,GACzC,UAAU,MAAM,QAAQ,KAAK,KAC7B,QAAQ,KAAK,QAAQ,MAAM,QAAQ,CAAC,GACnC;GACD,QAAQ,QAAQ,KAAK,KAAK,SAAS;GACnC,MAAM,KACL,KAAK,SAAS,YACX;IAAE,MAAM;IAAS,OAAO,QAAQ;IAAG,QAAQ;GAAK,IAChD;IAAE,MAAM;IAAU,OAAO,QAAQ;GAAE,CACvC;EACD;CACD;CACA,QAAQ,QAAQ,OAAO,YAAY;CACnC,OAAO;EAAE;EAAO;EAAS;CAAW;AACrC;AAEA,MAAM,WAAW,YAAoB,aAA6B;CACjE,IAAI,QAAQ;CACZ,KAAK,MAAM,QAAQ,YAAY,SAAS,SAAS,MAAO,WAAW;CACnE,OAAO;AACR;;;;AAKA,MAAM,aACL,MACA,OACA,YACkB;CAClB,MAAM,EAAE,SAAS,aAAa;CAC9B,MAAM,OAAO,UAAU,MAAO,IAAI,OAAO,QAAQ;CACjD,MAAM,iBAAiB,UACtB,UACG,IAAK,OAAO,KAAK,MAAM,QAAQ,QAAQ,CAAC,IAAI,IAAI,OAAO,QAAQ,QAAQ,IACvE,IAAI,OAAO,KAAK;CACpB,MAAM,EAAE,OAAO,SAAS,eAAe,UAAU,MAAM,KAAK;CAE5D,MAAM,aAAa,SAAiB;EACnC,MAAM,QAAQ,MAAM,KAAK,EAAE,SAAS;EACpC,IAAI,MAAM;EACV,OAAO,KAAK,SAAS,OAAO,KAAK,SAAS,KAAM;EAChD,OAAO,KAAK,MAAM,OAAO,GAAG;CAC7B;;CAEA,MAAM,WAAW,SAAiB;EACjC,MAAM,OAAO,MAAM,OAAO,EAAE,EAAE;EAC9B,IAAI,SAAS,KAAA,GAAW,OAAO,OAAO;EACtC,OAAO,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK;CACrD;CACA,MAAM,WAAW,SAAiB;EACjC,MAAM,OAAO,MAAM;EACnB,OACC,KAAK,SAAS,UACd,KAAK,SAAS,YACd,KAAK,MAAM,KAAK,OAAO,QAAQ,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM;CAEnD;CAIA,IAAI,eAAe;CACnB,OAAO,eAAe,MAAM,UAAU,QAAQ,YAAY,GAAG;CAC7D,IAAI,cAAc,MAAM,SAAS;CACjC,OAAO,eAAe,KAAK,QAAQ,WAAW,GAAG;CAEjD,MAAM,6BAAa,IAAI,IAA2B;CAClD,MAAM,aAAa,SAAgC;EAClD,IAAI,WAAW,IAAI,IAAI,GAAG,OAAO,WAAW,IAAI,IAAI,KAAK;EACzD,MAAM,OAAO,MAAM;EACnB,IAAI,SAAwB;EAC5B,IAAI,MAAM,SAAS,UAElB,SACC,SAAS,eAAe,UAAU,IAAI,IAAI,KAAK,OAAO,KAAK,KAAK;OAC3D,IAAI,MAAM,SAAS,SAAS;GAClC,MAAM,SAAS,UAAU,KAAK,MAAM;GACpC,MAAM,QACL,WAAW,OACR,IACA,QAAQ,QAAQ,QAAQ,IACzB,QAAQ,UAAU,KAAK,MAAM,GAAG,QAAQ;GAC3C,SAAS,cACR,KAAK,IAAI,GAAG,QAAQ,UAAU,IAAI,GAAG,QAAQ,IAAI,KAAK,CACvD;EACD;EACA,WAAW,IAAI,MAAM,MAAM;EAC3B,OAAO;CACR;CAEA,MAAM,QAAsB,CAAC;CAE7B,IAAI,gBAAgB;CAEpB,KAAK,MAAM,CAAC,OAAO,SAAS,MAAM,QAAQ,GAAG;EAC5C,IAAI,QAAQ,aAAa;EACzB,IAAI,QAAQ,cAAc;EAC1B,MAAM,QAAQ,KAAK;EACnB,MAAM,MAAM,QAAQ,KAAK;EACzB,IAAI,QAAQ,KAAK,GAAG;GACnB,IAAI,KAAK,SAAS,YAAY,eAC7B,MAAM,KAAK;IAAE;IAAO,KAAK,MAAM;IAAG,MAAM;GAAG,CAAC;QACtC,IAAI,MAAM,OAAO,MAAM,KAAK;IAAE;IAAO;IAAK,MAAM;GAAG,CAAC;GAC3D,gBAAgB;GAChB;EACD;EACA,gBAAgB;EAEhB,MAAM,SAAS,UAAU,KAAK;EAC9B,IAAI,WAAW,MAAM;GACpB,MAAM,UAAU,UAAU,KAAK;GAC/B,IAAI,YAAY,QACf,MAAM,KAAK;IAAE;IAAO,KAAK,QAAQ,QAAQ;IAAQ,MAAM;GAAO,CAAC;EAEjE;EACA,IAAI,QAAQ,UAAU,KAAK,SAAS,UAAU,UAAU,aAAa;GACpE,IAAI,OAAO;GACX,OAAO,OAAO,SAAS,UAAU,KAAK,KAAK,OAAO,EAAY,GAAG;GACjE,IAAI,OAAO,OAAO,CAAC,gBAAgB,YAAY,IAAI,GAClD,MAAM,KAAK;IAAE,OAAO;IAAM;IAAK,MAAM;GAAG,CAAC;EAE3C;CACD;CAEA,KAAK,MAAM,EAAE,MAAM,UAAU,YAAY;EACxC,MAAM,SAAS,UAAU,IAAI,KAAK,UAAU,IAAI;EAChD,MAAM,UAAU,eAAe,MAAM,MAAM,QAAQ,IAAI;EACvD,IAAI,YAAY,QAAQ,YAAY,KAAK,MAAM,KAAK,OAAO,KAAK,GAAG,GAClE,MAAM,KAAK;GAAE,OAAO,KAAK;GAAO,KAAK,KAAK;GAAK,MAAM;EAAQ,CAAC;CAEhE;CAEA,OAAO,MAAM,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG;AAC/D;AAEA,MAAM,mBACL,YACA,WACI,WAAW,MAAM,EAAE,WAAW,SAAS,KAAK,SAAS,SAAS,KAAK,GAAG;AAE3E,MAAM,cAAc,MAAc,UAAyC;CAC1E,IAAI,MAAM;CACV,IAAI,WAAW;CACf,KAAK,MAAM,QAAQ,OAAO;EACzB,OAAO,KAAK,MAAM,UAAU,KAAK,KAAK,IAAI,KAAK;EAC/C,WAAW,KAAK;CACjB;CACA,OAAO,MAAM,KAAK,MAAM,QAAQ;AACjC;;AAGA,MAAM,iBAAiB,UACtB,MACE,QAAQ,mBAAmB,EAAE,CAAC,CAC9B,QAAQ,iBAAiB,EAAE,CAAC,CAC5B,QAAQ,WAAW,IAAI;;AAG1B,MAAM,iBAAiB,UAA4B;CAClD,IAAI,MAAM,QAAQ,KAAK,GACtB,OAAO,MACL,IAAI,aAAa,CAAC,CAClB,QACC,SACA,EACC,OAAO,SAAS,YAChB,SAAS,QACR,KAA4B,SAAS,UACrC,KAA6B,UAAU,GAE3C;CAEF,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,OAAgC,CAAC;CACvC,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,KAAK,GAAG;EAChD,IAAI,QAAQ,UAAU,QAAQ,cAAc,QAAQ,UAAU;EAC9D,KAAK,OACJ,QAAQ,WAAY,MAA6B,SAAS,SACvD,cAAc,IAAc,IAC5B,cAAc,IAAI;CACvB;CACA,OAAO;AACR;;AAGA,MAAM,SAAS,SACd,KAAK,UAAU,cAAc,MAAM,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;;;;AAK1D,MAAa,eACZ,MACA,UAAyB,CAAC,MACR;CAClB,MAAM,SAAS,MAAM,MAAM,EAAE,OAAO,CAAC;CACrC,IAAI,OAAO,SAAS,SAAS,GAAG;EAC/B,MAAM,SAAS,IAAI,OAAO,iBAAiB,IAAI;EAC/C,MAAM,IAAI,gBACT,OAAO,SAAS,KAAK,YACpB,iBAAiB,QAAQ,QAAQ,MAAM,QAAQ,SAAS,QAAQ,IAAI,CACrE,GACA,MACD;CACD;CAEA,MAAM,WAAW,QAAQ,YAAY;CACrC,IAAI,CAAC,OAAO,UAAU,QAAQ,KAAK,WAAW,GAC7C,MAAM,IAAI,WACT,0DAA0D,UAC3D;CAED,IAAI,QAAQ,UAAU,MAAM,UAAU,IAAI,CAAC,CAAC,OAAO;EAClD,SAAS,QAAQ,WAAW;EAC5B;CACD,CAAC;CACD,MAAM,QAAQ,QAAQ;CACtB,IAAI,OACH,QAAQ,MAAM,QACZ,SAAS,KAAK,OAAO,MAAM,SAAS,KAAK,SAAS,MAAM,GAC1D;CAGD,MAAM,YAAY,WAAW,MAAM,KAAK;CAExC,IADgB,MAAM,WAAW,EAAE,OAAO,CAChC,CAAC,CAAC,SAAS,SAAS,KAAK,MAAM,SAAS,MAAM,MAAM,IAAI,GACjE,MAAM,IAAI,gBACT,sHACD;CAED,OAAO;AACR;;;;;;;;;;;AAYA,MAAa,UAAU,MAAc,UAAyB,CAAC,MAC9D,WAAW,MAAM,YAAY,MAAM,OAAO,CAAC"}
|
package/dist/format.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","names":[],"sources":["../src/formatter/format.ts"],"mappings":";KAQY;;EAEX;;EAEA;;EAEA;IAAU;IAAe;;;;KAId;EAAe;EAAe;EAAa;;;qBAG1C,wBAAwB;EAC3B;;;;;
|
|
1
|
+
{"version":3,"file":"format.d.ts","names":[],"sources":["../src/formatter/format.ts"],"mappings":";KAQY;;EAEX;;EAEA;;EAEA;IAAU;IAAe;;;;KAId;EAAe;EAAe;EAAa;;;qBAG1C,wBAAwB;EAC3B;;;;;qBAqoBG,cAAW,cACX,UACH,kBACP;;;;;;;;;;;qBAiDU,SAAM,cAAgB,UAAW"}
|
package/dist/format.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as KilnFormatError, n as format, r as formatEdits } from "./format-
|
|
1
|
+
export { t as KilnFormatError, n as format, r as formatEdits } from "./format-Di6-GUtH.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as PropType, l as ShapeKey, m as Position, p as TypeName, r as EscapeStrategy } from "./ast-
|
|
2
|
-
import { A as AbortSignalLike, B as islandScript, C as HtmlCheck, D as AnalysedProp, E as PrecompiledTemplate, F as IslandManifest, G as TemplateLocation, H as Diagnostic, I as IslandMode, L as JsonValue, M as RenderInfo, N as DeferredIslands, O as Analysis, P as IslandEntry, R as StreamedIslands, S as withRender, T as HtmlChecks, U as KilnRenderError, V as streamIslands, W as KilnSyntaxError, _ as TemplateName, a as KilnGlobals, b as memoryCache, c as KilnTemplates, d as Limits, f as Loader, g as TemplateContext, h as TemplateBlock, i as KilnFunctions, j as KilnCache, k as TemplateReference, l as KilnTests, m as RenderOptions, n as KilnCallable, o as KilnOptions, p as RenderAware, r as KilnFilters, s as KilnSchema, t as Kiln, u as KilnTypes, v as TypeChecks, w as HtmlCheckLevel, x as memoryLoader, y as createKiln, z as deferIslands } from "./environment-
|
|
1
|
+
import { c as PropType, l as ShapeKey, m as Position, p as TypeName, r as EscapeStrategy } from "./ast-DDhHuwaY.js";
|
|
2
|
+
import { A as AbortSignalLike, B as islandScript, C as HtmlCheck, D as AnalysedProp, E as PrecompiledTemplate, F as IslandManifest, G as TemplateLocation, H as Diagnostic, I as IslandMode, L as JsonValue, M as RenderInfo, N as DeferredIslands, O as Analysis, P as IslandEntry, R as StreamedIslands, S as withRender, T as HtmlChecks, U as KilnRenderError, V as streamIslands, W as KilnSyntaxError, _ as TemplateName, a as KilnGlobals, b as memoryCache, c as KilnTemplates, d as Limits, f as Loader, g as TemplateContext, h as TemplateBlock, i as KilnFunctions, j as KilnCache, k as TemplateReference, l as KilnTests, m as RenderOptions, n as KilnCallable, o as KilnOptions, p as RenderAware, r as KilnFilters, s as KilnSchema, t as Kiln, u as KilnTypes, v as TypeChecks, w as HtmlCheckLevel, x as memoryLoader, y as createKiln, z as deferIslands } from "./environment-DBvRrOn0.js";
|
|
3
3
|
//#region src/runtime/markup.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* A string that is already safe to output with one escaping strategy.
|