@askrjs/vite 0.2.0 → 0.2.2

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.
@@ -1,8 +1,8 @@
1
1
 
2
2
  import { r as IMAGE_METADATA_PATH, t as normalizeDeclarationOptions } from "./image-options-B-QnEqPc.js";
3
3
  import { Image } from "./image.js";
4
- import path from "node:path";
5
4
  import { createHash } from "node:crypto";
5
+ import path from "node:path";
6
6
  import { existsSync, readFileSync } from "node:fs";
7
7
  import { fileURLToPath } from "node:url";
8
8
  //#region src/image-node.ts
package/dist/index.js CHANGED
@@ -2,9 +2,213 @@
2
2
  import { n as normalizeImageOptions, r as IMAGE_METADATA_PATH, t as normalizeDeclarationOptions } from "./image-options-B-QnEqPc.js";
3
3
  import { createRequire } from "node:module";
4
4
  import { Visitor, parseSync } from "oxc-parser";
5
+ import { createHash } from "node:crypto";
5
6
  import fs from "node:fs/promises";
6
7
  import path from "node:path";
7
- import { createHash } from "node:crypto";
8
+ //#region src/source-map-rewrites.ts
9
+ const BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
10
+ const BASE64_VALUES = new Map([...BASE64].map((character, index) => [character, index]));
11
+ function decodeVlq(value, cursor) {
12
+ let result = 0;
13
+ let shift = 0;
14
+ for (;;) {
15
+ const digit = BASE64_VALUES.get(value[cursor.value++]);
16
+ if (digit === void 0) throw new Error("Invalid sourcemap VLQ segment.");
17
+ result += (digit & 31) << shift;
18
+ if ((digit & 32) === 0) break;
19
+ shift += 5;
20
+ }
21
+ const negative = (result & 1) === 1;
22
+ result >>= 1;
23
+ return negative ? -result : result;
24
+ }
25
+ function encodeVlq(value) {
26
+ let remaining = Math.abs(value) << 1 | (value < 0 ? 1 : 0);
27
+ let output = "";
28
+ do {
29
+ let digit = remaining & 31;
30
+ remaining >>>= 5;
31
+ if (remaining > 0) digit |= 32;
32
+ output += BASE64[digit];
33
+ } while (remaining > 0);
34
+ return output;
35
+ }
36
+ function decodeMappings(value) {
37
+ const lines = [];
38
+ let source = 0;
39
+ let originalLine = 0;
40
+ let originalColumn = 0;
41
+ let name = 0;
42
+ for (const encodedLine of value.split(";")) {
43
+ const segments = [];
44
+ let generatedColumn = 0;
45
+ for (const encoded of encodedLine.split(",")) {
46
+ if (!encoded) continue;
47
+ const cursor = { value: 0 };
48
+ generatedColumn += decodeVlq(encoded, cursor);
49
+ const segment = [generatedColumn];
50
+ if (cursor.value < encoded.length) {
51
+ source += decodeVlq(encoded, cursor);
52
+ originalLine += decodeVlq(encoded, cursor);
53
+ originalColumn += decodeVlq(encoded, cursor);
54
+ segment.push(source, originalLine, originalColumn);
55
+ if (cursor.value < encoded.length) {
56
+ name += decodeVlq(encoded, cursor);
57
+ segment.push(name);
58
+ }
59
+ }
60
+ segments.push(segment);
61
+ }
62
+ lines.push(segments);
63
+ }
64
+ return lines;
65
+ }
66
+ function encodeMappings(lines) {
67
+ let previousSource = 0;
68
+ let previousOriginalLine = 0;
69
+ let previousOriginalColumn = 0;
70
+ let previousName = 0;
71
+ return lines.map((segments) => {
72
+ let previousGeneratedColumn = 0;
73
+ return segments.map((segment) => {
74
+ let encoded = encodeVlq(segment[0] - previousGeneratedColumn);
75
+ previousGeneratedColumn = segment[0];
76
+ if (segment.length >= 4) {
77
+ encoded += encodeVlq(segment[1] - previousSource);
78
+ encoded += encodeVlq(segment[2] - previousOriginalLine);
79
+ encoded += encodeVlq(segment[3] - previousOriginalColumn);
80
+ previousSource = segment[1];
81
+ previousOriginalLine = segment[2];
82
+ previousOriginalColumn = segment[3];
83
+ if (segment.length === 5) {
84
+ encoded += encodeVlq(segment[4] - previousName);
85
+ previousName = segment[4];
86
+ }
87
+ }
88
+ return encoded;
89
+ }).join(",");
90
+ }).join(";");
91
+ }
92
+ function lineStarts(code) {
93
+ const starts = [0];
94
+ for (let index = 0; index < code.length; index += 1) if (code[index] === "\n") starts.push(index + 1);
95
+ return starts;
96
+ }
97
+ function offsetAt(starts, line, column) {
98
+ return (starts[line] ?? starts[starts.length - 1]) + column;
99
+ }
100
+ function positionAt(starts, offset) {
101
+ let low = 0;
102
+ let high = starts.length;
103
+ while (low + 1 < high) {
104
+ const middle = low + high >>> 1;
105
+ if (starts[middle] <= offset) low = middle;
106
+ else high = middle;
107
+ }
108
+ return [low, offset - starts[low]];
109
+ }
110
+ function forwardOffset(offset, edits) {
111
+ let delta = 0;
112
+ for (const edit of edits) {
113
+ if (offset < edit.start) break;
114
+ if (offset < edit.end) return edit.start + delta;
115
+ delta += edit.replacement.length - (edit.end - edit.start);
116
+ }
117
+ return offset + delta;
118
+ }
119
+ function reverseOffset(offset, edits) {
120
+ let delta = 0;
121
+ for (const edit of edits) {
122
+ const generatedStart = edit.start + delta;
123
+ const generatedEnd = generatedStart + edit.replacement.length;
124
+ if (offset < generatedStart) break;
125
+ if (offset < generatedEnd) return edit.start;
126
+ delta += edit.replacement.length - (edit.end - edit.start);
127
+ }
128
+ return offset - delta;
129
+ }
130
+ function normalize(lines) {
131
+ return lines.map((segments) => {
132
+ const sorted = segments.sort((left, right) => left[0] - right[0]);
133
+ return sorted.filter((segment, index) => index === 0 || segment[0] !== sorted[index - 1][0]);
134
+ });
135
+ }
136
+ function mappingAt(lines, starts, offset) {
137
+ const [line, column] = positionAt(starts, offset);
138
+ let match;
139
+ for (const segment of lines[line] ?? []) {
140
+ if (segment[0] > column) break;
141
+ if (segment.length >= 4) match = segment;
142
+ }
143
+ return match;
144
+ }
145
+ /** Move generated coordinates after deterministic text edits. */
146
+ function remapGenerated(map, before, after, edits) {
147
+ const beforeStarts = lineStarts(before);
148
+ const afterStarts = lineStarts(after);
149
+ const decoded = decodeMappings(map.mappings);
150
+ const output = Array.from({ length: afterStarts.length }, () => []);
151
+ for (const [line, segments] of decoded.entries()) for (const segment of segments) {
152
+ const [nextLine, nextColumn] = positionAt(afterStarts, forwardOffset(offsetAt(beforeStarts, line, segment[0]), edits));
153
+ output[nextLine].push([nextColumn, ...segment.slice(1)]);
154
+ }
155
+ let delta = 0;
156
+ for (const edit of edits) {
157
+ if (edit.mapTo !== void 0) {
158
+ const mapped = mappingAt(decoded, beforeStarts, edit.mapTo);
159
+ if (mapped) {
160
+ const [line, column] = positionAt(afterStarts, edit.start + delta);
161
+ output[line].push([column, ...mapped.slice(1)]);
162
+ }
163
+ }
164
+ delta += edit.replacement.length - (edit.end - edit.start);
165
+ }
166
+ return {
167
+ ...map,
168
+ mappings: encodeMappings(normalize(output))
169
+ };
170
+ }
171
+ /** Move original coordinates back through deterministic text edits. */
172
+ function remapOriginal(map, original, rewritten, edits) {
173
+ const originalStarts = lineStarts(original);
174
+ const rewrittenStarts = lineStarts(rewritten);
175
+ const lines = decodeMappings(map.mappings);
176
+ for (const segments of lines) for (const segment of segments) {
177
+ if (segment.length < 4 || segment[1] !== 0) continue;
178
+ const [line, column] = positionAt(originalStarts, reverseOffset(offsetAt(rewrittenStarts, segment[2], segment[3]), edits));
179
+ segment[2] = line;
180
+ segment[3] = column;
181
+ }
182
+ return {
183
+ ...map,
184
+ mappings: encodeMappings(lines),
185
+ sourcesContent: map.sources?.map((_source, index) => index === 0 ? original : map.sourcesContent?.[index] ?? null)
186
+ };
187
+ }
188
+ /** Build a complete map for a rewritten source when no downstream map exists. */
189
+ function sourceMapForRewrite(original, rewritten, edits, id) {
190
+ const originalStarts = lineStarts(original);
191
+ const rewrittenStarts = lineStarts(rewritten);
192
+ const lines = Array.from({ length: rewrittenStarts.length }, () => []);
193
+ for (let offset = 0; offset < rewritten.length; offset += 1) {
194
+ const [generatedLine, generatedColumn] = positionAt(rewrittenStarts, offset);
195
+ const [originalLine, originalColumn] = positionAt(originalStarts, reverseOffset(offset, edits));
196
+ lines[generatedLine].push([
197
+ generatedColumn,
198
+ 0,
199
+ originalLine,
200
+ originalColumn
201
+ ]);
202
+ }
203
+ return {
204
+ version: 3,
205
+ names: [],
206
+ sources: [id],
207
+ sourcesContent: [original],
208
+ mappings: encodeMappings(lines)
209
+ };
210
+ }
211
+ //#endregion
8
212
  //#region src/template-optimizer.ts
9
213
  const OPTIMIZED_PROPS = /* @__PURE__ */ new Set([
10
214
  "class",
@@ -40,14 +244,20 @@ function collectCandidate(property, code, candidates) {
40
244
  });
41
245
  candidates.set(cacheKey, group);
42
246
  }
