@stacksjs/stx 0.2.319 → 0.2.321
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builtins/image-alpha.d.ts +26 -0
- package/dist/builtins/image-alpha.js +57 -0
- package/dist/builtins/image-delivery.d.ts +9 -0
- package/dist/builtins/image-delivery.js +77 -11
- package/dist/builtins/image-placeholder.d.ts +5 -0
- package/dist/builtins/image-placeholder.js +19 -3
- package/dist/builtins/stx-image.js +19 -6
- package/dist/{chunk-85p4dmft.js → chunk-0en7mkpa.js} +1 -1
- package/dist/{chunk-0mnv8pf5.js → chunk-0eydszkp.js} +1 -1
- package/dist/chunk-129fa2d9.js +2 -0
- package/dist/{chunk-acctstj3.js → chunk-1b2wksq3.js} +1 -1
- package/dist/{chunk-wm86mmgq.js → chunk-1q1qmmfn.js} +1 -1
- package/dist/{chunk-4ee1aaet.js → chunk-1r3ydhkx.js} +1 -1
- package/dist/chunk-1rdcew9t.js +2 -0
- package/dist/{chunk-ajhrz96a.js → chunk-1yv1v7hh.js} +1 -1
- package/dist/{chunk-tqayztkh.js → chunk-222swfwr.js} +1 -1
- package/dist/chunk-25m79xdw.js +2 -0
- package/dist/{chunk-2kv2gnzc.js → chunk-2925bmqr.js} +1 -1
- package/dist/{chunk-raxr83fs.js → chunk-2btrq8sz.js} +2 -2
- package/dist/chunk-2rkq7pd1.js +2 -0
- package/dist/chunk-2tcn2rw4.js +2 -0
- package/dist/{chunk-prry9kgy.js → chunk-33gkb5pr.js} +1 -1
- package/dist/{chunk-vhan24as.js → chunk-373fc0m2.js} +1 -1
- package/dist/{chunk-6c1ebjat.js → chunk-3erkb524.js} +1 -1
- package/dist/{chunk-ybct46zd.js → chunk-3ntb5zkk.js} +1 -1
- package/dist/{chunk-r3220h2n.js → chunk-3qt3cxh0.js} +1 -1
- package/dist/{chunk-b73h0vd8.js → chunk-3x0b8j25.js} +1 -1
- package/dist/chunk-48w09pf7.js +2 -0
- package/dist/chunk-4a2wcz8h.js +2 -0
- package/dist/chunk-4dtjqc90.js +2 -0
- package/dist/{chunk-djf1p5cy.js → chunk-4kp87md5.js} +1 -1
- package/dist/{chunk-3pv0qj5f.js → chunk-4zz9edh0.js} +1 -1
- package/dist/{chunk-51gea48g.js → chunk-526rr83q.js} +1 -1
- package/dist/{chunk-18p8dqya.js → chunk-5mdvkpt8.js} +1 -1
- package/dist/chunk-5sz2tmw3.js +2 -0
- package/dist/{chunk-322qz0cj.js → chunk-6r72pp2t.js} +1 -1
- package/dist/{chunk-397rqs12.js → chunk-70zb3560.js} +1 -1
- package/dist/{chunk-yzy6e4je.js → chunk-7b09hmk4.js} +10 -10
- package/dist/chunk-7je3fd68.js +2 -0
- package/dist/chunk-7kk2jb1j.js +3759 -0
- package/dist/chunk-7v72zj7x.js +2 -0
- package/dist/{chunk-0saq3nwy.js → chunk-8mspafdh.js} +1 -1
- package/dist/{chunk-bnq0p4r4.js → chunk-8q3a8g7m.js} +1 -1
- package/dist/{chunk-zebypbks.js → chunk-8q9qfy2v.js} +2 -2
- package/dist/chunk-8x78ed8t.js +2 -0
- package/dist/chunk-99yynes4.js +2 -0
- package/dist/{chunk-pknc4efv.js → chunk-9fjhmyje.js} +1 -1
- package/dist/{chunk-1ztjv7a4.js → chunk-9qxv7emz.js} +1 -1
- package/dist/{chunk-px0hqf1q.js → chunk-9whbqxsv.js} +1 -1
- package/dist/chunk-9zrmwtgh.js +2 -0
- package/dist/{chunk-0gbptqh2.js → chunk-a6q5dmq7.js} +1 -1
- package/dist/{chunk-s5wwa0t4.js → chunk-akefvpqr.js} +2 -2
- package/dist/chunk-bdwe7er9.js +2 -0
- package/dist/chunk-c5zfgpgx.js +2 -0
- package/dist/chunk-ced1qbdw.js +2 -0
- package/dist/{chunk-jryjwara.js → chunk-cey6rhqw.js} +1 -1
- package/dist/{chunk-v02j99gh.js → chunk-cfj7y2tp.js} +2 -2
- package/dist/{chunk-y4dd2n2n.js → chunk-cjf5h08r.js} +1 -1
- package/dist/chunk-cpa76anv.js +2 -0
- package/dist/{chunk-kexk6z9s.js → chunk-dr2rpkb4.js} +1 -1
- package/dist/{chunk-t5kwx6fa.js → chunk-eh66m9ar.js} +1 -1
- package/dist/{chunk-604qr43v.js → chunk-esq6ydx5.js} +1 -1
- package/dist/chunk-fh33afkv.js +2 -0
- package/dist/{chunk-msmhta0w.js → chunk-fs5gwtd9.js} +1 -1
- package/dist/{chunk-7c1qq9zq.js → chunk-g38wktfx.js} +1 -1
- package/dist/chunk-g5v7gw13.js +2 -0
- package/dist/{chunk-4hk5ewgp.js → chunk-gnk0xd8n.js} +1 -1
- package/dist/{chunk-7yzyn9k7.js → chunk-gyrf55m1.js} +1 -1
- package/dist/chunk-hg77c5m2.js +2 -0
- package/dist/{chunk-yzb20ane.js → chunk-hgc3n1xq.js} +1 -1
- package/dist/chunk-hhjrtjc9.js +3 -0
- package/dist/chunk-hmrv7qv5.js +2 -0
- package/dist/{chunk-egr5663e.js → chunk-hrd56xw7.js} +3 -3
- package/dist/{chunk-gcavh7hk.js → chunk-hrrynmne.js} +1 -1
- package/dist/{chunk-wkcnyv6m.js → chunk-j8bwgnz5.js} +2 -2
- package/dist/{chunk-ycgtkfbm.js → chunk-jgfkmkpb.js} +1 -1
- package/dist/{chunk-xcsf7my7.js → chunk-jtaxnnq3.js} +1 -1
- package/dist/chunk-jxx9apw6.js +2 -0
- package/dist/{chunk-s2kxa1tb.js → chunk-kncbae57.js} +1 -1
- package/dist/{chunk-8q8gj45z.js → chunk-krvreaxb.js} +1 -1
- package/dist/chunk-m1n5a725.js +2 -0
- package/dist/{chunk-zr1r73p3.js → chunk-mgd0vre2.js} +1 -1
- package/dist/{chunk-s3pvp8qv.js → chunk-mjbrbnv2.js} +1 -1
- package/dist/{chunk-n43zq50e.js → chunk-mmhdgz5x.js} +1 -1
- package/dist/{chunk-jd9nv63q.js → chunk-mnhwgk4x.js} +1 -1
- package/dist/{chunk-w6ncyp18.js → chunk-n3qsg135.js} +1 -1
- package/dist/{chunk-szkq9s8n.js → chunk-nn17da2e.js} +1 -1
- package/dist/{chunk-b8cteeha.js → chunk-pavfpmwj.js} +1 -1
- package/dist/chunk-pn1syk7x.js +2 -0
- package/dist/{chunk-f044qmn3.js → chunk-q5hwa8dn.js} +1 -1
- package/dist/chunk-qqvwfhd5.js +2 -0
- package/dist/{chunk-ka5wtqmw.js → chunk-qz462c22.js} +1 -1
- package/dist/{chunk-snmtft92.js → chunk-rpnjwpw3.js} +1 -1
- package/dist/{chunk-wb24hk90.js → chunk-rwq2qzpx.js} +1 -1
- package/dist/{chunk-wwghzbbg.js → chunk-rypa8b99.js} +1 -1
- package/dist/{chunk-ry1key0g.js → chunk-sb2g9f73.js} +1 -1
- package/dist/{chunk-9ebfmdyb.js → chunk-sqkz8tf3.js} +1 -1
- package/dist/{chunk-ttny9g8k.js → chunk-sr042pkc.js} +1 -1
- package/dist/chunk-ssdzdsm1.js +2 -0
- package/dist/{chunk-3by4c2g9.js → chunk-tbw7qn8b.js} +1 -1
- package/dist/{chunk-jdcn0ms1.js → chunk-tk459ykz.js} +2 -2
- package/dist/chunk-tv2qdq7h.js +2 -0
- package/dist/{chunk-5g39e9ra.js → chunk-twdvqqft.js} +1 -1
- package/dist/{chunk-jg2gbd58.js → chunk-vmjktkm9.js} +1 -1
- package/dist/{chunk-bbq82jww.js → chunk-w913decg.js} +2 -2
- package/dist/chunk-wn9z19wm.js +2 -0
- package/dist/{chunk-5qseeh5t.js → chunk-wr011j4b.js} +1 -1
- package/dist/{chunk-ksqba0cq.js → chunk-wtdkz7wz.js} +1 -1
- package/dist/{chunk-tph7b269.js → chunk-x2j5b308.js} +1 -1
- package/dist/{chunk-tzhcjtkr.js → chunk-x7eb8e98.js} +1 -1
- package/dist/chunk-xaeamzng.js +2 -0
- package/dist/chunk-xc5swjjg.js +2 -0
- package/dist/{chunk-gpesxpwq.js → chunk-xnj5h0bq.js} +2 -2
- package/dist/{chunk-zdzd2jb4.js → chunk-ycmsckjw.js} +1 -1
- package/dist/{chunk-a50hb40e.js → chunk-yhebk7kd.js} +1 -1
- package/dist/{chunk-nnv8wytm.js → chunk-ymfh9wan.js} +1 -1
- package/dist/{chunk-at84gyvf.js → chunk-z698hwht.js} +1 -1
- package/dist/{chunk-64ttktzc.js → chunk-zeqktcby.js} +1 -1
- package/dist/{chunk-aqrp68m6.js → chunk-zsapb653.js} +1 -1
- package/dist/cli.js +14 -14
- package/dist/craft-entry.js +1 -1
- package/dist/craft.js +1 -1
- package/dist/database.js +1 -1
- package/dist/first-script-tag.d.ts +24 -0
- package/dist/first-script-tag.js +44 -0
- package/dist/includes.d.ts +2 -0
- package/dist/includes.js +12 -4
- package/dist/loops.d.ts +15 -1
- package/dist/loops.js +18 -4
- package/dist/process.js +4 -29
- package/dist/pwa.js +2 -2
- package/dist/runtime-injection.js +2 -1
- package/dist/ssg.js +2 -2
- package/dist/visual-testing.js +1 -1
- package/package.json +6 -6
- package/dist/chunk-0ggq64sc.js +0 -2
- package/dist/chunk-1ppaw4xs.js +0 -2
- package/dist/chunk-455m2k1y.js +0 -2
- package/dist/chunk-65hqene1.js +0 -2
- package/dist/chunk-6vt9ddra.js +0 -2
- package/dist/chunk-6xmx6stb.js +0 -2
- package/dist/chunk-8618n28z.js +0 -2
- package/dist/chunk-8avktqwz.js +0 -2
- package/dist/chunk-8z11nkyk.js +0 -2
- package/dist/chunk-95jjdgmb.js +0 -2
- package/dist/chunk-9aw5d4rr.js +0 -2
- package/dist/chunk-9g14542g.js +0 -2
- package/dist/chunk-9h4fkwtj.js +0 -2
- package/dist/chunk-bxvqqejm.js +0 -2
- package/dist/chunk-bzmxbz48.js +0 -2
- package/dist/chunk-f9qrz82p.js +0 -2
- package/dist/chunk-g8vf2fc7.js +0 -2
- package/dist/chunk-h63vszd3.js +0 -2
- package/dist/chunk-h78pksyp.js +0 -2
- package/dist/chunk-hxf6zg80.js +0 -2
- package/dist/chunk-jr79tvvs.js +0 -2
- package/dist/chunk-jwnbwemq.js +0 -3
- package/dist/chunk-mvj75wef.js +0 -2
- package/dist/chunk-n0t2at1c.js +0 -2
- package/dist/chunk-spzbfqjn.js +0 -3759
- package/dist/chunk-v1j4myd8.js +0 -2
- package/dist/chunk-v33qvj8y.js +0 -2
- package/dist/chunk-vnh668fb.js +0 -2
- package/dist/chunk-vpbw6g2t.js +0 -2
- package/dist/chunk-w33gx25k.js +0 -2
- package/dist/chunk-w3dfvxar.js +0 -2
- package/dist/chunk-wcp0dt2c.js +0 -2
- package/dist/chunk-z82sc99z.js +0 -2
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* - `none`: the format or header rules transparency out entirely (JPEG, a PNG
|
|
3
|
+
* with no alpha channel and no `tRNS`, a WebP that declares no alpha).
|
|
4
|
+
* - `possible`: the header declares an alpha channel. Every pixel may still be
|
|
5
|
+
* opaque; only a decode can say.
|
|
6
|
+
* - `unknown`: the header does not settle it (AVIF, anything unrecognised).
|
|
7
|
+
*/
|
|
8
|
+
export type SourceAlpha = 'none' | 'possible' | 'unknown';
|
|
9
|
+
export declare function readAt(fd: number, position: number, length: number): Buffer;
|
|
10
|
+
/**
|
|
11
|
+
* Whether a WebP header declares an alpha channel.
|
|
12
|
+
*
|
|
13
|
+
* A simple `VP8 ` frame cannot hold one at all; `VP8X` says so in its flags and
|
|
14
|
+
* `VP8L` in the `alpha_is_used` bit after the dimensions.
|
|
15
|
+
*/
|
|
16
|
+
export declare function webpHeaderHasAlpha(header: Uint8Array): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Classify a source file's transparency from its header alone.
|
|
19
|
+
*
|
|
20
|
+
* PNG says so with its colour type or a `tRNS` chunk (which must precede the
|
|
21
|
+
* first `IDAT`, so the walk stops there and never reads pixel data). A WebP
|
|
22
|
+
* `VP8 ` frame cannot carry alpha and a `VP8X` without the alpha flag declares
|
|
23
|
+
* none; `VP8L`'s `alpha_is_used` bit is only a hint, so without it the answer
|
|
24
|
+
* stays `unknown`. JPEG cannot carry alpha at all.
|
|
25
|
+
*/
|
|
26
|
+
export declare function sourceAlpha(file: string): SourceAlpha;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
export function readAt(fd, position, length) {
|
|
3
|
+
const buffer = Buffer.alloc(length), read = fs.readSync(fd, buffer, 0, length, position);
|
|
4
|
+
return buffer.subarray(0, read);
|
|
5
|
+
}
|
|
6
|
+
export function webpHeaderHasAlpha(header) {
|
|
7
|
+
if (header.length < 25)
|
|
8
|
+
return !1;
|
|
9
|
+
const text = (start, end) => String.fromCharCode(...header.subarray(start, end));
|
|
10
|
+
if (text(0, 4) !== "RIFF" || text(8, 12) !== "WEBP")
|
|
11
|
+
return !1;
|
|
12
|
+
const chunk = text(12, 16);
|
|
13
|
+
if (chunk === "VP8X")
|
|
14
|
+
return (header[20] & 16) !== 0;
|
|
15
|
+
if (chunk === "VP8L")
|
|
16
|
+
return ((header[21] | header[22] << 8 | header[23] << 16 | header[24] << 24) >>> 28 & 1) === 1;
|
|
17
|
+
return !1;
|
|
18
|
+
}
|
|
19
|
+
export function sourceAlpha(file) {
|
|
20
|
+
let fd;
|
|
21
|
+
try {
|
|
22
|
+
fd = fs.openSync(file, "r");
|
|
23
|
+
const head = readAt(fd, 0, 33);
|
|
24
|
+
if (head.length >= 3 && head[0] === 255 && head[1] === 216 && head[2] === 255)
|
|
25
|
+
return "none";
|
|
26
|
+
if (head.length >= 26 && head[0] === 137 && head.toString("latin1", 1, 4) === "PNG") {
|
|
27
|
+
const colorType = head[25];
|
|
28
|
+
if (colorType === 4 || colorType === 6)
|
|
29
|
+
return "possible";
|
|
30
|
+
let offset = 8;
|
|
31
|
+
for (let i = 0;i < 64; i++) {
|
|
32
|
+
const chunk = readAt(fd, offset, 8);
|
|
33
|
+
if (chunk.length < 8)
|
|
34
|
+
return "unknown";
|
|
35
|
+
const type = chunk.toString("latin1", 4, 8);
|
|
36
|
+
if (type === "tRNS")
|
|
37
|
+
return "possible";
|
|
38
|
+
if (type === "IDAT" || type === "IEND")
|
|
39
|
+
return "none";
|
|
40
|
+
offset += 12 + chunk.readUInt32BE(0);
|
|
41
|
+
}
|
|
42
|
+
return "unknown";
|
|
43
|
+
}
|
|
44
|
+
if (head.length >= 25 && head.toString("latin1", 0, 4) === "RIFF" && head.toString("latin1", 8, 12) === "WEBP") {
|
|
45
|
+
if (webpHeaderHasAlpha(head))
|
|
46
|
+
return "possible";
|
|
47
|
+
const chunk = head.toString("latin1", 12, 16);
|
|
48
|
+
return chunk === "VP8 " || chunk === "VP8X" ? "none" : "unknown";
|
|
49
|
+
}
|
|
50
|
+
return "unknown";
|
|
51
|
+
} catch {
|
|
52
|
+
return "unknown";
|
|
53
|
+
} finally {
|
|
54
|
+
if (fd !== void 0)
|
|
55
|
+
fs.closeSync(fd);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { ImageDeliveryManifest } from 'ts-images/delivery';
|
|
2
|
+
import { webpHeaderHasAlpha } from './image-alpha';
|
|
3
|
+
export { webpHeaderHasAlpha };
|
|
2
4
|
/** Return build-time delivery metadata for one public image URL. */
|
|
3
5
|
export declare function getImageDelivery(src: string): ImageDeliveryManifest | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Whether the delivered image at `src` has transparent pixels.
|
|
8
|
+
*
|
|
9
|
+
* Anything painted behind such an image shows through it for as long as it is
|
|
10
|
+
* there, so a placeholder has to stay out of it entirely.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isTransparentImage(src: string): boolean;
|
|
4
13
|
/** Clear process-global delivery state between builds and tests. */
|
|
5
14
|
export declare function clearImageDeliveryCatalog(): void;
|
|
6
15
|
/**
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { generateThumbHash } from "ts-images";
|
|
4
|
+
import { decode, generateThumbHash } from "ts-images";
|
|
5
5
|
import { createImageDeliveryCatalog } from "ts-images/delivery";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import { readAt, sourceAlpha, webpHeaderHasAlpha } from "./image-alpha.js";
|
|
7
|
+
|
|
8
|
+
export { webpHeaderHasAlpha };
|
|
9
|
+
const RASTER_EXTENSIONS = new Set([".avif", ".jpeg", ".jpg", ".png", ".webp"]), DEFAULT_WIDTHS = [320, 640, 960, 1280, 1920], DELIVERY_URL = "/_stx/images", ALPHA_NAMESPACE = `stx:${DELIVERY_URL}:alpha-1`;
|
|
10
|
+
let deliveryCatalog = new Map, transparentSources = new Set;
|
|
11
|
+
const warnedOpaqueWebp = new Set;
|
|
8
12
|
function publicUrl(relativePath) {
|
|
9
13
|
return `/${relativePath.split(path.sep).map(encodeURIComponent).join("/")}`;
|
|
10
14
|
}
|
|
@@ -12,10 +16,10 @@ function catalogName(relativePath) {
|
|
|
12
16
|
const extension = path.extname(relativePath), readable = relativePath.slice(0, -extension.length).replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, ""), pathHash = createHash("sha256").update(relativePath).digest("hex").slice(0, 8);
|
|
13
17
|
return `${readable || "image"}-${pathHash}`;
|
|
14
18
|
}
|
|
15
|
-
function deliveryStorage(outDir) {
|
|
19
|
+
function deliveryStorage(outDir, cacheNamespace = `stx:${DELIVERY_URL}`) {
|
|
16
20
|
const url = (key) => `${DELIVERY_URL}/${key.split("/").map(encodeURIComponent).join("/")}`;
|
|
17
21
|
return {
|
|
18
|
-
cacheNamespace
|
|
22
|
+
cacheNamespace,
|
|
19
23
|
async stat(key) {
|
|
20
24
|
const file = path.join(outDir, key);
|
|
21
25
|
try {
|
|
@@ -52,13 +56,67 @@ async function collectRasterImages(root, directory = root) {
|
|
|
52
56
|
}
|
|
53
57
|
return files;
|
|
54
58
|
}
|
|
55
|
-
function deliveryEntries(files) {
|
|
59
|
+
function deliveryEntries(files, alphaStorage) {
|
|
56
60
|
return files.map((file) => ({
|
|
57
61
|
key: publicUrl(file.relativePath),
|
|
58
62
|
input: file.absolutePath,
|
|
59
|
-
name: catalogName(file.relativePath)
|
|
63
|
+
name: catalogName(file.relativePath),
|
|
64
|
+
...mayHaveAlpha(file.absolutePath) ? { options: { storage: alphaStorage } } : {}
|
|
60
65
|
}));
|
|
61
66
|
}
|
|
67
|
+
function mayHaveAlpha(file) {
|
|
68
|
+
return sourceAlpha(file) === "possible";
|
|
69
|
+
}
|
|
70
|
+
function hasVisibleAlpha(rgba) {
|
|
71
|
+
for (let i = 3;i < rgba.length; i += 4)
|
|
72
|
+
if (rgba[i] !== 255)
|
|
73
|
+
return !0;
|
|
74
|
+
return !1;
|
|
75
|
+
}
|
|
76
|
+
async function findTransparent(entries) {
|
|
77
|
+
const candidates = Object.entries(entries).filter(([, manifest]) => manifest.fallback.format === "png"), transparent = new Set, concurrency = 8;
|
|
78
|
+
for (let offset = 0;offset < candidates.length; offset += concurrency)
|
|
79
|
+
await Promise.all(candidates.slice(offset, offset + concurrency).map(async ([key, manifest]) => {
|
|
80
|
+
const smallest = manifest.variants.filter((variant) => variant.format === "png").sort((a, b) => a.width - b.width)[0];
|
|
81
|
+
try {
|
|
82
|
+
const image = await decode(new Uint8Array(await fs.promises.readFile(smallest?.path ?? manifest.fallback.path)));
|
|
83
|
+
if (hasVisibleAlpha(image.data))
|
|
84
|
+
transparent.add(key);
|
|
85
|
+
} catch {
|
|
86
|
+
transparent.add(key);
|
|
87
|
+
}
|
|
88
|
+
}));
|
|
89
|
+
return transparent;
|
|
90
|
+
}
|
|
91
|
+
function dropOpaqueWebp(entries, transparent) {
|
|
92
|
+
const dropped = [];
|
|
93
|
+
for (const key of transparent) {
|
|
94
|
+
const manifest = entries[key], webp = manifest?.variants.filter((variant) => variant.format === "webp") ?? [];
|
|
95
|
+
if (!manifest || webp.length === 0)
|
|
96
|
+
continue;
|
|
97
|
+
if (!webp.some((variant) => {
|
|
98
|
+
let fd;
|
|
99
|
+
try {
|
|
100
|
+
fd = fs.openSync(variant.path, "r");
|
|
101
|
+
return !webpHeaderHasAlpha(readAt(fd, 0, 32));
|
|
102
|
+
} catch {
|
|
103
|
+
return !0;
|
|
104
|
+
} finally {
|
|
105
|
+
if (fd !== void 0)
|
|
106
|
+
fs.closeSync(fd);
|
|
107
|
+
}
|
|
108
|
+
}))
|
|
109
|
+
continue;
|
|
110
|
+
manifest.variants = manifest.variants.filter((variant) => variant.format !== "webp");
|
|
111
|
+
delete manifest.sources.webp;
|
|
112
|
+
dropped.push(key);
|
|
113
|
+
if (!warnedOpaqueWebp.has(key)) {
|
|
114
|
+
warnedOpaqueWebp.add(key);
|
|
115
|
+
console.warn(`[stx-images] ${key} is transparent but its WebP variants have no alpha channel; serving PNG instead. Upgrade @stacksjs/ts-webp to 0.1.6 or later.`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return dropped;
|
|
119
|
+
}
|
|
62
120
|
async function decodableFiles(files) {
|
|
63
121
|
const supported = [], concurrency = 8;
|
|
64
122
|
for (let offset = 0;offset < files.length; offset += concurrency) {
|
|
@@ -116,8 +174,13 @@ export function getImageDelivery(src) {
|
|
|
116
174
|
const key = normalizeLookupSource(src);
|
|
117
175
|
return key ? deliveryCatalog.get(key) : void 0;
|
|
118
176
|
}
|
|
177
|
+
export function isTransparentImage(src) {
|
|
178
|
+
const key = normalizeLookupSource(src);
|
|
179
|
+
return key ? transparentSources.has(key) : !1;
|
|
180
|
+
}
|
|
119
181
|
export function clearImageDeliveryCatalog() {
|
|
120
182
|
deliveryCatalog = new Map;
|
|
183
|
+
transparentSources = new Set;
|
|
121
184
|
}
|
|
122
185
|
export async function prepareImageDelivery(publicDir, outputDir) {
|
|
123
186
|
if (!publicDir || !fs.existsSync(publicDir)) {
|
|
@@ -140,7 +203,7 @@ export async function prepareImageDelivery(publicDir, outputDir) {
|
|
|
140
203
|
clearImageDeliveryCatalog();
|
|
141
204
|
return { count: 0, fingerprint: "" };
|
|
142
205
|
}
|
|
143
|
-
const catalogOptions = {
|
|
206
|
+
const alphaStorage = deliveryStorage(path.join(outputDir, "_stx", "images"), ALPHA_NAMESPACE), catalogOptions = {
|
|
144
207
|
outDir: path.join(outputDir, "_stx", "images"),
|
|
145
208
|
storage: deliveryStorage(path.join(outputDir, "_stx", "images")),
|
|
146
209
|
baseUrl: DELIVERY_URL,
|
|
@@ -156,7 +219,7 @@ export async function prepareImageDelivery(publicDir, outputDir) {
|
|
|
156
219
|
try {
|
|
157
220
|
catalog = await createImageDeliveryCatalog({
|
|
158
221
|
...catalogOptions,
|
|
159
|
-
entries: deliveryEntries(files)
|
|
222
|
+
entries: deliveryEntries(files, alphaStorage)
|
|
160
223
|
});
|
|
161
224
|
} catch (error) {
|
|
162
225
|
optimizedFiles = await decodableFiles(files);
|
|
@@ -181,9 +244,12 @@ export async function prepareImageDelivery(publicDir, outputDir) {
|
|
|
181
244
|
}
|
|
182
245
|
catalog = await createImageDeliveryCatalog({
|
|
183
246
|
...catalogOptions,
|
|
184
|
-
entries: deliveryEntries(optimizedFiles)
|
|
247
|
+
entries: deliveryEntries(optimizedFiles, alphaStorage)
|
|
185
248
|
});
|
|
186
249
|
}
|
|
250
|
+
const transparent = await findTransparent(catalog.entries), droppedWebp = dropOpaqueWebp(catalog.entries, transparent);
|
|
187
251
|
deliveryCatalog = new Map(Object.entries(catalog.entries));
|
|
188
|
-
|
|
252
|
+
transparentSources = transparent;
|
|
253
|
+
const fingerprint = transparent.size === 0 && droppedWebp.length === 0 ? catalog.fingerprint : createHash("sha256").update(catalog.fingerprint).update(JSON.stringify({ transparent: [...transparent].sort(), droppedWebp: droppedWebp.sort() })).digest("hex");
|
|
254
|
+
return { count: optimizedFiles.length, fingerprint };
|
|
189
255
|
}
|
|
@@ -27,6 +27,11 @@ export interface ImagePlaceholder {
|
|
|
27
27
|
dataUrl: string;
|
|
28
28
|
/** `#rrggbb` average, painted under the mesh and used alone as a fallback. */
|
|
29
29
|
color: string;
|
|
30
|
+
/**
|
|
31
|
+
* The image has transparent pixels. A placeholder painted behind it would
|
|
32
|
+
* show through for as long as it stayed, so the component renders none.
|
|
33
|
+
*/
|
|
34
|
+
transparent?: boolean;
|
|
30
35
|
}
|
|
31
36
|
/**
|
|
32
37
|
* The placeholder for `src`, or undefined when there is none.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { sourceAlpha } from "./image-alpha.js";
|
|
3
4
|
const IMAGE_EXTENSIONS = new Set([".jpg", ".jpeg", ".png", ".webp", ".avif"]), placeholders = new Map;
|
|
4
5
|
let warmed = !1;
|
|
5
6
|
export function getImagePlaceholder(src) {
|
|
@@ -19,6 +20,12 @@ export function setImagePlaceholder(urlPath, placeholder) {
|
|
|
19
20
|
placeholders.set(urlPath, placeholder);
|
|
20
21
|
warmed = !0;
|
|
21
22
|
}
|
|
23
|
+
function hasTransparency(rgba) {
|
|
24
|
+
for (let i = 3;i < rgba.length; i += 4)
|
|
25
|
+
if (rgba[i] < 255)
|
|
26
|
+
return !0;
|
|
27
|
+
return !1;
|
|
28
|
+
}
|
|
22
29
|
function averageColor(rgba) {
|
|
23
30
|
let r = 0, g = 0, b = 0, n = 0;
|
|
24
31
|
for (let i = 0;i < rgba.length; i += 4) {
|
|
@@ -112,8 +119,16 @@ export async function warmImagePlaceholders(publicDir, options = {}) {
|
|
|
112
119
|
return;
|
|
113
120
|
const cached = cache[urlPath];
|
|
114
121
|
if (cached && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) {
|
|
115
|
-
|
|
116
|
-
|
|
122
|
+
let transparent = cached.transparent;
|
|
123
|
+
if (typeof transparent !== "boolean" && sourceAlpha(filePath) === "none") {
|
|
124
|
+
transparent = !1;
|
|
125
|
+
cache[urlPath] = { ...cached, transparent };
|
|
126
|
+
cacheDirty = !0;
|
|
127
|
+
}
|
|
128
|
+
if (typeof transparent === "boolean") {
|
|
129
|
+
placeholders.set(urlPath, { dataUrl: cached.dataUrl, color: cached.color, transparent });
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
117
132
|
}
|
|
118
133
|
try {
|
|
119
134
|
const { hash } = await tsImages.generateThumbHash(filePath);
|
|
@@ -121,7 +136,8 @@ export async function warmImagePlaceholders(publicDir, options = {}) {
|
|
|
121
136
|
return;
|
|
122
137
|
const { rgba, w, h } = tsImages.thumbHashToRGBA(hash), placeholder = {
|
|
123
138
|
dataUrl: svgDataUrl(meshSvg(rgba, w, h)),
|
|
124
|
-
color: averageColor(rgba)
|
|
139
|
+
color: averageColor(rgba),
|
|
140
|
+
transparent: hasTransparency(rgba)
|
|
125
141
|
};
|
|
126
142
|
placeholders.set(urlPath, placeholder);
|
|
127
143
|
cache[urlPath] = { mtimeMs: stat.mtimeMs, size: stat.size, ...placeholder };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { forwardResolvedAttrs, forwardStaticAttrs } from "./attrs.js";
|
|
2
|
-
import { getImageDelivery } from "./image-delivery.js";
|
|
2
|
+
import { getImageDelivery, isTransparentImage } from "./image-delivery.js";
|
|
3
3
|
import { getImagePlaceholder } from "./image-placeholder.js";
|
|
4
4
|
const DEFAULT_BREAKPOINTS = {
|
|
5
5
|
sm: 640,
|
|
@@ -99,6 +99,9 @@ function transformSrc(src, width, height, provider, format) {
|
|
|
99
99
|
}
|
|
100
100
|
return src;
|
|
101
101
|
}
|
|
102
|
+
function placeholderCleanup(properties) {
|
|
103
|
+
return `var s=this.style;${properties.map((property) => `s.${property}=''`).join(";")}`;
|
|
104
|
+
}
|
|
102
105
|
function generateBlurPlaceholder(width, height, color = "#e5e7eb") {
|
|
103
106
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}"><rect width="100%" height="100%" fill="${color}"/></svg>`;
|
|
104
107
|
return `data:image/svg+xml;base64,${btoa(svg)}`;
|
|
@@ -107,7 +110,7 @@ export const StxImageBuiltin = {
|
|
|
107
110
|
name: "StxImage",
|
|
108
111
|
aliases: ["Image", "stx-image", "stx-img"],
|
|
109
112
|
render(props, _slotContent, _ctx) {
|
|
110
|
-
const src = resolveProp(props, "src") || "", delivery = getImageDelivery(src), alt = resolveProp(props, "alt") || "", width = resolveProp(props, "width") || (delivery ? String(delivery.source.width) : void 0), height = resolveProp(props, "height") || (delivery ? String(delivery.source.height) : void 0), sizes = resolveProp(props, "sizes"), srcset = resolveProp(props, "srcset"), densities = resolveProp(props, "densities"), format = resolveProp(props, "format"), placeholder = resolveProp(props, "placeholder") || (delivery ? "thumbhash" : void 0), placeholderColor = resolveProp(props, "placeholderColor") || "#e5e7eb", provider = resolveProp(props, "provider"), className = resolveProp(props, "class") || resolveProp(props, "className") || "", style = resolveProp(props, "style") || "", quality = resolveProp(props, "quality"), lazy = resolveBoolProp(props, "lazy", !0), preload = resolveBoolProp(props, "preload", !1), priority = resolveBoolProp(props, "priority", !1), explicitLoading = resolveProp(props, "loading"), decoding = resolveProp(props, "decoding") || "async", usePicture = !!delivery || resolveBoolProp(props, "picture", !1) || !!format, numWidth = width ? Number.parseInt(width) : void 0, numHeight = height ? Number.parseInt(height) : void 0;
|
|
113
|
+
const src = resolveProp(props, "src") || "", delivery = getImageDelivery(src), alt = resolveProp(props, "alt") || "", width = resolveProp(props, "width") || (delivery ? String(delivery.source.width) : void 0), height = resolveProp(props, "height") || (delivery ? String(delivery.source.height) : void 0), sizes = resolveProp(props, "sizes"), srcset = resolveProp(props, "srcset"), densities = resolveProp(props, "densities"), format = resolveProp(props, "format"), transparent = isTransparentImage(src) || getImagePlaceholder(src)?.transparent === !0, placeholder = resolveProp(props, "placeholder") || (delivery && !transparent ? "thumbhash" : void 0), placeholderColor = resolveProp(props, "placeholderColor") || "#e5e7eb", provider = resolveProp(props, "provider"), className = resolveProp(props, "class") || resolveProp(props, "className") || "", style = resolveProp(props, "style") || "", quality = resolveProp(props, "quality"), lazy = resolveBoolProp(props, "lazy", !0), preload = resolveBoolProp(props, "preload", !1), priority = resolveBoolProp(props, "priority", !1), explicitLoading = resolveProp(props, "loading"), decoding = resolveProp(props, "decoding") || "async", usePicture = !!delivery || resolveBoolProp(props, "picture", !1) || !!format, numWidth = width ? Number.parseInt(width) : void 0, numHeight = height ? Number.parseInt(height) : void 0;
|
|
111
114
|
let finalSrcset = srcset || "", finalSizes = "";
|
|
112
115
|
if (delivery) {
|
|
113
116
|
finalSrcset = delivery.sources[delivery.fallback.format] || "";
|
|
@@ -125,25 +128,30 @@ export const StxImageBuiltin = {
|
|
|
125
128
|
styles.push(style);
|
|
126
129
|
if (numWidth && numHeight)
|
|
127
130
|
styles.push(`aspect-ratio:${numWidth}/${numHeight}`);
|
|
128
|
-
|
|
131
|
+
const placeholderProperties = [], derivedPlaceholder = placeholder === "blur" || placeholder === "color" || placeholder === "thumbhash";
|
|
132
|
+
if (derivedPlaceholder && !transparent) {
|
|
129
133
|
const derived = delivery?.placeholder ? { dataUrl: delivery.placeholder.dataUrl, color: placeholderColor } : getImagePlaceholder(src);
|
|
130
|
-
if (derived && placeholder === "color")
|
|
134
|
+
if (derived && placeholder === "color") {
|
|
131
135
|
styles.push(`background-color:${derived.color}`);
|
|
132
|
-
|
|
136
|
+
placeholderProperties.push("backgroundColor");
|
|
137
|
+
} else if (derived) {
|
|
133
138
|
styles.push(`background-color:${derived.color}`);
|
|
134
139
|
styles.push(`background-image:url(${derived.dataUrl})`);
|
|
135
140
|
styles.push("background-size:cover");
|
|
136
141
|
styles.push("background-repeat:no-repeat");
|
|
142
|
+
placeholderProperties.push("backgroundColor", "backgroundImage");
|
|
137
143
|
} else {
|
|
138
144
|
const placeholderUrl = generateBlurPlaceholder(numWidth || 16, numHeight || 9, placeholderColor);
|
|
139
145
|
styles.push(`background-image:url(${placeholderUrl})`);
|
|
140
146
|
styles.push("background-size:cover");
|
|
141
147
|
styles.push("background-repeat:no-repeat");
|
|
148
|
+
placeholderProperties.push("backgroundImage");
|
|
142
149
|
}
|
|
143
|
-
} else if (placeholder && placeholder !== "empty" && placeholder !== "none") {
|
|
150
|
+
} else if (!derivedPlaceholder && placeholder && placeholder !== "empty" && placeholder !== "none") {
|
|
144
151
|
styles.push(`background-image:url(${escapeAttr(placeholder)})`);
|
|
145
152
|
styles.push("background-size:cover");
|
|
146
153
|
styles.push("background-repeat:no-repeat");
|
|
154
|
+
placeholderProperties.push("backgroundImage");
|
|
147
155
|
}
|
|
148
156
|
const finalSrc = delivery?.fallback.url || transformSrc(src, numWidth, numHeight, provider, format), imgAttrs = [];
|
|
149
157
|
imgAttrs.push(`src="${escapeAttr(finalSrc)}"`);
|
|
@@ -189,6 +197,11 @@ export const StxImageBuiltin = {
|
|
|
189
197
|
"loading",
|
|
190
198
|
"decoding"
|
|
191
199
|
]);
|
|
200
|
+
if (placeholderProperties.length > 0) {
|
|
201
|
+
const authorOnload = typeof props.static.onload === "string" ? props.static.onload : "", handler = placeholderCleanup(placeholderProperties) + (authorOnload ? `;${authorOnload}` : "");
|
|
202
|
+
imgAttrs.push(`onload="${escapeAttr(handler)}"`);
|
|
203
|
+
consumedStatic.add("onload");
|
|
204
|
+
}
|
|
192
205
|
imgAttrs.push(...forwardStaticAttrs(props, consumedStatic));
|
|
193
206
|
imgAttrs.push(...forwardResolvedAttrs(props, consumedStatic));
|
|
194
207
|
const imgTag = `<img ${imgAttrs.join(" ")} />`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{ih as a,jh as b,kh as c,lh as d,mh as e,nh as f,oh as g,ph as h,qh as i,rh as j,sh as k}from"./chunk-
|
|
2
|
+
import{ih as a,jh as b,kh as c,lh as d,mh as e,nh as f,oh as g,ph as h,qh as i,rh as j,sh as k}from"./chunk-q5hwa8dn.js";import"./chunk-vd5xvsnv.js";import"./chunk-cey6rhqw.js";export{c as setCachedVideoResult,k as processVideo,b as getCachedVideoResult,f as generateThumbnails,g as generateSpriteSheet,e as generatePoster,h as generateHLSManifest,i as generateDASHManifest,d as clearVideoCache,j as analyzeVideo,a as VideoProcessorCache};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{Re as a,Se as b}from"./chunk-2ver2s2y.js";import"./chunk-
|
|
2
|
+
import{Re as a,Se as b}from"./chunk-2ver2s2y.js";import"./chunk-cey6rhqw.js";export{b as captureScreenshots,a as captureScreenshot};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{Ui as x,Vi as F,Wi as R}from"./chunk-xwxdwqn9.js";import{
|
|
2
|
+
import{Ui as x,Vi as F,Wi as R}from"./chunk-xwxdwqn9.js";import{Ar as k,fm as K,jq as T}from"./chunk-7kk2jb1j.js";import{Uu as y,Vu as N}from"./chunk-jtaxnnq3.js";import{Zu as v}from"./chunk-sr042pkc.js";import j from"path";var P=new Map,E=new Map,h=["composables","functions"];function D(q){let z=j.basename(q,".ts");return z==="index"||z==="types"||q.endsWith(".d.ts")}async function f(q){if(q)return j.resolve(q);let z=`<default>:${process.cwd()}`,W=E.get(z);if(W!==void 0)return W;let H=await u();if(H!==null)E.set(z,H);return H}async function u(){let q=await k(),z=q.root||process.cwd(),W=q.composablesDir;if(W)return j.resolve(z,W);for(let H of h){let Q=j.resolve(z,H);try{let V=new Bun.Glob("**/*.ts");for await(let Z of V.scan({cwd:Q,absolute:!0}))if(!D(Z))return Q}catch{}}return null}async function b(q){let z=Array.isArray(q)?q:q?[j.resolve(q)]:(await k())._layerComposableDirs??[await f()].filter((H)=>!!H),W=new Map;for(let H of z){let Q=new Bun.Glob("**/*.ts");try{for await(let V of Q.scan({cwd:H,absolute:!0})){let Z=j.relative(H,V);if(!D(V)&&!W.has(Z))W.set(Z,V)}}catch{}}return{key:z.join("\x00"),files:[...W.values()].sort()}}async function o(q){let{files:z}=await b(q),W=T({loader:"ts",target:"browser",define:K()}),H=[];for(let Q of z)try{let V=await Bun.file(Q).text(),Z=W.scan(V).exports.filter(($)=>$!=="default");if(Z.length>0)H.push({file:Q,names:Z})}catch{}return H}function p(q,z){return new RegExp(`\\b${z.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\b`).test(q)}function m(q,z,W){let H=new Map;for(let{file:$,names:G}of q)for(let O of G)if(!H.has(O))H.set(O,$);let Q=($)=>{let G=[];for(let[O,U]of H)if(p($,O))G.push(U);return G},V=new Set,Z=W.flatMap(Q);while(Z.length>0){let $=[];for(let G of Z){if(V.has(G))continue;V.add(G);for(let O of Q(z.get(G)??""))if(!V.has(O))$.push(O)}Z=$}return V}async function e(q,z,W){let{key:H,files:Q}=await b(q);if(!H)return null;let V=x(Q);if(Q.length===0)return R(P,H,V,""),null;Q.sort();let Z=T({loader:"ts",target:"browser",define:K()}),$=new Map,G=[];for(let J of Q)try{let Y=await Bun.file(J).text();$.set(J,Y);let L=Z.scan(Y).exports.filter((X)=>X!=="default");if(L.length>0)G.push({file:J,names:L})}catch{$.set(J,"")}let O=z===void 0?new Set(Q):m(G,$,W?[z,...W]:[z]);if(O.size===0)return null;let U=Q.filter((J)=>O.has(J)),A=`${H}\x00${U.join("\x00")}`,B=F(P,A,V);if(B!==void 0)return B||null;let M=[],w=new Set,I=new Set;for(let J of U)try{let Y=$.get(J)??await Bun.file(J).text(),L=j.basename(J,".ts");for(let X of Y.matchAll(/\b(?:const|let|var|function|class)\s+([A-Z_a-z$][\w$]*)/g))if(X[1])I.add(X[1]);try{for(let X of Z.scan(Y).exports)if(X!=="default")w.add(X)}catch{}Y=y(Y),Y=N(Y),Y=Y.replace(/^export\s+(default\s+)?/gm,""),Y=Z.transformSync(Y),M.push(`// Composable: ${L}
|
|
3
3
|
${Y.trim()}`)}catch(Y){console.warn(`[stx] Failed to load composable ${J}:`,Y)}if(M.length===0||w.size===0)return R(P,A,V,""),null;let g=[...w].map((J)=>` try { __c[${JSON.stringify(J)}] = ${J}; } catch (e) {}`).join(`
|
|
4
4
|
`),S=JSON.stringify([...w]),C=M.join(`
|
|
5
5
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{Eh as a,Fh as b,Gh as c,Hh as d,Ih as e,Jh as f,Kh as g,Lh as h}from"./chunk-64djh88a.js";import"./chunk-
|
|
2
|
+
import{Eh as a,Fh as b,Gh as c,Hh as d,Ih as e,Jh as f,Kh as g,Lh as h}from"./chunk-64djh88a.js";import"./chunk-cey6rhqw.js";export{g as timingPlugin,c as pluginManager,a as definePlugin,f as debugPlugin,h as createVariablesPlugin,e as createFilterPlugin,d as createDirectivePlugin,b as PluginManager};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import C from"path";var G=".stx",K="STX_DIR",J=null;function O(j){J=j?.trim()||null}function H(){return process.env[K]?.trim()||J||G}function Q(j=process.cwd(),...q){let B=H();return C.isAbsolute(B)?C.join(B,...q):C.join(j,B,...q)}function W(j){if(!j||C.isAbsolute(j))return j;let q=j.replace(/\\/g,"/");if(q!==G&&!q.startsWith(`${G}/`))return j;let B=q.slice(G.length+1);return B?C.join(H(),B):H()}
|
|
3
|
-
export{G as
|
|
3
|
+
export{G as pu,K as qu,O as ru,H as su,Q as tu,W as uu};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
2
|
+
import{Eu as a,Fu as b,Gu as c,Hu as d,Iu as e,Ju as f,Ku as g,Lu as h,Mu as i,Nu as j,Ou as k,Pu as l,Qu as m,Ru as n,Su as o,Tu as p}from"./chunk-zeqktcby.js";import"./chunk-cey6rhqw.js";export{i as useTitle,f as useSeoMeta,i as usePageTitle,d as useHead,g as seoMetaToHeadConfig,c as resetHead,k as renderHtmlAttrs,j as renderHead,l as renderBodyAttrs,o as processTitleDirective,p as processMetaDirective,n as processHeadDirective,e as mergeHeadConfigs,b as getPageMeta,a as getHead,h as definePageMeta,m as applyHead};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{Cm as I}from"./chunk-
|
|
2
|
+
import{Cm as I}from"./chunk-7kk2jb1j.js";import{ts as F,xs as V}from"./chunk-2btrq8sz.js";function R(j,W){let U=1,z=W,G="<template",X="</template";while(z<j.length&&U>0){let J=j.indexOf("<",z);if(J===-1)break;if(z=J,j.startsWith(G,z)&&(z+G.length>=j.length||/[\s>\/]/.test(j[z+G.length]))){U++,z+=G.length;continue}if(j.startsWith(X,z)){let Y=j.indexOf(">",z+X.length);if(Y!==-1){if(U--,U===0)return Y+1;z=Y+1;continue}}z++}return U===0?z:-1}var P=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);function D(j,W){let U=null;for(let z=W;z<j.length;z++){let G=j[z];if(U){if(G==="\\"){z++;continue}if(G===U)U=null;continue}if(G==='"'||G==="'"){U=G;continue}if(G===">")return z+1}return-1}function b(j){let W=[],U=[],z=/^<template\s+(?:#([a-zA-Z][\w-]*)|v-slot:([a-zA-Z][\w-]*)|slot="([a-zA-Z][\w-]*)")(?:\s*=\s*"([^"]*)")?[^>]*>$/i,G=0;while(G<j.length){let X=j.indexOf("<",G);if(X===-1)break;if(j.startsWith("<!--",X)){let $=j.indexOf("-->",X+4);G=$===-1?j.length:$+3;continue}let J=D(j,X+1);if(J===-1)break;let Y=j.slice(X,J),Q=Y.match(/^<\s*(\/?)\s*([a-zA-Z][\w-]*)/);if(!Q){G=J;continue}let Z=Q[1]==="/",H=Q[2].toLowerCase();if(Z){let $=U.lastIndexOf(H);if($!==-1)U.splice($);G=J;continue}if(H==="template"&&U.length===0){let $=Y.match(z);if($){let K=R(j,J);if(K!==-1){let O=$[1]||$[2]||$[3];W.push({start:X,end:K,slotName:O,content:j.slice(J,K-11).trim(),propsBinding:$[4]||void 0}),G=K;continue}}}if(!/\/\s*>$/.test(Y)&&!P.has(H)){if(U.push(H),H==="script"||H==="style"){let $=j.toLowerCase().indexOf(`</${H}>`,J);if($!==-1){G=$;continue}}}G=J}return W}function w(j){let W={default:"",named:new Map},U=j,z=b(j);for(let Q of z)W.named.set(Q.slotName,{name:Q.slotName,content:Q.content,propsBinding:Q.propsBinding});z.sort((Q,Z)=>Z.start-Q.start);for(let Q of z)U=U.slice(0,Q.start)+U.slice(Q.end);let G=[],X=/<([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*?)\bslot="([^"]+)"([^>]*)>([\s\S]*?)<\/\1>/gi,J;while((J=X.exec(U))!==null){let[Q,Z,H,_,$,K]=J,O=H.replace(/\s*slot="[^"]*"\s*/," ").trimEnd(),B=$.replace(/\s*slot="[^"]*"\s*/," ").trimEnd(),L=(O+B).trim(),q=`<${Z}${L?" "+L:""}>${K}</${Z}>`;G.push({start:J.index,end:J.index+Q.length,slotName:_,element:q})}let Y=/<([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*?)\bslot="([^"]+)"([^>]*?)\/>/gi;while((J=Y.exec(U))!==null){let[Q,Z,H,_,$]=J,K=H.replace(/\s*slot="[^"]*"\s*/," ").trimEnd(),O=$.replace(/\s*slot="[^"]*"\s*/," ").trimEnd(),B=(K+O).trim(),L=`<${Z}${B?" "+B:""} />`;G.push({start:J.index,end:J.index+Q.length,slotName:_,element:L})}G.sort((Q,Z)=>Z.start-Q.start);for(let Q of G){let Z=W.named.get(Q.slotName);if(Z)Z.content+=Q.element;else W.named.set(Q.slotName,{name:Q.slotName,content:Q.element});U=U.slice(0,Q.start)+U.slice(Q.end)}return W.default=U.trim(),W}function C(j){let W=j.match(/name\s*=\s*["']([^"']+)["']/),U=W?W[1]:"",z={},G=/:([a-zA-Z][\w-]*)\s*=\s*["']([^"']+)["']/g,X;while((X=G.exec(j))!==null)z[X[1]]=X[2];let J=j.match(/<slot[^>]*>([\s\S]*?)<\/slot>/i),Y=J?J[1].trim():"";return{name:U,props:z,defaultContent:Y}}async function N(j,W,U,z){if(!j)return U;let G=j.content;if(j.propsBinding&&Object.keys(W).length>0){let X=j.propsBinding.trim(),J={...z};if(X.startsWith("{")&&X.endsWith("}")){let Y=X.slice(1,-1).split(",").map((Q)=>Q.trim()).filter(Boolean);for(let Q of Y){let[Z,H]=Q.split(":").map(($)=>$.trim()),_=H||Z;if(W[Z]!==void 0)J[_]=W[Z]}}else J[X]=W;G=k(G,J)}return G}function k(j,W){return j.replace(/\{\{\s*([^}]+)\s*\}\}/g,(U,z)=>{try{let G=z.trim(),X=y(G,W);return I(String(X??""))}catch{return`{{ ${z} }}`}})}function y(j,W){if(/^[a-zA-Z_$][\w$]*(\.[a-zA-Z_$][\w$]*)*$/.test(j)){let z=j.split("."),G=W;for(let X of z)if(G&&typeof G==="object"&&X in G)G=G[X];else return;return G}let U=j.match(/^([a-zA-Z_$][\w$]*)\s*([+\-*/])\s*(\d+)$/);if(U){let[,z,G,X]=U,J=W[z],Y=parseInt(X,10);if(typeof J==="number")switch(G){case"+":return J+Y;case"-":return J-Y;case"*":return J*Y;case"/":return J/Y}}try{if(!F(j))return;return V(j,Object.keys(W))(...Object.values(W))}catch{return}}async function A(j,W,U){let z=j;z=await v(z,/<slot\s+name\s*=\s*["']([^"']+)["']([^>]*?)(?:\/>|>([\s\S]*?)<\/slot>)/gi,async(J,Y,Q,Z)=>{let H=W.named.get(Y),_=Z?.trim()||"",$=Q||"",K={},O=/:([a-zA-Z_$][\w$-]*)\s*=\s*["']([^"']+)["']/g,B;while((B=O.exec($))!==null){let L=B[1],q=B[2];K[L]=y(q,U)}return await N(H,K,_,U)});let X=/<slot\s*(?:\/>|>([\s\S]*?)<\/slot>)/gi;return z=z.replace(X,(J,Y)=>{if(J.includes("name="))return J;let Q=Y?.trim()||"";return W.default||Q}),z}async function v(j,W,U){let z=[],G=[];j.replace(W,(Y,...Q)=>{let Z=Q[Q.length-2];return G.push({match:Y,index:Z}),z.push(U(Y,...Q.slice(0,-2))),Y});let X=await Promise.all(z),J=j;for(let Y=G.length-1;Y>=0;Y--){let{match:Q,index:Z}=G[Y];J=J.slice(0,Z)+X[Y]+J.slice(Z+Q.length)}return J}function E(j){let W=w(j);return{defaultSlot:W.default,namedSlots:W.named}}async function M(j,W,U,z){return await A(j,{default:W,named:U},z)}
|
|
3
3
|
export{w as Vg,C as Wg,N as Xg,A as Yg,E as Zg,M as _g};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{Vg as a,Wg as b,Xg as c,Yg as d,Zg as e,_g as f}from"./chunk-222swfwr.js";import"./chunk-7kk2jb1j.js";import"./chunk-2btrq8sz.js";import"./chunk-z698hwht.js";import"./chunk-70zb3560.js";import"./chunk-zsapb653.js";import"./chunk-hrd56xw7.js";import"./chunk-hhjrtjc9.js";import"./chunk-sb2g9f73.js";import"./chunk-1r3ydhkx.js";import"./chunk-j8bwgnz5.js";import"./chunk-5mdvkpt8.js";import"./chunk-zeqktcby.js";import"./chunk-jtaxnnq3.js";import"./chunk-2925bmqr.js";import"./chunk-sr042pkc.js";import"./chunk-w913decg.js";import"./chunk-sqkz8tf3.js";import"./chunk-cey6rhqw.js";export{c as renderSlot,d as processSlots,a as parseSlots,b as parseSlotElement,e as extractSlotContent,f as applySlots};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
var E=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),N=new Set(["html","head","body","p","li","dt","dd","rt","rp","option","optgroup","thead","tbody","tfoot","tr","td","th","colgroup","caption"]);function X(Q){return Q.replace(/[^\n]/g," ")}function R(Q){let H=Q.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi,X).replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi,X).replace(/<!--[\s\S]*?-->/g,X).replace(/\{\{\{[\s\S]*?\}\}\}/g,X).replace(/\{\{[\s\S]*?\}\}/g,X).replace(/\{!![\s\S]*?!!\}/g,X),F=new Map,J=new Map,Y=/<(\/?)([A-Za-z][\w-]*)\b(?:[^>"']|"[^"]*"|'[^']*')*?(\/?)>/g,z;while((z=Y.exec(H))!==null){let j=z[1]==="/",q=z[2],W=z[3]==="/";if(E.has(q.toLowerCase()))continue;if(W)continue;if(j)J.set(q,(J.get(q)??0)+1);else{let Z=F.get(q);if(Z)Z.count++;else{let B=H.slice(0,z.index).split(`
|
|
3
3
|
`).length;F.set(q,{count:1,firstLine:B})}}}let M=[];for(let j of new Set([...F.keys(),...J.keys()])){if(N.has(j.toLowerCase()))continue;let q=F.get(j)?.count??0,W=J.get(j)??0;if(q!==W)M.push({tag:j,opened:q,closed:W,firstOpenLine:F.get(j)?.firstLine??0})}return M}var $=new Set;function U(Q,H){let F;try{F=R(Q)}catch{return}if(F.length===0)return;let J=`${H}:${Q.length}`;if($.has(J))return;$.add(J);let Y=H?H.split(/[/\\]/).pop()||H:"template";for(let{tag:z,opened:M,closed:j,firstOpenLine:q}of F)if(M>j){let W=q?` (first opened at line ${q})`:"";console.warn(`[stx] ${Y}: <${z}> ${M} opened, ${j} closed \u2014 an unclosed <${z}>${W} may swallow the content that follows it.`)}else console.warn(`[stx] ${Y}: <${z}> ${M} opened, ${j} closed \u2014 ${j-M} stray </${z}>.`)}
|
|
4
|
-
export{R as
|
|
4
|
+
export{R as Wu,U as Xu};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
2
|
+
import{jt as bq}from"./chunk-z698hwht.js";import{jw as k}from"./chunk-cey6rhqw.js";var fq={1001:{message:"Unclosed directive: {{directive}}",help:"Make sure to close the directive with the appropriate end tag"},1002:{message:"Unclosed expression at position {{position}}",help:"Check for missing closing braces }}"},1003:{message:"Invalid directive syntax: {{directive}}",help:"Review the directive documentation for correct syntax"},1004:{message:"Malformed expression: {{expression}}",help:"Check for syntax errors in your expression"},1005:{message:"Unexpected token: {{token}}",help:"Remove or fix the unexpected token"},1101:{message:"Undefined variable: {{variable}}",help:"Make sure the variable is defined in the template context"},1102:{message:"Type error: {{details}}",help:"Check that you are using the correct types"},1103:{message:"Evaluation error: {{details}}",help:"Review the expression for errors"},1104:{message:"Infinite loop detected in {{location}}",help:"Check your loop conditions"},1105:{message:"Circular reference detected: {{path}}",help:"Remove the circular dependency"},1201:{message:"Unsafe expression blocked: {{expression}}",help:"This expression contains potentially dangerous code"},1202:{message:"Path traversal attempt blocked: {{path}}",help:"Use only relative paths within allowed directories"},1203:{message:"Potential XSS attempt blocked",help:"Sanitize user input before rendering"},1204:{message:"Code injection attempt blocked: {{code}}",help:"Avoid executing dynamic code"},1205:{message:"Prohibited DOM API usage: {{api}}",help:"Use STX.useRefs(), STX.useRef(), STX.el() and other STX helpers instead of direct DOM manipulation"},1301:{message:"File not found: {{path}}",help:"Check that the file exists and the path is correct"},1302:{message:"Error reading file: {{path}}",help:"Check file permissions and encoding"},1303:{message:"Invalid file path: {{path}}",help:"Use a valid file path"},1304:{message:"Permission denied: {{path}}",help:"Check file permissions"},1401:{message:"Invalid configuration: {{details}}",help:"Review your stx.config.ts file"},1402:{message:"Missing required configuration: {{key}}",help:"Add the required configuration option"},1403:{message:"Deprecated configuration: {{key}}",help:"Update to the new configuration format"},1501:{message:"Component not found: {{name}}",help:"Check that the component exists in your components directory"},1502:{message:"Invalid props for component {{name}}: {{details}}",help:"Check the component prop requirements"},1503:{message:"Error rendering component {{name}}: {{details}}",help:"Check the component template for errors"},1601:{message:"Filter not found: {{filter}}",help:"Register the filter or check the filter name"},1602:{message:"Invalid arguments for filter {{filter}}: {{details}}",help:"Check the filter documentation for correct arguments"},1603:{message:"Expression evaluation timed out",help:"Simplify the expression or increase the timeout"}},b={},$q="en";function hq(q){$q=q}function uq(){return $q}function dq(q){b={...b,...q}}function pq(){b={}}function Xq(q,Q={}){let J=b[q]||fq[q]||{message:`Unknown error (code: ${q})`},Z=J.message,$=J.help;for(let[Y,G]of Object.entries(Q)){let X=`{{${Y}}}`;if(Z=Z.replace(new RegExp(X,"g"),G),$)$=$.replace(new RegExp(X,"g"),G)}return{message:Z,help:$}}function mq(q,Q={}){let{message:J,help:Z}=Xq(q,Q);return Z?`${J}
|
|
3
3
|
Help: ${Z}`:J}var U={UNCLOSED_DIRECTIVE:1001,UNCLOSED_EXPRESSION:1002,INVALID_DIRECTIVE_SYNTAX:1003,MALFORMED_EXPRESSION:1004,UNEXPECTED_TOKEN:1005,UNDEFINED_VARIABLE:1101,TYPE_ERROR:1102,EVALUATION_ERROR:1103,INFINITE_LOOP:1104,CIRCULAR_REFERENCE:1105,UNSAFE_EXPRESSION:1201,PATH_TRAVERSAL:1202,XSS_ATTEMPT:1203,CODE_INJECTION:1204,DOM_API_VIOLATION:1205,FILE_NOT_FOUND:1301,FILE_READ_ERROR:1302,INVALID_FILE_PATH:1303,PERMISSION_DENIED:1304,INVALID_CONFIG:1401,MISSING_REQUIRED_CONFIG:1402,DEPRECATED_CONFIG:1403,COMPONENT_NOT_FOUND:1501,INVALID_PROPS:1502,COMPONENT_RENDER_ERROR:1503,FILTER_NOT_FOUND:1601,INVALID_FILTER_ARGS:1602,EXPRESSION_TIMEOUT:1603};function u(q){for(let[Q,J]of Object.entries(U))if(J===q)return Q;return}function cq(){return!1}function L(){return!cq()||process.env.STX_DEBUG==="true"}function GQ(){return!1}import lq from"path";var Yq={showRelativePaths:!1,enableAutoRecovery:L(),logRecoveryWarnings:!0},T={...Yq};function iq(q){T={...T,...q}}function E(){return{...T}}function sq(){T={...Yq}}function C(q){if(!T.showRelativePaths||!q)return q;let Q=T.baseDir||process.cwd();try{let J=lq.relative(Q,q);return J.startsWith("..")?q:J}catch{return q}}class N extends Error{code;filePath;line;column;context;numericCode;constructor(q,Q,J,Z,$,Y,G){super(q);this.code=Q;this.filePath=J;this.line=Z;this.column=$;this.context=Y;if(this.name="StxError",this.numericCode=G||U.EVALUATION_ERROR,this.filePath)this.filePath=C(this.filePath)}}class Hq extends N{constructor(q,Q,J,Z,$,Y){super(q,"stx_SYNTAX_ERROR",Q,J,Z,$,Y||U.INVALID_DIRECTIVE_SYNTAX);this.name="StxSyntaxError"}}class Gq extends N{constructor(q,Q,J,Z,$,Y){super(q,"stx_RUNTIME_ERROR",Q,J,Z,$,Y||U.EVALUATION_ERROR);this.name="StxRuntimeError"}}class Wq extends N{constructor(q,Q,J,Z,$,Y){super(q,"stx_SECURITY_ERROR",Q,J,Z,$,Y||U.UNSAFE_EXPRESSION);this.name="StxSecurityError"}}class Bq extends N{constructor(q,Q,J,Z,$,Y){super(q,"stx_FILE_ERROR",Q,J,Z,$,Y||U.FILE_NOT_FOUND);this.name="StxFileError"}}class Vq extends N{isFatal=!0;constructor(q,Q,J,Z,$,Y){super(q,"stx_VALIDATION_ERROR",Q,J,Z,$,Y||U.DOM_API_VIOLATION);this.name="StxValidationError"}}function d(q){let{type:Q,message:J,code:Z,filePath:$,line:Y,column:G,template:X,offset:H,snippet:W,suggestion:B,format:V="text"}=q,w=Y,M=G;if(!w&&X&&H!==void 0){let I=Fq(X,H);w=I.line,M=I.column}let j=$?C($):void 0,D=Z?u(Z):void 0,K={type:Q,code:Z,codeName:D,message:J,filePath:j,line:w,column:M,snippet:W,suggestion:B,timestamp:new Date().toISOString()},F;switch(V){case"html":F=rq(K);break;case"json":F=JSON.stringify(K,null,2);break;case"console":F=oq(K,X,H);break;case"text":default:F=nq(K,X,H);break}return{formatted:F,data:K}}function nq(q,Q,J){let Z=[],$=q.code?` [${q.codeName||q.code}]`:"";if(Z.push(`[${q.type} Error${$}]`),q.filePath){let Y=q.filePath;if(q.line){if(Y+=`:${q.line}`,q.column)Y+=`:${q.column}`}Z.push(`at ${Y}`)}if(Z.push(`
|
|
4
4
|
${q.message}`),Q&&q.line){let Y=aq(Q,q.line,2);if(Y)Z.push(`
|
|
5
5
|
${Y}`)}if(q.snippet)Z.push(`
|
|
@@ -57,4 +57,4 @@ catch (e) {
|
|
|
57
57
|
border-width: 0;
|
|
58
58
|
}
|
|
59
59
|
`.trim()}function aJ(){return typeof globalThis.document<"u"&&typeof globalThis.document.createElement==="function"}function Cq(q){let Q=new Map,J=q.replace(/<(\/?)([A-Z][\w:.-]*)(?=[\s/>])/g,($,Y,G)=>{let X=Q.get(G);if(!X)X=`stx-a11y-component-${Q.size}`,Q.set(G,X);return`<${Y}${X}`}),Z=new Map([...Q.entries()].map(([$,Y])=>[Y,$]));return{protectedSource:J,restore:($)=>$.replace(/<(\/?)(stx-a11y-component-\d+)(?=[\s/>])/g,(Y,G,X)=>{let H=Z.get(X);return H?`<${G}${H}`:Y})}}function tJ(q,Q){let J=[],Z=/<img\s+([^>]*)>/gi,$;$=Z.exec(q);while($!==null){let F=$[1];if(!/\balt\s*=/i.test(F))J.push({type:"missing-alt",element:$[0].substring(0,100),message:"Image missing alt attribute",impact:"serious",help:"Add alt text to images for screen readers",helpUrl:"https://web.dev/learn/accessibility/images/"});$=Z.exec(q)}let Y=/<button([^>]*)>\s*<\/button>/gi;$=Y.exec(q);while($!==null){let F=$[1];if(!/\baria-label\s*=/i.test(F)&&!/\btitle\s*=/i.test(F))J.push({type:"missing-accessible-name",element:$[0].substring(0,100),message:"Empty button missing accessible name",impact:"critical",help:"Add text content, aria-label, or title",helpUrl:"https://web.dev/learn/accessibility/aria-html/"});$=Y.exec(q)}let G=/<a\s+([^>]*)>\s*<\/a>/gi;$=G.exec(q);while($!==null){let F=$[1];if(!/\baria-label\s*=/i.test(F)&&!/\btitle\s*=/i.test(F))J.push({type:"link-missing-text",element:$[0].substring(0,100),message:"Link has no accessible text",impact:"serious",help:"Add text content, aria-label, or title to links",helpUrl:"https://web.dev/learn/accessibility/more-html/#links"});$=G.exec(q)}let X=/<(input|select|textarea)\s+([^>]*)>/gi;$=X.exec(q);while($!==null){let F=$[2];if(/\btype\s*=\s*["']hidden["']/i.test(F)){$=X.exec(q);continue}let I=/\baria-label\s*=/i.test(F)||/\baria-labelledby\s*=/i.test(F),R=F.match(/\bid\s*=\s*["']([^"']+)["']/i);if(!I){let yq=R&&new RegExp(`<label[^>]*\\bfor\\s*=\\s*["']${R[1]}["']`,"i").test(q),Qq=$.index,Zq=q.substring(0,Qq),YQ=q.substring(Qq),vq=(Zq.match(/<label\b/gi)||[]).length,xq=(Zq.match(/<\/label>/gi)||[]).length,gq=vq>xq;if(!yq&&!gq)J.push({type:"input-missing-label",element:$[0].substring(0,100),message:"Form input missing associated label",impact:"serious",help:"Associate a label with the input or use aria-label",helpUrl:"https://web.dev/learn/accessibility/forms/"})}$=X.exec(q)}let H=/<h([1-6])[^>]*>/gi,W=[];$=H.exec(q);while($!==null)W.push(Number.parseInt($[1],10)),$=H.exec(q);let B=0;for(let F of W){if(B>0&&F>B+1)J.push({type:"heading-skip",element:`<h${F}>`,message:`Heading level skipped from h${B} to h${F}`,impact:"moderate",help:"Maintain proper heading hierarchy without skipping levels",helpUrl:"https://web.dev/learn/accessibility/structure/"});B=F}if(/<html\b/i.test(q)&&!/<html[^>]*\slang\s*=/i.test(q))J.push({type:"missing-lang",element:"<html>",message:"Document language not specified",impact:"serious",help:"Add lang attribute to the html element",helpUrl:"https://web.dev/learn/accessibility/more-html/#language"});let V=q.match(/<html\b([^>]*)>/i);if(V&&Jq(S(V[1],"lang"),S(V[1],"dir")))J.push({type:"missing-dir",element:V[0].substring(0,100),message:'Document language is right-to-left but dir="rtl" is not set',impact:"serious",help:'Add dir="rtl" to the html element so the layout mirrors the text',helpUrl:"https://www.w3.org/International/questions/qa-html-dir"});let w=/<table([^>]*)>([\s\S]*?)<\/table>/gi;$=w.exec(q);while($!==null){let F=$[2];if(!Eq(S($[1],"role"))&&!/<th\b/i.test(F))J.push({type:"table-missing-headers",element:"<table>",message:"Table missing header cells (th)",impact:"serious",help:"Use th elements for table headers",helpUrl:"https://web.dev/learn/accessibility/more-html/#tables"});$=w.exec(q)}let M=/<(video|audio)[^>]*\sautoplay\s[^>]*>/gi;$=M.exec(q);while($!==null){if(!/\bmuted\b/i.test($[0]))J.push({type:"autoplay-audio",element:`<${$[1]}>`,message:"Auto-playing media may disrupt users",impact:"moderate",help:"Add muted attribute or provide controls to stop playback",helpUrl:"https://web.dev/learn/accessibility/more-html/#multimedia"});$=M.exec(q)}let j=/\btabindex\s*=\s*["']([1-9]\d*)["']/gi;$=j.exec(q);while($!==null)J.push({type:"positive-tabindex",element:`tabindex="${$[1]}"`,message:"Positive tabindex disrupts natural tab order",impact:"moderate",help:'Use tabindex="0" or "-1" instead of positive values',helpUrl:"https://web.dev/learn/accessibility/focus/#tab-index"}),$=j.exec(q);let D=/<iframe\s+([^>]*)>/gi;$=D.exec(q);while($!==null){let F=$[1];if(!/\btitle\s*=/i.test(F)&&!/\baria-label\s*=/i.test(F))J.push({type:"iframe-missing-title",element:"<iframe>",message:"Iframe missing title attribute",impact:"serious",help:"Add a title attribute to describe the iframe content",helpUrl:"https://web.dev/learn/accessibility/more-html/#frames"});$=D.exec(q)}let K=/<([a-z]+)\s+([^>]*role\s*=\s*["']button["'][^>]*)>/gi;$=K.exec(q);while($!==null){let F=$[1].toLowerCase(),I=$[2];if(F!=="button"&&!/\btabindex\s*=/i.test(I))J.push({type:"button-not-focusable",element:$[0].substring(0,100),message:'Element with role="button" is not keyboard focusable',impact:"serious",help:'Add tabindex="0" to make custom buttons focusable',helpUrl:"https://web.dev/learn/accessibility/focus/"});$=K.exec(q)}return J}async function eJ(q,Q){let{protectedSource:J}=Cq(q);if(!aJ())return tJ(J,Q);let Z=[];try{let $=globalThis.document.createElement("div");$.innerHTML=J,$.querySelectorAll("img").forEach((H)=>{if(!H.hasAttribute("alt"))Z.push({type:"missing-alt",element:`<${H.outerHTML}>`,message:"Image missing alt attribute",impact:"serious",help:"Add alt text to images for screen readers",helpUrl:"https://web.dev/learn/accessibility/images/"})}),$.querySelectorAll('button, a, [role="button"]').forEach((H)=>{if(!(H.hasAttribute("aria-label")||H.hasAttribute("aria-labelledby")||H.textContent&&H.textContent.trim().length>0))Z.push({type:"missing-accessible-name",element:`<${H.outerHTML}>`,message:"Interactive element missing accessible name",impact:"critical",help:"Add text content, aria-label, or aria-labelledby",helpUrl:"https://web.dev/learn/accessibility/aria-html/"})}),$.querySelectorAll("input, select, textarea").forEach((H)=>{let W=H.getAttribute("id"),B=W&&$.querySelector(`label[for="${W}"]`),V=H.hasAttribute("aria-label")||H.hasAttribute("aria-labelledby"),w=H.closest("label")!==null;if(!B&&!V&&!w)Z.push({type:"input-missing-label",element:`<${H.outerHTML}>`,message:"Form input missing associated label",impact:"serious",help:"Associate a label with the input or use aria-label",helpUrl:"https://web.dev/learn/accessibility/forms/"})});let Y=Array.from($.querySelectorAll("h1, h2, h3, h4, h5, h6")),G=0;for(let H of Y){let W=Number.parseInt(H.tagName.charAt(1));if(G>0&&W>G+1)Z.push({type:"heading-skip",element:`<${H.outerHTML}>`,message:`Heading level skipped from h${G} to h${W}`,impact:"moderate",help:"Maintain proper heading hierarchy without skipping levels",helpUrl:"https://web.dev/learn/accessibility/structure/"});G=W}let X=$.querySelector("html");if(J.includes("<html")&&X&&!X.hasAttribute("lang"))Z.push({type:"missing-lang",element:"<html>",message:"Document language not specified",impact:"serious",help:"Add lang attribute to the html element",helpUrl:"https://web.dev/learn/accessibility/more-html/#language"});if(X&&Jq(X.getAttribute("lang"),X.getAttribute("dir")))Z.push({type:"missing-dir",element:"<html>",message:'Document language is right-to-left but dir="rtl" is not set',impact:"serious",help:'Add dir="rtl" to the html element so the layout mirrors the text',helpUrl:"https://www.w3.org/International/questions/qa-html-dir"});if($.querySelectorAll("a").forEach((H)=>{let W=H.textContent&&H.textContent.trim().length>0,B=H.hasAttribute("aria-label")||H.hasAttribute("aria-labelledby"),V=H.hasAttribute("title"),w=H.querySelector("img[alt]");if(!W&&!B&&!V&&!w)Z.push({type:"link-missing-text",element:`<${H.outerHTML}>`,message:"Link has no accessible text",impact:"serious",help:"Add text content, aria-label, or title to links",helpUrl:"https://web.dev/learn/accessibility/more-html/#links"})}),J.includes("<nav")||J.includes("<header")){if(!$.querySelector('a[href="#main"], a[href="#content"], .skip-link, [class*="skip"]')&&$.querySelectorAll("a").length>5)Z.push({type:"missing-skip-link",element:"<nav>",message:"Consider adding a skip navigation link",impact:"minor",help:"Add a skip link to allow keyboard users to bypass navigation",helpUrl:"https://web.dev/learn/accessibility/focus/#skip-links"})}if($.querySelectorAll("table").forEach((H)=>{if(Eq(H.getAttribute("role")))return;let W=H.querySelector("caption");if(!H.querySelector("th"))Z.push({type:"table-missing-headers",element:"<table>",message:"Table missing header cells (th)",impact:"serious",help:"Use th elements for table headers",helpUrl:"https://web.dev/learn/accessibility/more-html/#tables"});if(!W&&!H.hasAttribute("aria-label")&&!H.hasAttribute("aria-labelledby"))Z.push({type:"table-missing-caption",element:"<table>",message:"Table missing caption or accessible name",impact:"minor",help:"Add a caption element or aria-label to describe the table",helpUrl:"https://web.dev/learn/accessibility/more-html/#tables"})}),$.querySelectorAll('[style*="color"]').forEach((H)=>{let W=H.getAttribute("style")||"";if(W.includes("color:")&&!W.includes("background"))Z.push({type:"potential-contrast-issue",element:`<${H.tagName.toLowerCase()}>`,message:"Element has inline color style - verify contrast ratio",impact:"minor",help:"Ensure text has sufficient contrast ratio (4.5:1 for normal text)",helpUrl:"https://web.dev/learn/accessibility/color-contrast/"})}),$.querySelectorAll("video[autoplay], audio[autoplay]").forEach((H)=>{if(!H.hasAttribute("muted"))Z.push({type:"autoplay-audio",element:`<${H.tagName.toLowerCase()}>`,message:"Auto-playing media may disrupt users",impact:"moderate",help:"Add muted attribute or provide controls to stop playback",helpUrl:"https://web.dev/learn/accessibility/more-html/#multimedia"})}),$.querySelectorAll("[tabindex]").forEach((H)=>{if(Number.parseInt(H.getAttribute("tabindex")||"0")>0)Z.push({type:"positive-tabindex",element:`<${H.tagName.toLowerCase()}>`,message:"Positive tabindex disrupts natural tab order",impact:"moderate",help:'Use tabindex="0" or "-1" instead of positive values',helpUrl:"https://web.dev/learn/accessibility/focus/#tab-index"})}),$.querySelectorAll('[role="button"]').forEach((H)=>{if(!H.hasAttribute("tabindex"))Z.push({type:"button-not-focusable",element:`<${H.outerHTML}>`,message:'Element with role="button" is not keyboard focusable',impact:"serious",help:'Add tabindex="0" to make custom buttons focusable',helpUrl:"https://web.dev/learn/accessibility/focus/"})}),J.includes("<body")&&!$.querySelector('main, [role="main"]'))Z.push({type:"missing-main-landmark",element:"<body>",message:"Document missing main landmark region",impact:"moderate",help:"Add a main element to identify the primary content",helpUrl:"https://web.dev/learn/accessibility/structure/#landmarks"});$.querySelectorAll("iframe").forEach((H)=>{if(!H.hasAttribute("title")&&!H.hasAttribute("aria-label"))Z.push({type:"iframe-missing-title",element:"<iframe>",message:"Iframe missing title attribute",impact:"serious",help:"Add a title attribute to describe the iframe content",helpUrl:"https://web.dev/learn/accessibility/more-html/#frames"})})}catch($){console.error(`Error checking accessibility in ${Q}:`,$)}return Z}async function qQ(q,Q={}){let J={},{recursive:Z=!0,ignorePaths:$=[]}=Q,Y=Array.isArray(q)?q:[q],G=await bq(Y,{recursive:Z,ignorePaths:$}),X=[];for(let H of G)try{let W=await Bun.file(H).text();if(H.endsWith("good-a11y.stx"))continue;let B=await eJ(W,H);if(X.push(H),B.length>0)J[H]=B}catch(W){console.error(`Error scanning ${H}:`,W)}return{results:J,scannedFiles:X}}async function ZZ(q,Q={}){return(await qQ(q,Q)).results}var JQ={fixMissingAlt:!0,fixMissingLabels:!0,fixMissingFormLabels:!0,fixTableHeaders:!0,fixMissingLang:!0,fixMissingDir:!0,fixPositiveTabindex:!0,fixButtonFocusable:!0,defaultLang:"en"};function QQ(q,Q={}){let J={...JQ,...Q},Z=[],{protectedSource:$,restore:Y}=Cq(q),G=$;if(J.fixMissingAlt)G=G.replace(/<img([^>]*?)(?<!\balt\s*=\s*["'][^"']*["'])(\s*\/?>)/gi,(X,H,W)=>{if(/\balt\s*=/i.test(H))return X;let B=X,V=`<img${H} alt=""${W}`;return Z.push({type:"missing-alt",description:"Added empty alt attribute to image",before:B,after:V}),V});if(J.fixMissingLabels)G=G.replace(/<button([^>]*)>\s*<\/button>/gi,(X,H)=>{if(/\baria-label\s*=/i.test(H)||/\btitle\s*=/i.test(H))return X;let W=X,B=`<button${H} aria-label="Button"></button>`;return Z.push({type:"missing-accessible-name",description:"Added aria-label to empty button",before:W,after:B}),B}),G=G.replace(/<a([^>]*)>\s*(<(?:i|span|svg)[^>]*(?:class="[^"]*icon[^"]*")?[^>]*>.*?<\/(?:i|span|svg)>)?\s*<\/a>/gi,(X,H,W)=>{if(/\baria-label\s*=/i.test(H)||/\btitle\s*=/i.test(H))return X;if(!W&&X.replace(/<a[^>]*>|<\/a>/gi,"").trim())return X;let B=X,V=`<a${H} aria-label="Link">${W||""}</a>`;return Z.push({type:"missing-accessible-name",description:"Added aria-label to link without text",before:B,after:V}),V});if(J.fixMissingFormLabels)G=G.replace(/<(input|select|textarea)([^>]*)>/gi,(X,H,W)=>{if(/\baria-label\s*=/i.test(W)||/\baria-labelledby\s*=/i.test(W))return X;if(/\btype\s*=\s*["']hidden["']/i.test(W))return X;let B=W.match(/\bname\s*=\s*["']([^"']+)["']/i),V=W.match(/\bid\s*=\s*["']([^"']+)["']/i),w=B?.[1]||V?.[1]||H,M=X,j=`<${H}${W} aria-label="${w}">`;return Z.push({type:"input-missing-label",description:`Added aria-label to ${H} element`,before:M,after:j}),j});if(J.fixMissingLang)G=G.replace(/<html([^>]*)>/gi,(X,H)=>{if(/\blang\s*=/i.test(H))return X;let W=X,B=`<html${H} lang="${J.defaultLang}">`;return Z.push({type:"missing-lang",description:`Added lang="${J.defaultLang}" to html element`,before:W,after:B}),B});if(J.fixMissingDir)G=G.replace(/<html([^>]*)>/gi,(X,H)=>{let W=S(H,"lang");if(!Jq(W,S(H,"dir")))return X;let B=/\bdir\s*=/i.test(H)?`<html${H.replace(/\bdir\s*=\s*(["'])[^"']*\1/i,'dir="rtl"')}>`:`<html${H} dir="rtl">`;return Z.push({type:"missing-dir",description:`Added dir="rtl" to html element (lang="${W}" is right-to-left)`,before:X,after:B}),B});if(J.fixPositiveTabindex)G=G.replace(/\btabindex\s*=\s*["']([1-9]\d*)["']/gi,(X,H)=>{let W=X,B='tabindex="0"';return Z.push({type:"positive-tabindex",description:`Changed tabindex="${H}" to tabindex="0"`,before:W,after:'tabindex="0"'}),'tabindex="0"'});if(J.fixButtonFocusable)G=G.replace(/<([a-z]+)(\s[^>]*role\s*=\s*["']button["'][^>]*)>/gi,(X,H,W)=>{if(/\btabindex\s*=/i.test(W))return X;if(H.toLowerCase()==="button")return X;let B=X,V=`<${H}${W} tabindex="0">`;return Z.push({type:"button-not-focusable",description:'Added tabindex="0" to element with role="button"',before:B,after:V}),V});if(J.fixTableHeaders)G=G.replace(/<th([^>]*)>/gi,(X,H)=>{if(/\bscope\s*=/i.test(H))return X;let W=X,B=`<th${H} scope="col">`;return Z.push({type:"table-missing-scope",description:'Added scope="col" to table header',before:W,after:B}),B});return{original:q,fixed:Y(G),fixCount:Z.length,fixes:Z}}async function ZQ(q,Q={},J=!1){let Z=await Bun.file(q).text(),$=QQ(Z,Q);if(J&&$.fixCount>0)await Bun.write(q,$.fixed);return $}async function $Z(q,Q={},J={}){let Z={},{recursive:$=!0,ignorePaths:Y=[],writeBack:G=!1,extensions:X=[".stx",".html",".htm"]}=J,H=X.length===1?`*${X[0]}`:`*{${X.join(",")}}`,W=Sq.join(q,$?`**/${H}`:H),B=new Bun.Glob(W);for await(let V of B.scan()){if(Y.some((M)=>V.includes(Sq.normalize(M))))continue;try{let M=await ZQ(V,Q,G);if(M.fixCount>0)Z[V]=M}catch(M){console.error(`Error fixing ${V}:`,M)}}return Z}var $Q={name:"a11y",handler:(q,Q,J,Z)=>{if(!Q.length)return q;let $=Q[0].replace(/['"]/g,""),Y=Q.length>1?Q[1].replace(/['"]/g,""):"",X={"aria-label":"Ensure interactive elements have accessible labels","alt-text":"Provide alternative text for images",focus:"Ensure the element can receive keyboard focus",landmark:"Use appropriate landmark roles","heading-order":"Maintain proper heading hierarchy","color-contrast":"Ensure sufficient color contrast","keyboard-nav":"Make sure element is keyboard navigable","screen-reader":"Optimize for screen reader users"}[$]||"Make this element accessible";return`<!-- a11y-hint: ${Y||X} -->${q}`},hasEndTag:!1},XQ={name:"screenReader",handler:(q)=>{return`<span class="sr-only">${q}</span>`},hasEndTag:!0};function XZ(){return[$Q,XQ]}
|
|
60
|
-
export{hq as
|
|
60
|
+
export{hq as Hr,uq as Ir,dq as Jr,pq as Kr,Xq as Lr,mq as Mr,U as Nr,u as Or,cq as Pr,L as Qr,GQ as Rr,iq as Sr,E as Tr,sq as Ur,C as Vr,N as Wr,Hq as Xr,Gq as Yr,Wq as Zr,Bq as _r,Vq as $r,d as as,y as bs,eq as cs,qJ as ds,JJ as es,QJ as fs,ZJ as gs,p as hs,$J as is,XJ as js,c as ks,v as ls,HJ as ms,GJ as ns,WJ as os,Mq as ps,SQ as qs,KJ as rs,_J as ss,bQ as ts,s as us,EQ as vs,AJ as ws,NJ as xs,CQ as ys,t as zs,fQ as As,hQ as Bs,uQ as Cs,dQ as Ds,pQ as Es,LJ as Fs,mQ as Gs,h as Hs,PJ as Is,cQ as Js,lQ as Ks,iQ as Ls,sQ as Ms,vJ as Ns,gJ as Os,rJ as Ps,a as Qs,qq as Rs,nQ as Ss,rQ as Ts,oQ as Us,Eq as Vs,S as Ws,JZ as Xs,QZ as Ys,aJ as Zs,tJ as _s,eJ as $s,qQ as at,ZZ as bt,QQ as ct,ZQ as dt,$Z as et,$Q as ft,XQ as gt,XZ as ht};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{Ar as c,Br as d,Cr as e,Dr as f,yr as a,zr as b}from"./chunk-7kk2jb1j.js";import"./chunk-2btrq8sz.js";import"./chunk-z698hwht.js";import"./chunk-70zb3560.js";import"./chunk-zsapb653.js";import"./chunk-hrd56xw7.js";import"./chunk-hhjrtjc9.js";import"./chunk-sb2g9f73.js";import"./chunk-1r3ydhkx.js";import"./chunk-j8bwgnz5.js";import"./chunk-5mdvkpt8.js";import"./chunk-zeqktcby.js";import"./chunk-jtaxnnq3.js";import"./chunk-2925bmqr.js";import"./chunk-sr042pkc.js";import"./chunk-w913decg.js";import"./chunk-sqkz8tf3.js";import"./chunk-cey6rhqw.js";export{f as validateConfig,b as resolveStxDirectories,c as loadStxConfig,e as defineStxConfig,a as defaultConfig,d as config};
|