@stacksjs/stx 0.2.119 → 0.2.121
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/attrs.d.ts +16 -0
- package/dist/builtins/attrs.js +16 -0
- package/dist/builtins/safe-image.js +2 -9
- package/dist/builtins/stx-image.js +2 -9
- package/dist/builtins/stx-link.js +2 -9
- package/dist/cli.js +1869 -863
- package/dist/client-script-bundler.d.ts +9 -7
- package/dist/client-script-bundler.js +43 -4
- package/dist/client-script.d.ts +24 -0
- package/dist/client-script.js +59 -5
- package/dist/component-library.js +30 -12
- package/dist/component-registry.d.ts +1 -0
- package/dist/component-renderer.js +13 -5
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/index.js +1 -0
- package/dist/composables/use-scroll-lock.d.ts +13 -0
- package/dist/composables/use-scroll-lock.js +55 -0
- package/dist/composition-api.d.ts +1 -1
- package/dist/composition-api.js +13 -4
- package/dist/craft-bridge.d.ts +80 -1
- package/dist/craft-bridge.js +80 -1
- package/dist/craft-components.d.ts +77 -3
- package/dist/craft-components.js +138 -9
- package/dist/craft.js +12708 -118
- package/dist/dev-server/crosswind.d.ts +15 -1
- package/dist/dev-server/crosswind.js +12 -3
- package/dist/dev-server/serve-app.js +3 -3
- package/dist/document-shell.d.ts +17 -0
- package/dist/document-shell.js +72 -2
- package/dist/expressions.js +14 -7
- package/dist/head.d.ts +8 -0
- package/dist/head.js +11 -8
- package/dist/html-masking.d.ts +12 -0
- package/dist/html-masking.js +50 -15
- package/dist/index.d.ts +9 -1
- package/dist/index.js +9 -1
- package/dist/native-build.d.ts +6 -0
- package/dist/native-build.js +77 -60
- package/dist/process.js +11 -3
- package/dist/pwa.js +1232 -508
- package/dist/render.js +6 -1
- package/dist/runtime-globals.d.ts +7 -4
- package/dist/runtime-globals.js +10 -2
- package/dist/runtime-injection.js +15 -1
- package/dist/signal-processing.js +19 -28
- package/dist/signals-api.d.ts +2 -0
- package/dist/signals-api.js +9 -0
- package/dist/signals.js +785 -62
- package/dist/ssg.js +1176 -452
- package/dist/state-management.d.ts +1 -1
- package/dist/state-management.js +1 -1
- package/dist/strict-lint.d.ts +1 -1
- package/dist/strict-lint.js +1 -1
- package/dist/stx.d.ts +6 -0
- package/dist/style-scoping.js +10 -0
- package/dist/utils.js +5 -3
- package/dist/variable-extractor.js +14 -22
- package/dist/vue-template.js +3 -2
- package/dist/x-element.d.ts +2 -2
- package/dist/x-element.js +9 -8
- package/package.json +5 -5
- package/stx.d.ts +6 -0
|
@@ -46,7 +46,20 @@ export declare function rebuildCrosswindCSS(cwd: string): Promise<void>;
|
|
|
46
46
|
*/
|
|
47
47
|
export declare function getCachedCSS(): string;
|
|
48
48
|
/**
|
|
49
|
-
* Extract all CSS class names from HTML content
|
|
49
|
+
* Extract all CSS class names from HTML content.
|
|
50
|
+
*
|
|
51
|
+
* This is the FALLBACK. `generateCrosswindCSS` prefers Crosswind's own
|
|
52
|
+
* `extractClasses`, and the difference is not cosmetic: this function only
|
|
53
|
+
* understands `class=""` and quoted literals inside `x-class` / `:class`, so
|
|
54
|
+
* every class that lives in code — a helper returning a class string, an icon
|
|
55
|
+
* keyed by status, anything inside a `<script client>` block — is invisible to
|
|
56
|
+
* it. Those classes silently generate no CSS and the element renders unstyled,
|
|
57
|
+
* which is what drove projects to pre-generate whole icon stylesheets and ship
|
|
58
|
+
* them alongside the page.
|
|
59
|
+
*
|
|
60
|
+
* Keeping a second, weaker copy of Crosswind's extraction rules in this package
|
|
61
|
+
* is what let the two drift apart in the first place. It stays only for the
|
|
62
|
+
* case where the installed Crosswind predates the export.
|
|
50
63
|
*/
|
|
51
64
|
export declare function extractClassNames(htmlContent: string): Set<string>;
|
|
52
65
|
/**
|
|
@@ -64,6 +77,7 @@ declare interface CrosswindModule {
|
|
|
64
77
|
config: CrosswindConfig
|
|
65
78
|
build?: (config: CrosswindConfig) => Promise<CrosswindBuildResult>
|
|
66
79
|
defaultConfig?: CrosswindConfig
|
|
80
|
+
extractClasses?: (content: string) => Set<string>
|
|
67
81
|
}
|
|
68
82
|
declare interface CrosswindConfig {
|
|
69
83
|
content?: string[]
|
|
@@ -44,7 +44,8 @@ async function tryImportCrosswind(importPath) {
|
|
|
44
44
|
CSSGenerator: pkg.CSSGenerator,
|
|
45
45
|
config: pkg.config,
|
|
46
46
|
build: pkg.build,
|
|
47
|
-
defaultConfig: pkg.defaultConfig
|
|
47
|
+
defaultConfig: pkg.defaultConfig,
|
|
48
|
+
extractClasses: pkg.extractClasses
|
|
48
49
|
};
|
|
49
50
|
} catch {}
|
|
50
51
|
return null;
|
|
@@ -97,7 +98,15 @@ export async function loadCrosswind() {
|
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
return null;
|
|
100
|
-
}
|
|
101
|
+
};
|
|
102
|
+
if (process.env.CROSSWIND_SRC) {
|
|
103
|
+
const explicitPath = path.resolve(process.env.CROSSWIND_SRC), explicitModule = await loadFrom([explicitPath]);
|
|
104
|
+
if (!explicitModule)
|
|
105
|
+
throw Error(`CROSSWIND_SRC did not resolve to a Crosswind module: ${explicitPath}`);
|
|
106
|
+
crosswindModule = explicitModule;
|
|
107
|
+
return crosswindModule;
|
|
108
|
+
}
|
|
109
|
+
const projectModule = await loadFrom(findProjectCrosswindPaths());
|
|
101
110
|
if (projectModule) {
|
|
102
111
|
crosswindModule = projectModule;
|
|
103
112
|
return crosswindModule;
|
|
@@ -243,7 +252,7 @@ export async function generateCrosswindCSS(htmlContent, appDir) {
|
|
|
243
252
|
const hw = await loadCrosswind();
|
|
244
253
|
if (!hw)
|
|
245
254
|
return "";
|
|
246
|
-
const classes = extractClassNames(htmlContent);
|
|
255
|
+
const classes = typeof hw.extractClasses === "function" ? hw.extractClasses(htmlContent) : extractClassNames(htmlContent);
|
|
247
256
|
if (classes.size === 0)
|
|
248
257
|
return "";
|
|
249
258
|
const resolveRoot = appDir ? path.resolve(appDir) : process.cwd();
|
|
@@ -226,9 +226,9 @@ export async function serveApp(appDir = ".", options = {}) {
|
|
|
226
226
|
const context = {
|
|
227
227
|
__filename: route.filePath,
|
|
228
228
|
__dirname: path.dirname(route.filePath),
|
|
229
|
-
params: requestParams ?? {}
|
|
230
|
-
|
|
231
|
-
|
|
229
|
+
params: requestParams ?? {},
|
|
230
|
+
__stx_runtime_head: {}
|
|
231
|
+
};
|
|
232
232
|
for (const scriptBody of serverScripts)
|
|
233
233
|
try {
|
|
234
234
|
await extractVariables(scriptBody, context, route.filePath);
|
package/dist/document-shell.d.ts
CHANGED
|
@@ -6,6 +6,23 @@ import type { AppHeadConfig } from './types/config-types';
|
|
|
6
6
|
* the runtime's late injection.
|
|
7
7
|
*/
|
|
8
8
|
export declare function injectCloakStyle(html: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Pull the page's own `<link>` / `<style>` off the front of a fragment so the
|
|
11
|
+
* shell can put them in `<head>` where they belong.
|
|
12
|
+
*
|
|
13
|
+
* A fragment page (no `<html>/<head>/<body>` of its own) writes its font links
|
|
14
|
+
* and scoped styles at the top of the file. Without this they land verbatim in
|
|
15
|
+
* `<body>`, which *renders* fine — browsers honour `<link>` and `<style>` in
|
|
16
|
+
* body — but breaks SPA navigation: the router reconciles `head style` and
|
|
17
|
+
* `head link[rel=stylesheet]` only, so on a container-only swap the incoming
|
|
18
|
+
* page's CSS is never applied and the form/page paints unstyled. It looked
|
|
19
|
+
* correct on reload and wrong on navigation, which is what made it hard to see.
|
|
20
|
+
*
|
|
21
|
+
* Deliberately conservative: only the leading run is hoisted (whitespace,
|
|
22
|
+
* comments and `<script>` blocks are stepped over, never moved), so a `<style>`
|
|
23
|
+
* sitting next to the markup it styles further down the page is left alone.
|
|
24
|
+
*/
|
|
25
|
+
export declare function hoistLeadingHeadTags(content: string): { body: string, hoisted: string[] };
|
|
9
26
|
/**
|
|
10
27
|
* Generate the full HTML document shell wrapping page content.
|
|
11
28
|
*
|
package/dist/document-shell.js
CHANGED
|
@@ -8,6 +8,75 @@ export function injectCloakStyle(html) {
|
|
|
8
8
|
return `${html.slice(0, headCloseIdx)}${CLOAK_STYLE}
|
|
9
9
|
${html.slice(headCloseIdx)}`;
|
|
10
10
|
}
|
|
11
|
+
export function hoistLeadingHeadTags(content) {
|
|
12
|
+
const hoisted = [];
|
|
13
|
+
let i = 0;
|
|
14
|
+
while (i < content.length) {
|
|
15
|
+
const rest = content.slice(i), ws = rest.match(/^\s+/);
|
|
16
|
+
if (ws) {
|
|
17
|
+
i += ws[0].length;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (rest.startsWith("<!--")) {
|
|
21
|
+
const end = content.indexOf("-->", i);
|
|
22
|
+
if (end === -1)
|
|
23
|
+
break;
|
|
24
|
+
i = end + 3;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const scriptOpen = rest.match(/^<script\b[^>]*>/i);
|
|
28
|
+
if (scriptOpen) {
|
|
29
|
+
const end = content.toLowerCase().indexOf("</script>", i + scriptOpen[0].length);
|
|
30
|
+
if (end === -1)
|
|
31
|
+
break;
|
|
32
|
+
i = end + 9;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const link = rest.match(/^<link\b[^>]*>/i);
|
|
36
|
+
if (link) {
|
|
37
|
+
hoisted.push(link[0]);
|
|
38
|
+
i += link[0].length;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const meta = rest.match(/^<meta\b[^>]*>/i);
|
|
42
|
+
if (meta) {
|
|
43
|
+
hoisted.push(meta[0]);
|
|
44
|
+
i += meta[0].length;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const style = rest.match(/^<style\b[^>]*>[\s\S]*?<\/style>/i);
|
|
48
|
+
if (style) {
|
|
49
|
+
hoisted.push(style[0]);
|
|
50
|
+
i += style[0].length;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
if (hoisted.length === 0)
|
|
56
|
+
return { body: content, hoisted };
|
|
57
|
+
let body = "", j = 0;
|
|
58
|
+
while (j < content.length && j < i) {
|
|
59
|
+
const rest = content.slice(j), link = rest.match(/^<link\b[^>]*>/i);
|
|
60
|
+
if (link && hoisted.includes(link[0])) {
|
|
61
|
+
j += link[0].length;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const meta = rest.match(/^<meta\b[^>]*>/i);
|
|
65
|
+
if (meta && hoisted.includes(meta[0])) {
|
|
66
|
+
j += meta[0].length;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const style = rest.match(/^<style\b[^>]*>[\s\S]*?<\/style>/i);
|
|
70
|
+
if (style && hoisted.includes(style[0])) {
|
|
71
|
+
j += style[0].length;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
body += content[j];
|
|
75
|
+
j++;
|
|
76
|
+
}
|
|
77
|
+
body += content.slice(i);
|
|
78
|
+
return { body, hoisted };
|
|
79
|
+
}
|
|
11
80
|
export function generateDocumentShell(content, headConfig = {}, options = {}) {
|
|
12
81
|
const {
|
|
13
82
|
title: configTitle = "stx App",
|
|
@@ -34,7 +103,7 @@ export function generateDocumentShell(content, headConfig = {}, options = {}) {
|
|
|
34
103
|
return ` <script>${s.content}</script>`;
|
|
35
104
|
return "";
|
|
36
105
|
}).filter(Boolean).join(`
|
|
37
|
-
`), bodyAttrStr = Object.entries(bodyAttrs).map(([k, v]) => ` ${k}="${v}"`).join(""), bodyClassStr = bodyClass ? ` class="${bodyClass}"` : "", headParts = [
|
|
106
|
+
`), bodyAttrStr = Object.entries(bodyAttrs).map(([k, v]) => ` ${k}="${v}"`).join(""), bodyClassStr = bodyClass ? ` class="${bodyClass}"` : "", { body: pageBody, hoisted: pageHeadTags } = hoistLeadingHeadTags(content), headParts = [
|
|
38
107
|
metaTags,
|
|
39
108
|
` <title>${pageTitle}</title>`,
|
|
40
109
|
` ${CLOAK_STYLE}`,
|
|
@@ -42,10 +111,11 @@ export function generateDocumentShell(content, headConfig = {}, options = {}) {
|
|
|
42
111
|
configHeadScripts,
|
|
43
112
|
headRaw ? ` ${headRaw}` : "",
|
|
44
113
|
...(options.styles || []).map((s) => ` ${s}`),
|
|
114
|
+
...pageHeadTags.map((s) => ` ${s}`),
|
|
45
115
|
...(options.headScripts || []).map((s) => ` ${s}`),
|
|
46
116
|
options.headStack || ""
|
|
47
117
|
].filter(Boolean), bodyParts = [
|
|
48
|
-
|
|
118
|
+
pageBody,
|
|
49
119
|
...(options.bodyScripts || []).map((s) => s),
|
|
50
120
|
options.bodyStack || ""
|
|
51
121
|
].filter(Boolean);
|
package/dist/expressions.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createSafeFunction, isExpressionSafe, safeEvaluate } from "./safe-evaluator.js";
|
|
2
2
|
import { createDetailedErrorMessage } from "./utils.js";
|
|
3
3
|
import { createPlaceholder } from "./placeholder.js";
|
|
4
|
-
import { maskAtElementPosition, matchScriptElement, matchStyleElement } from "./html-masking.js";
|
|
4
|
+
import { maskAtElementPosition, matchScriptElement, matchStyleElement, restoreStashedScripts, stashScriptElements } from "./html-masking.js";
|
|
5
5
|
const customFilters = {}, translateRegexCache = new Map;
|
|
6
6
|
function getTranslateRegex(key) {
|
|
7
7
|
let re = translateRegexCache.get(key);
|
|
@@ -236,10 +236,12 @@ export function escapeHtml(unsafe) {
|
|
|
236
236
|
return unsafe.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
237
237
|
}
|
|
238
238
|
export function usesSignalsInScript(template) {
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
239
|
+
const { scripts } = stashScriptElements(template);
|
|
240
|
+
for (const script of scripts) {
|
|
241
|
+
const match = script.match(/^<script\b([^>]*)>([\s\S]*?)<\/script\s*>$/i);
|
|
242
|
+
if (!match || /\bserver\b|\bsrc\s*=/.test(match[1]))
|
|
243
|
+
continue;
|
|
244
|
+
const content = match[2];
|
|
243
245
|
if (/\b(state|derived|effect|ref|reactive|computed|watch|watchEffect)\s*(?:<[^>]*>)?\s*\(/.test(content))
|
|
244
246
|
return !0;
|
|
245
247
|
}
|
|
@@ -324,7 +326,11 @@ export function interpolateScriptExpressions(scriptBody, context) {
|
|
|
324
326
|
return output;
|
|
325
327
|
}
|
|
326
328
|
export function interpolateScriptsInTemplate(template, context, options = {}) {
|
|
327
|
-
|
|
329
|
+
const { output, scripts } = stashScriptElements(template), interpolatedScripts = scripts.map((full) => {
|
|
330
|
+
const match = full.match(/^<script\b([^>]*)>([\s\S]*?)<\/script\s*>$/i), opening = full.match(/^<script\b[^>]*>/i), closingStart = full.search(/<\/script\s*>$/i);
|
|
331
|
+
if (!match || !opening || closingStart === -1)
|
|
332
|
+
return full;
|
|
333
|
+
const attrs = match[1], body = match[2];
|
|
328
334
|
if (/\bsrc\s*=/.test(attrs))
|
|
329
335
|
return full;
|
|
330
336
|
if (/\bdata-raw\b/.test(attrs))
|
|
@@ -334,8 +340,9 @@ export function interpolateScriptsInTemplate(template, context, options = {}) {
|
|
|
334
340
|
if (options.skipServer && /\bserver\b/.test(attrs))
|
|
335
341
|
return full;
|
|
336
342
|
const interpolated = interpolateScriptExpressions(body, context);
|
|
337
|
-
return
|
|
343
|
+
return opening[0] + interpolated + full.slice(closingStart);
|
|
338
344
|
});
|
|
345
|
+
return restoreStashedScripts(output, interpolatedScripts);
|
|
339
346
|
}
|
|
340
347
|
export function processExpressions(template, context, filePath, options) {
|
|
341
348
|
let output = template;
|
package/dist/head.d.ts
CHANGED
|
@@ -31,6 +31,10 @@ export declare function resetHead(): void;
|
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
33
|
export declare function useHead(config: HeadConfig): void;
|
|
34
|
+
/**
|
|
35
|
+
* Merge two head configs.
|
|
36
|
+
*/
|
|
37
|
+
export declare function mergeHeadConfigs(base: HeadConfig, override: HeadConfig): HeadConfig;
|
|
34
38
|
/**
|
|
35
39
|
* Set SEO meta tags with a simplified API.
|
|
36
40
|
*
|
|
@@ -45,6 +49,10 @@ export declare function useHead(config: HeadConfig): void;
|
|
|
45
49
|
* ```
|
|
46
50
|
*/
|
|
47
51
|
export declare function useSeoMeta(config: SeoMeta): void;
|
|
52
|
+
/**
|
|
53
|
+
* Convert SEO metadata into a head configuration without mutating global state.
|
|
54
|
+
*/
|
|
55
|
+
export declare function seoMetaToHeadConfig(config: SeoMeta): HeadConfig;
|
|
48
56
|
/**
|
|
49
57
|
* Define page-level metadata.
|
|
50
58
|
*
|
package/dist/head.js
CHANGED
|
@@ -13,9 +13,9 @@ export function resetHead() {
|
|
|
13
13
|
currentPageMeta = {};
|
|
14
14
|
}
|
|
15
15
|
export function useHead(config) {
|
|
16
|
-
currentHead =
|
|
16
|
+
currentHead = mergeHeadConfigs(currentHead, config);
|
|
17
17
|
}
|
|
18
|
-
function
|
|
18
|
+
export function mergeHeadConfigs(base, override) {
|
|
19
19
|
return {
|
|
20
20
|
title: override.title ?? base.title,
|
|
21
21
|
titleTemplate: override.titleTemplate ?? base.titleTemplate,
|
|
@@ -29,6 +29,9 @@ function mergeHead(base, override) {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
export function useSeoMeta(config) {
|
|
32
|
+
useHead(seoMetaToHeadConfig(config));
|
|
33
|
+
}
|
|
34
|
+
export function seoMetaToHeadConfig(config) {
|
|
32
35
|
const meta = [];
|
|
33
36
|
if (config.description)
|
|
34
37
|
meta.push({ name: "description", content: config.description });
|
|
@@ -82,12 +85,12 @@ export function useSeoMeta(config) {
|
|
|
82
85
|
const link = [];
|
|
83
86
|
if (config.canonical)
|
|
84
87
|
link.push({ rel: "canonical", href: config.canonical });
|
|
85
|
-
|
|
88
|
+
return {
|
|
86
89
|
title: config.title,
|
|
87
90
|
titleTemplate: config.titleTemplate,
|
|
88
91
|
meta,
|
|
89
92
|
link
|
|
90
|
-
}
|
|
93
|
+
};
|
|
91
94
|
}
|
|
92
95
|
export function definePageMeta(config) {
|
|
93
96
|
currentPageMeta = { ...currentPageMeta, ...config };
|
|
@@ -206,15 +209,15 @@ export function processHeadDirective(content) {
|
|
|
206
209
|
}
|
|
207
210
|
export function processTitleDirective(content, context) {
|
|
208
211
|
return content.replace(/@title\s*\(\s*(?:(['"`])(.+?)\1|([^)]+))\s*\)/g, (_, quote, quotedTitle, unquotedTitle) => {
|
|
209
|
-
const resolvedTitle = quote ? quotedTitle : context[(unquotedTitle || "").trim()] ?? unquotedTitle;
|
|
210
|
-
|
|
212
|
+
const resolvedTitle = quote ? quotedTitle : context[(unquotedTitle || "").trim()] ?? unquotedTitle, existing = context.__stx_runtime_head ?? {};
|
|
213
|
+
context.__stx_runtime_head = mergeHeadConfigs(existing, { title: resolvedTitle });
|
|
211
214
|
return "";
|
|
212
215
|
});
|
|
213
216
|
}
|
|
214
217
|
export function processMetaDirective(content, context) {
|
|
215
218
|
return content.replace(/@meta\s*\(\s*(['"`])(.+?)\1\s*,\s*(?:(['"`])(.+?)\3|([^)]+))\s*\)/g, (_, _q1, name, q2, quotedValue, unquotedValue) => {
|
|
216
|
-
const value = q2 ? quotedValue : unquotedValue, resolvedValue = q2 ? value : context[(value || "").trim()] ?? value, meta = name.includes(":") ? { property: name, content: resolvedValue } : { name, content: resolvedValue };
|
|
217
|
-
|
|
219
|
+
const value = q2 ? quotedValue : unquotedValue, resolvedValue = q2 ? value : context[(value || "").trim()] ?? value, meta = name.includes(":") ? { property: name, content: resolvedValue } : { name, content: resolvedValue }, existing = context.__stx_runtime_head ?? {};
|
|
220
|
+
context.__stx_runtime_head = mergeHeadConfigs(existing, { meta: [meta] });
|
|
218
221
|
return "";
|
|
219
222
|
});
|
|
220
223
|
}
|
package/dist/html-masking.d.ts
CHANGED
|
@@ -4,6 +4,13 @@ export declare function matchScriptElement(html: string, i: number): number;
|
|
|
4
4
|
export declare function matchStyleElement(html: string, i: number): number;
|
|
5
5
|
/** Matches an HTML comment `<!-- … -->` (through the first `-->`). */
|
|
6
6
|
export declare function matchHtmlComment(html: string, i: number): number;
|
|
7
|
+
/**
|
|
8
|
+
* Find tokens that begin where an HTML element can actually start.
|
|
9
|
+
*
|
|
10
|
+
* The walk also treats comments and script/style raw-text bodies as opaque, so
|
|
11
|
+
* callers never see tag-like text nested inside those regions.
|
|
12
|
+
*/
|
|
13
|
+
export declare function scanAtElementPosition(html: string, match: TokenMatcher): ElementPositionToken[];
|
|
7
14
|
/**
|
|
8
15
|
* Mask every token (per `match`) that begins at element position, replacing it
|
|
9
16
|
* with `placeholder(token, index)`. Returns the rewritten string plus the ordered
|
|
@@ -22,6 +29,11 @@ export declare function maskAtElementPosition(html: string, match: TokenMatcher,
|
|
|
22
29
|
export declare function stashScriptElements(html: string): { output: string, scripts: string[] };
|
|
23
30
|
/** Restore scripts stashed by {@link stashScriptElements}. */
|
|
24
31
|
export declare function restoreStashedScripts(html: string, scripts: string[]): string;
|
|
32
|
+
export declare interface ElementPositionToken {
|
|
33
|
+
start: number
|
|
34
|
+
end: number
|
|
35
|
+
token: string
|
|
36
|
+
}
|
|
25
37
|
/**
|
|
26
38
|
* Element-position-aware masking.
|
|
27
39
|
*
|
package/dist/html-masking.js
CHANGED
|
@@ -24,15 +24,33 @@ export function matchHtmlComment(html, i) {
|
|
|
24
24
|
return -1;
|
|
25
25
|
return closeRel + 3;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
function matchOpaqueRegion(html, i) {
|
|
28
|
+
if (html.startsWith("<!--", i)) {
|
|
29
|
+
const end = matchHtmlComment(html, i);
|
|
30
|
+
return end === -1 ? html.length : end;
|
|
31
|
+
}
|
|
32
|
+
for (const [open, close] of [
|
|
33
|
+
[SCRIPT_OPEN, SCRIPT_CLOSE],
|
|
34
|
+
[STYLE_OPEN, STYLE_CLOSE]
|
|
35
|
+
]) {
|
|
36
|
+
open.lastIndex = i;
|
|
37
|
+
const opening = open.exec(html);
|
|
38
|
+
if (!opening || opening.index !== i)
|
|
39
|
+
continue;
|
|
40
|
+
close.lastIndex = open.lastIndex;
|
|
41
|
+
const closing = close.exec(html);
|
|
42
|
+
return closing ? closing.index + closing[0].length : html.length;
|
|
43
|
+
}
|
|
44
|
+
return -1;
|
|
45
|
+
}
|
|
46
|
+
export function scanAtElementPosition(html, match) {
|
|
28
47
|
const tokens = [];
|
|
29
|
-
let
|
|
48
|
+
let i = 0;
|
|
30
49
|
const n = html.length;
|
|
31
50
|
let inTag = !1, quote = null;
|
|
32
51
|
while (i < n) {
|
|
33
52
|
const ch = html[i];
|
|
34
53
|
if (inTag) {
|
|
35
|
-
output += ch;
|
|
36
54
|
if (quote) {
|
|
37
55
|
if (ch === quote)
|
|
38
56
|
quote = null;
|
|
@@ -43,23 +61,40 @@ export function maskAtElementPosition(html, match, placeholder) {
|
|
|
43
61
|
i++;
|
|
44
62
|
continue;
|
|
45
63
|
}
|
|
46
|
-
if (ch
|
|
47
|
-
const end = match(html, i);
|
|
48
|
-
if (end > i) {
|
|
49
|
-
output += placeholder(html.slice(i, end), tokens.length);
|
|
50
|
-
tokens.push(html.slice(i, end));
|
|
51
|
-
i = end;
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (/^<\/?[a-zA-Z]/.test(html.slice(i, i + 2)))
|
|
55
|
-
inTag = !0;
|
|
56
|
-
output += ch;
|
|
64
|
+
if (ch !== "<") {
|
|
57
65
|
i++;
|
|
58
66
|
continue;
|
|
59
67
|
}
|
|
60
|
-
|
|
68
|
+
const end = match(html, i);
|
|
69
|
+
if (end > i) {
|
|
70
|
+
tokens.push({ start: i, end, token: html.slice(i, end) });
|
|
71
|
+
i = end;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const opaqueEnd = matchOpaqueRegion(html, i);
|
|
75
|
+
if (opaqueEnd > i) {
|
|
76
|
+
i = opaqueEnd;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (/^<\/?[a-zA-Z]/.test(html.slice(i, i + 2)))
|
|
80
|
+
inTag = !0;
|
|
61
81
|
i++;
|
|
62
82
|
}
|
|
83
|
+
return tokens;
|
|
84
|
+
}
|
|
85
|
+
export function maskAtElementPosition(html, match, placeholder) {
|
|
86
|
+
const matches = scanAtElementPosition(html, match);
|
|
87
|
+
if (matches.length === 0)
|
|
88
|
+
return { output: html, tokens: [] };
|
|
89
|
+
const tokens = matches.map((item) => item.token);
|
|
90
|
+
let output = "", cursor = 0;
|
|
91
|
+
for (let index = 0;index < matches.length; index++) {
|
|
92
|
+
const item = matches[index];
|
|
93
|
+
output += html.slice(cursor, item.start);
|
|
94
|
+
output += placeholder(item.token, index);
|
|
95
|
+
cursor = item.end;
|
|
96
|
+
}
|
|
97
|
+
output += html.slice(cursor);
|
|
63
98
|
return { output, tokens };
|
|
64
99
|
}
|
|
65
100
|
export function stashScriptElements(html) {
|
package/dist/index.d.ts
CHANGED
|
@@ -131,7 +131,15 @@ export * from './hydration';
|
|
|
131
131
|
// ssg moved to stx/ssg
|
|
132
132
|
export * from './ssr';
|
|
133
133
|
// State management — explicit exports to avoid conflicts with runtime.ts and reactivity.ts
|
|
134
|
-
export {
|
|
134
|
+
export {
|
|
135
|
+
createStore,
|
|
136
|
+
defineStore,
|
|
137
|
+
getStore,
|
|
138
|
+
getStoreNames,
|
|
139
|
+
hasStore,
|
|
140
|
+
registerStoresClient,
|
|
141
|
+
useStore,
|
|
142
|
+
} from './state-management';
|
|
135
143
|
// visual-testing moved to stx/visual-testing
|
|
136
144
|
export * from './image-optimization/index';
|
|
137
145
|
export * from './media/index';
|
package/dist/index.js
CHANGED
|
@@ -84,7 +84,15 @@ export * from "./client-script.js";
|
|
|
84
84
|
export * from "./component-hmr.js";
|
|
85
85
|
export * from "./hydration.js";
|
|
86
86
|
export * from "./ssr.js";
|
|
87
|
-
export {
|
|
87
|
+
export {
|
|
88
|
+
createStore,
|
|
89
|
+
defineStore,
|
|
90
|
+
getStore,
|
|
91
|
+
getStoreNames,
|
|
92
|
+
hasStore,
|
|
93
|
+
registerStoresClient,
|
|
94
|
+
useStore
|
|
95
|
+
} from "./state-management.js";
|
|
88
96
|
export * from "./image-optimization/index.js";
|
|
89
97
|
export * from "./media/index.js";
|
|
90
98
|
export * from "./build-views.js";
|
package/dist/native-build.d.ts
CHANGED
|
@@ -62,10 +62,16 @@ export declare interface NativeBuildConfig {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
systemTray?: boolean
|
|
65
|
+
menubarOnly?: boolean
|
|
66
|
+
infoPlist?: Record<string, string | number | boolean>
|
|
67
|
+
minimumSystemVersion?: string
|
|
68
|
+
category?: string
|
|
69
|
+
copyright?: string
|
|
65
70
|
hotReload?: boolean
|
|
66
71
|
devTools?: boolean
|
|
67
72
|
craftPath?: string
|
|
68
73
|
env?: Record<string, string>
|
|
74
|
+
context?: Record<string, unknown>
|
|
69
75
|
verbose?: boolean
|
|
70
76
|
}
|
|
71
77
|
export declare interface NativeBuildResult {
|