43
- function optimizeTemplateOutput(code) {
247
+ function optimizeTemplateOutputWithEdits(code) {
44
248
  const parsed = parseSync("askr-compiled.js", code, {
45
249
  lang: "js",
46
250
  sourceType: "module"
47
251
  });
48
- if (parsed.errors.length > 0) return code;
252
+ if (parsed.errors.length > 0) return {
253
+ code,
254
+ edits: []
255
+ };
49
256
  const runtimeFactories = collectRuntimeFactories(parsed.program);
50
- if (runtimeFactories.size === 0) return code;
257
+ if (runtimeFactories.size === 0) return {
258
+ code,
259
+ edits: []
260
+ };
51
261
  const candidates = /* @__PURE__ */ new Map();
52
262
  const identifiers = /* @__PURE__ */ new Set();
53
263
  new Visitor({
@@ -76,10 +286,27 @@ function optimizeTemplateOutput(code) {
76
286
  identifier
77
287
  });
78
288
  }
79
- if (declarations.length === 0) return code;
289
+ if (declarations.length === 0) return {
290
+ code,
291
+ edits: []
292
+ };
293
+ const prefix = `${declarations.join("\n")}\n`;
294
+ const edits = [{
295
+ start: 0,
296
+ end: 0,
297
+ replacement: prefix,
298
+ mapTo: replacements[0].start
299
+ }, ...replacements.map(({ start, end, identifier }) => ({
300
+ start,
301
+ end,
302
+ replacement: identifier
303
+ })).sort((left, right) => left.start - right.start)];
80
304
  let optimized = code;
81
305
  for (const replacement of replacements.sort((left, right) => right.start - left.start)) optimized = optimized.slice(0, replacement.start) + replacement.identifier + optimized.slice(replacement.end);
82
- return `${declarations.join("\n")}\n${optimized}`;
306
+ return {
307
+ code: `${prefix}${optimized}`,
308
+ edits
309
+ };
83
310
  }
84
311
  //#endregion
85
312
  //#region src/image-lexical.ts
@@ -130,6 +357,119 @@ function imageDeclarationMask(code) {
130
357
  for (let match = IMAGE_IMPORT.exec(code); match; match = IMAGE_IMPORT.exec(code)) if (mask[match.index]) return mask;
131
358
  }
132
359
  //#endregion
360
+ //#region src/image-declarations.ts
361
+ const IMAGE_CALL = /\bimage\s*\(\s*new\s+URL\s*\(\s*(["'])([^"']+)\1\s*,\s*import\.meta\.url\s*\)/g;
362
+ function staticJson(source, id) {
363
+ let output = "";
364
+ for (let index = 0; index < source.length;) {
365
+ const character = source[index];
366
+ if (/\s/.test(character) || "{}[]:".includes(character)) {
367
+ output += character;
368
+ index += 1;
369
+ continue;
370
+ }
371
+ if (character === ",") {
372
+ let next = index + 1;
373
+ while (/\s/.test(source[next] ?? "")) next += 1;
374
+ if (source[next] !== "}" && source[next] !== "]") output += character;
375
+ index += 1;
376
+ continue;
377
+ }
378
+ if (character === "\"" || character === "'") {
379
+ let end = index + 1;
380
+ while (end < source.length && source[end] !== character) {
381
+ if (source[end] === "\\") throw new Error(`@askrjs/vite image() option strings in ${id} cannot contain escape sequences.`);
382
+ end += 1;
383
+ }
384
+ if (end >= source.length) throw new Error(`@askrjs/vite found an unterminated image option in ${id}.`);
385
+ output += JSON.stringify(source.slice(index + 1, end));
386
+ index = end + 1;
387
+ continue;
388
+ }
389
+ const number = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:e[+-]?\d+)?/i.exec(source.slice(index));
390
+ if (number) {
391
+ output += number[0];
392
+ index += number[0].length;
393
+ continue;
394
+ }
395
+ const identifier = /^[A-Za-z_]\w*/.exec(source.slice(index));
396
+ if (identifier) {
397
+ let next = index + identifier[0].length;
398
+ while (/\s/.test(source[next] ?? "")) next += 1;
399
+ if (source[next] === ":") output += JSON.stringify(identifier[0]);
400
+ else if ([
401
+ "true",
402
+ "false",
403
+ "null"
404
+ ].includes(identifier[0])) output += identifier[0];
405
+ else throw new Error(`@askrjs/vite image() options in ${id} must not reference ${identifier[0]}; use a static object literal.`);
406
+ index += identifier[0].length;
407
+ continue;
408
+ }
409
+ throw new Error(`@askrjs/vite image() options in ${id} must be a static object literal so builds and direct SSG imports agree.`);
410
+ }
411
+ return output;
412
+ }
413
+ function staticOptions(source, id) {
414
+ const trimmed = source.trim();
415
+ if (!trimmed) return {};
416
+ let value;
417
+ try {
418
+ value = JSON.parse(staticJson(trimmed, id));
419
+ } catch (error) {
420
+ if (error instanceof Error && error.message.startsWith("@askrjs/vite")) throw error;
421
+ throw new Error(`@askrjs/vite could not parse image() options in ${id}.`, { cause: error });
422
+ }
423
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`@askrjs/vite image() options in ${id} must be an object literal.`);
424
+ return value;
425
+ }
426
+ function findCallEnd(code, start) {
427
+ let depth = 1;
428
+ let quote = "";
429
+ let escaped = false;
430
+ for (let index = start; index < code.length; index += 1) {
431
+ const character = code[index];
432
+ if (quote) {
433
+ if (escaped) escaped = false;
434
+ else if (character === "\\") escaped = true;
435
+ else if (character === quote) quote = "";
436
+ continue;
437
+ }
438
+ if (character === "\"" || character === "'") {
439
+ quote = character;
440
+ continue;
441
+ }
442
+ if (character === "(") depth += 1;
443
+ if (character === ")") {
444
+ depth -= 1;
445
+ if (depth === 0) return index;
446
+ }
447
+ }
448
+ return -1;
449
+ }
450
+ function imageDeclarations(code, id) {
451
+ const mask = imageDeclarationMask(code);
452
+ if (!mask) return [];
453
+ const output = [];
454
+ IMAGE_CALL.lastIndex = 0;
455
+ for (let match = IMAGE_CALL.exec(code); match; match = IMAGE_CALL.exec(code)) {
456
+ if (!mask[match.index]) continue;
457
+ const afterUrl = IMAGE_CALL.lastIndex;
458
+ const end = findCallEnd(code, afterUrl);
459
+ if (end < 0) throw new Error(`@askrjs/vite found an unterminated image() call in ${id}.`);
460
+ const remainder = code.slice(afterUrl, end).trim();
461
+ if (remainder && !remainder.startsWith(",")) throw new Error(`@askrjs/vite could not parse image() declaration in ${id}.`);
462
+ output.push({
463
+ start: match.index,
464
+ end: end + 1,
465
+ source: match[2],
466
+ options: staticOptions(remainder.replace(/^,/, ""), id)
467
+ });
468
+ IMAGE_CALL.lastIndex = end + 1;
469
+ }
470
+ return output;
471
+ }
472
+ //#endregion
133
473
  //#region src/image-inspection.ts
134
474
  function positiveDimensions(width, height, format, transformable, animated = false) {
135
475
  return width > 0 && height > 0 ? {
@@ -421,117 +761,6 @@ async function processImage(context, sourcePath, declarationOptions, globalOptio
421
761
  }
422
762
  //#endregion
423
763
  //#region src/image-pipeline.ts
424
- const IMAGE_CALL = /\bimage\s*\(\s*new\s+URL\s*\(\s*(["'])([^"']+)\1\s*,\s*import\.meta\.url\s*\)/g;
425
- function staticJson(source, id) {
426
- let output = "";
427
- for (let index = 0; index < source.length;) {
428
- const character = source[index];
429
- if (/\s/.test(character) || "{}[]:".includes(character)) {
430
- output += character;
431
- index += 1;
432
- continue;
433
- }
434
- if (character === ",") {
435
- let next = index + 1;
436
- while (/\s/.test(source[next] ?? "")) next += 1;
437
- if (source[next] !== "}" && source[next] !== "]") output += character;
438
- index += 1;
439
- continue;
440
- }
441
- if (character === "\"" || character === "'") {
442
- let end = index + 1;
443
- while (end < source.length && source[end] !== character) {
444
- if (source[end] === "\\") throw new Error(`@askrjs/vite image() option strings in ${id} cannot contain escape sequences.`);
445
- end += 1;
446
- }
447
- if (end >= source.length) throw new Error(`@askrjs/vite found an unterminated image option in ${id}.`);
448
- output += JSON.stringify(source.slice(index + 1, end));
449
- index = end + 1;
450
- continue;
451
- }
452
- const number = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:e[+-]?\d+)?/i.exec(source.slice(index));
453
- if (number) {
454
- output += number[0];
455
- index += number[0].length;
456
- continue;
457
- }
458
- const identifier = /^[A-Za-z_]\w*/.exec(source.slice(index));
459
- if (identifier) {
460
- let next = index + identifier[0].length;
461
- while (/\s/.test(source[next] ?? "")) next += 1;
462
- if (source[next] === ":") output += JSON.stringify(identifier[0]);
463
- else if ([
464
- "true",
465
- "false",
466
- "null"
467
- ].includes(identifier[0])) output += identifier[0];
468
- else throw new Error(`@askrjs/vite image() options in ${id} must not reference ${identifier[0]}; use a static object literal.`);
469
- index += identifier[0].length;
470
- continue;
471
- }
472
- throw new Error(`@askrjs/vite image() options in ${id} must be a static object literal so builds and direct SSG imports agree.`);
473
- }
474
- return output;
475
- }
476
- function staticOptions(source, id) {
477
- const trimmed = source.trim();
478
- if (!trimmed) return {};
479
- let value;
480
- try {
481
- value = JSON.parse(staticJson(trimmed, id));
482
- } catch (error) {
483
- if (error instanceof Error && error.message.startsWith("@askrjs/vite")) throw error;
484
- throw new Error(`@askrjs/vite could not parse image() options in ${id}.`, { cause: error });
485
- }
486
- if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`@askrjs/vite image() options in ${id} must be an object literal.`);
487
- return value;
488
- }
489
- function findCallEnd(code, start) {
490
- let depth = 1;
491
- let quote = "";
492
- let escaped = false;
493
- for (let index = start; index < code.length; index += 1) {
494
- const character = code[index];
495
- if (quote) {
496
- if (escaped) escaped = false;
497
- else if (character === "\\") escaped = true;
498
- else if (character === quote) quote = "";
499
- continue;
500
- }
501
- if (character === "\"" || character === "'") {
502
- quote = character;
503
- continue;
504
- }
505
- if (character === "(") depth += 1;
506
- if (character === ")") {
507
- depth -= 1;
508
- if (depth === 0) return index;
509
- }
510
- }
511
- return -1;
512
- }
513
- function declarations(code, id) {
514
- const mask = imageDeclarationMask(code);
515
- if (!mask) return [];
516
- const output = [];
517
- IMAGE_CALL.lastIndex = 0;
518
- for (let match = IMAGE_CALL.exec(code); match; match = IMAGE_CALL.exec(code)) {
519
- if (!mask[match.index]) continue;
520
- const afterUrl = IMAGE_CALL.lastIndex;
521
- const end = findCallEnd(code, afterUrl);
522
- if (end < 0) throw new Error(`@askrjs/vite found an unterminated image() call in ${id}.`);
523
- const remainder = code.slice(afterUrl, end).trim();
524
- if (remainder && !remainder.startsWith(",")) throw new Error(`@askrjs/vite could not parse image() declaration in ${id}.`);
525
- output.push({
526
- start: match.index,
527
- end: end + 1,
528
- source: match[2],
529
- options: staticOptions(remainder.replace(/^,/, ""), id)
530
- });
531
- IMAGE_CALL.lastIndex = end + 1;
532
- }
533
- return output;
534
- }
535
764
  function urlExpression(referenceId) {
536
765
  return `import.meta.ROLLUP_FILE_URL_${referenceId}`;
537
766
  }
@@ -586,23 +815,39 @@ var ImagePipeline = class {
586
815
  this.#config = config;
587
816
  }
588
817
  async transform(context, code, id) {
589
- const found = declarations(code, id);
818
+ return (await this.transformWithEdits(context, code, id))?.code;
819
+ }
820
+ async transformWithEdits(context, code, id) {
821
+ const found = imageDeclarations(code, id);
590
822
  if (found.length === 0) return void 0;
591
823
  if (!this.#config) throw new Error("@askrjs/vite image pipeline was not configured.");
592
824
  if (this.#config.command !== "build") throw new Error("@askrjs/vite responsive image declarations currently require a Vite build.");
593
825
  const cacheDir = path.join(this.#config.root, "node_modules/.cache/@askrjs/vite/images");
594
826
  let transformed = code;
827
+ const edits = [];
595
828
  for (const declaration of [...found].reverse()) {
596
829
  const sourcePath = path.resolve(path.dirname(id.split("?", 1)[0]), declaration.source);
597
830
  const key = declarationKey(sourcePath, declaration.options);
598
831
  let processed = this.#processed.get(key);
832
+ if (processed) {
833
+ if (createHash("sha256").update(await fs.readFile(sourcePath)).digest("hex") !== processed.sourceHash) processed = void 0;
834
+ }
599
835
  if (!processed) {
600
836
  processed = await processImage(context, sourcePath, declaration.options, this.#options, cacheDir, this.#sharpLoader);
601
837
  this.#processed.set(key, processed);
602
838
  }
603
- transformed = `${transformed.slice(0, declaration.start)}${imageExpression(processed)}${transformed.slice(declaration.end)}`;
839
+ const replacement = imageExpression(processed);
840
+ edits.push({
841
+ start: declaration.start,
842
+ end: declaration.end,
843
+ replacement
844
+ });
845
+ transformed = `${transformed.slice(0, declaration.start)}${replacement}${transformed.slice(declaration.end)}`;
604
846
  }
605
- return transformed;
847
+ return {
848
+ code: transformed,
849
+ edits: edits.sort((left, right) => left.start - right.start)
850
+ };
606
851
  }
607
852
  async writeMetadata(context) {
608
853
  if (!this.#config || this.#processed.size === 0) return;
@@ -704,11 +949,11 @@ function askrVitePlugin(options = {}) {
704
949
  },
705
950
  async transform(code, id) {
706
951
  if (id.includes("node_modules")) return null;
707
- const imageTransformed = imagePipeline ? await imagePipeline.transform(this, code, id) : void 0;
708
- const input = imageTransformed ?? code;
952
+ const imageTransformed = imagePipeline ? await imagePipeline.transformWithEdits(this, code, id) : void 0;
953
+ const input = imageTransformed?.code ?? code;
709
954
  if (!shouldTransform || !/\.(jsx|tsx)$/.test(id)) return imageTransformed ? {
710
- code: imageTransformed,
711
- map: null
955
+ code: imageTransformed.code,
956
+ map: sourceMapForRewrite(code, imageTransformed.code, imageTransformed.edits, id)
712
957
  } : null;
713
958
  try {
714
959
  const result = await (await loadTransformWithOxc())(input, id, {
@@ -720,9 +965,16 @@ function askrVitePlugin(options = {}) {
720
965
  sourcemap: true
721
966
  });
722
967
  if (!result?.code) return null;
968
+ let map = result.map;
969
+ if (imageTransformed) map = remapOriginal(map, code, input, imageTransformed.edits);
970
+ if (!shouldOptimizeTemplates) return {
971
+ code: result.code,
972
+ map
973
+ };
974
+ const optimized = optimizeTemplateOutputWithEdits(result.code);
723
975
  return {
724
- code: shouldOptimizeTemplates ? optimizeTemplateOutput(result.code) : result.code,
725
- map: result.map
976
+ code: optimized.code,
977
+ map: remapGenerated(map, result.code, optimized.code, optimized.edits)
726
978
  };
727
979
  } catch (error) {
728
980
  const detail = error instanceof Error ? error.message : String(error);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["mime","#options","#processed","#sharpLoader","#config"],"sources":["../src/template-optimizer.ts","../src/image-lexical.ts","../src/image-inspection.ts","../src/image-transform.ts","../src/image-pipeline.ts","../src/jsx-plugin.ts"],"sourcesContent":["import { parseSync, Visitor, type ObjectProperty } from \"oxc-parser\";\n\nconst OPTIMIZED_PROPS = new Set([\"class\", \"className\", \"style\"]);\nconst JSX_RUNTIME_SOURCE = \"@askrjs/askr/jsx-runtime\";\nconst JSX_FACTORIES = new Set([\"jsx\", \"jsxs\", \"jsxDEV\"]);\n\ntype Candidate = {\n literal: string;\n start: number;\n end: number;\n};\n\nfunction importedName(specifier: { imported: { type: string; name?: string; value?: unknown } }) {\n return specifier.imported.type === \"Identifier\"\n ? specifier.imported.name\n : specifier.imported.value;\n}\n\nfunction collectRuntimeFactories(program: ReturnType<typeof parseSync>[\"program\"]): Set<string> {\n const factories = new Set<string>();\n\n for (const statement of program.body) {\n if (statement.type !== \"ImportDeclaration\" || statement.source.value !== JSX_RUNTIME_SOURCE) {\n continue;\n }\n\n for (const specifier of statement.specifiers) {\n if (\n specifier.type === \"ImportSpecifier\" &&\n JSX_FACTORIES.has(String(importedName(specifier)))\n ) {\n factories.add(specifier.local.name);\n }\n }\n }\n\n return factories;\n}\n\nfunction collectCandidate(\n property: ObjectProperty,\n code: string,\n candidates: Map<string, Candidate[]>,\n) {\n if (\n property.kind !== \"init\" ||\n property.computed ||\n property.method ||\n property.key.type !== \"Identifier\" ||\n !OPTIMIZED_PROPS.has(property.key.name) ||\n property.value.type !== \"Literal\" ||\n typeof property.value.value !== \"string\"\n ) {\n return;\n }\n\n const literal = code.slice(property.value.start, property.value.end);\n const cacheKey = `${property.key.name}:${literal}`;\n const group = candidates.get(cacheKey) ?? [];\n group.push({\n literal,\n start: property.value.start,\n end: property.value.end,\n });\n candidates.set(cacheKey, group);\n}\n\nexport function optimizeTemplateOutput(code: string): string {\n const parsed = parseSync(\"askr-compiled.js\", code, {\n lang: \"js\",\n sourceType: \"module\",\n });\n if (parsed.errors.length > 0) return code;\n\n const runtimeFactories = collectRuntimeFactories(parsed.program);\n if (runtimeFactories.size === 0) return code;\n\n const candidates = new Map<string, Candidate[]>();\n const identifiers = new Set<string>();\n new Visitor({\n Identifier(identifier) {\n identifiers.add(identifier.name);\n },\n CallExpression(call) {\n if (\n call.callee.type !== \"Identifier\" ||\n !runtimeFactories.has(call.callee.name) ||\n call.arguments[1]?.type !== \"ObjectExpression\"\n ) {\n return;\n }\n\n for (const property of call.arguments[1].properties) {\n if (property.type === \"Property\") {\n collectCandidate(property, code, candidates);\n }\n }\n },\n }).visit(parsed.program);\n\n const declarations: string[] = [];\n const replacements: Array<{ start: number; end: number; identifier: string }> = [];\n let hoistIndex = 0;\n for (const group of candidates.values()) {\n if (group.length < 2) continue;\n\n let identifier: string;\n do {\n identifier = `__askrStaticLiteral${hoistIndex++}`;\n } while (identifiers.has(identifier));\n identifiers.add(identifier);\n declarations.push(`const ${identifier} = ${group[0].literal};`);\n for (const candidate of group) {\n replacements.push({ start: candidate.start, end: candidate.end, identifier });\n }\n }\n\n if (declarations.length === 0) return code;\n\n let optimized = code;\n for (const replacement of replacements.sort((left, right) => right.start - left.start)) {\n optimized =\n optimized.slice(0, replacement.start) +\n replacement.identifier +\n optimized.slice(replacement.end);\n }\n return `${declarations.join(\"\\n\")}\\n${optimized}`;\n}\n","const IMAGE_IMPORT = /from\\s+[\"']@askrjs\\/vite\\/image[\"']/g;\n\nfunction lexicalCodeMask(source: string): Uint8Array {\n const mask = new Uint8Array(source.length);\n let state: \"code\" | \"single\" | \"double\" | \"template\" | \"line-comment\" | \"block-comment\" = \"code\";\n let escaped = false;\n for (let index = 0; index < source.length; index += 1) {\n const character = source[index]!;\n const next = source[index + 1];\n if (state === \"code\") {\n if (character === \"/\" && next === \"/\") {\n state = \"line-comment\";\n index += 1;\n } else if (character === \"/\" && next === \"*\") {\n state = \"block-comment\";\n index += 1;\n } else if (character === \"'\") state = \"single\";\n else if (character === '\"') state = \"double\";\n else if (character === \"`\") state = \"template\";\n else mask[index] = 1;\n continue;\n }\n if (state === \"line-comment\") {\n if (character === \"\\n\" || character === \"\\r\") {\n state = \"code\";\n mask[index] = 1;\n }\n continue;\n }\n if (state === \"block-comment\") {\n if (character === \"*\" && next === \"/\") {\n state = \"code\";\n index += 1;\n }\n continue;\n }\n if (escaped) escaped = false;\n else if (character === \"\\\\\") escaped = true;\n else if (\n (state === \"single\" && character === \"'\") ||\n (state === \"double\" && character === '\"') ||\n (state === \"template\" && character === \"`\")\n ) {\n state = \"code\";\n }\n }\n return mask;\n}\n\nexport function imageDeclarationMask(code: string): Uint8Array | undefined {\n const mask = lexicalCodeMask(code);\n IMAGE_IMPORT.lastIndex = 0;\n for (let match = IMAGE_IMPORT.exec(code); match; match = IMAGE_IMPORT.exec(code)) {\n if (mask[match.index]) return mask;\n }\n return undefined;\n}\n","export type AssetFormat = \"avif\" | \"webp\" | \"jpeg\" | \"png\" | \"gif\" | \"svg\";\n\nexport interface SourceInspection {\n width: number;\n height: number;\n format: AssetFormat;\n transformable: boolean;\n animated: boolean;\n}\n\nfunction positiveDimensions(\n width: number,\n height: number,\n format: AssetFormat,\n transformable: boolean,\n animated = false,\n): SourceInspection | undefined {\n return width > 0 && height > 0 ? { width, height, format, transformable, animated } : undefined;\n}\n\nfunction inspectPng(source: Buffer): SourceInspection | undefined {\n if (\n source.length < 24 ||\n !source.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))\n ) {\n return undefined;\n }\n return positiveDimensions(\n source.readUInt32BE(16),\n source.readUInt32BE(20),\n \"png\",\n true,\n source.includes(Buffer.from(\"acTL\")),\n );\n}\n\nfunction inspectGif(source: Buffer): SourceInspection | undefined {\n if (source.length < 10 || !/^GIF8[79]a$/.test(source.subarray(0, 6).toString(\"ascii\"))) {\n return undefined;\n }\n return positiveDimensions(source.readUInt16LE(6), source.readUInt16LE(8), \"gif\", false, true);\n}\n\nfunction exifOrientation(segment: Buffer): number | undefined {\n if (segment.length < 14 || segment.subarray(0, 6).toString(\"binary\") !== \"Exif\\0\\0\") {\n return undefined;\n }\n const tiff = 6;\n const byteOrder = segment.subarray(tiff, tiff + 2).toString(\"ascii\");\n const littleEndian = byteOrder === \"II\";\n if (!littleEndian && byteOrder !== \"MM\") return undefined;\n const read16 = (offset: number): number | undefined => {\n const absolute = tiff + offset;\n if (absolute < tiff || absolute + 2 > segment.length) return undefined;\n return littleEndian ? segment.readUInt16LE(absolute) : segment.readUInt16BE(absolute);\n };\n const read32 = (offset: number): number | undefined => {\n const absolute = tiff + offset;\n if (absolute < tiff || absolute + 4 > segment.length) return undefined;\n return littleEndian ? segment.readUInt32LE(absolute) : segment.readUInt32BE(absolute);\n };\n if (read16(2) !== 42) return undefined;\n const directoryOffset = read32(4);\n if (directoryOffset === undefined) return undefined;\n const entries = read16(directoryOffset);\n if (entries === undefined) return undefined;\n for (let index = 0; index < entries; index += 1) {\n const entry = directoryOffset + 2 + index * 12;\n if (read16(entry) !== 0x0112 || read16(entry + 2) !== 3 || read32(entry + 4) !== 1) {\n continue;\n }\n const orientation = read16(entry + 8);\n return orientation && orientation >= 1 && orientation <= 8 ? orientation : undefined;\n }\n return undefined;\n}\n\nfunction inspectJpeg(source: Buffer): SourceInspection | undefined {\n if (source.length < 4 || source[0] !== 0xff || source[1] !== 0xd8) return undefined;\n const startOfFrame = new Set([\n 0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf,\n ]);\n let orientation: number | undefined;\n let offset = 2;\n while (offset + 8 < source.length) {\n if (source[offset] !== 0xff) {\n offset += 1;\n continue;\n }\n while (source[offset] === 0xff) offset += 1;\n const marker = source[offset++]!;\n if (marker === 0xd8 || marker === 0xd9 || marker === 0x01) continue;\n if (marker >= 0xd0 && marker <= 0xd7) continue;\n if (offset + 2 > source.length) break;\n const length = source.readUInt16BE(offset);\n if (length < 2 || offset + length > source.length) break;\n if (marker === 0xe1) {\n orientation = exifOrientation(source.subarray(offset + 2, offset + length)) ?? orientation;\n }\n if (startOfFrame.has(marker) && length >= 7) {\n const width = source.readUInt16BE(offset + 5);\n const height = source.readUInt16BE(offset + 3);\n return positiveDimensions(\n orientation !== undefined && orientation >= 5 ? height : width,\n orientation !== undefined && orientation >= 5 ? width : height,\n \"jpeg\",\n true,\n );\n }\n offset += length;\n }\n return undefined;\n}\n\nfunction inspectSvg(source: Buffer): SourceInspection | undefined {\n const openingTag = source\n .subarray(0, 16_384)\n .toString(\"utf8\")\n .match(/<svg\\b[^>]*>/i)?.[0];\n if (!openingTag) return undefined;\n const numberAttribute = (name: string): number | undefined => {\n const value = openingTag.match(new RegExp(`\\\\b${name}\\\\s*=\\\\s*[\"']\\\\s*([0-9.]+)`, \"i\"))?.[1];\n const parsed = value ? Number(value) : Number.NaN;\n return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n };\n let width = numberAttribute(\"width\");\n let height = numberAttribute(\"height\");\n const viewBox = openingTag\n .match(/\\bviewBox\\s*=\\s*[\"']\\s*[-+0-9.e]+[ ,]+[-+0-9.e]+[ ,]+([-+0-9.e]+)[ ,]+([-+0-9.e]+)/i)\n ?.slice(1)\n .map(Number);\n if (!width && viewBox?.[0] && viewBox[0] > 0) width = viewBox[0];\n if (!height && viewBox?.[1] && viewBox[1] > 0) height = viewBox[1];\n if (!width && height && viewBox?.[0] && viewBox?.[1]) width = height * (viewBox[0] / viewBox[1]);\n if (!height && width && viewBox?.[0] && viewBox?.[1]) height = width / (viewBox[0] / viewBox[1]);\n return width && height ? positiveDimensions(width, height, \"svg\", false) : undefined;\n}\n\nfunction inspectWebp(source: Buffer): SourceInspection | undefined {\n if (\n source.length < 30 ||\n source.subarray(0, 4).toString(\"ascii\") !== \"RIFF\" ||\n source.subarray(8, 12).toString(\"ascii\") !== \"WEBP\"\n ) {\n return undefined;\n }\n const chunk = source.subarray(12, 16).toString(\"ascii\");\n if (chunk === \"VP8X\") {\n const width = 1 + source.readUIntLE(24, 3);\n const height = 1 + source.readUIntLE(27, 3);\n return positiveDimensions(width, height, \"webp\", false, Boolean(source[20]! & 0x02));\n }\n if (chunk === \"VP8 \") {\n return positiveDimensions(\n source.readUInt16LE(26) & 0x3fff,\n source.readUInt16LE(28) & 0x3fff,\n \"webp\",\n false,\n );\n }\n if (chunk === \"VP8L\" && source[20] === 0x2f) {\n const bits = source.readUInt32LE(21);\n return positiveDimensions(1 + (bits & 0x3fff), 1 + ((bits >>> 14) & 0x3fff), \"webp\", false);\n }\n return undefined;\n}\n\nfunction inspectAvif(source: Buffer): SourceInspection | undefined {\n if (source.length < 24 || source.subarray(4, 8).toString(\"ascii\") !== \"ftyp\") return undefined;\n const typeOffset = source.indexOf(Buffer.from(\"ispe\"));\n if (typeOffset < 0 || typeOffset + 16 > source.length) return undefined;\n return positiveDimensions(\n source.readUInt32BE(typeOffset + 8),\n source.readUInt32BE(typeOffset + 12),\n \"avif\",\n false,\n );\n}\n\nexport function inspectSource(sourcePath: string, source: Buffer): SourceInspection {\n const inspection =\n inspectPng(source) ??\n inspectGif(source) ??\n inspectJpeg(source) ??\n inspectSvg(source) ??\n inspectWebp(source) ??\n inspectAvif(source);\n if (!inspection) {\n throw new Error(\n `@askrjs/vite could not determine intrinsic dimensions for pass-through image ${sourcePath}.`,\n );\n }\n return inspection;\n}\n","import { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { inspectSource, type AssetFormat } from \"./image-inspection\";\nimport { normalizeDeclarationOptions, normalizeImageOptions } from \"./image-options\";\nimport type { ImageOptions, ImageOutputFormat, ImagePipelineOptions } from \"./image-types\";\n\ntype SharpFactory = (typeof import(\"sharp\"))[\"default\"];\nexport type SharpLoader = () => Promise<SharpFactory>;\ntype TransformFormat = \"avif\" | \"webp\" | \"jpeg\" | \"png\";\n\nexport interface EmittedVariant {\n referenceId: string;\n width: number;\n height: number;\n format: AssetFormat;\n mime: string;\n}\n\nexport interface AssetPluginContext {\n emitFile(file: { type: \"asset\"; name: string; source: string | Uint8Array }): string;\n getFileName(referenceId: string): string;\n}\n\nexport interface ProcessedImage {\n declarationKey: string;\n sourcePath: string;\n sourceHash: string;\n declarationOptions: ImageOptions;\n transformKey: string;\n encoder: string;\n fallback: EmittedVariant;\n variants: EmittedVariant[];\n passThrough: boolean;\n}\n\nfunction hash(value: string | Buffer): string {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nexport function declarationKey(sourcePath: string, options: ImageOptions): string {\n return hash(`${sourcePath}\\0${JSON.stringify(normalizeDeclarationOptions(options))}`);\n}\n\nexport const defaultSharpLoader: SharpLoader = async () => (await import(\"sharp\")).default;\n\nasync function loadSharp(loader: SharpLoader): Promise<SharpFactory> {\n try {\n return await loader();\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ERR_MODULE_NOT_FOUND\") {\n throw new Error(\n '@askrjs/vite responsive images require the optional peer \"sharp\". Install sharp@^0.35.3 and rebuild.',\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nfunction sourceFormat(format: string | undefined): \"jpeg\" | \"png\" | undefined {\n if (format === \"jpeg\" || format === \"jpg\") return \"jpeg\";\n return format === \"png\" ? \"png\" : undefined;\n}\n\nfunction extension(format: AssetFormat): string {\n return format === \"jpeg\" ? \"jpg\" : format;\n}\n\nfunction mime(format: AssetFormat): string {\n return format === \"jpeg\" ? \"image/jpeg\" : `image/${format}`;\n}\n\nfunction outputName(sourcePath: string, width: number, format: EmittedVariant[\"format\"]): string {\n const basename = path.basename(sourcePath, path.extname(sourcePath));\n return `${basename}-${width}.${extension(format)}`;\n}\n\nfunction outputHeight(\n width: number,\n sourceWidth: number,\n sourceHeight: number,\n aspectRatio: number | undefined,\n): number {\n return Math.max(1, Math.round(width / (aspectRatio ?? sourceWidth / sourceHeight)));\n}\n\nasync function encodedVariant(\n sharp: SharpFactory,\n source: Buffer,\n cacheDir: string,\n transformKey: string,\n width: number,\n height: number,\n format: TransformFormat,\n options: ReturnType<typeof normalizeImageOptions>,\n): Promise<Buffer> {\n const cachePath = path.join(cacheDir, `${transformKey}-${width}.${extension(format)}`);\n const cached = await fs.readFile(cachePath).catch(() => undefined);\n if (cached) return cached;\n\n let pipeline = sharp(source, { animated: false }).autoOrient();\n pipeline =\n options.fit === \"cover\"\n ? pipeline.resize({ width, height, fit: \"cover\", position: options.position })\n : pipeline.resize({ width, fit: \"inside\", withoutEnlargement: true });\n if (format === \"avif\") pipeline = pipeline.avif({ quality: options.quality.avif });\n else if (format === \"webp\") pipeline = pipeline.webp({ quality: options.quality.webp });\n else if (format === \"jpeg\") pipeline = pipeline.jpeg({ quality: options.quality.jpeg });\n else {\n pipeline = pipeline.png(\n options.quality.png === 100\n ? { compressionLevel: 9 }\n : { compressionLevel: 9, quality: options.quality.png },\n );\n }\n const encoded = await pipeline.toBuffer();\n await fs.mkdir(cacheDir, { recursive: true });\n await fs.writeFile(cachePath, encoded);\n return encoded;\n}\n\nfunction variantFormats(\n formats: readonly ImageOutputFormat[],\n fallback: \"jpeg\" | \"png\",\n): Array<\"avif\" | \"webp\" | \"jpeg\" | \"png\"> {\n const output: Array<\"avif\" | \"webp\" | \"jpeg\" | \"png\"> = [];\n for (const format of formats) {\n const resolved = format === \"source\" ? fallback : format;\n if (!output.includes(resolved)) output.push(resolved);\n }\n if (!output.includes(fallback)) output.push(fallback);\n return output;\n}\n\nfunction passThroughImage(\n context: AssetPluginContext,\n sourcePath: string,\n source: Buffer,\n width: number,\n height: number,\n format: AssetFormat,\n): { fallback: EmittedVariant; variants: EmittedVariant[] } {\n const referenceId = context.emitFile({ type: \"asset\", name: path.basename(sourcePath), source });\n const fallback = { referenceId, width, height, format, mime: mime(format) };\n return { fallback, variants: [fallback] };\n}\n\nexport async function processImage(\n context: AssetPluginContext,\n sourcePath: string,\n declarationOptions: ImageOptions,\n globalOptions: ImagePipelineOptions,\n cacheDir: string,\n sharpLoader: SharpLoader,\n): Promise<ProcessedImage> {\n const source = await fs.readFile(sourcePath);\n const sourceHash = hash(source);\n const normalized = normalizeImageOptions(globalOptions, declarationOptions);\n const inspection = inspectSource(sourcePath, source);\n const key = declarationKey(sourcePath, declarationOptions);\n const shouldPassThroughWithoutSharp =\n !inspection.transformable ||\n inspection.animated ||\n (normalized.fit === \"inside\" && inspection.width <= normalized.widths[0]!);\n if (shouldPassThroughWithoutSharp) {\n const encoder = \"passthrough\";\n return {\n declarationKey: key,\n sourcePath,\n sourceHash,\n declarationOptions: normalizeDeclarationOptions(declarationOptions),\n transformKey: hash(`${sourceHash}\\0${JSON.stringify(normalized)}\\0${encoder}`),\n encoder,\n ...passThroughImage(\n context,\n sourcePath,\n source,\n inspection.width,\n inspection.height,\n inspection.format,\n ),\n passThrough: true,\n };\n }\n const sharp = await loadSharp(sharpLoader);\n const metadata = await sharp(source, { animated: true }).metadata();\n const sourceWidth = metadata.autoOrient.width ?? metadata.width;\n const sourceHeight =\n (metadata.pages ?? 1) > 1\n ? (metadata.pageHeight ?? metadata.height)\n : (metadata.autoOrient.height ?? metadata.height);\n if (!sourceWidth || !sourceHeight) {\n throw new Error(`@askrjs/vite could not determine intrinsic dimensions for ${sourcePath}.`);\n }\n const encoder = `sharp@${sharp.versions.sharp}`;\n const transformKey = hash(`${sourceHash}\\0${JSON.stringify(normalized)}\\0${encoder}`);\n const fallbackFormat = sourceFormat(metadata.format);\n\n const shouldPassThrough = (metadata.pages ?? 1) > 1 || !fallbackFormat;\n if (shouldPassThrough) {\n return {\n declarationKey: key,\n sourcePath,\n sourceHash,\n declarationOptions: normalizeDeclarationOptions(declarationOptions),\n transformKey,\n encoder,\n ...passThroughImage(\n context,\n sourcePath,\n source,\n sourceWidth,\n sourceHeight,\n fallbackFormat ?? inspection.format,\n ),\n passThrough: true,\n };\n }\n\n const maximumWidth =\n normalized.fit === \"cover\"\n ? Math.min(sourceWidth, Math.floor(sourceHeight * normalized.aspectRatio!))\n : sourceWidth;\n if (maximumWidth < 1) {\n throw new Error(\n `@askrjs/vite cannot crop ${sourcePath} to aspect ratio ${normalized.aspectRatio} without upscaling.`,\n );\n }\n const widths = normalized.widths.filter((width) => width <= maximumWidth);\n if (!widths.includes(maximumWidth)) widths.push(maximumWidth);\n widths.sort((left, right) => left - right);\n const variants: EmittedVariant[] = [];\n for (const format of variantFormats(normalized.formats, fallbackFormat)) {\n for (const width of widths) {\n const height = outputHeight(\n width,\n sourceWidth,\n sourceHeight,\n normalized.fit === \"cover\" ? normalized.aspectRatio : undefined,\n );\n const buffer = await encodedVariant(\n sharp,\n source,\n cacheDir,\n transformKey,\n width,\n height,\n format,\n normalized,\n );\n variants.push({\n referenceId: context.emitFile({\n type: \"asset\",\n name: outputName(sourcePath, width, format),\n source: buffer,\n }),\n width,\n height,\n format,\n mime: mime(format),\n });\n }\n }\n return {\n declarationKey: key,\n sourcePath,\n sourceHash,\n declarationOptions: normalizeDeclarationOptions(declarationOptions),\n transformKey,\n encoder,\n fallback: variants.filter((variant) => variant.format === fallbackFormat).at(-1)!,\n variants,\n passThrough: false,\n };\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ResolvedConfig } from \"vite\";\nimport { imageDeclarationMask } from \"./image-lexical\";\nimport {\n IMAGE_METADATA_PATH,\n IMAGE_METADATA_VERSION,\n type ImageMetadataEntry,\n type ImageMetadataRecord,\n} from \"./image-metadata\";\nimport type { ImageOptions, ImagePipelineOptions, ResponsiveImage } from \"./image-types\";\nimport {\n declarationKey,\n defaultSharpLoader,\n processImage,\n type AssetPluginContext,\n type EmittedVariant,\n type ProcessedImage,\n type SharpLoader,\n} from \"./image-transform\";\n\ninterface Declaration {\n start: number;\n end: number;\n source: string;\n options: ImageOptions;\n}\n\nconst IMAGE_CALL = /\\bimage\\s*\\(\\s*new\\s+URL\\s*\\(\\s*([\"'])([^\"']+)\\1\\s*,\\s*import\\.meta\\.url\\s*\\)/g;\n\nfunction staticJson(source: string, id: string): string {\n let output = \"\";\n for (let index = 0; index < source.length;) {\n const character = source[index]!;\n if (/\\s/.test(character) || \"{}[]:\".includes(character)) {\n output += character;\n index += 1;\n continue;\n }\n if (character === \",\") {\n let next = index + 1;\n while (/\\s/.test(source[next] ?? \"\")) next += 1;\n if (source[next] !== \"}\" && source[next] !== \"]\") output += character;\n index += 1;\n continue;\n }\n if (character === '\"' || character === \"'\") {\n let end = index + 1;\n while (end < source.length && source[end] !== character) {\n if (source[end] === \"\\\\\") {\n throw new Error(\n `@askrjs/vite image() option strings in ${id} cannot contain escape sequences.`,\n );\n }\n end += 1;\n }\n if (end >= source.length) {\n throw new Error(`@askrjs/vite found an unterminated image option in ${id}.`);\n }\n output += JSON.stringify(source.slice(index + 1, end));\n index = end + 1;\n continue;\n }\n const number = /^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:e[+-]?\\d+)?/i.exec(source.slice(index));\n if (number) {\n output += number[0];\n index += number[0].length;\n continue;\n }\n const identifier = /^[A-Za-z_]\\w*/.exec(source.slice(index));\n if (identifier) {\n let next = index + identifier[0].length;\n while (/\\s/.test(source[next] ?? \"\")) next += 1;\n if (source[next] === \":\") output += JSON.stringify(identifier[0]);\n else if ([\"true\", \"false\", \"null\"].includes(identifier[0])) output += identifier[0];\n else {\n throw new Error(\n `@askrjs/vite image() options in ${id} must not reference ${identifier[0]}; use a static object literal.`,\n );\n }\n index += identifier[0].length;\n continue;\n }\n throw new Error(\n `@askrjs/vite image() options in ${id} must be a static object literal so builds and direct SSG imports agree.`,\n );\n }\n return output;\n}\n\nfunction staticOptions(source: string, id: string): ImageOptions {\n const trimmed = source.trim();\n if (!trimmed) return {};\n let value: unknown;\n try {\n value = JSON.parse(staticJson(trimmed, id));\n } catch (error) {\n if (error instanceof Error && error.message.startsWith(\"@askrjs/vite\")) throw error;\n throw new Error(`@askrjs/vite could not parse image() options in ${id}.`, { cause: error });\n }\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(`@askrjs/vite image() options in ${id} must be an object literal.`);\n }\n return value as ImageOptions;\n}\n\nfunction findCallEnd(code: string, start: number): number {\n let depth = 1;\n let quote = \"\";\n let escaped = false;\n for (let index = start; index < code.length; index += 1) {\n const character = code[index]!;\n if (quote) {\n if (escaped) escaped = false;\n else if (character === \"\\\\\") escaped = true;\n else if (character === quote) quote = \"\";\n continue;\n }\n if (character === '\"' || character === \"'\") {\n quote = character;\n continue;\n }\n if (character === \"(\") depth += 1;\n if (character === \")\") {\n depth -= 1;\n if (depth === 0) return index;\n }\n }\n return -1;\n}\n\nfunction declarations(code: string, id: string): Declaration[] {\n const mask = imageDeclarationMask(code);\n if (!mask) return [];\n const output: Declaration[] = [];\n IMAGE_CALL.lastIndex = 0;\n for (let match = IMAGE_CALL.exec(code); match; match = IMAGE_CALL.exec(code)) {\n if (!mask[match.index]) continue;\n const afterUrl = IMAGE_CALL.lastIndex;\n const end = findCallEnd(code, afterUrl);\n if (end < 0) throw new Error(`@askrjs/vite found an unterminated image() call in ${id}.`);\n const remainder = code.slice(afterUrl, end).trim();\n if (remainder && !remainder.startsWith(\",\")) {\n throw new Error(`@askrjs/vite could not parse image() declaration in ${id}.`);\n }\n output.push({\n start: match.index,\n end: end + 1,\n source: match[2]!,\n options: staticOptions(remainder.replace(/^,/, \"\"), id),\n });\n IMAGE_CALL.lastIndex = end + 1;\n }\n return output;\n}\n\nfunction urlExpression(referenceId: string): string {\n return `import.meta.ROLLUP_FILE_URL_${referenceId}`;\n}\n\nfunction mime(format: EmittedVariant[\"format\"]): string {\n return format === \"jpeg\" ? \"image/jpeg\" : `image/${format}`;\n}\n\nfunction srcsetExpression(variants: readonly EmittedVariant[]): string {\n return `[${variants.map((variant) => `${urlExpression(variant.referenceId)} + ${JSON.stringify(` ${variant.width}w`)}`).join(\",\")}].join(\", \")`;\n}\n\nfunction imageExpression(processed: ProcessedImage): string {\n const fallbackVariants = processed.variants.filter(\n (variant) => variant.format === processed.fallback.format,\n );\n const modernFormats = [\"avif\", \"webp\"] as const;\n const sources = processed.passThrough\n ? []\n : modernFormats.flatMap((format) => {\n const variants = processed.variants.filter((variant) => variant.format === format);\n return variants.length === 0\n ? []\n : [`{type:${JSON.stringify(mime(format))},srcset:${srcsetExpression(variants)}}`];\n });\n return `image({__askrImage:true,src:${urlExpression(processed.fallback.referenceId)},${\n processed.passThrough ? \"\" : `srcset:${srcsetExpression(fallbackVariants)},`\n }width:${processed.fallback.width},height:${processed.fallback.height},sources:[${sources.join(\",\")}]})`;\n}\n\nfunction builtUrl(base: string, fileName: string): string {\n if (/^https?:\\/\\//.test(base))\n return new URL(fileName, base.endsWith(\"/\") ? base : `${base}/`).href;\n if (base === \"\" || base === \"./\" || base === \".\")\n return `${base === \".\" ? \"./\" : base}${fileName}`;\n return `${base.endsWith(\"/\") ? base : `${base}/`}${fileName}`;\n}\n\nfunction responsiveMetadata(\n processed: ProcessedImage,\n fileName: (referenceId: string) => string,\n base: string,\n): ResponsiveImage {\n const url = (variant: EmittedVariant) => builtUrl(base, fileName(variant.referenceId));\n const srcset = (variants: readonly EmittedVariant[]) =>\n variants.map((variant) => `${url(variant)} ${variant.width}w`).join(\", \");\n const fallbackVariants = processed.variants.filter(\n (variant) => variant.format === processed.fallback.format,\n );\n return {\n __askrImage: true,\n src: url(processed.fallback),\n ...(processed.passThrough ? {} : { srcset: srcset(fallbackVariants) }),\n width: processed.fallback.width,\n height: processed.fallback.height,\n sources: processed.passThrough\n ? []\n : ([\"avif\", \"webp\"] as const).flatMap((format) => {\n const variants = processed.variants.filter((variant) => variant.format === format);\n return variants.length === 0 ? [] : [{ type: mime(format), srcset: srcset(variants) }];\n }),\n };\n}\n\nexport class ImagePipeline {\n readonly #options: ImagePipelineOptions;\n readonly #processed = new Map<string, ProcessedImage>();\n readonly #sharpLoader: SharpLoader;\n #config: ResolvedConfig | undefined;\n\n constructor(options: ImagePipelineOptions, sharpLoader: SharpLoader = defaultSharpLoader) {\n this.#options = options;\n this.#sharpLoader = sharpLoader;\n }\n\n configure(config: ResolvedConfig): void {\n this.#config = config;\n }\n\n async transform(\n context: AssetPluginContext,\n code: string,\n id: string,\n ): Promise<string | undefined> {\n const found = declarations(code, id);\n if (found.length === 0) return undefined;\n if (!this.#config) throw new Error(\"@askrjs/vite image pipeline was not configured.\");\n if (this.#config.command !== \"build\") {\n throw new Error(\"@askrjs/vite responsive image declarations currently require a Vite build.\");\n }\n const cacheDir = path.join(this.#config.root, \"node_modules/.cache/@askrjs/vite/images\");\n let transformed = code;\n for (const declaration of [...found].reverse()) {\n const sourcePath = path.resolve(path.dirname(id.split(\"?\", 1)[0]!), declaration.source);\n const key = declarationKey(sourcePath, declaration.options);\n let processed = this.#processed.get(key);\n if (!processed) {\n processed = await processImage(\n context,\n sourcePath,\n declaration.options,\n this.#options,\n cacheDir,\n this.#sharpLoader,\n );\n this.#processed.set(key, processed);\n }\n transformed = `${transformed.slice(0, declaration.start)}${imageExpression(processed)}${transformed.slice(declaration.end)}`;\n }\n return transformed;\n }\n\n async writeMetadata(context: AssetPluginContext): Promise<void> {\n if (!this.#config || this.#processed.size === 0) return;\n const entries: Record<string, ImageMetadataEntry> = {};\n for (const processed of [...this.#processed.values()].sort((left, right) =>\n left.declarationKey.localeCompare(right.declarationKey),\n )) {\n entries[processed.declarationKey] = {\n sourcePath: processed.sourcePath,\n sourceHash: processed.sourceHash,\n declarationOptions: processed.declarationOptions,\n transformKey: processed.transformKey,\n encoder: processed.encoder,\n image: responsiveMetadata(\n processed,\n (referenceId) => context.getFileName(referenceId),\n this.#config.base,\n ),\n };\n }\n const record: ImageMetadataRecord = {\n version: IMAGE_METADATA_VERSION,\n entries,\n };\n const metadataPath = path.join(this.#config.root, IMAGE_METADATA_PATH);\n await fs.mkdir(path.dirname(metadataPath), { recursive: true });\n await fs.writeFile(metadataPath, `${JSON.stringify(record, null, 2)}\\n`, \"utf8\");\n }\n}\n","import { createRequire } from \"node:module\";\nimport type { Plugin } from \"vite\";\nimport { optimizeTemplateOutput } from \"./template-optimizer\";\nimport { ImagePipeline } from \"./image-pipeline\";\nimport type { ImagePipelineOptions } from \"./image-types\";\n\nconst require = createRequire(import.meta.url);\ntype TransformWithOxc = (typeof import(\"vite\"))[\"transformWithOxc\"];\nlet transformWithOxcPromise: Promise<TransformWithOxc> | undefined;\n\nasync function loadTransformWithOxc(): Promise<TransformWithOxc> {\n transformWithOxcPromise ??= (async () => {\n for (const packageName of [\"vite-plus\", \"vite\"] as const) {\n try {\n const buildTool = await import(packageName);\n if (typeof buildTool.transformWithOxc === \"function\") {\n return buildTool.transformWithOxc as TransformWithOxc;\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ERR_MODULE_NOT_FOUND\") throw error;\n }\n }\n throw new Error(\"@askrjs/vite requires either vite or vite-plus to transform JSX.\");\n })();\n return transformWithOxcPromise;\n}\n\n/** Options accepted by {@link askrVitePlugin}. */\nexport interface AskrVitePluginOptions {\n /** Transform `.jsx`/`.tsx` files with the Askr JSX runtime. Defaults to `true`. */\n transformJsx?: boolean;\n /** Hoist repeated JSX class/style literals using parsed compiled output. Defaults to `false`. */\n optimizeTemplates?: boolean;\n ssrPrecompile?: boolean;\n /** Opt into declared responsive image transforms. */\n images?: boolean | ImagePipelineOptions;\n}\n\n/**\n * Portable public plugin identity.\n *\n * Vite-compatible runners only require the plugin name. Keeping versioned Vite\n * hook types out of the installed declaration prevents consumers such as\n * vite-plus from comparing two distinct copies of Vite's recursive Plugin type.\n */\nexport interface AskrVitePlugin {\n readonly name: \"askr:vite\";\n}\n\n/**\n * Create the Askr Vite plugin, which transforms Askr JSX/TSX with oxc, wires\n * up dependency pre-bundling and aliasing for `@askrjs/askr`, and optionally\n * runs the responsive image pipeline and template optimizer.\n * JSX transform failures are reported through the active Vite/Rollup plugin\n * context with the source file and original transform detail.\n *\n * @param options Plugin configuration; all fields are optional.\n * @returns A Vite-compatible plugin object exposing the `askr:vite` name.\n */\nexport function askrVitePlugin(options: AskrVitePluginOptions = {}): AskrVitePlugin {\n const shouldTransform = options.transformJsx ?? true;\n const shouldOptimizeTemplates = options.optimizeTemplates ?? false;\n const imagePipeline = options.images\n ? new ImagePipeline(options.images === true ? {} : options.images)\n : undefined;\n const plugin = {\n name: \"askr:vite\" as const,\n enforce: \"pre\",\n config() {\n let askrEntry: string | null = null;\n try {\n askrEntry = require.resolve(\"@askrjs/askr\");\n } catch {\n askrEntry = null;\n }\n return {\n define: {\n __ASKR_OPTIMIZE_TEMPLATES__: JSON.stringify(shouldOptimizeTemplates),\n },\n resolve: {\n alias: askrEntry ? [{ find: \"@askrjs/askr\", replacement: askrEntry }] : [],\n dedupe: [\"@askrjs/askr\"],\n },\n optimizeDeps: {\n include: [\n \"@askrjs/askr\",\n \"@askrjs/askr/router\",\n \"@askrjs/askr/boot\",\n \"@askrjs/askr/control\",\n \"@askrjs/askr/fx\",\n \"@askrjs/askr/resources\",\n \"@askrjs/askr/data\",\n \"@askrjs/askr/foundations\",\n \"@askrjs/askr/foundations/icon\",\n \"@askrjs/askr/foundations/interactions\",\n \"@askrjs/askr/foundations/state\",\n \"@askrjs/askr/foundations/structures\",\n \"@askrjs/askr/foundations/utilities\",\n \"@askrjs/askr/jsx-runtime\",\n \"@askrjs/askr/jsx-dev-runtime\",\n ],\n },\n oxc: {\n jsx: { runtime: \"automatic\", importSource: \"@askrjs/askr\" },\n jsxInject: \"import { jsx, jsxs, Fragment } from '@askrjs/askr/jsx-runtime';\",\n },\n };\n },\n configResolved(config) {\n imagePipeline?.configure(config);\n },\n async transform(code, id) {\n if (id.includes(\"node_modules\")) return null;\n const imageTransformed = imagePipeline\n ? await imagePipeline.transform(this, code, id)\n : undefined;\n const input = imageTransformed ?? code;\n if (!shouldTransform || !/\\.(jsx|tsx)$/.test(id)) {\n return imageTransformed ? { code: imageTransformed, map: null } : null;\n }\n try {\n const transformWithOxc = await loadTransformWithOxc();\n const result = await transformWithOxc(input, id, {\n lang: id.endsWith(\".tsx\") ? \"tsx\" : \"jsx\",\n jsx: { runtime: \"automatic\", importSource: \"@askrjs/askr\" },\n sourcemap: true,\n });\n if (!result?.code) return null;\n return {\n code: shouldOptimizeTemplates ? optimizeTemplateOutput(result.code) : result.code,\n map: result.map,\n };\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n this.error(`@askrjs/vite failed to transform ${id}: ${detail}`);\n }\n },\n async writeBundle() {\n await imagePipeline?.writeMetadata(this);\n },\n } satisfies Plugin;\n return plugin;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["mime","#options","#processed","#sharpLoader","#config"],"sources":["../src/source-map-rewrites.ts","../src/template-optimizer.ts","../src/image-lexical.ts","../src/image-declarations.ts","../src/image-inspection.ts","../src/image-transform.ts","../src/image-pipeline.ts","../src/jsx-plugin.ts"],"sourcesContent":["export interface TextEdit {\n start: number;\n end: number;\n replacement: string;\n mapTo?: number;\n}\n\nexport interface RawSourceMap {\n version: number;\n mappings: string;\n names?: string[];\n sources?: string[];\n sourcesContent?: Array<string | null>;\n file?: string;\n sourceRoot?: string;\n}\n\nconst BASE64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nconst BASE64_VALUES = new Map([...BASE64].map((character, index) => [character, index]));\n\nfunction decodeVlq(value: string, cursor: { value: number }): number {\n let result = 0;\n let shift = 0;\n for (;;) {\n const digit = BASE64_VALUES.get(value[cursor.value++]);\n if (digit === undefined) throw new Error(\"Invalid sourcemap VLQ segment.\");\n result += (digit & 31) << shift;\n if ((digit & 32) === 0) break;\n shift += 5;\n }\n const negative = (result & 1) === 1;\n result >>= 1;\n return negative ? -result : result;\n}\n\nfunction encodeVlq(value: number): string {\n let remaining = (Math.abs(value) << 1) | (value < 0 ? 1 : 0);\n let output = \"\";\n do {\n let digit = remaining & 31;\n remaining >>>= 5;\n if (remaining > 0) digit |= 32;\n output += BASE64[digit];\n } while (remaining > 0);\n return output;\n}\n\nfunction decodeMappings(value: string): number[][][] {\n const lines: number[][][] = [];\n let source = 0;\n let originalLine = 0;\n let originalColumn = 0;\n let name = 0;\n for (const encodedLine of value.split(\";\")) {\n const segments: number[][] = [];\n let generatedColumn = 0;\n for (const encoded of encodedLine.split(\",\")) {\n if (!encoded) continue;\n const cursor = { value: 0 };\n generatedColumn += decodeVlq(encoded, cursor);\n const segment = [generatedColumn];\n if (cursor.value < encoded.length) {\n source += decodeVlq(encoded, cursor);\n originalLine += decodeVlq(encoded, cursor);\n originalColumn += decodeVlq(encoded, cursor);\n segment.push(source, originalLine, originalColumn);\n if (cursor.value < encoded.length) {\n name += decodeVlq(encoded, cursor);\n segment.push(name);\n }\n }\n segments.push(segment);\n }\n lines.push(segments);\n }\n return lines;\n}\n\nfunction encodeMappings(lines: number[][][]): string {\n let previousSource = 0;\n let previousOriginalLine = 0;\n let previousOriginalColumn = 0;\n let previousName = 0;\n return lines\n .map((segments) => {\n let previousGeneratedColumn = 0;\n return segments\n .map((segment) => {\n let encoded = encodeVlq(segment[0]! - previousGeneratedColumn);\n previousGeneratedColumn = segment[0]!;\n if (segment.length >= 4) {\n encoded += encodeVlq(segment[1]! - previousSource);\n encoded += encodeVlq(segment[2]! - previousOriginalLine);\n encoded += encodeVlq(segment[3]! - previousOriginalColumn);\n previousSource = segment[1]!;\n previousOriginalLine = segment[2]!;\n previousOriginalColumn = segment[3]!;\n if (segment.length === 5) {\n encoded += encodeVlq(segment[4]! - previousName);\n previousName = segment[4]!;\n }\n }\n return encoded;\n })\n .join(\",\");\n })\n .join(\";\");\n}\n\nfunction lineStarts(code: string): number[] {\n const starts = [0];\n for (let index = 0; index < code.length; index += 1) {\n if (code[index] === \"\\n\") starts.push(index + 1);\n }\n return starts;\n}\n\nfunction offsetAt(starts: number[], line: number, column: number): number {\n return (starts[line] ?? starts[starts.length - 1]!) + column;\n}\n\nfunction positionAt(starts: number[], offset: number): [number, number] {\n let low = 0;\n let high = starts.length;\n while (low + 1 < high) {\n const middle = (low + high) >>> 1;\n if (starts[middle]! <= offset) low = middle;\n else high = middle;\n }\n return [low, offset - starts[low]!];\n}\n\nfunction forwardOffset(offset: number, edits: readonly TextEdit[]): number {\n let delta = 0;\n for (const edit of edits) {\n if (offset < edit.start) break;\n if (offset < edit.end) return edit.start + delta;\n delta += edit.replacement.length - (edit.end - edit.start);\n }\n return offset + delta;\n}\n\nfunction reverseOffset(offset: number, edits: readonly TextEdit[]): number {\n let delta = 0;\n for (const edit of edits) {\n const generatedStart = edit.start + delta;\n const generatedEnd = generatedStart + edit.replacement.length;\n if (offset < generatedStart) break;\n if (offset < generatedEnd) return edit.start;\n delta += edit.replacement.length - (edit.end - edit.start);\n }\n return offset - delta;\n}\n\nfunction normalize(lines: number[][][]): number[][][] {\n return lines.map((segments) => {\n const sorted = segments.sort((left, right) => left[0]! - right[0]!);\n return sorted.filter((segment, index) => index === 0 || segment[0] !== sorted[index - 1]![0]);\n });\n}\n\nfunction mappingAt(lines: number[][][], starts: number[], offset: number): number[] | undefined {\n const [line, column] = positionAt(starts, offset);\n let match: number[] | undefined;\n for (const segment of lines[line] ?? []) {\n if (segment[0]! > column) break;\n if (segment.length >= 4) match = segment;\n }\n return match;\n}\n\n/** Move generated coordinates after deterministic text edits. */\nexport function remapGenerated(\n map: RawSourceMap,\n before: string,\n after: string,\n edits: readonly TextEdit[],\n): RawSourceMap {\n const beforeStarts = lineStarts(before);\n const afterStarts = lineStarts(after);\n const decoded = decodeMappings(map.mappings);\n const output: number[][][] = Array.from({ length: afterStarts.length }, () => []);\n for (const [line, segments] of decoded.entries()) {\n for (const segment of segments) {\n const offset = forwardOffset(offsetAt(beforeStarts, line, segment[0]!), edits);\n const [nextLine, nextColumn] = positionAt(afterStarts, offset);\n output[nextLine]!.push([nextColumn, ...segment.slice(1)]);\n }\n }\n let delta = 0;\n for (const edit of edits) {\n if (edit.mapTo !== undefined) {\n const mapped = mappingAt(decoded, beforeStarts, edit.mapTo);\n if (mapped) {\n const [line, column] = positionAt(afterStarts, edit.start + delta);\n output[line]!.push([column, ...mapped.slice(1)]);\n }\n }\n delta += edit.replacement.length - (edit.end - edit.start);\n }\n return { ...map, mappings: encodeMappings(normalize(output)) };\n}\n\n/** Move original coordinates back through deterministic text edits. */\nexport function remapOriginal(\n map: RawSourceMap,\n original: string,\n rewritten: string,\n edits: readonly TextEdit[],\n): RawSourceMap {\n const originalStarts = lineStarts(original);\n const rewrittenStarts = lineStarts(rewritten);\n const lines = decodeMappings(map.mappings);\n for (const segments of lines) {\n for (const segment of segments) {\n if (segment.length < 4 || segment[1] !== 0) continue;\n const offset = reverseOffset(offsetAt(rewrittenStarts, segment[2]!, segment[3]!), edits);\n const [line, column] = positionAt(originalStarts, offset);\n segment[2] = line;\n segment[3] = column;\n }\n }\n return {\n ...map,\n mappings: encodeMappings(lines),\n sourcesContent: map.sources?.map((_source, index) =>\n index === 0 ? original : (map.sourcesContent?.[index] ?? null),\n ),\n };\n}\n\n/** Build a complete map for a rewritten source when no downstream map exists. */\nexport function sourceMapForRewrite(\n original: string,\n rewritten: string,\n edits: readonly TextEdit[],\n id: string,\n): RawSourceMap {\n const originalStarts = lineStarts(original);\n const rewrittenStarts = lineStarts(rewritten);\n const lines: number[][][] = Array.from({ length: rewrittenStarts.length }, () => []);\n for (let offset = 0; offset < rewritten.length; offset += 1) {\n const [generatedLine, generatedColumn] = positionAt(rewrittenStarts, offset);\n const [originalLine, originalColumn] = positionAt(originalStarts, reverseOffset(offset, edits));\n lines[generatedLine]!.push([generatedColumn, 0, originalLine, originalColumn]);\n }\n return {\n version: 3,\n names: [],\n sources: [id],\n sourcesContent: [original],\n mappings: encodeMappings(lines),\n };\n}\n\nexport function traceSourcePosition(\n map: RawSourceMap,\n line: number,\n column: number,\n): { line: number; column: number } | undefined {\n const segments = decodeMappings(map.mappings)[line] ?? [];\n let match: number[] | undefined;\n for (const segment of segments) {\n if (segment[0]! > column) break;\n if (segment.length >= 4) match = segment;\n }\n return match ? { line: match[2]!, column: match[3]! } : undefined;\n}\n","import { parseSync, Visitor, type ObjectProperty } from \"oxc-parser\";\nimport type { TextEdit } from \"./source-map-rewrites\";\n\nconst OPTIMIZED_PROPS = new Set([\"class\", \"className\", \"style\"]);\nconst JSX_RUNTIME_SOURCE = \"@askrjs/askr/jsx-runtime\";\nconst JSX_FACTORIES = new Set([\"jsx\", \"jsxs\", \"jsxDEV\"]);\n\ntype Candidate = {\n literal: string;\n start: number;\n end: number;\n};\n\nfunction importedName(specifier: { imported: { type: string; name?: string; value?: unknown } }) {\n return specifier.imported.type === \"Identifier\"\n ? specifier.imported.name\n : specifier.imported.value;\n}\n\nfunction collectRuntimeFactories(program: ReturnType<typeof parseSync>[\"program\"]): Set<string> {\n const factories = new Set<string>();\n\n for (const statement of program.body) {\n if (statement.type !== \"ImportDeclaration\" || statement.source.value !== JSX_RUNTIME_SOURCE) {\n continue;\n }\n\n for (const specifier of statement.specifiers) {\n if (\n specifier.type === \"ImportSpecifier\" &&\n JSX_FACTORIES.has(String(importedName(specifier)))\n ) {\n factories.add(specifier.local.name);\n }\n }\n }\n\n return factories;\n}\n\nfunction collectCandidate(\n property: ObjectProperty,\n code: string,\n candidates: Map<string, Candidate[]>,\n) {\n if (\n property.kind !== \"init\" ||\n property.computed ||\n property.method ||\n property.key.type !== \"Identifier\" ||\n !OPTIMIZED_PROPS.has(property.key.name) ||\n property.value.type !== \"Literal\" ||\n typeof property.value.value !== \"string\"\n ) {\n return;\n }\n\n const literal = code.slice(property.value.start, property.value.end);\n const cacheKey = `${property.key.name}:${literal}`;\n const group = candidates.get(cacheKey) ?? [];\n group.push({\n literal,\n start: property.value.start,\n end: property.value.end,\n });\n candidates.set(cacheKey, group);\n}\n\nexport interface OptimizedTemplateOutput {\n code: string;\n edits: TextEdit[];\n}\n\nexport function optimizeTemplateOutputWithEdits(code: string): OptimizedTemplateOutput {\n const parsed = parseSync(\"askr-compiled.js\", code, {\n lang: \"js\",\n sourceType: \"module\",\n });\n if (parsed.errors.length > 0) return { code, edits: [] };\n\n const runtimeFactories = collectRuntimeFactories(parsed.program);\n if (runtimeFactories.size === 0) return { code, edits: [] };\n\n const candidates = new Map<string, Candidate[]>();\n const identifiers = new Set<string>();\n new Visitor({\n Identifier(identifier) {\n identifiers.add(identifier.name);\n },\n CallExpression(call) {\n if (\n call.callee.type !== \"Identifier\" ||\n !runtimeFactories.has(call.callee.name) ||\n call.arguments[1]?.type !== \"ObjectExpression\"\n ) {\n return;\n }\n\n for (const property of call.arguments[1].properties) {\n if (property.type === \"Property\") {\n collectCandidate(property, code, candidates);\n }\n }\n },\n }).visit(parsed.program);\n\n const declarations: string[] = [];\n const replacements: Array<{ start: number; end: number; identifier: string }> = [];\n let hoistIndex = 0;\n for (const group of candidates.values()) {\n if (group.length < 2) continue;\n\n let identifier: string;\n do {\n identifier = `__askrStaticLiteral${hoistIndex++}`;\n } while (identifiers.has(identifier));\n identifiers.add(identifier);\n declarations.push(`const ${identifier} = ${group[0].literal};`);\n for (const candidate of group) {\n replacements.push({ start: candidate.start, end: candidate.end, identifier });\n }\n }\n\n if (declarations.length === 0) return { code, edits: [] };\n\n const prefix = `${declarations.join(\"\\n\")}\\n`;\n const edits: TextEdit[] = [\n { start: 0, end: 0, replacement: prefix, mapTo: replacements[0]!.start },\n ...replacements\n .map(({ start, end, identifier }) => ({ start, end, replacement: identifier }))\n .sort((left, right) => left.start - right.start),\n ];\n let optimized = code;\n for (const replacement of replacements.sort((left, right) => right.start - left.start)) {\n optimized =\n optimized.slice(0, replacement.start) +\n replacement.identifier +\n optimized.slice(replacement.end);\n }\n return { code: `${prefix}${optimized}`, edits };\n}\n\nexport function optimizeTemplateOutput(code: string): string {\n return optimizeTemplateOutputWithEdits(code).code;\n}\n","const IMAGE_IMPORT = /from\\s+[\"']@askrjs\\/vite\\/image[\"']/g;\n\nfunction lexicalCodeMask(source: string): Uint8Array {\n const mask = new Uint8Array(source.length);\n let state: \"code\" | \"single\" | \"double\" | \"template\" | \"line-comment\" | \"block-comment\" = \"code\";\n let escaped = false;\n for (let index = 0; index < source.length; index += 1) {\n const character = source[index]!;\n const next = source[index + 1];\n if (state === \"code\") {\n if (character === \"/\" && next === \"/\") {\n state = \"line-comment\";\n index += 1;\n } else if (character === \"/\" && next === \"*\") {\n state = \"block-comment\";\n index += 1;\n } else if (character === \"'\") state = \"single\";\n else if (character === '\"') state = \"double\";\n else if (character === \"`\") state = \"template\";\n else mask[index] = 1;\n continue;\n }\n if (state === \"line-comment\") {\n if (character === \"\\n\" || character === \"\\r\") {\n state = \"code\";\n mask[index] = 1;\n }\n continue;\n }\n if (state === \"block-comment\") {\n if (character === \"*\" && next === \"/\") {\n state = \"code\";\n index += 1;\n }\n continue;\n }\n if (escaped) escaped = false;\n else if (character === \"\\\\\") escaped = true;\n else if (\n (state === \"single\" && character === \"'\") ||\n (state === \"double\" && character === '\"') ||\n (state === \"template\" && character === \"`\")\n ) {\n state = \"code\";\n }\n }\n return mask;\n}\n\nexport function imageDeclarationMask(code: string): Uint8Array | undefined {\n const mask = lexicalCodeMask(code);\n IMAGE_IMPORT.lastIndex = 0;\n for (let match = IMAGE_IMPORT.exec(code); match; match = IMAGE_IMPORT.exec(code)) {\n if (mask[match.index]) return mask;\n }\n return undefined;\n}\n","import { imageDeclarationMask } from \"./image-lexical\";\nimport type { ImageOptions } from \"./image-types\";\n\nexport interface ImageDeclaration {\n start: number;\n end: number;\n source: string;\n options: ImageOptions;\n}\n\nconst IMAGE_CALL = /\\bimage\\s*\\(\\s*new\\s+URL\\s*\\(\\s*([\"'])([^\"']+)\\1\\s*,\\s*import\\.meta\\.url\\s*\\)/g;\n\nfunction staticJson(source: string, id: string): string {\n let output = \"\";\n for (let index = 0; index < source.length;) {\n const character = source[index]!;\n if (/\\s/.test(character) || \"{}[]:\".includes(character)) {\n output += character;\n index += 1;\n continue;\n }\n if (character === \",\") {\n let next = index + 1;\n while (/\\s/.test(source[next] ?? \"\")) next += 1;\n if (source[next] !== \"}\" && source[next] !== \"]\") output += character;\n index += 1;\n continue;\n }\n if (character === '\"' || character === \"'\") {\n let end = index + 1;\n while (end < source.length && source[end] !== character) {\n if (source[end] === \"\\\\\") {\n throw new Error(\n `@askrjs/vite image() option strings in ${id} cannot contain escape sequences.`,\n );\n }\n end += 1;\n }\n if (end >= source.length) {\n throw new Error(`@askrjs/vite found an unterminated image option in ${id}.`);\n }\n output += JSON.stringify(source.slice(index + 1, end));\n index = end + 1;\n continue;\n }\n const number = /^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:e[+-]?\\d+)?/i.exec(source.slice(index));\n if (number) {\n output += number[0];\n index += number[0].length;\n continue;\n }\n const identifier = /^[A-Za-z_]\\w*/.exec(source.slice(index));\n if (identifier) {\n let next = index + identifier[0].length;\n while (/\\s/.test(source[next] ?? \"\")) next += 1;\n if (source[next] === \":\") output += JSON.stringify(identifier[0]);\n else if ([\"true\", \"false\", \"null\"].includes(identifier[0])) output += identifier[0];\n else {\n throw new Error(\n `@askrjs/vite image() options in ${id} must not reference ${identifier[0]}; use a static object literal.`,\n );\n }\n index += identifier[0].length;\n continue;\n }\n throw new Error(\n `@askrjs/vite image() options in ${id} must be a static object literal so builds and direct SSG imports agree.`,\n );\n }\n return output;\n}\n\nfunction staticOptions(source: string, id: string): ImageOptions {\n const trimmed = source.trim();\n if (!trimmed) return {};\n let value: unknown;\n try {\n value = JSON.parse(staticJson(trimmed, id));\n } catch (error) {\n if (error instanceof Error && error.message.startsWith(\"@askrjs/vite\")) throw error;\n throw new Error(`@askrjs/vite could not parse image() options in ${id}.`, { cause: error });\n }\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(`@askrjs/vite image() options in ${id} must be an object literal.`);\n }\n return value as ImageOptions;\n}\n\nfunction findCallEnd(code: string, start: number): number {\n let depth = 1;\n let quote = \"\";\n let escaped = false;\n for (let index = start; index < code.length; index += 1) {\n const character = code[index]!;\n if (quote) {\n if (escaped) escaped = false;\n else if (character === \"\\\\\") escaped = true;\n else if (character === quote) quote = \"\";\n continue;\n }\n if (character === '\"' || character === \"'\") {\n quote = character;\n continue;\n }\n if (character === \"(\") depth += 1;\n if (character === \")\") {\n depth -= 1;\n if (depth === 0) return index;\n }\n }\n return -1;\n}\n\nexport function imageDeclarations(code: string, id: string): ImageDeclaration[] {\n const mask = imageDeclarationMask(code);\n if (!mask) return [];\n const output: ImageDeclaration[] = [];\n IMAGE_CALL.lastIndex = 0;\n for (let match = IMAGE_CALL.exec(code); match; match = IMAGE_CALL.exec(code)) {\n if (!mask[match.index]) continue;\n const afterUrl = IMAGE_CALL.lastIndex;\n const end = findCallEnd(code, afterUrl);\n if (end < 0) throw new Error(`@askrjs/vite found an unterminated image() call in ${id}.`);\n const remainder = code.slice(afterUrl, end).trim();\n if (remainder && !remainder.startsWith(\",\")) {\n throw new Error(`@askrjs/vite could not parse image() declaration in ${id}.`);\n }\n output.push({\n start: match.index,\n end: end + 1,\n source: match[2]!,\n options: staticOptions(remainder.replace(/^,/, \"\"), id),\n });\n IMAGE_CALL.lastIndex = end + 1;\n }\n return output;\n}\n","export type AssetFormat = \"avif\" | \"webp\" | \"jpeg\" | \"png\" | \"gif\" | \"svg\";\n\nexport interface SourceInspection {\n width: number;\n height: number;\n format: AssetFormat;\n transformable: boolean;\n animated: boolean;\n}\n\nfunction positiveDimensions(\n width: number,\n height: number,\n format: AssetFormat,\n transformable: boolean,\n animated = false,\n): SourceInspection | undefined {\n return width > 0 && height > 0 ? { width, height, format, transformable, animated } : undefined;\n}\n\nfunction inspectPng(source: Buffer): SourceInspection | undefined {\n if (\n source.length < 24 ||\n !source.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))\n ) {\n return undefined;\n }\n return positiveDimensions(\n source.readUInt32BE(16),\n source.readUInt32BE(20),\n \"png\",\n true,\n source.includes(Buffer.from(\"acTL\")),\n );\n}\n\nfunction inspectGif(source: Buffer): SourceInspection | undefined {\n if (source.length < 10 || !/^GIF8[79]a$/.test(source.subarray(0, 6).toString(\"ascii\"))) {\n return undefined;\n }\n return positiveDimensions(source.readUInt16LE(6), source.readUInt16LE(8), \"gif\", false, true);\n}\n\nfunction exifOrientation(segment: Buffer): number | undefined {\n if (segment.length < 14 || segment.subarray(0, 6).toString(\"binary\") !== \"Exif\\0\\0\") {\n return undefined;\n }\n const tiff = 6;\n const byteOrder = segment.subarray(tiff, tiff + 2).toString(\"ascii\");\n const littleEndian = byteOrder === \"II\";\n if (!littleEndian && byteOrder !== \"MM\") return undefined;\n const read16 = (offset: number): number | undefined => {\n const absolute = tiff + offset;\n if (absolute < tiff || absolute + 2 > segment.length) return undefined;\n return littleEndian ? segment.readUInt16LE(absolute) : segment.readUInt16BE(absolute);\n };\n const read32 = (offset: number): number | undefined => {\n const absolute = tiff + offset;\n if (absolute < tiff || absolute + 4 > segment.length) return undefined;\n return littleEndian ? segment.readUInt32LE(absolute) : segment.readUInt32BE(absolute);\n };\n if (read16(2) !== 42) return undefined;\n const directoryOffset = read32(4);\n if (directoryOffset === undefined) return undefined;\n const entries = read16(directoryOffset);\n if (entries === undefined) return undefined;\n for (let index = 0; index < entries; index += 1) {\n const entry = directoryOffset + 2 + index * 12;\n if (read16(entry) !== 0x0112 || read16(entry + 2) !== 3 || read32(entry + 4) !== 1) {\n continue;\n }\n const orientation = read16(entry + 8);\n return orientation && orientation >= 1 && orientation <= 8 ? orientation : undefined;\n }\n return undefined;\n}\n\nfunction inspectJpeg(source: Buffer): SourceInspection | undefined {\n if (source.length < 4 || source[0] !== 0xff || source[1] !== 0xd8) return undefined;\n const startOfFrame = new Set([\n 0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf,\n ]);\n let orientation: number | undefined;\n let offset = 2;\n while (offset + 8 < source.length) {\n if (source[offset] !== 0xff) {\n offset += 1;\n continue;\n }\n while (source[offset] === 0xff) offset += 1;\n const marker = source[offset++]!;\n if (marker === 0xd8 || marker === 0xd9 || marker === 0x01) continue;\n if (marker >= 0xd0 && marker <= 0xd7) continue;\n if (offset + 2 > source.length) break;\n const length = source.readUInt16BE(offset);\n if (length < 2 || offset + length > source.length) break;\n if (marker === 0xe1) {\n orientation = exifOrientation(source.subarray(offset + 2, offset + length)) ?? orientation;\n }\n if (startOfFrame.has(marker) && length >= 7) {\n const width = source.readUInt16BE(offset + 5);\n const height = source.readUInt16BE(offset + 3);\n return positiveDimensions(\n orientation !== undefined && orientation >= 5 ? height : width,\n orientation !== undefined && orientation >= 5 ? width : height,\n \"jpeg\",\n true,\n );\n }\n offset += length;\n }\n return undefined;\n}\n\nfunction inspectSvg(source: Buffer): SourceInspection | undefined {\n const openingTag = source\n .subarray(0, 16_384)\n .toString(\"utf8\")\n .match(/<svg\\b[^>]*>/i)?.[0];\n if (!openingTag) return undefined;\n const numberAttribute = (name: string): number | undefined => {\n const value = openingTag.match(new RegExp(`\\\\b${name}\\\\s*=\\\\s*[\"']\\\\s*([0-9.]+)`, \"i\"))?.[1];\n const parsed = value ? Number(value) : Number.NaN;\n return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n };\n let width = numberAttribute(\"width\");\n let height = numberAttribute(\"height\");\n const viewBox = openingTag\n .match(/\\bviewBox\\s*=\\s*[\"']\\s*[-+0-9.e]+[ ,]+[-+0-9.e]+[ ,]+([-+0-9.e]+)[ ,]+([-+0-9.e]+)/i)\n ?.slice(1)\n .map(Number);\n if (!width && viewBox?.[0] && viewBox[0] > 0) width = viewBox[0];\n if (!height && viewBox?.[1] && viewBox[1] > 0) height = viewBox[1];\n if (!width && height && viewBox?.[0] && viewBox?.[1]) width = height * (viewBox[0] / viewBox[1]);\n if (!height && width && viewBox?.[0] && viewBox?.[1]) height = width / (viewBox[0] / viewBox[1]);\n return width && height ? positiveDimensions(width, height, \"svg\", false) : undefined;\n}\n\nfunction inspectWebp(source: Buffer): SourceInspection | undefined {\n if (\n source.length < 30 ||\n source.subarray(0, 4).toString(\"ascii\") !== \"RIFF\" ||\n source.subarray(8, 12).toString(\"ascii\") !== \"WEBP\"\n ) {\n return undefined;\n }\n const chunk = source.subarray(12, 16).toString(\"ascii\");\n if (chunk === \"VP8X\") {\n const width = 1 + source.readUIntLE(24, 3);\n const height = 1 + source.readUIntLE(27, 3);\n return positiveDimensions(width, height, \"webp\", false, Boolean(source[20]! & 0x02));\n }\n if (chunk === \"VP8 \") {\n return positiveDimensions(\n source.readUInt16LE(26) & 0x3fff,\n source.readUInt16LE(28) & 0x3fff,\n \"webp\",\n false,\n );\n }\n if (chunk === \"VP8L\" && source[20] === 0x2f) {\n const bits = source.readUInt32LE(21);\n return positiveDimensions(1 + (bits & 0x3fff), 1 + ((bits >>> 14) & 0x3fff), \"webp\", false);\n }\n return undefined;\n}\n\nfunction inspectAvif(source: Buffer): SourceInspection | undefined {\n if (source.length < 24 || source.subarray(4, 8).toString(\"ascii\") !== \"ftyp\") return undefined;\n const typeOffset = source.indexOf(Buffer.from(\"ispe\"));\n if (typeOffset < 0 || typeOffset + 16 > source.length) return undefined;\n return positiveDimensions(\n source.readUInt32BE(typeOffset + 8),\n source.readUInt32BE(typeOffset + 12),\n \"avif\",\n false,\n );\n}\n\nexport function inspectSource(sourcePath: string, source: Buffer): SourceInspection {\n const inspection =\n inspectPng(source) ??\n inspectGif(source) ??\n inspectJpeg(source) ??\n inspectSvg(source) ??\n inspectWebp(source) ??\n inspectAvif(source);\n if (!inspection) {\n throw new Error(\n `@askrjs/vite could not determine intrinsic dimensions for pass-through image ${sourcePath}.`,\n );\n }\n return inspection;\n}\n","import { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { inspectSource, type AssetFormat } from \"./image-inspection\";\nimport { normalizeDeclarationOptions, normalizeImageOptions } from \"./image-options\";\nimport type { ImageOptions, ImageOutputFormat, ImagePipelineOptions } from \"./image-types\";\n\ntype SharpFactory = (typeof import(\"sharp\"))[\"default\"];\nexport type SharpLoader = () => Promise<SharpFactory>;\ntype TransformFormat = \"avif\" | \"webp\" | \"jpeg\" | \"png\";\n\nexport interface EmittedVariant {\n referenceId: string;\n width: number;\n height: number;\n format: AssetFormat;\n mime: string;\n}\n\nexport interface AssetPluginContext {\n emitFile(file: { type: \"asset\"; name: string; source: string | Uint8Array }): string;\n getFileName(referenceId: string): string;\n}\n\nexport interface ProcessedImage {\n declarationKey: string;\n sourcePath: string;\n sourceHash: string;\n declarationOptions: ImageOptions;\n transformKey: string;\n encoder: string;\n fallback: EmittedVariant;\n variants: EmittedVariant[];\n passThrough: boolean;\n}\n\nfunction hash(value: string | Buffer): string {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nexport function declarationKey(sourcePath: string, options: ImageOptions): string {\n return hash(`${sourcePath}\\0${JSON.stringify(normalizeDeclarationOptions(options))}`);\n}\n\nexport const defaultSharpLoader: SharpLoader = async () => (await import(\"sharp\")).default;\n\nasync function loadSharp(loader: SharpLoader): Promise<SharpFactory> {\n try {\n return await loader();\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ERR_MODULE_NOT_FOUND\") {\n throw new Error(\n '@askrjs/vite responsive images require the optional peer \"sharp\". Install sharp@^0.35.3 and rebuild.',\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nfunction sourceFormat(format: string | undefined): \"jpeg\" | \"png\" | undefined {\n if (format === \"jpeg\" || format === \"jpg\") return \"jpeg\";\n return format === \"png\" ? \"png\" : undefined;\n}\n\nfunction extension(format: AssetFormat): string {\n return format === \"jpeg\" ? \"jpg\" : format;\n}\n\nfunction mime(format: AssetFormat): string {\n return format === \"jpeg\" ? \"image/jpeg\" : `image/${format}`;\n}\n\nfunction outputName(sourcePath: string, width: number, format: EmittedVariant[\"format\"]): string {\n const basename = path.basename(sourcePath, path.extname(sourcePath));\n return `${basename}-${width}.${extension(format)}`;\n}\n\nfunction outputHeight(\n width: number,\n sourceWidth: number,\n sourceHeight: number,\n aspectRatio: number | undefined,\n): number {\n return Math.max(1, Math.round(width / (aspectRatio ?? sourceWidth / sourceHeight)));\n}\n\nasync function encodedVariant(\n sharp: SharpFactory,\n source: Buffer,\n cacheDir: string,\n transformKey: string,\n width: number,\n height: number,\n format: TransformFormat,\n options: ReturnType<typeof normalizeImageOptions>,\n): Promise<Buffer> {\n const cachePath = path.join(cacheDir, `${transformKey}-${width}.${extension(format)}`);\n const cached = await fs.readFile(cachePath).catch(() => undefined);\n if (cached) return cached;\n\n let pipeline = sharp(source, { animated: false }).autoOrient();\n pipeline =\n options.fit === \"cover\"\n ? pipeline.resize({ width, height, fit: \"cover\", position: options.position })\n : pipeline.resize({ width, fit: \"inside\", withoutEnlargement: true });\n if (format === \"avif\") pipeline = pipeline.avif({ quality: options.quality.avif });\n else if (format === \"webp\") pipeline = pipeline.webp({ quality: options.quality.webp });\n else if (format === \"jpeg\") pipeline = pipeline.jpeg({ quality: options.quality.jpeg });\n else {\n pipeline = pipeline.png(\n options.quality.png === 100\n ? { compressionLevel: 9 }\n : { compressionLevel: 9, quality: options.quality.png },\n );\n }\n const encoded = await pipeline.toBuffer();\n await fs.mkdir(cacheDir, { recursive: true });\n await fs.writeFile(cachePath, encoded);\n return encoded;\n}\n\nfunction variantFormats(\n formats: readonly ImageOutputFormat[],\n fallback: \"jpeg\" | \"png\",\n): Array<\"avif\" | \"webp\" | \"jpeg\" | \"png\"> {\n const output: Array<\"avif\" | \"webp\" | \"jpeg\" | \"png\"> = [];\n for (const format of formats) {\n const resolved = format === \"source\" ? fallback : format;\n if (!output.includes(resolved)) output.push(resolved);\n }\n if (!output.includes(fallback)) output.push(fallback);\n return output;\n}\n\nfunction passThroughImage(\n context: AssetPluginContext,\n sourcePath: string,\n source: Buffer,\n width: number,\n height: number,\n format: AssetFormat,\n): { fallback: EmittedVariant; variants: EmittedVariant[] } {\n const referenceId = context.emitFile({ type: \"asset\", name: path.basename(sourcePath), source });\n const fallback = { referenceId, width, height, format, mime: mime(format) };\n return { fallback, variants: [fallback] };\n}\n\nexport async function processImage(\n context: AssetPluginContext,\n sourcePath: string,\n declarationOptions: ImageOptions,\n globalOptions: ImagePipelineOptions,\n cacheDir: string,\n sharpLoader: SharpLoader,\n): Promise<ProcessedImage> {\n const source = await fs.readFile(sourcePath);\n const sourceHash = hash(source);\n const normalized = normalizeImageOptions(globalOptions, declarationOptions);\n const inspection = inspectSource(sourcePath, source);\n const key = declarationKey(sourcePath, declarationOptions);\n const shouldPassThroughWithoutSharp =\n !inspection.transformable ||\n inspection.animated ||\n (normalized.fit === \"inside\" && inspection.width <= normalized.widths[0]!);\n if (shouldPassThroughWithoutSharp) {\n const encoder = \"passthrough\";\n return {\n declarationKey: key,\n sourcePath,\n sourceHash,\n declarationOptions: normalizeDeclarationOptions(declarationOptions),\n transformKey: hash(`${sourceHash}\\0${JSON.stringify(normalized)}\\0${encoder}`),\n encoder,\n ...passThroughImage(\n context,\n sourcePath,\n source,\n inspection.width,\n inspection.height,\n inspection.format,\n ),\n passThrough: true,\n };\n }\n const sharp = await loadSharp(sharpLoader);\n const metadata = await sharp(source, { animated: true }).metadata();\n const sourceWidth = metadata.autoOrient.width ?? metadata.width;\n const sourceHeight =\n (metadata.pages ?? 1) > 1\n ? (metadata.pageHeight ?? metadata.height)\n : (metadata.autoOrient.height ?? metadata.height);\n if (!sourceWidth || !sourceHeight) {\n throw new Error(`@askrjs/vite could not determine intrinsic dimensions for ${sourcePath}.`);\n }\n const encoder = `sharp@${sharp.versions.sharp}`;\n const transformKey = hash(`${sourceHash}\\0${JSON.stringify(normalized)}\\0${encoder}`);\n const fallbackFormat = sourceFormat(metadata.format);\n\n const shouldPassThrough = (metadata.pages ?? 1) > 1 || !fallbackFormat;\n if (shouldPassThrough) {\n return {\n declarationKey: key,\n sourcePath,\n sourceHash,\n declarationOptions: normalizeDeclarationOptions(declarationOptions),\n transformKey,\n encoder,\n ...passThroughImage(\n context,\n sourcePath,\n source,\n sourceWidth,\n sourceHeight,\n fallbackFormat ?? inspection.format,\n ),\n passThrough: true,\n };\n }\n\n const maximumWidth =\n normalized.fit === \"cover\"\n ? Math.min(sourceWidth, Math.floor(sourceHeight * normalized.aspectRatio!))\n : sourceWidth;\n if (maximumWidth < 1) {\n throw new Error(\n `@askrjs/vite cannot crop ${sourcePath} to aspect ratio ${normalized.aspectRatio} without upscaling.`,\n );\n }\n const widths = normalized.widths.filter((width) => width <= maximumWidth);\n if (!widths.includes(maximumWidth)) widths.push(maximumWidth);\n widths.sort((left, right) => left - right);\n const variants: EmittedVariant[] = [];\n for (const format of variantFormats(normalized.formats, fallbackFormat)) {\n for (const width of widths) {\n const height = outputHeight(\n width,\n sourceWidth,\n sourceHeight,\n normalized.fit === \"cover\" ? normalized.aspectRatio : undefined,\n );\n const buffer = await encodedVariant(\n sharp,\n source,\n cacheDir,\n transformKey,\n width,\n height,\n format,\n normalized,\n );\n variants.push({\n referenceId: context.emitFile({\n type: \"asset\",\n name: outputName(sourcePath, width, format),\n source: buffer,\n }),\n width,\n height,\n format,\n mime: mime(format),\n });\n }\n }\n return {\n declarationKey: key,\n sourcePath,\n sourceHash,\n declarationOptions: normalizeDeclarationOptions(declarationOptions),\n transformKey,\n encoder,\n fallback: variants.filter((variant) => variant.format === fallbackFormat).at(-1)!,\n variants,\n passThrough: false,\n };\n}\n","import { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ResolvedConfig } from \"vite\";\nimport { imageDeclarations } from \"./image-declarations\";\nimport {\n IMAGE_METADATA_PATH,\n IMAGE_METADATA_VERSION,\n type ImageMetadataEntry,\n type ImageMetadataRecord,\n} from \"./image-metadata\";\nimport type { ImagePipelineOptions, ResponsiveImage } from \"./image-types\";\nimport type { TextEdit } from \"./source-map-rewrites\";\nimport {\n declarationKey,\n defaultSharpLoader,\n processImage,\n type AssetPluginContext,\n type EmittedVariant,\n type ProcessedImage,\n type SharpLoader,\n} from \"./image-transform\";\n\nexport interface ImagePipelineTransform {\n code: string;\n edits: TextEdit[];\n}\n\nfunction urlExpression(referenceId: string): string {\n return `import.meta.ROLLUP_FILE_URL_${referenceId}`;\n}\n\nfunction mime(format: EmittedVariant[\"format\"]): string {\n return format === \"jpeg\" ? \"image/jpeg\" : `image/${format}`;\n}\n\nfunction srcsetExpression(variants: readonly EmittedVariant[]): string {\n return `[${variants.map((variant) => `${urlExpression(variant.referenceId)} + ${JSON.stringify(` ${variant.width}w`)}`).join(\",\")}].join(\", \")`;\n}\n\nfunction imageExpression(processed: ProcessedImage): string {\n const fallbackVariants = processed.variants.filter(\n (variant) => variant.format === processed.fallback.format,\n );\n const modernFormats = [\"avif\", \"webp\"] as const;\n const sources = processed.passThrough\n ? []\n : modernFormats.flatMap((format) => {\n const variants = processed.variants.filter((variant) => variant.format === format);\n return variants.length === 0\n ? []\n : [`{type:${JSON.stringify(mime(format))},srcset:${srcsetExpression(variants)}}`];\n });\n return `image({__askrImage:true,src:${urlExpression(processed.fallback.referenceId)},${\n processed.passThrough ? \"\" : `srcset:${srcsetExpression(fallbackVariants)},`\n }width:${processed.fallback.width},height:${processed.fallback.height},sources:[${sources.join(\",\")}]})`;\n}\n\nfunction builtUrl(base: string, fileName: string): string {\n if (/^https?:\\/\\//.test(base))\n return new URL(fileName, base.endsWith(\"/\") ? base : `${base}/`).href;\n if (base === \"\" || base === \"./\" || base === \".\")\n return `${base === \".\" ? \"./\" : base}${fileName}`;\n return `${base.endsWith(\"/\") ? base : `${base}/`}${fileName}`;\n}\n\nfunction responsiveMetadata(\n processed: ProcessedImage,\n fileName: (referenceId: string) => string,\n base: string,\n): ResponsiveImage {\n const url = (variant: EmittedVariant) => builtUrl(base, fileName(variant.referenceId));\n const srcset = (variants: readonly EmittedVariant[]) =>\n variants.map((variant) => `${url(variant)} ${variant.width}w`).join(\", \");\n const fallbackVariants = processed.variants.filter(\n (variant) => variant.format === processed.fallback.format,\n );\n return {\n __askrImage: true,\n src: url(processed.fallback),\n ...(processed.passThrough ? {} : { srcset: srcset(fallbackVariants) }),\n width: processed.fallback.width,\n height: processed.fallback.height,\n sources: processed.passThrough\n ? []\n : ([\"avif\", \"webp\"] as const).flatMap((format) => {\n const variants = processed.variants.filter((variant) => variant.format === format);\n return variants.length === 0 ? [] : [{ type: mime(format), srcset: srcset(variants) }];\n }),\n };\n}\n\nexport class ImagePipeline {\n readonly #options: ImagePipelineOptions;\n readonly #processed = new Map<string, ProcessedImage>();\n readonly #sharpLoader: SharpLoader;\n #config: ResolvedConfig | undefined;\n\n constructor(options: ImagePipelineOptions, sharpLoader: SharpLoader = defaultSharpLoader) {\n this.#options = options;\n this.#sharpLoader = sharpLoader;\n }\n\n configure(config: ResolvedConfig): void {\n this.#config = config;\n }\n\n async transform(\n context: AssetPluginContext,\n code: string,\n id: string,\n ): Promise<string | undefined> {\n return (await this.transformWithEdits(context, code, id))?.code;\n }\n\n async transformWithEdits(\n context: AssetPluginContext,\n code: string,\n id: string,\n ): Promise<ImagePipelineTransform | undefined> {\n const found = imageDeclarations(code, id);\n if (found.length === 0) return undefined;\n if (!this.#config) throw new Error(\"@askrjs/vite image pipeline was not configured.\");\n if (this.#config.command !== \"build\") {\n throw new Error(\"@askrjs/vite responsive image declarations currently require a Vite build.\");\n }\n const cacheDir = path.join(this.#config.root, \"node_modules/.cache/@askrjs/vite/images\");\n let transformed = code;\n const edits: TextEdit[] = [];\n for (const declaration of [...found].reverse()) {\n const sourcePath = path.resolve(path.dirname(id.split(\"?\", 1)[0]!), declaration.source);\n const key = declarationKey(sourcePath, declaration.options);\n let processed = this.#processed.get(key);\n if (processed) {\n const sourceHash = createHash(\"sha256\")\n .update(await fs.readFile(sourcePath))\n .digest(\"hex\");\n if (sourceHash !== processed.sourceHash) processed = undefined;\n }\n if (!processed) {\n processed = await processImage(\n context,\n sourcePath,\n declaration.options,\n this.#options,\n cacheDir,\n this.#sharpLoader,\n );\n this.#processed.set(key, processed);\n }\n const replacement = imageExpression(processed);\n edits.push({ start: declaration.start, end: declaration.end, replacement });\n transformed = `${transformed.slice(0, declaration.start)}${replacement}${transformed.slice(declaration.end)}`;\n }\n return { code: transformed, edits: edits.sort((left, right) => left.start - right.start) };\n }\n\n async writeMetadata(context: AssetPluginContext): Promise<void> {\n if (!this.#config || this.#processed.size === 0) return;\n const entries: Record<string, ImageMetadataEntry> = {};\n for (const processed of [...this.#processed.values()].sort((left, right) =>\n left.declarationKey.localeCompare(right.declarationKey),\n )) {\n entries[processed.declarationKey] = {\n sourcePath: processed.sourcePath,\n sourceHash: processed.sourceHash,\n declarationOptions: processed.declarationOptions,\n transformKey: processed.transformKey,\n encoder: processed.encoder,\n image: responsiveMetadata(\n processed,\n (referenceId) => context.getFileName(referenceId),\n this.#config.base,\n ),\n };\n }\n const record: ImageMetadataRecord = {\n version: IMAGE_METADATA_VERSION,\n entries,\n };\n const metadataPath = path.join(this.#config.root, IMAGE_METADATA_PATH);\n await fs.mkdir(path.dirname(metadataPath), { recursive: true });\n await fs.writeFile(metadataPath, `${JSON.stringify(record, null, 2)}\\n`, \"utf8\");\n }\n}\n","import { createRequire } from \"node:module\";\nimport type { Plugin } from \"vite\";\nimport {\n remapGenerated,\n remapOriginal,\n sourceMapForRewrite,\n type RawSourceMap,\n} from \"./source-map-rewrites\";\nimport { optimizeTemplateOutputWithEdits } from \"./template-optimizer\";\nimport { ImagePipeline } from \"./image-pipeline\";\nimport type { ImagePipelineOptions } from \"./image-types\";\n\nconst require = createRequire(import.meta.url);\ntype TransformWithOxc = (typeof import(\"vite\"))[\"transformWithOxc\"];\nlet transformWithOxcPromise: Promise<TransformWithOxc> | undefined;\n\nasync function loadTransformWithOxc(): Promise<TransformWithOxc> {\n transformWithOxcPromise ??= (async () => {\n for (const packageName of [\"vite-plus\", \"vite\"] as const) {\n try {\n const buildTool = await import(packageName);\n if (typeof buildTool.transformWithOxc === \"function\") {\n return buildTool.transformWithOxc as TransformWithOxc;\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ERR_MODULE_NOT_FOUND\") throw error;\n }\n }\n throw new Error(\"@askrjs/vite requires either vite or vite-plus to transform JSX.\");\n })();\n return transformWithOxcPromise;\n}\n\n/** Options accepted by {@link askrVitePlugin}. */\nexport interface AskrVitePluginOptions {\n /** Transform `.jsx`/`.tsx` files with the Askr JSX runtime. Defaults to `true`. */\n transformJsx?: boolean;\n /** Hoist repeated JSX class/style literals using parsed compiled output. Defaults to `false`. */\n optimizeTemplates?: boolean;\n ssrPrecompile?: boolean;\n /** Opt into declared responsive image transforms. */\n images?: boolean | ImagePipelineOptions;\n}\n\n/**\n * Portable public plugin identity.\n *\n * Vite-compatible runners only require the plugin name. Keeping versioned Vite\n * hook types out of the installed declaration prevents consumers such as\n * vite-plus from comparing two distinct copies of Vite's recursive Plugin type.\n */\nexport interface AskrVitePlugin {\n readonly name: \"askr:vite\";\n}\n\n/**\n * Create the Askr Vite plugin, which transforms Askr JSX/TSX with oxc, wires\n * up dependency pre-bundling and aliasing for `@askrjs/askr`, and optionally\n * runs the responsive image pipeline and template optimizer.\n * JSX transform failures are reported through the active Vite/Rollup plugin\n * context with the source file and original transform detail.\n *\n * @param options Plugin configuration; all fields are optional.\n * @returns A Vite-compatible plugin object exposing the `askr:vite` name.\n */\nexport function askrVitePlugin(options: AskrVitePluginOptions = {}): AskrVitePlugin {\n const shouldTransform = options.transformJsx ?? true;\n const shouldOptimizeTemplates = options.optimizeTemplates ?? false;\n const imagePipeline = options.images\n ? new ImagePipeline(options.images === true ? {} : options.images)\n : undefined;\n const plugin = {\n name: \"askr:vite\" as const,\n enforce: \"pre\",\n config() {\n let askrEntry: string | null = null;\n try {\n askrEntry = require.resolve(\"@askrjs/askr\");\n } catch {\n askrEntry = null;\n }\n return {\n define: {\n __ASKR_OPTIMIZE_TEMPLATES__: JSON.stringify(shouldOptimizeTemplates),\n },\n resolve: {\n alias: askrEntry ? [{ find: \"@askrjs/askr\", replacement: askrEntry }] : [],\n dedupe: [\"@askrjs/askr\"],\n },\n optimizeDeps: {\n include: [\n \"@askrjs/askr\",\n \"@askrjs/askr/router\",\n \"@askrjs/askr/boot\",\n \"@askrjs/askr/control\",\n \"@askrjs/askr/fx\",\n \"@askrjs/askr/resources\",\n \"@askrjs/askr/data\",\n \"@askrjs/askr/foundations\",\n \"@askrjs/askr/foundations/icon\",\n \"@askrjs/askr/foundations/interactions\",\n \"@askrjs/askr/foundations/state\",\n \"@askrjs/askr/foundations/structures\",\n \"@askrjs/askr/foundations/utilities\",\n \"@askrjs/askr/jsx-runtime\",\n \"@askrjs/askr/jsx-dev-runtime\",\n ],\n },\n oxc: {\n jsx: { runtime: \"automatic\", importSource: \"@askrjs/askr\" },\n jsxInject: \"import { jsx, jsxs, Fragment } from '@askrjs/askr/jsx-runtime';\",\n },\n };\n },\n configResolved(config) {\n imagePipeline?.configure(config);\n },\n async transform(code, id) {\n if (id.includes(\"node_modules\")) return null;\n const imageTransformed = imagePipeline\n ? await imagePipeline.transformWithEdits(this, code, id)\n : undefined;\n const input = imageTransformed?.code ?? code;\n if (!shouldTransform || !/\\.(jsx|tsx)$/.test(id)) {\n return imageTransformed\n ? {\n code: imageTransformed.code,\n map: sourceMapForRewrite(code, imageTransformed.code, imageTransformed.edits, id),\n }\n : null;\n }\n try {\n const transformWithOxc = await loadTransformWithOxc();\n const result = await transformWithOxc(input, id, {\n lang: id.endsWith(\".tsx\") ? \"tsx\" : \"jsx\",\n jsx: { runtime: \"automatic\", importSource: \"@askrjs/askr\" },\n sourcemap: true,\n });\n if (!result?.code) return null;\n let map = result.map as RawSourceMap;\n if (imageTransformed) {\n map = remapOriginal(map, code, input, imageTransformed.edits);\n }\n if (!shouldOptimizeTemplates) return { code: result.code, map };\n const optimized = optimizeTemplateOutputWithEdits(result.code);\n return {\n code: optimized.code,\n map: remapGenerated(map, result.code, optimized.code, optimized.edits),\n };\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n this.error(`@askrjs/vite failed to transform ${id}: ${detail}`);\n }\n },\n async writeBundle() {\n await imagePipeline?.writeMetadata(this);\n },\n } satisfies Plugin;\n return plugin;\n}\n"],"mappings":";;;;;;;;AAiBA,MAAM,SAAS;AACf,MAAM,gBAAgB,IAAI,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,WAAW,UAAU,CAAC,WAAW,KAAK,CAAC,CAAC;AAEvF,SAAS,UAAU,OAAe,QAAmC;CACnE,IAAI,SAAS;CACb,IAAI,QAAQ;CACZ,SAAS;EACP,MAAM,QAAQ,cAAc,IAAI,MAAM,OAAO,QAAQ;EACrD,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,gCAAgC;EACzE,WAAW,QAAQ,OAAO;EAC1B,KAAK,QAAQ,QAAQ,GAAG;EACxB,SAAS;CACX;CACA,MAAM,YAAY,SAAS,OAAO;CAClC,WAAW;CACX,OAAO,WAAW,CAAC,SAAS;AAC9B;AAEA,SAAS,UAAU,OAAuB;CACxC,IAAI,YAAa,KAAK,IAAI,KAAK,KAAK,KAAM,QAAQ,IAAI,IAAI;CAC1D,IAAI,SAAS;CACb,GAAG;EACD,IAAI,QAAQ,YAAY;EACxB,eAAe;EACf,IAAI,YAAY,GAAG,SAAS;EAC5B,UAAU,OAAO;CACnB,SAAS,YAAY;CACrB,OAAO;AACT;AAEA,SAAS,eAAe,OAA6B;CACnD,MAAM,QAAsB,CAAC;CAC7B,IAAI,SAAS;CACb,IAAI,eAAe;CACnB,IAAI,iBAAiB;CACrB,IAAI,OAAO;CACX,KAAK,MAAM,eAAe,MAAM,MAAM,GAAG,GAAG;EAC1C,MAAM,WAAuB,CAAC;EAC9B,IAAI,kBAAkB;EACtB,KAAK,MAAM,WAAW,YAAY,MAAM,GAAG,GAAG;GAC5C,IAAI,CAAC,SAAS;GACd,MAAM,SAAS,EAAE,OAAO,EAAE;GAC1B,mBAAmB,UAAU,SAAS,MAAM;GAC5C,MAAM,UAAU,CAAC,eAAe;GAChC,IAAI,OAAO,QAAQ,QAAQ,QAAQ;IACjC,UAAU,UAAU,SAAS,MAAM;IACnC,gBAAgB,UAAU,SAAS,MAAM;IACzC,kBAAkB,UAAU,SAAS,MAAM;IAC3C,QAAQ,KAAK,QAAQ,cAAc,cAAc;IACjD,IAAI,OAAO,QAAQ,QAAQ,QAAQ;KACjC,QAAQ,UAAU,SAAS,MAAM;KACjC,QAAQ,KAAK,IAAI;IACnB;GACF;GACA,SAAS,KAAK,OAAO;EACvB;EACA,MAAM,KAAK,QAAQ;CACrB;CACA,OAAO;AACT;AAEA,SAAS,eAAe,OAA6B;CACnD,IAAI,iBAAiB;CACrB,IAAI,uBAAuB;CAC3B,IAAI,yBAAyB;CAC7B,IAAI,eAAe;CACnB,OAAO,MACJ,KAAK,aAAa;EACjB,IAAI,0BAA0B;EAC9B,OAAO,SACJ,KAAK,YAAY;GAChB,IAAI,UAAU,UAAU,QAAQ,KAAM,uBAAuB;GAC7D,0BAA0B,QAAQ;GAClC,IAAI,QAAQ,UAAU,GAAG;IACvB,WAAW,UAAU,QAAQ,KAAM,cAAc;IACjD,WAAW,UAAU,QAAQ,KAAM,oBAAoB;IACvD,WAAW,UAAU,QAAQ,KAAM,sBAAsB;IACzD,iBAAiB,QAAQ;IACzB,uBAAuB,QAAQ;IAC/B,yBAAyB,QAAQ;IACjC,IAAI,QAAQ,WAAW,GAAG;KACxB,WAAW,UAAU,QAAQ,KAAM,YAAY;KAC/C,eAAe,QAAQ;IACzB;GACF;GACA,OAAO;EACT,CAAC,CAAC,CACD,KAAK,GAAG;CACb,CAAC,CAAC,CACD,KAAK,GAAG;AACb;AAEA,SAAS,WAAW,MAAwB;CAC1C,MAAM,SAAS,CAAC,CAAC;CACjB,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAChD,IAAI,KAAK,WAAW,MAAM,OAAO,KAAK,QAAQ,CAAC;CAEjD,OAAO;AACT;AAEA,SAAS,SAAS,QAAkB,MAAc,QAAwB;CACxE,QAAQ,OAAO,SAAS,OAAO,OAAO,SAAS,MAAO;AACxD;AAEA,SAAS,WAAW,QAAkB,QAAkC;CACtE,IAAI,MAAM;CACV,IAAI,OAAO,OAAO;CAClB,OAAO,MAAM,IAAI,MAAM;EACrB,MAAM,SAAU,MAAM,SAAU;EAChC,IAAI,OAAO,WAAY,QAAQ,MAAM;OAChC,OAAO;CACd;CACA,OAAO,CAAC,KAAK,SAAS,OAAO,IAAK;AACpC;AAEA,SAAS,cAAc,QAAgB,OAAoC;CACzE,IAAI,QAAQ;CACZ,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,SAAS,KAAK,OAAO;EACzB,IAAI,SAAS,KAAK,KAAK,OAAO,KAAK,QAAQ;EAC3C,SAAS,KAAK,YAAY,UAAU,KAAK,MAAM,KAAK;CACtD;CACA,OAAO,SAAS;AAClB;AAEA,SAAS,cAAc,QAAgB,OAAoC;CACzE,IAAI,QAAQ;CACZ,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,iBAAiB,KAAK,QAAQ;EACpC,MAAM,eAAe,iBAAiB,KAAK,YAAY;EACvD,IAAI,SAAS,gBAAgB;EAC7B,IAAI,SAAS,cAAc,OAAO,KAAK;EACvC,SAAS,KAAK,YAAY,UAAU,KAAK,MAAM,KAAK;CACtD;CACA,OAAO,SAAS;AAClB;AAEA,SAAS,UAAU,OAAmC;CACpD,OAAO,MAAM,KAAK,aAAa;EAC7B,MAAM,SAAS,SAAS,MAAM,MAAM,UAAU,KAAK,KAAM,MAAM,EAAG;EAClE,OAAO,OAAO,QAAQ,SAAS,UAAU,UAAU,KAAK,QAAQ,OAAO,OAAO,QAAQ,EAAE,CAAE,EAAE;CAC9F,CAAC;AACH;AAEA,SAAS,UAAU,OAAqB,QAAkB,QAAsC;CAC9F,MAAM,CAAC,MAAM,UAAU,WAAW,QAAQ,MAAM;CAChD,IAAI;CACJ,KAAK,MAAM,WAAW,MAAM,SAAS,CAAC,GAAG;EACvC,IAAI,QAAQ,KAAM,QAAQ;EAC1B,IAAI,QAAQ,UAAU,GAAG,QAAQ;CACnC;CACA,OAAO;AACT;;AAGA,SAAgB,eACd,KACA,QACA,OACA,OACc;CACd,MAAM,eAAe,WAAW,MAAM;CACtC,MAAM,cAAc,WAAW,KAAK;CACpC,MAAM,UAAU,eAAe,IAAI,QAAQ;CAC3C,MAAM,SAAuB,MAAM,KAAK,EAAE,QAAQ,YAAY,OAAO,SAAS,CAAC,CAAC;CAChF,KAAK,MAAM,CAAC,MAAM,aAAa,QAAQ,QAAQ,GAC7C,KAAK,MAAM,WAAW,UAAU;EAE9B,MAAM,CAAC,UAAU,cAAc,WAAW,aAD3B,cAAc,SAAS,cAAc,MAAM,QAAQ,EAAG,GAAG,KACZ,CAAC;EAC7D,OAAO,SAAS,CAAE,KAAK,CAAC,YAAY,GAAG,QAAQ,MAAM,CAAC,CAAC,CAAC;CAC1D;CAEF,IAAI,QAAQ;CACZ,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,UAAU,KAAA,GAAW;GAC5B,MAAM,SAAS,UAAU,SAAS,cAAc,KAAK,KAAK;GAC1D,IAAI,QAAQ;IACV,MAAM,CAAC,MAAM,UAAU,WAAW,aAAa,KAAK,QAAQ,KAAK;IACjE,OAAO,KAAK,CAAE,KAAK,CAAC,QAAQ,GAAG,OAAO,MAAM,CAAC,CAAC,CAAC;GACjD;EACF;EACA,SAAS,KAAK,YAAY,UAAU,KAAK,MAAM,KAAK;CACtD;CACA,OAAO;EAAE,GAAG;EAAK,UAAU,eAAe,UAAU,MAAM,CAAC;CAAE;AAC/D;;AAGA,SAAgB,cACd,KACA,UACA,WACA,OACc;CACd,MAAM,iBAAiB,WAAW,QAAQ;CAC1C,MAAM,kBAAkB,WAAW,SAAS;CAC5C,MAAM,QAAQ,eAAe,IAAI,QAAQ;CACzC,KAAK,MAAM,YAAY,OACrB,KAAK,MAAM,WAAW,UAAU;EAC9B,IAAI,QAAQ,SAAS,KAAK,QAAQ,OAAO,GAAG;EAE5C,MAAM,CAAC,MAAM,UAAU,WAAW,gBADnB,cAAc,SAAS,iBAAiB,QAAQ,IAAK,QAAQ,EAAG,GAAG,KAC3B,CAAC;EACxD,QAAQ,KAAK;EACb,QAAQ,KAAK;CACf;CAEF,OAAO;EACL,GAAG;EACH,UAAU,eAAe,KAAK;EAC9B,gBAAgB,IAAI,SAAS,KAAK,SAAS,UACzC,UAAU,IAAI,WAAY,IAAI,iBAAiB,UAAU,IAC3D;CACF;AACF;;AAGA,SAAgB,oBACd,UACA,WACA,OACA,IACc;CACd,MAAM,iBAAiB,WAAW,QAAQ;CAC1C,MAAM,kBAAkB,WAAW,SAAS;CAC5C,MAAM,QAAsB,MAAM,KAAK,EAAE,QAAQ,gBAAgB,OAAO,SAAS,CAAC,CAAC;CACnF,KAAK,IAAI,SAAS,GAAG,SAAS,UAAU,QAAQ,UAAU,GAAG;EAC3D,MAAM,CAAC,eAAe,mBAAmB,WAAW,iBAAiB,MAAM;EAC3E,MAAM,CAAC,cAAc,kBAAkB,WAAW,gBAAgB,cAAc,QAAQ,KAAK,CAAC;EAC9F,MAAM,cAAc,CAAE,KAAK;GAAC;GAAiB;GAAG;GAAc;EAAc,CAAC;CAC/E;CACA,OAAO;EACL,SAAS;EACT,OAAO,CAAC;EACR,SAAS,CAAC,EAAE;EACZ,gBAAgB,CAAC,QAAQ;EACzB,UAAU,eAAe,KAAK;CAChC;AACF;;;AC1PA,MAAM,kCAAkB,IAAI,IAAI;CAAC;CAAS;CAAa;AAAO,CAAC;AAC/D,MAAM,qBAAqB;AAC3B,MAAM,gCAAgB,IAAI,IAAI;CAAC;CAAO;CAAQ;AAAQ,CAAC;AAQvD,SAAS,aAAa,WAA2E;CAC/F,OAAO,UAAU,SAAS,SAAS,eAC/B,UAAU,SAAS,OACnB,UAAU,SAAS;AACzB;AAEA,SAAS,wBAAwB,SAA+D;CAC9F,MAAM,4BAAY,IAAI,IAAY;CAElC,KAAK,MAAM,aAAa,QAAQ,MAAM;EACpC,IAAI,UAAU,SAAS,uBAAuB,UAAU,OAAO,UAAU,oBACvE;EAGF,KAAK,MAAM,aAAa,UAAU,YAChC,IACE,UAAU,SAAS,qBACnB,cAAc,IAAI,OAAO,aAAa,SAAS,CAAC,CAAC,GAEjD,UAAU,IAAI,UAAU,MAAM,IAAI;CAGxC;CAEA,OAAO;AACT;AAEA,SAAS,iBACP,UACA,MACA,YACA;CACA,IACE,SAAS,SAAS,UAClB,SAAS,YACT,SAAS,UACT,SAAS,IAAI,SAAS,gBACtB,CAAC,gBAAgB,IAAI,SAAS,IAAI,IAAI,KACtC,SAAS,MAAM,SAAS,aACxB,OAAO,SAAS,MAAM,UAAU,UAEhC;CAGF,MAAM,UAAU,KAAK,MAAM,SAAS,MAAM,OAAO,SAAS,MAAM,GAAG;CACnE,MAAM,WAAW,GAAG,SAAS,IAAI,KAAK,GAAG;CACzC,MAAM,QAAQ,WAAW,IAAI,QAAQ,KAAK,CAAC;CAC3C,MAAM,KAAK;EACT;EACA,OAAO,SAAS,MAAM;EACtB,KAAK,SAAS,MAAM;CACtB,CAAC;CACD,WAAW,IAAI,UAAU,KAAK;AAChC;AAOA,SAAgB,gCAAgC,MAAuC;CACrF,MAAM,SAAS,UAAU,oBAAoB,MAAM;EACjD,MAAM;EACN,YAAY;CACd,CAAC;CACD,IAAI,OAAO,OAAO,SAAS,GAAG,OAAO;EAAE;EAAM,OAAO,CAAC;CAAE;CAEvD,MAAM,mBAAmB,wBAAwB,OAAO,OAAO;CAC/D,IAAI,iBAAiB,SAAS,GAAG,OAAO;EAAE;EAAM,OAAO,CAAC;CAAE;CAE1D,MAAM,6BAAa,IAAI,IAAyB;CAChD,MAAM,8BAAc,IAAI,IAAY;CACpC,IAAI,QAAQ;EACV,WAAW,YAAY;GACrB,YAAY,IAAI,WAAW,IAAI;EACjC;EACA,eAAe,MAAM;GACnB,IACE,KAAK,OAAO,SAAS,gBACrB,CAAC,iBAAiB,IAAI,KAAK,OAAO,IAAI,KACtC,KAAK,UAAU,EAAE,EAAE,SAAS,oBAE5B;GAGF,KAAK,MAAM,YAAY,KAAK,UAAU,EAAE,CAAC,YACvC,IAAI,SAAS,SAAS,YACpB,iBAAiB,UAAU,MAAM,UAAU;EAGjD;CACF,CAAC,CAAC,CAAC,MAAM,OAAO,OAAO;CAEvB,MAAM,eAAyB,CAAC;CAChC,MAAM,eAA0E,CAAC;CACjF,IAAI,aAAa;CACjB,KAAK,MAAM,SAAS,WAAW,OAAO,GAAG;EACvC,IAAI,MAAM,SAAS,GAAG;EAEtB,IAAI;EACJ;GACE,aAAa,sBAAsB;SAC5B,YAAY,IAAI,UAAU;EACnC,YAAY,IAAI,UAAU;EAC1B,aAAa,KAAK,SAAS,WAAW,KAAK,MAAM,EAAE,CAAC,QAAQ,EAAE;EAC9D,KAAK,MAAM,aAAa,OACtB,aAAa,KAAK;GAAE,OAAO,UAAU;GAAO,KAAK,UAAU;GAAK;EAAW,CAAC;CAEhF;CAEA,IAAI,aAAa,WAAW,GAAG,OAAO;EAAE;EAAM,OAAO,CAAC;CAAE;CAExD,MAAM,SAAS,GAAG,aAAa,KAAK,IAAI,EAAE;CAC1C,MAAM,QAAoB,CACxB;EAAE,OAAO;EAAG,KAAK;EAAG,aAAa;EAAQ,OAAO,aAAa,EAAE,CAAE;CAAM,GACvE,GAAG,aACA,KAAK,EAAE,OAAO,KAAK,kBAAkB;EAAE;EAAO;EAAK,aAAa;CAAW,EAAE,CAAC,CAC9E,MAAM,MAAM,UAAU,KAAK,QAAQ,MAAM,KAAK,CACnD;CACA,IAAI,YAAY;CAChB,KAAK,MAAM,eAAe,aAAa,MAAM,MAAM,UAAU,MAAM,QAAQ,KAAK,KAAK,GACnF,YACE,UAAU,MAAM,GAAG,YAAY,KAAK,IACpC,YAAY,aACZ,UAAU,MAAM,YAAY,GAAG;CAEnC,OAAO;EAAE,MAAM,GAAG,SAAS;EAAa;CAAM;AAChD;;;AC5IA,MAAM,eAAe;AAErB,SAAS,gBAAgB,QAA4B;CACnD,MAAM,OAAO,IAAI,WAAW,OAAO,MAAM;CACzC,IAAI,QAAsF;CAC1F,IAAI,UAAU;CACd,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,GAAG;EACrD,MAAM,YAAY,OAAO;EACzB,MAAM,OAAO,OAAO,QAAQ;EAC5B,IAAI,UAAU,QAAQ;GACpB,IAAI,cAAc,OAAO,SAAS,KAAK;IACrC,QAAQ;IACR,SAAS;GACX,OAAO,IAAI,cAAc,OAAO,SAAS,KAAK;IAC5C,QAAQ;IACR,SAAS;GACX,OAAO,IAAI,cAAc,KAAK,QAAQ;QACjC,IAAI,cAAc,MAAK,QAAQ;QAC/B,IAAI,cAAc,KAAK,QAAQ;QAC/B,KAAK,SAAS;GACnB;EACF;EACA,IAAI,UAAU,gBAAgB;GAC5B,IAAI,cAAc,QAAQ,cAAc,MAAM;IAC5C,QAAQ;IACR,KAAK,SAAS;GAChB;GACA;EACF;EACA,IAAI,UAAU,iBAAiB;GAC7B,IAAI,cAAc,OAAO,SAAS,KAAK;IACrC,QAAQ;IACR,SAAS;GACX;GACA;EACF;EACA,IAAI,SAAS,UAAU;OAClB,IAAI,cAAc,MAAM,UAAU;OAClC,IACF,UAAU,YAAY,cAAc,OACpC,UAAU,YAAY,cAAc,QACpC,UAAU,cAAc,cAAc,KAEvC,QAAQ;CAEZ;CACA,OAAO;AACT;AAEA,SAAgB,qBAAqB,MAAsC;CACzE,MAAM,OAAO,gBAAgB,IAAI;CACjC,aAAa,YAAY;CACzB,KAAK,IAAI,QAAQ,aAAa,KAAK,IAAI,GAAG,OAAO,QAAQ,aAAa,KAAK,IAAI,GAC7E,IAAI,KAAK,MAAM,QAAQ,OAAO;AAGlC;;;AC9CA,MAAM,aAAa;AAEnB,SAAS,WAAW,QAAgB,IAAoB;CACtD,IAAI,SAAS;CACb,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,SAAS;EAC1C,MAAM,YAAY,OAAO;EACzB,IAAI,KAAK,KAAK,SAAS,KAAK,QAAQ,SAAS,SAAS,GAAG;GACvD,UAAU;GACV,SAAS;GACT;EACF;EACA,IAAI,cAAc,KAAK;GACrB,IAAI,OAAO,QAAQ;GACnB,OAAO,KAAK,KAAK,OAAO,SAAS,EAAE,GAAG,QAAQ;GAC9C,IAAI,OAAO,UAAU,OAAO,OAAO,UAAU,KAAK,UAAU;GAC5D,SAAS;GACT;EACF;EACA,IAAI,cAAc,QAAO,cAAc,KAAK;GAC1C,IAAI,MAAM,QAAQ;GAClB,OAAO,MAAM,OAAO,UAAU,OAAO,SAAS,WAAW;IACvD,IAAI,OAAO,SAAS,MAClB,MAAM,IAAI,MACR,0CAA0C,GAAG,kCAC/C;IAEF,OAAO;GACT;GACA,IAAI,OAAO,OAAO,QAChB,MAAM,IAAI,MAAM,sDAAsD,GAAG,EAAE;GAE7E,UAAU,KAAK,UAAU,OAAO,MAAM,QAAQ,GAAG,GAAG,CAAC;GACrD,QAAQ,MAAM;GACd;EACF;EACA,MAAM,SAAS,6CAA6C,KAAK,OAAO,MAAM,KAAK,CAAC;EACpF,IAAI,QAAQ;GACV,UAAU,OAAO;GACjB,SAAS,OAAO,EAAE,CAAC;GACnB;EACF;EACA,MAAM,aAAa,gBAAgB,KAAK,OAAO,MAAM,KAAK,CAAC;EAC3D,IAAI,YAAY;GACd,IAAI,OAAO,QAAQ,WAAW,EAAE,CAAC;GACjC,OAAO,KAAK,KAAK,OAAO,SAAS,EAAE,GAAG,QAAQ;GAC9C,IAAI,OAAO,UAAU,KAAK,UAAU,KAAK,UAAU,WAAW,EAAE;QAC3D,IAAI;IAAC;IAAQ;IAAS;GAAM,CAAC,CAAC,SAAS,WAAW,EAAE,GAAG,UAAU,WAAW;QAE/E,MAAM,IAAI,MACR,mCAAmC,GAAG,sBAAsB,WAAW,GAAG,+BAC5E;GAEF,SAAS,WAAW,EAAE,CAAC;GACvB;EACF;EACA,MAAM,IAAI,MACR,mCAAmC,GAAG,yEACxC;CACF;CACA,OAAO;AACT;AAEA,SAAS,cAAc,QAAgB,IAA0B;CAC/D,MAAM,UAAU,OAAO,KAAK;CAC5B,IAAI,CAAC,SAAS,OAAO,CAAC;CACtB,IAAI;CACJ,IAAI;EACF,QAAQ,KAAK,MAAM,WAAW,SAAS,EAAE,CAAC;CAC5C,SAAS,OAAO;EACd,IAAI,iBAAiB,SAAS,MAAM,QAAQ,WAAW,cAAc,GAAG,MAAM;EAC9E,MAAM,IAAI,MAAM,mDAAmD,GAAG,IAAI,EAAE,OAAO,MAAM,CAAC;CAC5F;CACA,IAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAC5D,MAAM,IAAI,MAAM,mCAAmC,GAAG,4BAA4B;CAEpF,OAAO;AACT;AAEA,SAAS,YAAY,MAAc,OAAuB;CACxD,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,IAAI,UAAU;CACd,KAAK,IAAI,QAAQ,OAAO,QAAQ,KAAK,QAAQ,SAAS,GAAG;EACvD,MAAM,YAAY,KAAK;EACvB,IAAI,OAAO;GACT,IAAI,SAAS,UAAU;QAClB,IAAI,cAAc,MAAM,UAAU;QAClC,IAAI,cAAc,OAAO,QAAQ;GACtC;EACF;EACA,IAAI,cAAc,QAAO,cAAc,KAAK;GAC1C,QAAQ;GACR;EACF;EACA,IAAI,cAAc,KAAK,SAAS;EAChC,IAAI,cAAc,KAAK;GACrB,SAAS;GACT,IAAI,UAAU,GAAG,OAAO;EAC1B;CACF;CACA,OAAO;AACT;AAEA,SAAgB,kBAAkB,MAAc,IAAgC;CAC9E,MAAM,OAAO,qBAAqB,IAAI;CACtC,IAAI,CAAC,MAAM,OAAO,CAAC;CACnB,MAAM,SAA6B,CAAC;CACpC,WAAW,YAAY;CACvB,KAAK,IAAI,QAAQ,WAAW,KAAK,IAAI,GAAG,OAAO,QAAQ,WAAW,KAAK,IAAI,GAAG;EAC5E,IAAI,CAAC,KAAK,MAAM,QAAQ;EACxB,MAAM,WAAW,WAAW;EAC5B,MAAM,MAAM,YAAY,MAAM,QAAQ;EACtC,IAAI,MAAM,GAAG,MAAM,IAAI,MAAM,sDAAsD,GAAG,EAAE;EACxF,MAAM,YAAY,KAAK,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK;EACjD,IAAI,aAAa,CAAC,UAAU,WAAW,GAAG,GACxC,MAAM,IAAI,MAAM,uDAAuD,GAAG,EAAE;EAE9E,OAAO,KAAK;GACV,OAAO,MAAM;GACb,KAAK,MAAM;GACX,QAAQ,MAAM;GACd,SAAS,cAAc,UAAU,QAAQ,MAAM,EAAE,GAAG,EAAE;EACxD,CAAC;EACD,WAAW,YAAY,MAAM;CAC/B;CACA,OAAO;AACT;;;AC9HA,SAAS,mBACP,OACA,QACA,QACA,eACA,WAAW,OACmB;CAC9B,OAAO,QAAQ,KAAK,SAAS,IAAI;EAAE;EAAO;EAAQ;EAAQ;EAAe;CAAS,IAAI,KAAA;AACxF;AAEA,SAAS,WAAW,QAA8C;CAChE,IACE,OAAO,SAAS,MAChB,CAAC,OAAO,SAAS,GAAG,CAAC,CAAC,CAAC,OAAO,OAAO,KAAK;EAAC;EAAK;EAAI;EAAI;EAAI;EAAI;EAAI;EAAI;CAAE,CAAC,CAAC,GAE5E;CAEF,OAAO,mBACL,OAAO,aAAa,EAAE,GACtB,OAAO,aAAa,EAAE,GACtB,OACA,MACA,OAAO,SAAS,OAAO,KAAK,MAAM,CAAC,CACrC;AACF;AAEA,SAAS,WAAW,QAA8C;CAChE,IAAI,OAAO,SAAS,MAAM,CAAC,cAAc,KAAK,OAAO,SAAS,GAAG,CAAC,CAAC,CAAC,SAAS,OAAO,CAAC,GACnF;CAEF,OAAO,mBAAmB,OAAO,aAAa,CAAC,GAAG,OAAO,aAAa,CAAC,GAAG,OAAO,OAAO,IAAI;AAC9F;AAEA,SAAS,gBAAgB,SAAqC;CAC5D,IAAI,QAAQ,SAAS,MAAM,QAAQ,SAAS,GAAG,CAAC,CAAC,CAAC,SAAS,QAAQ,MAAM,YACvE;CAEF,MAAM,OAAO;CACb,MAAM,YAAY,QAAQ,SAAS,MAAM,CAAQ,CAAC,CAAC,SAAS,OAAO;CACnE,MAAM,eAAe,cAAc;CACnC,IAAI,CAAC,gBAAgB,cAAc,MAAM,OAAO,KAAA;CAChD,MAAM,UAAU,WAAuC;EACrD,MAAM,WAAW,OAAO;EACxB,IAAI,WAAW,QAAQ,WAAW,IAAI,QAAQ,QAAQ,OAAO,KAAA;EAC7D,OAAO,eAAe,QAAQ,aAAa,QAAQ,IAAI,QAAQ,aAAa,QAAQ;CACtF;CACA,MAAM,UAAU,WAAuC;EACrD,MAAM,WAAW,OAAO;EACxB,IAAI,WAAW,QAAQ,WAAW,IAAI,QAAQ,QAAQ,OAAO,KAAA;EAC7D,OAAO,eAAe,QAAQ,aAAa,QAAQ,IAAI,QAAQ,aAAa,QAAQ;CACtF;CACA,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,KAAA;CAC7B,MAAM,kBAAkB,OAAO,CAAC;CAChC,IAAI,oBAAoB,KAAA,GAAW,OAAO,KAAA;CAC1C,MAAM,UAAU,OAAO,eAAe;CACtC,IAAI,YAAY,KAAA,GAAW,OAAO,KAAA;CAClC,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,SAAS,GAAG;EAC/C,MAAM,QAAQ,kBAAkB,IAAI,QAAQ;EAC5C,IAAI,OAAO,KAAK,MAAM,OAAU,OAAO,QAAQ,CAAC,MAAM,KAAK,OAAO,QAAQ,CAAC,MAAM,GAC/E;EAEF,MAAM,cAAc,OAAO,QAAQ,CAAC;EACpC,OAAO,eAAe,eAAe,KAAK,eAAe,IAAI,cAAc,KAAA;CAC7E;AAEF;AAEA,SAAS,YAAY,QAA8C;CACjE,IAAI,OAAO,SAAS,KAAK,OAAO,OAAO,OAAQ,OAAO,OAAO,KAAM,OAAO,KAAA;CAC1E,MAAM,+BAAe,IAAI,IAAI;EAC3B;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;CAC1E,CAAC;CACD,IAAI;CACJ,IAAI,SAAS;CACb,OAAO,SAAS,IAAI,OAAO,QAAQ;EACjC,IAAI,OAAO,YAAY,KAAM;GAC3B,UAAU;GACV;EACF;EACA,OAAO,OAAO,YAAY,KAAM,UAAU;EAC1C,MAAM,SAAS,OAAO;EACtB,IAAI,WAAW,OAAQ,WAAW,OAAQ,WAAW,GAAM;EAC3D,IAAI,UAAU,OAAQ,UAAU,KAAM;EACtC,IAAI,SAAS,IAAI,OAAO,QAAQ;EAChC,MAAM,SAAS,OAAO,aAAa,MAAM;EACzC,IAAI,SAAS,KAAK,SAAS,SAAS,OAAO,QAAQ;EACnD,IAAI,WAAW,KACb,cAAc,gBAAgB,OAAO,SAAS,SAAS,GAAG,SAAS,MAAM,CAAC,KAAK;EAEjF,IAAI,aAAa,IAAI,MAAM,KAAK,UAAU,GAAG;GAC3C,MAAM,QAAQ,OAAO,aAAa,SAAS,CAAC;GAC5C,MAAM,SAAS,OAAO,aAAa,SAAS,CAAC;GAC7C,OAAO,mBACL,gBAAgB,KAAA,KAAa,eAAe,IAAI,SAAS,OACzD,gBAAgB,KAAA,KAAa,eAAe,IAAI,QAAQ,QACxD,QACA,IACF;EACF;EACA,UAAU;CACZ;AAEF;AAEA,SAAS,WAAW,QAA8C;CAChE,MAAM,aAAa,OAChB,SAAS,GAAG,KAAM,CAAC,CACnB,SAAS,MAAM,CAAC,CAChB,MAAM,eAAe,CAAC,GAAG;CAC5B,IAAI,CAAC,YAAY,OAAO,KAAA;CACxB,MAAM,mBAAmB,SAAqC;EAC5D,MAAM,QAAQ,WAAW,MAAM,IAAI,OAAO,MAAM,KAAK,6BAA6B,GAAG,CAAC,CAAC,GAAG;EAC1F,MAAM,SAAS,QAAQ,OAAO,KAAK,IAAI;EACvC,OAAO,OAAO,SAAS,MAAM,KAAK,SAAS,IAAI,SAAS,KAAA;CAC1D;CACA,IAAI,QAAQ,gBAAgB,OAAO;CACnC,IAAI,SAAS,gBAAgB,QAAQ;CACrC,MAAM,UAAU,WACb,MAAM,qFAAqF,CAAC,EAC3F,MAAM,CAAC,CAAC,CACT,IAAI,MAAM;CACb,IAAI,CAAC,SAAS,UAAU,MAAM,QAAQ,KAAK,GAAG,QAAQ,QAAQ;CAC9D,IAAI,CAAC,UAAU,UAAU,MAAM,QAAQ,KAAK,GAAG,SAAS,QAAQ;CAChE,IAAI,CAAC,SAAS,UAAU,UAAU,MAAM,UAAU,IAAI,QAAQ,UAAU,QAAQ,KAAK,QAAQ;CAC7F,IAAI,CAAC,UAAU,SAAS,UAAU,MAAM,UAAU,IAAI,SAAS,SAAS,QAAQ,KAAK,QAAQ;CAC7F,OAAO,SAAS,SAAS,mBAAmB,OAAO,QAAQ,OAAO,KAAK,IAAI,KAAA;AAC7E;AAEA,SAAS,YAAY,QAA8C;CACjE,IACE,OAAO,SAAS,MAChB,OAAO,SAAS,GAAG,CAAC,CAAC,CAAC,SAAS,OAAO,MAAM,UAC5C,OAAO,SAAS,GAAG,EAAE,CAAC,CAAC,SAAS,OAAO,MAAM,QAE7C;CAEF,MAAM,QAAQ,OAAO,SAAS,IAAI,EAAE,CAAC,CAAC,SAAS,OAAO;CACtD,IAAI,UAAU,QAGZ,OAAO,mBAFO,IAAI,OAAO,WAAW,IAAI,CAAC,GAC1B,IAAI,OAAO,WAAW,IAAI,CAAC,GACD,QAAQ,OAAO,QAAQ,OAAO,MAAO,CAAI,CAAC;CAErF,IAAI,UAAU,QACZ,OAAO,mBACL,OAAO,aAAa,EAAE,IAAI,OAC1B,OAAO,aAAa,EAAE,IAAI,OAC1B,QACA,KACF;CAEF,IAAI,UAAU,UAAU,OAAO,QAAQ,IAAM;EAC3C,MAAM,OAAO,OAAO,aAAa,EAAE;EACnC,OAAO,mBAAmB,KAAK,OAAO,QAAS,KAAM,SAAS,KAAM,QAAS,QAAQ,KAAK;CAC5F;AAEF;AAEA,SAAS,YAAY,QAA8C;CACjE,IAAI,OAAO,SAAS,MAAM,OAAO,SAAS,GAAG,CAAC,CAAC,CAAC,SAAS,OAAO,MAAM,QAAQ,OAAO,KAAA;CACrF,MAAM,aAAa,OAAO,QAAQ,OAAO,KAAK,MAAM,CAAC;CACrD,IAAI,aAAa,KAAK,aAAa,KAAK,OAAO,QAAQ,OAAO,KAAA;CAC9D,OAAO,mBACL,OAAO,aAAa,aAAa,CAAC,GAClC,OAAO,aAAa,aAAa,EAAE,GACnC,QACA,KACF;AACF;AAEA,SAAgB,cAAc,YAAoB,QAAkC;CAClF,MAAM,aACJ,WAAW,MAAM,KACjB,WAAW,MAAM,KACjB,YAAY,MAAM,KAClB,WAAW,MAAM,KACjB,YAAY,MAAM,KAClB,YAAY,MAAM;CACpB,IAAI,CAAC,YACH,MAAM,IAAI,MACR,gFAAgF,WAAW,EAC7F;CAEF,OAAO;AACT;;;AC7JA,SAAS,KAAK,OAAgC;CAC5C,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK;AACxD;AAEA,SAAgB,eAAe,YAAoB,SAA+B;CAChF,OAAO,KAAK,GAAG,WAAW,IAAI,KAAK,UAAU,4BAA4B,OAAO,CAAC,GAAG;AACtF;AAEA,MAAa,qBAAkC,aAAa,MAAM,OAAO,SAAA,CAAU;AAEnF,eAAe,UAAU,QAA4C;CACnE,IAAI;EACF,OAAO,MAAM,OAAO;CACtB,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,wBAC5C,MAAM,IAAI,MACR,0GACA,EAAE,OAAO,MAAM,CACjB;EAEF,MAAM;CACR;AACF;AAEA,SAAS,aAAa,QAAwD;CAC5E,IAAI,WAAW,UAAU,WAAW,OAAO,OAAO;CAClD,OAAO,WAAW,QAAQ,QAAQ,KAAA;AACpC;AAEA,SAAS,UAAU,QAA6B;CAC9C,OAAO,WAAW,SAAS,QAAQ;AACrC;AAEA,SAASA,OAAK,QAA6B;CACzC,OAAO,WAAW,SAAS,eAAe,SAAS;AACrD;AAEA,SAAS,WAAW,YAAoB,OAAe,QAA0C;CAE/F,OAAO,GADU,KAAK,SAAS,YAAY,KAAK,QAAQ,UAAU,CACjD,EAAE,GAAG,MAAM,GAAG,UAAU,MAAM;AACjD;AAEA,SAAS,aACP,OACA,aACA,cACA,aACQ;CACR,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,eAAe,cAAc,aAAa,CAAC;AACpF;AAEA,eAAe,eACb,OACA,QACA,UACA,cACA,OACA,QACA,QACA,SACiB;CACjB,MAAM,YAAY,KAAK,KAAK,UAAU,GAAG,aAAa,GAAG,MAAM,GAAG,UAAU,MAAM,GAAG;CACrF,MAAM,SAAS,MAAM,GAAG,SAAS,SAAS,CAAC,CAAC,YAAY,KAAA,CAAS;CACjE,IAAI,QAAQ,OAAO;CAEnB,IAAI,WAAW,MAAM,QAAQ,EAAE,UAAU,MAAM,CAAC,CAAC,CAAC,WAAW;CAC7D,WACE,QAAQ,QAAQ,UACZ,SAAS,OAAO;EAAE;EAAO;EAAQ,KAAK;EAAS,UAAU,QAAQ;CAAS,CAAC,IAC3E,SAAS,OAAO;EAAE;EAAO,KAAK;EAAU,oBAAoB;CAAK,CAAC;CACxE,IAAI,WAAW,QAAQ,WAAW,SAAS,KAAK,EAAE,SAAS,QAAQ,QAAQ,KAAK,CAAC;MAC5E,IAAI,WAAW,QAAQ,WAAW,SAAS,KAAK,EAAE,SAAS,QAAQ,QAAQ,KAAK,CAAC;MACjF,IAAI,WAAW,QAAQ,WAAW,SAAS,KAAK,EAAE,SAAS,QAAQ,QAAQ,KAAK,CAAC;MAEpF,WAAW,SAAS,IAClB,QAAQ,QAAQ,QAAQ,MACpB,EAAE,kBAAkB,EAAE,IACtB;EAAE,kBAAkB;EAAG,SAAS,QAAQ,QAAQ;CAAI,CAC1D;CAEF,MAAM,UAAU,MAAM,SAAS,SAAS;CACxC,MAAM,GAAG,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;CAC5C,MAAM,GAAG,UAAU,WAAW,OAAO;CACrC,OAAO;AACT;AAEA,SAAS,eACP,SACA,UACyC;CACzC,MAAM,SAAkD,CAAC;CACzD,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,WAAW,WAAW,WAAW,WAAW;EAClD,IAAI,CAAC,OAAO,SAAS,QAAQ,GAAG,OAAO,KAAK,QAAQ;CACtD;CACA,IAAI,CAAC,OAAO,SAAS,QAAQ,GAAG,OAAO,KAAK,QAAQ;CACpD,OAAO;AACT;AAEA,SAAS,iBACP,SACA,YACA,QACA,OACA,QACA,QAC0D;CAE1D,MAAM,WAAW;EAAE,aADC,QAAQ,SAAS;GAAE,MAAM;GAAS,MAAM,KAAK,SAAS,UAAU;GAAG;EAAO,CACjE;EAAG;EAAO;EAAQ;EAAQ,MAAMA,OAAK,MAAM;CAAE;CAC1E,OAAO;EAAE;EAAU,UAAU,CAAC,QAAQ;CAAE;AAC1C;AAEA,eAAsB,aACpB,SACA,YACA,oBACA,eACA,UACA,aACyB;CACzB,MAAM,SAAS,MAAM,GAAG,SAAS,UAAU;CAC3C,MAAM,aAAa,KAAK,MAAM;CAC9B,MAAM,aAAa,sBAAsB,eAAe,kBAAkB;CAC1E,MAAM,aAAa,cAAc,YAAY,MAAM;CACnD,MAAM,MAAM,eAAe,YAAY,kBAAkB;CAKzD,IAHE,CAAC,WAAW,iBACZ,WAAW,YACV,WAAW,QAAQ,YAAY,WAAW,SAAS,WAAW,OAAO,IACrC;EACjC,MAAM,UAAU;EAChB,OAAO;GACL,gBAAgB;GAChB;GACA;GACA,oBAAoB,4BAA4B,kBAAkB;GAClE,cAAc,KAAK,GAAG,WAAW,IAAI,KAAK,UAAU,UAAU,EAAE,IAAI,SAAS;GAC7E;GACA,GAAG,iBACD,SACA,YACA,QACA,WAAW,OACX,WAAW,QACX,WAAW,MACb;GACA,aAAa;EACf;CACF;CACA,MAAM,QAAQ,MAAM,UAAU,WAAW;CACzC,MAAM,WAAW,MAAM,MAAM,QAAQ,EAAE,UAAU,KAAK,CAAC,CAAC,CAAC,SAAS;CAClE,MAAM,cAAc,SAAS,WAAW,SAAS,SAAS;CAC1D,MAAM,gBACH,SAAS,SAAS,KAAK,IACnB,SAAS,cAAc,SAAS,SAChC,SAAS,WAAW,UAAU,SAAS;CAC9C,IAAI,CAAC,eAAe,CAAC,cACnB,MAAM,IAAI,MAAM,6DAA6D,WAAW,EAAE;CAE5F,MAAM,UAAU,SAAS,MAAM,SAAS;CACxC,MAAM,eAAe,KAAK,GAAG,WAAW,IAAI,KAAK,UAAU,UAAU,EAAE,IAAI,SAAS;CACpF,MAAM,iBAAiB,aAAa,SAAS,MAAM;CAGnD,KAD2B,SAAS,SAAS,KAAK,KAAK,CAAC,gBAEtD,OAAO;EACL,gBAAgB;EAChB;EACA;EACA,oBAAoB,4BAA4B,kBAAkB;EAClE;EACA;EACA,GAAG,iBACD,SACA,YACA,QACA,aACA,cACA,kBAAkB,WAAW,MAC/B;EACA,aAAa;CACf;CAGF,MAAM,eACJ,WAAW,QAAQ,UACf,KAAK,IAAI,aAAa,KAAK,MAAM,eAAe,WAAW,WAAY,CAAC,IACxE;CACN,IAAI,eAAe,GACjB,MAAM,IAAI,MACR,4BAA4B,WAAW,mBAAmB,WAAW,YAAY,oBACnF;CAEF,MAAM,SAAS,WAAW,OAAO,QAAQ,UAAU,SAAS,YAAY;CACxE,IAAI,CAAC,OAAO,SAAS,YAAY,GAAG,OAAO,KAAK,YAAY;CAC5D,OAAO,MAAM,MAAM,UAAU,OAAO,KAAK;CACzC,MAAM,WAA6B,CAAC;CACpC,KAAK,MAAM,UAAU,eAAe,WAAW,SAAS,cAAc,GACpE,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,SAAS,aACb,OACA,aACA,cACA,WAAW,QAAQ,UAAU,WAAW,cAAc,KAAA,CACxD;EACA,MAAM,SAAS,MAAM,eACnB,OACA,QACA,UACA,cACA,OACA,QACA,QACA,UACF;EACA,SAAS,KAAK;GACZ,aAAa,QAAQ,SAAS;IAC5B,MAAM;IACN,MAAM,WAAW,YAAY,OAAO,MAAM;IAC1C,QAAQ;GACV,CAAC;GACD;GACA;GACA;GACA,MAAMA,OAAK,MAAM;EACnB,CAAC;CACH;CAEF,OAAO;EACL,gBAAgB;EAChB;EACA;EACA,oBAAoB,4BAA4B,kBAAkB;EAClE;EACA;EACA,UAAU,SAAS,QAAQ,YAAY,QAAQ,WAAW,cAAc,CAAC,CAAC,GAAG,EAAE;EAC/E;EACA,aAAa;CACf;AACF;;;ACvPA,SAAS,cAAc,aAA6B;CAClD,OAAO,+BAA+B;AACxC;AAEA,SAAS,KAAK,QAA0C;CACtD,OAAO,WAAW,SAAS,eAAe,SAAS;AACrD;AAEA,SAAS,iBAAiB,UAA6C;CACrE,OAAO,IAAI,SAAS,KAAK,YAAY,GAAG,cAAc,QAAQ,WAAW,EAAE,KAAK,KAAK,UAAU,IAAI,QAAQ,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE;AACpI;AAEA,SAAS,gBAAgB,WAAmC;CAC1D,MAAM,mBAAmB,UAAU,SAAS,QACzC,YAAY,QAAQ,WAAW,UAAU,SAAS,MACrD;CAEA,MAAM,UAAU,UAAU,cACtB,CAAC,IACD,CAHmB,QAAQ,MAGf,CAAC,CAAC,SAAS,WAAW;EAChC,MAAM,WAAW,UAAU,SAAS,QAAQ,YAAY,QAAQ,WAAW,MAAM;EACjF,OAAO,SAAS,WAAW,IACvB,CAAC,IACD,CAAC,SAAS,KAAK,UAAU,KAAK,MAAM,CAAC,EAAE,UAAU,iBAAiB,QAAQ,EAAE,EAAE;CACpF,CAAC;CACL,OAAO,+BAA+B,cAAc,UAAU,SAAS,WAAW,EAAE,GAClF,UAAU,cAAc,KAAK,UAAU,iBAAiB,gBAAgB,EAAE,GAC3E,QAAQ,UAAU,SAAS,MAAM,UAAU,UAAU,SAAS,OAAO,YAAY,QAAQ,KAAK,GAAG,EAAE;AACtG;AAEA,SAAS,SAAS,MAAc,UAA0B;CACxD,IAAI,eAAe,KAAK,IAAI,GAC1B,OAAO,IAAI,IAAI,UAAU,KAAK,SAAS,GAAG,IAAI,OAAO,GAAG,KAAK,EAAE,CAAC,CAAC;CACnE,IAAI,SAAS,MAAM,SAAS,QAAQ,SAAS,KAC3C,OAAO,GAAG,SAAS,MAAM,OAAO,OAAO;CACzC,OAAO,GAAG,KAAK,SAAS,GAAG,IAAI,OAAO,GAAG,KAAK,KAAK;AACrD;AAEA,SAAS,mBACP,WACA,UACA,MACiB;CACjB,MAAM,OAAO,YAA4B,SAAS,MAAM,SAAS,QAAQ,WAAW,CAAC;CACrF,MAAM,UAAU,aACd,SAAS,KAAK,YAAY,GAAG,IAAI,OAAO,EAAE,GAAG,QAAQ,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI;CAC1E,MAAM,mBAAmB,UAAU,SAAS,QACzC,YAAY,QAAQ,WAAW,UAAU,SAAS,MACrD;CACA,OAAO;EACL,aAAa;EACb,KAAK,IAAI,UAAU,QAAQ;EAC3B,GAAI,UAAU,cAAc,CAAC,IAAI,EAAE,QAAQ,OAAO,gBAAgB,EAAE;EACpE,OAAO,UAAU,SAAS;EAC1B,QAAQ,UAAU,SAAS;EAC3B,SAAS,UAAU,cACf,CAAC,IACA,CAAC,QAAQ,MAAM,CAAC,CAAW,SAAS,WAAW;GAC9C,MAAM,WAAW,UAAU,SAAS,QAAQ,YAAY,QAAQ,WAAW,MAAM;GACjF,OAAO,SAAS,WAAW,IAAI,CAAC,IAAI,CAAC;IAAE,MAAM,KAAK,MAAM;IAAG,QAAQ,OAAO,QAAQ;GAAE,CAAC;EACvF,CAAC;CACP;AACF;AAEA,IAAa,gBAAb,MAA2B;CACzB;CACA,6BAAsB,IAAI,IAA4B;CACtD;CACA;CAEA,YAAY,SAA+B,cAA2B,oBAAoB;EACxF,KAAKC,WAAW;EAChB,KAAKE,eAAe;CACtB;CAEA,UAAU,QAA8B;EACtC,KAAKC,UAAU;CACjB;CAEA,MAAM,UACJ,SACA,MACA,IAC6B;EAC7B,QAAQ,MAAM,KAAK,mBAAmB,SAAS,MAAM,EAAE,EAAA,EAAI;CAC7D;CAEA,MAAM,mBACJ,SACA,MACA,IAC6C;EAC7C,MAAM,QAAQ,kBAAkB,MAAM,EAAE;EACxC,IAAI,MAAM,WAAW,GAAG,OAAO,KAAA;EAC/B,IAAI,CAAC,KAAKA,SAAS,MAAM,IAAI,MAAM,iDAAiD;EACpF,IAAI,KAAKA,QAAQ,YAAY,SAC3B,MAAM,IAAI,MAAM,4EAA4E;EAE9F,MAAM,WAAW,KAAK,KAAK,KAAKA,QAAQ,MAAM,yCAAyC;EACvF,IAAI,cAAc;EAClB,MAAM,QAAoB,CAAC;EAC3B,KAAK,MAAM,eAAe,CAAC,GAAG,KAAK,CAAC,CAAC,QAAQ,GAAG;GAC9C,MAAM,aAAa,KAAK,QAAQ,KAAK,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,EAAG,GAAG,YAAY,MAAM;GACtF,MAAM,MAAM,eAAe,YAAY,YAAY,OAAO;GAC1D,IAAI,YAAY,KAAKF,WAAW,IAAI,GAAG;GACvC,IAAI,WACiB;QAAA,WAAW,QAAQ,CAAC,CACpC,OAAO,MAAM,GAAG,SAAS,UAAU,CAAC,CAAC,CACrC,OAAO,KACG,MAAM,UAAU,YAAY,YAAY,KAAA;GAAA;GAEvD,IAAI,CAAC,WAAW;IACd,YAAY,MAAM,aAChB,SACA,YACA,YAAY,SACZ,KAAKD,UACL,UACA,KAAKE,YACP;IACA,KAAKD,WAAW,IAAI,KAAK,SAAS;GACpC;GACA,MAAM,cAAc,gBAAgB,SAAS;GAC7C,MAAM,KAAK;IAAE,OAAO,YAAY;IAAO,KAAK,YAAY;IAAK;GAAY,CAAC;GAC1E,cAAc,GAAG,YAAY,MAAM,GAAG,YAAY,KAAK,IAAI,cAAc,YAAY,MAAM,YAAY,GAAG;EAC5G;EACA,OAAO;GAAE,MAAM;GAAa,OAAO,MAAM,MAAM,MAAM,UAAU,KAAK,QAAQ,MAAM,KAAK;EAAE;CAC3F;CAEA,MAAM,cAAc,SAA4C;EAC9D,IAAI,CAAC,KAAKE,WAAW,KAAKF,WAAW,SAAS,GAAG;EACjD,MAAM,UAA8C,CAAC;EACrD,KAAK,MAAM,aAAa,CAAC,GAAG,KAAKA,WAAW,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,UAChE,KAAK,eAAe,cAAc,MAAM,cAAc,CACxD,GACE,QAAQ,UAAU,kBAAkB;GAClC,YAAY,UAAU;GACtB,YAAY,UAAU;GACtB,oBAAoB,UAAU;GAC9B,cAAc,UAAU;GACxB,SAAS,UAAU;GACnB,OAAO,mBACL,YACC,gBAAgB,QAAQ,YAAY,WAAW,GAChD,KAAKE,QAAQ,IACf;EACF;EAEF,MAAM,SAA8B;GAClC,SAAA;GACA;EACF;EACA,MAAM,eAAe,KAAK,KAAK,KAAKA,QAAQ,MAAM,mBAAmB;EACrE,MAAM,GAAG,MAAM,KAAK,QAAQ,YAAY,GAAG,EAAE,WAAW,KAAK,CAAC;EAC9D,MAAM,GAAG,UAAU,cAAc,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,KAAK,MAAM;CACjF;AACF;;;AC5KA,MAAM,UAAU,cAAc,YAAY,GAAG;AAE7C,IAAI;AAEJ,eAAe,uBAAkD;CAC/D,6BAA6B,YAAY;EACvC,KAAK,MAAM,eAAe,CAAC,aAAa,MAAM,GAC5C,IAAI;GACF,MAAM,YAAY,MAAM,OAAO;GAC/B,IAAI,OAAO,UAAU,qBAAqB,YACxC,OAAO,UAAU;EAErB,SAAS,OAAO;GACd,IAAK,MAAgC,SAAS,wBAAwB,MAAM;EAC9E;EAEF,MAAM,IAAI,MAAM,kEAAkE;CACpF,EAAA,CAAG;CACH,OAAO;AACT;;;;;;;;;;;AAkCA,SAAgB,eAAe,UAAiC,CAAC,GAAmB;CAClF,MAAM,kBAAkB,QAAQ,gBAAgB;CAChD,MAAM,0BAA0B,QAAQ,qBAAqB;CAC7D,MAAM,gBAAgB,QAAQ,SAC1B,IAAI,cAAc,QAAQ,WAAW,OAAO,CAAC,IAAI,QAAQ,MAAM,IAC/D,KAAA;CAwFJ,OAAO;EAtFL,MAAM;EACN,SAAS;EACT,SAAS;GACP,IAAI,YAA2B;GAC/B,IAAI;IACF,YAAY,QAAQ,QAAQ,cAAc;GAC5C,QAAQ;IACN,YAAY;GACd;GACA,OAAO;IACL,QAAQ,EACN,6BAA6B,KAAK,UAAU,uBAAuB,EACrE;IACA,SAAS;KACP,OAAO,YAAY,CAAC;MAAE,MAAM;MAAgB,aAAa;KAAU,CAAC,IAAI,CAAC;KACzE,QAAQ,CAAC,cAAc;IACzB;IACA,cAAc,EACZ,SAAS;KACP;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF,EACF;IACA,KAAK;KACH,KAAK;MAAE,SAAS;MAAa,cAAc;KAAe;KAC1D,WAAW;IACb;GACF;EACF;EACA,eAAe,QAAQ;GACrB,eAAe,UAAU,MAAM;EACjC;EACA,MAAM,UAAU,MAAM,IAAI;GACxB,IAAI,GAAG,SAAS,cAAc,GAAG,OAAO;GACxC,MAAM,mBAAmB,gBACrB,MAAM,cAAc,mBAAmB,MAAM,MAAM,EAAE,IACrD,KAAA;GACJ,MAAM,QAAQ,kBAAkB,QAAQ;GACxC,IAAI,CAAC,mBAAmB,CAAC,eAAe,KAAK,EAAE,GAC7C,OAAO,mBACH;IACE,MAAM,iBAAiB;IACvB,KAAK,oBAAoB,MAAM,iBAAiB,MAAM,iBAAiB,OAAO,EAAE;GAClF,IACA;GAEN,IAAI;IAEF,MAAM,SAAS,OAAM,MADU,qBAAqB,EAAA,CACd,OAAO,IAAI;KAC/C,MAAM,GAAG,SAAS,MAAM,IAAI,QAAQ;KACpC,KAAK;MAAE,SAAS;MAAa,cAAc;KAAe;KAC1D,WAAW;IACb,CAAC;IACD,IAAI,CAAC,QAAQ,MAAM,OAAO;IAC1B,IAAI,MAAM,OAAO;IACjB,IAAI,kBACF,MAAM,cAAc,KAAK,MAAM,OAAO,iBAAiB,KAAK;IAE9D,IAAI,CAAC,yBAAyB,OAAO;KAAE,MAAM,OAAO;KAAM;IAAI;IAC9D,MAAM,YAAY,gCAAgC,OAAO,IAAI;IAC7D,OAAO;KACL,MAAM,UAAU;KAChB,KAAK,eAAe,KAAK,OAAO,MAAM,UAAU,MAAM,UAAU,KAAK;IACvE;GACF,SAAS,OAAO;IACd,MAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IACpE,KAAK,MAAM,oCAAoC,GAAG,IAAI,QAAQ;GAChE;EACF;EACA,MAAM,cAAc;GAClB,MAAM,eAAe,cAAc,IAAI;EACzC;CAEU;AACd"}
package/dist/server.js CHANGED
@@ -174,6 +174,7 @@ function composeDocumentBody(fragment, prefix, suffix) {
174
174
  let suffixPending = true;
175
175
  let reading = false;
176
176
  let cancelled = false;
177
+ let finished = false;
177
178
  return new ReadableStream({
178
179
  pull(controller) {
179
180
  if (prefixPending) {
@@ -181,7 +182,7 @@ function composeDocumentBody(fragment, prefix, suffix) {
181
182
  if (prefix) controller.enqueue(encoder.encode(prefix));
182
183
  return;
183
184
  }
184
- if (reading) return;
185
+ if (reading || finished) return;
185
186
  reading = true;
186
187
  reader.read().then((part) => {
187
188
  reading = false;
@@ -190,8 +191,10 @@ function composeDocumentBody(fragment, prefix, suffix) {
190
191
  controller.enqueue(part.value);
191
192
  return;
192
193
  }
193
- if (suffixPending && suffix) controller.enqueue(encoder.encode(suffix));
194
+ const finalSuffix = suffixPending ? suffix : "";
195
+ finished = true;
194
196
  suffixPending = false;
197
+ if (finalSuffix) controller.enqueue(encoder.encode(finalSuffix));
195
198
  controller.close();
196
199
  }, (error) => {
197
200
  reading = false;
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","names":[],"sources":["../src/server/head.ts","../src/server/document.ts","../src/server/development.ts","../src/server/plugin.ts"],"sourcesContent":["import { parseFragment, serialize, type DefaultTreeAdapterMap } from \"parse5\";\n\nconst htmlNamespace = \"http://www.w3.org/1999/xhtml\";\nconst linkAttributes = new Set([\n \"as\",\n \"crossorigin\",\n \"data-askr-head\",\n \"fetchpriority\",\n \"href\",\n \"hreflang\",\n \"imagesizes\",\n \"imagesrcset\",\n \"media\",\n \"referrerpolicy\",\n \"rel\",\n \"sizes\",\n \"type\",\n]);\n\nfunction headMarkupError(message: string): never {\n throw new TypeError(`Invalid x-askr-head metadata: ${message}`);\n}\n\nfunction attributesOf(node: DefaultTreeAdapterMap[\"element\"]): Map<string, string> {\n const attributes = new Map<string, string>();\n for (const attribute of node.attrs) {\n if (attribute.namespace || attribute.prefix)\n headMarkupError(\"namespaced attributes are not allowed.\");\n attributes.set(attribute.name.toLowerCase(), attribute.value);\n }\n return attributes;\n}\n\nfunction requireAllowedAttributes(\n attributes: Map<string, string>,\n allowed: ReadonlySet<string>,\n): void {\n for (const name of attributes.keys()) {\n if (!allowed.has(name)) headMarkupError(`attribute ${name} is not allowed.`);\n }\n if (attributes.get(\"data-askr-head\") !== \"\")\n headMarkupError(\"every metadata node must be Askr-owned.\");\n}\n\nfunction isTextNode(\n node: DefaultTreeAdapterMap[\"childNode\"],\n): node is DefaultTreeAdapterMap[\"textNode\"] {\n return \"value\" in node;\n}\n\nfunction textContent(node: DefaultTreeAdapterMap[\"element\"]): string {\n let value = \"\";\n for (const child of node.childNodes) {\n if (!isTextNode(child)) headMarkupError(`${node.tagName} must contain only text.`);\n value += child.value;\n }\n return value;\n}\n\nfunction validateHeadElement(node: DefaultTreeAdapterMap[\"element\"]): void {\n if (node.namespaceURI !== htmlNamespace) headMarkupError(\"foreign elements are not allowed.\");\n const attributes = attributesOf(node);\n if (node.tagName === \"title\") {\n requireAllowedAttributes(attributes, new Set([\"data-askr-head\"]));\n textContent(node);\n return;\n }\n if (node.tagName === \"meta\") {\n requireAllowedAttributes(\n attributes,\n new Set([\"content\", \"data-askr-head\", \"name\", \"property\"]),\n );\n const hasName = attributes.has(\"name\");\n const hasProperty = attributes.has(\"property\");\n if (hasName === hasProperty || !attributes.has(\"content\"))\n headMarkupError(\"meta requires content and exactly one of name or property.\");\n if (node.childNodes.length) headMarkupError(\"meta cannot contain child nodes.\");\n return;\n }\n if (node.tagName === \"link\") {\n requireAllowedAttributes(attributes, linkAttributes);\n if (!attributes.has(\"rel\") || !attributes.has(\"href\"))\n headMarkupError(\"link requires rel and href.\");\n if (node.childNodes.length) headMarkupError(\"link cannot contain child nodes.\");\n return;\n }\n if (node.tagName === \"script\") {\n requireAllowedAttributes(attributes, new Set([\"data-askr-head\", \"type\"]));\n if (attributes.get(\"type\") !== \"application/ld+json\")\n headMarkupError(\"only application/ld+json script nodes are allowed.\");\n const json = textContent(node);\n try {\n JSON.parse(json);\n } catch {\n headMarkupError(\"JSON-LD content must be valid JSON.\");\n }\n return;\n }\n headMarkupError(`element ${node.tagName} is not allowed.`);\n}\n\nexport function normalizeAskrHead(head: string): string {\n const fragment = parseFragment(head);\n for (const node of fragment.childNodes) {\n if (isTextNode(node)) {\n if (node.value.trim()) headMarkupError(\"top-level text is not allowed.\");\n continue;\n }\n if (!(\"tagName\" in node)) headMarkupError(\"non-element nodes are not allowed.\");\n validateHeadElement(node);\n }\n return serialize(fragment);\n}\n","import type { ServerApp } from \"@askrjs/server\";\nimport { normalizeAskrHead } from \"./head\";\n\ninterface ViteTelemetryFields {\n status?: number;\n}\n\ninterface ViteTelemetry {\n viteDocument?<T>(fields: ViteTelemetryFields, work: () => T): T;\n}\n\n/** Options for composing a rendered Askr fragment into the HTML document. */\nexport interface AskrDocumentOptions {\n telemetry?: ViteTelemetry;\n}\n\n/** Placeholder marker in `index.html` replaced with the rendered app fragment. */\nexport const ASKR_APP_MARKER = \"<!--askr-app-->\";\n/** Placeholder marker in `index.html` replaced with rendered `<head>` content. */\nexport const ASKR_HEAD_MARKER = \"<!--askr-head-->\";\n\nfunction markerCount(document: string): number {\n return document.split(ASKR_APP_MARKER).length - 1;\n}\n\nfunction headMarkerCount(document: string): number {\n return document.split(ASKR_HEAD_MARKER).length - 1;\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction patchHtmlAttribute(document: string, name: \"lang\" | \"dir\", value: string): string {\n return document.replace(/<html\\b([^>]*)>/i, (_match, attributes: string) => {\n const matcher = new RegExp(\n `\\\\s+${name}(?:\\\\s*=\\\\s*(?:\"[^\"]*\"|'[^']*'|[^\\\\s\"'=<>\\u0060]+))?`,\n \"gi\",\n );\n const withoutExisting = attributes.replace(matcher, \"\");\n return `<html${withoutExisting} ${name}=\"${escapeAttribute(value)}\">`;\n });\n}\n\n/**\n * Replace the single {@link ASKR_APP_MARKER} in `document` with `fragment`.\n *\n * @throws If `document` does not contain exactly one app marker.\n */\nexport function insertAskrFragment(document: string, fragment: string): string {\n const count = markerCount(document);\n if (count !== 1) {\n throw new Error(\n `index.html must contain exactly one ${ASKR_APP_MARKER} marker; found ${count}.`,\n );\n }\n return document.replace(ASKR_APP_MARKER, fragment);\n}\n\n/**\n * Replace the {@link ASKR_HEAD_MARKER} in `document` with normalized `head`\n * markup, and patch the `<html>` tag's `lang`/`dir` attributes when given.\n */\nexport function composeAskrHead(\n document: string,\n head: string,\n lang?: string,\n dir?: string,\n): string {\n let output = document.replace(ASKR_HEAD_MARKER, normalizeAskrHead(head));\n if (lang) output = patchHtmlAttribute(output, \"lang\", lang);\n if (dir) output = patchHtmlAttribute(output, \"dir\", dir);\n return output;\n}\n\n/** Whether `response` carries the `askr-fragment=1` content-type marker. */\nexport function isAskrFragment(response: Response): boolean {\n return (\n response.headers\n .get(\"content-type\")\n ?.split(\";\")\n .some((part) => part.trim().toLowerCase() === \"askr-fragment=1\") ?? false\n );\n}\n\nfunction documentHeaders(response: Response): Headers {\n const headers = new Headers(response.headers);\n const type = response.headers\n .get(\"content-type\")\n ?.split(\";\")\n .map((part) => part.trim())\n .filter((part) => part.toLowerCase() !== \"askr-fragment=1\")\n .join(\"; \");\n if (type) headers.set(\"content-type\", type);\n for (const name of [\n \"accept-ranges\",\n \"content-digest\",\n \"content-encoding\",\n \"content-length\",\n \"content-md5\",\n \"content-range\",\n \"digest\",\n \"etag\",\n \"last-modified\",\n \"repr-digest\",\n \"trailer\",\n ]) {\n headers.delete(name);\n }\n const internalHeaders: string[] = [];\n headers.forEach((_value, key) => {\n if (key.toLowerCase().startsWith(\"x-askr-\")) internalHeaders.push(key);\n });\n for (const key of internalHeaders) headers.delete(key);\n return headers;\n}\n\nfunction composeDocumentBody(\n fragment: ReadableStream<Uint8Array> | null,\n prefix: string,\n suffix: string,\n): BodyInit {\n if (!fragment) return `${prefix}${suffix}`;\n const encoder = new TextEncoder();\n const reader = fragment.getReader();\n let prefixPending = true;\n let suffixPending = true;\n let reading = false;\n let cancelled = false;\n\n return new ReadableStream<Uint8Array>({\n pull(controller) {\n if (prefixPending) {\n prefixPending = false;\n if (prefix) controller.enqueue(encoder.encode(prefix));\n return;\n }\n if (reading) return;\n reading = true;\n void reader.read().then(\n (part) => {\n reading = false;\n if (cancelled) return;\n if (!part.done) {\n controller.enqueue(part.value);\n return;\n }\n if (suffixPending && suffix) controller.enqueue(encoder.encode(suffix));\n suffixPending = false;\n controller.close();\n },\n (error) => {\n reading = false;\n if (cancelled) return;\n controller.error(error);\n void reader.cancel(error).catch(() => undefined);\n },\n );\n },\n async cancel(reason) {\n cancelled = true;\n await reader.cancel(reason).catch(() => undefined);\n },\n });\n}\n\n/**\n * Compose an Askr fragment response into the full `transformedDocument` HTML,\n * streaming the fragment's body between the document prefix and suffix.\n * Non-fragment responses are returned unchanged.\n *\n * @param response The upstream response, expected to be an Askr fragment.\n * @param transformedDocument The `index.html` document with app/head markers.\n * @param options Optional telemetry hook wrapping the compose work.\n * @returns The composed full-document `Response`, or `response` unchanged.\n */\nexport async function composeAskrDocumentResponse(\n response: Response,\n transformedDocument: string,\n options: AskrDocumentOptions = {},\n): Promise<Response> {\n if (!isAskrFragment(response)) return response;\n const compose = () => {\n if (headMarkerCount(transformedDocument) !== 1) {\n throw new Error(\n `index.html must contain exactly one ${ASKR_HEAD_MARKER} marker; found ${headMarkerCount(transformedDocument)}.`,\n );\n }\n const withHead = composeAskrHead(\n transformedDocument,\n response.headers.get(\"x-askr-head\") ?? \"\",\n response.headers.get(\"x-askr-html-lang\") ?? undefined,\n response.headers.get(\"x-askr-html-dir\") ?? undefined,\n );\n const appCount = markerCount(withHead);\n if (appCount !== 1) {\n throw new Error(\n `index.html must contain exactly one ${ASKR_APP_MARKER} marker; found ${appCount}.`,\n );\n }\n const markerIndex = withHead.indexOf(ASKR_APP_MARKER);\n const prefix = withHead.slice(0, markerIndex);\n const suffix = withHead.slice(markerIndex + ASKR_APP_MARKER.length);\n return new Response(composeDocumentBody(response.body, prefix, suffix), {\n status: response.status,\n statusText: response.statusText,\n headers: documentHeaders(response),\n });\n };\n return options.telemetry?.viteDocument\n ? options.telemetry.viteDocument({ status: response.status }, compose)\n : compose();\n}\n\n/**\n * Wrap `app` so every response is composed into `transformedDocument` via\n * {@link composeAskrDocumentResponse}.\n */\nexport function createDocumentApp(\n app: ServerApp,\n transformedDocument: string,\n options: AskrDocumentOptions = {},\n): ServerApp {\n return {\n async fetch(request) {\n return composeAskrDocumentResponse(await app.fetch(request), transformedDocument, options);\n },\n };\n}\n","import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport type { ServerApp } from \"@askrjs/server\";\nimport type { ViteDevServer } from \"vite\";\nimport { composeAskrDocumentResponse, isAskrFragment } from \"./document\";\nimport type { AskrServerOptions } from \"./types\";\n\nfunction serverApp(module: Record<string, unknown>, options: AskrServerOptions): ServerApp {\n const value = module[options.exportName ?? \"app\"] ?? module.default;\n if (!value || typeof (value as ServerApp).fetch !== \"function\") {\n throw new Error(\n `@askrjs/vite: ${options.entry} must export a ServerApp as ${options.exportName ?? \"app\"} or default`,\n );\n }\n return value as ServerApp;\n}\n\nfunction moduleTelemetry(module: Record<string, unknown>) {\n const telemetry = module[\"telemetry\"];\n return telemetry && typeof telemetry === \"object\"\n ? {\n telemetry: telemetry as NonNullable<\n Parameters<typeof composeAskrDocumentResponse>[2]\n >[\"telemetry\"],\n }\n : undefined;\n}\n\nexport function createDevelopmentApp(server: ViteDevServer, options: AskrServerOptions): ServerApp {\n return {\n async fetch(request) {\n const module = await server.ssrLoadModule(options.entry);\n const response = await serverApp(module, options).fetch(request);\n if (!isAskrFragment(response)) return response;\n const file = resolve(server.config.root, options.indexHtml ?? \"index.html\");\n const document = await readFile(file, \"utf8\");\n const transformed = await server.transformIndexHtml(new URL(request.url).pathname, document);\n return composeAskrDocumentResponse(response, transformed, moduleTelemetry(module));\n },\n };\n}\n","import { createNodeHandler } from \"@askrjs/node\";\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Plugin, ResolvedConfig, ViteDevServer } from \"vite\";\nimport { createDevelopmentApp } from \"./development\";\nimport type { AskrServerOptions } from \"./types\";\n\n/** Virtual module id that resolves to the generated server document app. */\nexport const ASKR_SERVER_MODULE_ID = \"virtual:askr-server\";\nconst RESOLVED_SERVER_MODULE_ID = \"\\0askr:server\";\n\n/** Portable public identity for the server integration plugin. */\nexport interface AskrServerPlugin {\n readonly name: \"askr:server\";\n}\n\nfunction createNodeHandlerOptions(server: ViteDevServer): {\n baseUrl?: string;\n allowedHosts?: readonly string[];\n} {\n const serverConfig = server.config?.server;\n const baseUrl = serverConfig?.origin;\n\n if (\n serverConfig?.allowedHosts &&\n serverConfig.allowedHosts !== true &&\n serverConfig.allowedHosts.length > 0\n ) {\n return { baseUrl, allowedHosts: serverConfig.allowedHosts };\n }\n\n if (baseUrl) {\n return { baseUrl };\n }\n\n const host = typeof serverConfig?.host === \"string\" ? serverConfig.host : \"localhost\";\n const allowedHosts = new Set([host, \"localhost\", \"127.0.0.1\", \"[::1]\"]);\n return { allowedHosts: Array.from(allowedHosts) };\n}\n\n/**\n * Create the Vite plugin that serves Askr's server-rendered document during\n * development and generates the {@link ASKR_SERVER_MODULE_ID} virtual module\n * that composes the built server app with the HTML document.\n *\n * @param options Server entry and document configuration.\n * @returns A Vite-compatible plugin object exposing the `askr:server` name.\n */\nexport function askrServer(options: AskrServerOptions): AskrServerPlugin {\n let config: ResolvedConfig | undefined;\n const plugin = {\n name: \"askr:server\" as const,\n config() {\n // Askr owns document routing. Vite should serve modules and assets, but\n // must not rewrite page URLs to /index.html before the Askr fallback.\n // Keep the Askr package family inside Vite's module graph so file-linked\n // peers cannot load a second runtime with a different component context.\n // Vitest derives its dependency inlining from resolve.noExternal, which\n // is also Vite 8's replacement for the deprecated ssr.noExternal option.\n return {\n appType: \"custom\",\n resolve: { noExternal: [\"@askrjs/*\"] },\n };\n },\n configResolved(resolved) {\n config = resolved;\n },\n resolveId(id) {\n return id === ASKR_SERVER_MODULE_ID ? RESOLVED_SERVER_MODULE_ID : null;\n },\n async load(id) {\n if (id !== RESOLVED_SERVER_MODULE_ID) return null;\n if (!config) throw new Error(\"@askrjs/vite: server plugin was not configured.\");\n const sourceDocument = resolve(config.root, options.indexHtml ?? \"index.html\");\n const serverOutDocument = resolve(config.root, config.build.outDir, \"index.html\");\n const clientOutDocument = resolve(config.root, config.build.outDir, \"..\", \"index.html\");\n const builtDocument = [serverOutDocument, clientOutDocument].find(existsSync);\n const document = await readFile(builtDocument ?? sourceDocument, \"utf8\");\n const entry = resolve(config.root, options.entry);\n const exportName = options.exportName ?? \"app\";\n return [\n `import * as source from ${JSON.stringify(entry)};`,\n `import { createDocumentApp } from '@askrjs/vite/server';`,\n `const sourceApp = source[${JSON.stringify(exportName)}] ?? source.default;`,\n `const sourceTelemetry = Reflect.get(source, 'telemetry');`,\n `if (!sourceApp?.fetch) throw new Error(${JSON.stringify(`@askrjs/vite: ${options.entry} must export a ServerApp`)});`,\n `export const app = createDocumentApp(sourceApp, ${JSON.stringify(document)}, sourceTelemetry ? { telemetry: sourceTelemetry } : undefined);`,\n `export default app;`,\n ].join(\"\\n\");\n },\n configureServer(server) {\n const handler = createNodeHandler(\n createDevelopmentApp(server, options),\n createNodeHandlerOptions(server),\n );\n // Page rendering is the development fallback. Register it after Vite's\n // module, asset, and HTML middleware so client entries and imported CSS\n // are served by Vite instead of being mistaken for application routes.\n return () => server.middlewares.use(handler);\n },\n } satisfies Plugin;\n return plugin;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.js","names":[],"sources":["../src/server/head.ts","../src/server/document.ts","../src/server/development.ts","../src/server/plugin.ts"],"sourcesContent":["import { parseFragment, serialize, type DefaultTreeAdapterMap } from \"parse5\";\n\nconst htmlNamespace = \"http://www.w3.org/1999/xhtml\";\nconst linkAttributes = new Set([\n \"as\",\n \"crossorigin\",\n \"data-askr-head\",\n \"fetchpriority\",\n \"href\",\n \"hreflang\",\n \"imagesizes\",\n \"imagesrcset\",\n \"media\",\n \"referrerpolicy\",\n \"rel\",\n \"sizes\",\n \"type\",\n]);\n\nfunction headMarkupError(message: string): never {\n throw new TypeError(`Invalid x-askr-head metadata: ${message}`);\n}\n\nfunction attributesOf(node: DefaultTreeAdapterMap[\"element\"]): Map<string, string> {\n const attributes = new Map<string, string>();\n for (const attribute of node.attrs) {\n if (attribute.namespace || attribute.prefix)\n headMarkupError(\"namespaced attributes are not allowed.\");\n attributes.set(attribute.name.toLowerCase(), attribute.value);\n }\n return attributes;\n}\n\nfunction requireAllowedAttributes(\n attributes: Map<string, string>,\n allowed: ReadonlySet<string>,\n): void {\n for (const name of attributes.keys()) {\n if (!allowed.has(name)) headMarkupError(`attribute ${name} is not allowed.`);\n }\n if (attributes.get(\"data-askr-head\") !== \"\")\n headMarkupError(\"every metadata node must be Askr-owned.\");\n}\n\nfunction isTextNode(\n node: DefaultTreeAdapterMap[\"childNode\"],\n): node is DefaultTreeAdapterMap[\"textNode\"] {\n return \"value\" in node;\n}\n\nfunction textContent(node: DefaultTreeAdapterMap[\"element\"]): string {\n let value = \"\";\n for (const child of node.childNodes) {\n if (!isTextNode(child)) headMarkupError(`${node.tagName} must contain only text.`);\n value += child.value;\n }\n return value;\n}\n\nfunction validateHeadElement(node: DefaultTreeAdapterMap[\"element\"]): void {\n if (node.namespaceURI !== htmlNamespace) headMarkupError(\"foreign elements are not allowed.\");\n const attributes = attributesOf(node);\n if (node.tagName === \"title\") {\n requireAllowedAttributes(attributes, new Set([\"data-askr-head\"]));\n textContent(node);\n return;\n }\n if (node.tagName === \"meta\") {\n requireAllowedAttributes(\n attributes,\n new Set([\"content\", \"data-askr-head\", \"name\", \"property\"]),\n );\n const hasName = attributes.has(\"name\");\n const hasProperty = attributes.has(\"property\");\n if (hasName === hasProperty || !attributes.has(\"content\"))\n headMarkupError(\"meta requires content and exactly one of name or property.\");\n if (node.childNodes.length) headMarkupError(\"meta cannot contain child nodes.\");\n return;\n }\n if (node.tagName === \"link\") {\n requireAllowedAttributes(attributes, linkAttributes);\n if (!attributes.has(\"rel\") || !attributes.has(\"href\"))\n headMarkupError(\"link requires rel and href.\");\n if (node.childNodes.length) headMarkupError(\"link cannot contain child nodes.\");\n return;\n }\n if (node.tagName === \"script\") {\n requireAllowedAttributes(attributes, new Set([\"data-askr-head\", \"type\"]));\n if (attributes.get(\"type\") !== \"application/ld+json\")\n headMarkupError(\"only application/ld+json script nodes are allowed.\");\n const json = textContent(node);\n try {\n JSON.parse(json);\n } catch {\n headMarkupError(\"JSON-LD content must be valid JSON.\");\n }\n return;\n }\n headMarkupError(`element ${node.tagName} is not allowed.`);\n}\n\nexport function normalizeAskrHead(head: string): string {\n const fragment = parseFragment(head);\n for (const node of fragment.childNodes) {\n if (isTextNode(node)) {\n if (node.value.trim()) headMarkupError(\"top-level text is not allowed.\");\n continue;\n }\n if (!(\"tagName\" in node)) headMarkupError(\"non-element nodes are not allowed.\");\n validateHeadElement(node);\n }\n return serialize(fragment);\n}\n","import type { ServerApp } from \"@askrjs/server\";\nimport { normalizeAskrHead } from \"./head\";\n\ninterface ViteTelemetryFields {\n status?: number;\n}\n\ninterface ViteTelemetry {\n viteDocument?<T>(fields: ViteTelemetryFields, work: () => T): T;\n}\n\n/** Options for composing a rendered Askr fragment into the HTML document. */\nexport interface AskrDocumentOptions {\n telemetry?: ViteTelemetry;\n}\n\n/** Placeholder marker in `index.html` replaced with the rendered app fragment. */\nexport const ASKR_APP_MARKER = \"<!--askr-app-->\";\n/** Placeholder marker in `index.html` replaced with rendered `<head>` content. */\nexport const ASKR_HEAD_MARKER = \"<!--askr-head-->\";\n\nfunction markerCount(document: string): number {\n return document.split(ASKR_APP_MARKER).length - 1;\n}\n\nfunction headMarkerCount(document: string): number {\n return document.split(ASKR_HEAD_MARKER).length - 1;\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction patchHtmlAttribute(document: string, name: \"lang\" | \"dir\", value: string): string {\n return document.replace(/<html\\b([^>]*)>/i, (_match, attributes: string) => {\n const matcher = new RegExp(\n `\\\\s+${name}(?:\\\\s*=\\\\s*(?:\"[^\"]*\"|'[^']*'|[^\\\\s\"'=<>\\u0060]+))?`,\n \"gi\",\n );\n const withoutExisting = attributes.replace(matcher, \"\");\n return `<html${withoutExisting} ${name}=\"${escapeAttribute(value)}\">`;\n });\n}\n\n/**\n * Replace the single {@link ASKR_APP_MARKER} in `document` with `fragment`.\n *\n * @throws If `document` does not contain exactly one app marker.\n */\nexport function insertAskrFragment(document: string, fragment: string): string {\n const count = markerCount(document);\n if (count !== 1) {\n throw new Error(\n `index.html must contain exactly one ${ASKR_APP_MARKER} marker; found ${count}.`,\n );\n }\n return document.replace(ASKR_APP_MARKER, fragment);\n}\n\n/**\n * Replace the {@link ASKR_HEAD_MARKER} in `document` with normalized `head`\n * markup, and patch the `<html>` tag's `lang`/`dir` attributes when given.\n */\nexport function composeAskrHead(\n document: string,\n head: string,\n lang?: string,\n dir?: string,\n): string {\n let output = document.replace(ASKR_HEAD_MARKER, normalizeAskrHead(head));\n if (lang) output = patchHtmlAttribute(output, \"lang\", lang);\n if (dir) output = patchHtmlAttribute(output, \"dir\", dir);\n return output;\n}\n\n/** Whether `response` carries the `askr-fragment=1` content-type marker. */\nexport function isAskrFragment(response: Response): boolean {\n return (\n response.headers\n .get(\"content-type\")\n ?.split(\";\")\n .some((part) => part.trim().toLowerCase() === \"askr-fragment=1\") ?? false\n );\n}\n\nfunction documentHeaders(response: Response): Headers {\n const headers = new Headers(response.headers);\n const type = response.headers\n .get(\"content-type\")\n ?.split(\";\")\n .map((part) => part.trim())\n .filter((part) => part.toLowerCase() !== \"askr-fragment=1\")\n .join(\"; \");\n if (type) headers.set(\"content-type\", type);\n for (const name of [\n \"accept-ranges\",\n \"content-digest\",\n \"content-encoding\",\n \"content-length\",\n \"content-md5\",\n \"content-range\",\n \"digest\",\n \"etag\",\n \"last-modified\",\n \"repr-digest\",\n \"trailer\",\n ]) {\n headers.delete(name);\n }\n const internalHeaders: string[] = [];\n headers.forEach((_value, key) => {\n if (key.toLowerCase().startsWith(\"x-askr-\")) internalHeaders.push(key);\n });\n for (const key of internalHeaders) headers.delete(key);\n return headers;\n}\n\nfunction composeDocumentBody(\n fragment: ReadableStream<Uint8Array> | null,\n prefix: string,\n suffix: string,\n): BodyInit {\n if (!fragment) return `${prefix}${suffix}`;\n const encoder = new TextEncoder();\n const reader = fragment.getReader();\n let prefixPending = true;\n let suffixPending = true;\n let reading = false;\n let cancelled = false;\n let finished = false;\n\n return new ReadableStream<Uint8Array>({\n pull(controller) {\n if (prefixPending) {\n prefixPending = false;\n if (prefix) controller.enqueue(encoder.encode(prefix));\n return;\n }\n if (reading || finished) return;\n reading = true;\n void reader.read().then(\n (part) => {\n reading = false;\n if (cancelled) return;\n if (!part.done) {\n controller.enqueue(part.value);\n return;\n }\n const finalSuffix = suffixPending ? suffix : \"\";\n finished = true;\n suffixPending = false;\n if (finalSuffix) controller.enqueue(encoder.encode(finalSuffix));\n controller.close();\n },\n (error) => {\n reading = false;\n if (cancelled) return;\n controller.error(error);\n void reader.cancel(error).catch(() => undefined);\n },\n );\n },\n async cancel(reason) {\n cancelled = true;\n await reader.cancel(reason).catch(() => undefined);\n },\n });\n}\n\n/**\n * Compose an Askr fragment response into the full `transformedDocument` HTML,\n * streaming the fragment's body between the document prefix and suffix.\n * Non-fragment responses are returned unchanged.\n *\n * @param response The upstream response, expected to be an Askr fragment.\n * @param transformedDocument The `index.html` document with app/head markers.\n * @param options Optional telemetry hook wrapping the compose work.\n * @returns The composed full-document `Response`, or `response` unchanged.\n */\nexport async function composeAskrDocumentResponse(\n response: Response,\n transformedDocument: string,\n options: AskrDocumentOptions = {},\n): Promise<Response> {\n if (!isAskrFragment(response)) return response;\n const compose = () => {\n if (headMarkerCount(transformedDocument) !== 1) {\n throw new Error(\n `index.html must contain exactly one ${ASKR_HEAD_MARKER} marker; found ${headMarkerCount(transformedDocument)}.`,\n );\n }\n const withHead = composeAskrHead(\n transformedDocument,\n response.headers.get(\"x-askr-head\") ?? \"\",\n response.headers.get(\"x-askr-html-lang\") ?? undefined,\n response.headers.get(\"x-askr-html-dir\") ?? undefined,\n );\n const appCount = markerCount(withHead);\n if (appCount !== 1) {\n throw new Error(\n `index.html must contain exactly one ${ASKR_APP_MARKER} marker; found ${appCount}.`,\n );\n }\n const markerIndex = withHead.indexOf(ASKR_APP_MARKER);\n const prefix = withHead.slice(0, markerIndex);\n const suffix = withHead.slice(markerIndex + ASKR_APP_MARKER.length);\n return new Response(composeDocumentBody(response.body, prefix, suffix), {\n status: response.status,\n statusText: response.statusText,\n headers: documentHeaders(response),\n });\n };\n return options.telemetry?.viteDocument\n ? options.telemetry.viteDocument({ status: response.status }, compose)\n : compose();\n}\n\n/**\n * Wrap `app` so every response is composed into `transformedDocument` via\n * {@link composeAskrDocumentResponse}.\n */\nexport function createDocumentApp(\n app: ServerApp,\n transformedDocument: string,\n options: AskrDocumentOptions = {},\n): ServerApp {\n return {\n async fetch(request) {\n return composeAskrDocumentResponse(await app.fetch(request), transformedDocument, options);\n },\n };\n}\n","import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport type { ServerApp } from \"@askrjs/server\";\nimport type { ViteDevServer } from \"vite\";\nimport { composeAskrDocumentResponse, isAskrFragment } from \"./document\";\nimport type { AskrServerOptions } from \"./types\";\n\nfunction serverApp(module: Record<string, unknown>, options: AskrServerOptions): ServerApp {\n const value = module[options.exportName ?? \"app\"] ?? module.default;\n if (!value || typeof (value as ServerApp).fetch !== \"function\") {\n throw new Error(\n `@askrjs/vite: ${options.entry} must export a ServerApp as ${options.exportName ?? \"app\"} or default`,\n );\n }\n return value as ServerApp;\n}\n\nfunction moduleTelemetry(module: Record<string, unknown>) {\n const telemetry = module[\"telemetry\"];\n return telemetry && typeof telemetry === \"object\"\n ? {\n telemetry: telemetry as NonNullable<\n Parameters<typeof composeAskrDocumentResponse>[2]\n >[\"telemetry\"],\n }\n : undefined;\n}\n\nexport function createDevelopmentApp(server: ViteDevServer, options: AskrServerOptions): ServerApp {\n return {\n async fetch(request) {\n const module = await server.ssrLoadModule(options.entry);\n const response = await serverApp(module, options).fetch(request);\n if (!isAskrFragment(response)) return response;\n const file = resolve(server.config.root, options.indexHtml ?? \"index.html\");\n const document = await readFile(file, \"utf8\");\n const transformed = await server.transformIndexHtml(new URL(request.url).pathname, document);\n return composeAskrDocumentResponse(response, transformed, moduleTelemetry(module));\n },\n };\n}\n","import { createNodeHandler } from \"@askrjs/node\";\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Plugin, ResolvedConfig, ViteDevServer } from \"vite\";\nimport { createDevelopmentApp } from \"./development\";\nimport type { AskrServerOptions } from \"./types\";\n\n/** Virtual module id that resolves to the generated server document app. */\nexport const ASKR_SERVER_MODULE_ID = \"virtual:askr-server\";\nconst RESOLVED_SERVER_MODULE_ID = \"\\0askr:server\";\n\n/** Portable public identity for the server integration plugin. */\nexport interface AskrServerPlugin {\n readonly name: \"askr:server\";\n}\n\nfunction createNodeHandlerOptions(server: ViteDevServer): {\n baseUrl?: string;\n allowedHosts?: readonly string[];\n} {\n const serverConfig = server.config?.server;\n const baseUrl = serverConfig?.origin;\n\n if (\n serverConfig?.allowedHosts &&\n serverConfig.allowedHosts !== true &&\n serverConfig.allowedHosts.length > 0\n ) {\n return { baseUrl, allowedHosts: serverConfig.allowedHosts };\n }\n\n if (baseUrl) {\n return { baseUrl };\n }\n\n const host = typeof serverConfig?.host === \"string\" ? serverConfig.host : \"localhost\";\n const allowedHosts = new Set([host, \"localhost\", \"127.0.0.1\", \"[::1]\"]);\n return { allowedHosts: Array.from(allowedHosts) };\n}\n\n/**\n * Create the Vite plugin that serves Askr's server-rendered document during\n * development and generates the {@link ASKR_SERVER_MODULE_ID} virtual module\n * that composes the built server app with the HTML document.\n *\n * @param options Server entry and document configuration.\n * @returns A Vite-compatible plugin object exposing the `askr:server` name.\n */\nexport function askrServer(options: AskrServerOptions): AskrServerPlugin {\n let config: ResolvedConfig | undefined;\n const plugin = {\n name: \"askr:server\" as const,\n config() {\n // Askr owns document routing. Vite should serve modules and assets, but\n // must not rewrite page URLs to /index.html before the Askr fallback.\n // Keep the Askr package family inside Vite's module graph so file-linked\n // peers cannot load a second runtime with a different component context.\n // Vitest derives its dependency inlining from resolve.noExternal, which\n // is also Vite 8's replacement for the deprecated ssr.noExternal option.\n return {\n appType: \"custom\",\n resolve: { noExternal: [\"@askrjs/*\"] },\n };\n },\n configResolved(resolved) {\n config = resolved;\n },\n resolveId(id) {\n return id === ASKR_SERVER_MODULE_ID ? RESOLVED_SERVER_MODULE_ID : null;\n },\n async load(id) {\n if (id !== RESOLVED_SERVER_MODULE_ID) return null;\n if (!config) throw new Error(\"@askrjs/vite: server plugin was not configured.\");\n const sourceDocument = resolve(config.root, options.indexHtml ?? \"index.html\");\n const serverOutDocument = resolve(config.root, config.build.outDir, \"index.html\");\n const clientOutDocument = resolve(config.root, config.build.outDir, \"..\", \"index.html\");\n const builtDocument = [serverOutDocument, clientOutDocument].find(existsSync);\n const document = await readFile(builtDocument ?? sourceDocument, \"utf8\");\n const entry = resolve(config.root, options.entry);\n const exportName = options.exportName ?? \"app\";\n return [\n `import * as source from ${JSON.stringify(entry)};`,\n `import { createDocumentApp } from '@askrjs/vite/server';`,\n `const sourceApp = source[${JSON.stringify(exportName)}] ?? source.default;`,\n `const sourceTelemetry = Reflect.get(source, 'telemetry');`,\n `if (!sourceApp?.fetch) throw new Error(${JSON.stringify(`@askrjs/vite: ${options.entry} must export a ServerApp`)});`,\n `export const app = createDocumentApp(sourceApp, ${JSON.stringify(document)}, sourceTelemetry ? { telemetry: sourceTelemetry } : undefined);`,\n `export default app;`,\n ].join(\"\\n\");\n },\n configureServer(server) {\n const handler = createNodeHandler(\n createDevelopmentApp(server, options),\n createNodeHandlerOptions(server),\n );\n // Page rendering is the development fallback. Register it after Vite's\n // module, asset, and HTML middleware so client entries and imported CSS\n // are served by Vite instead of being mistaken for application routes.\n return () => server.middlewares.use(handler);\n },\n } satisfies Plugin;\n return plugin;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askrjs/vite",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Vite plugin for Askr JSX and template transforms",
5
5
  "homepage": "https://github.com/askrjs/askr-vite#readme",
6
6
  "bugs": {
@@ -59,26 +59,26 @@
59
59
  "prepublishOnly": "npm run check"
60
60
  },
61
61
  "dependencies": {
62
- "@askrjs/node": ">=0.2.0 <0.3.0",
63
- "oxc-parser": "^0.144.0",
62
+ "@askrjs/node": ">=0.2.1 <0.3.0",
63
+ "oxc-parser": "^0.147.0",
64
64
  "parse5": "^8.0.1"
65
65
  },
66
66
  "devDependencies": {
67
- "@askrjs/askr": ">=0.2.0 <0.3.0",
68
- "@askrjs/server": ">=0.2.0 <0.3.0",
69
- "@types/node": "^26.2.0",
70
- "publint": "^0.3.23",
67
+ "@askrjs/askr": ">=0.2.3 <0.3.0",
68
+ "@askrjs/server": ">=0.2.1 <0.3.0",
69
+ "@types/node": "^26.3.0",
70
+ "publint": "^0.3.24",
71
71
  "sharp": "^0.35.3",
72
72
  "typescript": "^7.0.2",
73
- "vite": "^8.2.1",
74
- "vite-plus": "^0.2.8",
75
- "vitest": "^4.1.10"
73
+ "vite": "^8.2.2",
74
+ "vite-plus": "^0.3.0",
75
+ "vitest": "^4.1.11"
76
76
  },
77
77
  "peerDependencies": {
78
- "@askrjs/askr": ">=0.2.0 <0.3.0",
78
+ "@askrjs/askr": ">=0.2.3 <0.3.0",
79
79
  "sharp": "^0.35.3",
80
- "vite": "^8.2.1",
81
- "vite-plus": "^0.2.8"
80
+ "vite": "^8.2.2",
81
+ "vite-plus": "^0.2.8 || ^0.3.0"
82
82
  },
83
83
  "peerDependenciesMeta": {
84
84
  "sharp": {