@stacksjs/stx 0.2.152 → 0.2.154
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/animation.js +6 -6
- package/dist/app-shell.js +2 -1
- package/dist/browser-composables.d.ts +8 -0
- package/dist/build-id.d.ts +49 -0
- package/dist/build-id.js +20 -0
- package/dist/build-message.d.ts +10 -0
- package/dist/build-message.js +26 -0
- package/dist/builtins/attrs.js +6 -1
- package/dist/cli.js +1743 -1255
- package/dist/client-script-bundler.js +2 -4
- package/dist/client-script.d.ts +29 -0
- package/dist/client-script.js +142 -97
- package/dist/color-mode-boot.d.ts +46 -10
- package/dist/color-mode-boot.js +53 -13
- package/dist/component-client-factories.js +3 -2
- package/dist/component-renderer.js +10 -21
- package/dist/composables/index.d.ts +8 -1
- package/dist/composables/use-clipboard.d.ts +1 -5
- package/dist/composables/use-clipboard.js +57 -46
- package/dist/composables/use-color-mode.d.ts +19 -4
- package/dist/composables/use-color-mode.js +49 -28
- package/dist/composables/use-router.d.ts +28 -11
- package/dist/composables/use-router.js +63 -9
- package/dist/composables/use-storage.d.ts +14 -15
- package/dist/composables/use-storage.js +63 -2
- package/dist/config.js +22 -7
- package/dist/craft.js +1319 -841
- package/dist/dev-server/crosswind.js +8 -6
- package/dist/dev-server/serve-app.js +13 -7
- package/dist/dev-server/serve-markdown.js +4 -1
- package/dist/dev-server/serve-multi.js +32 -20
- package/dist/dev-server/types.d.ts +8 -1
- package/dist/document-shell.d.ts +120 -0
- package/dist/document-shell.js +161 -14
- package/dist/dynamic-components.js +123 -4
- package/dist/events.d.ts +26 -49
- package/dist/events.js +23 -9
- package/dist/expressions.d.ts +1 -1
- package/dist/expressions.js +3 -3
- package/dist/framework-composables.d.ts +41 -0
- package/dist/framework-composables.js +115 -0
- package/dist/head.js +5 -1
- package/dist/hot-reload.js +8 -2
- package/dist/includes.js +4 -4
- package/dist/index.d.ts +17 -0
- package/dist/index.js +9 -0
- package/dist/isolated-build.d.ts +12 -0
- package/dist/isolated-build.js +18 -0
- package/dist/plugin-system.d.ts +1 -1
- package/dist/process.js +46 -12
- package/dist/production-builder.js +3 -1
- package/dist/production-server.js +4 -1
- package/dist/prop-sentinels.d.ts +31 -0
- package/dist/prop-sentinels.js +7 -0
- package/dist/pwa.js +1258 -780
- package/dist/reactive.js +1 -1
- package/dist/reactivity.d.ts +0 -15
- package/dist/reactivity.js +15 -6
- package/dist/runtime-globals.d.ts +40 -2
- package/dist/runtime-globals.js +90 -0
- package/dist/runtime-injection.d.ts +51 -0
- package/dist/runtime-injection.js +13 -0
- package/dist/script-emit.d.ts +20 -0
- package/dist/script-emit.js +11 -0
- package/dist/script-validation.js +12 -7
- package/dist/signal-processing.js +25 -40
- package/dist/signals-api.d.ts +30 -0
- package/dist/signals-api.js +18 -0
- package/dist/signals.js +532 -85
- package/dist/site-builder/build.js +21 -7
- package/dist/site-builder/seo.js +19 -10
- package/dist/site-builder/theme.js +5 -4
- package/dist/site-builder/types.d.ts +1 -0
- package/dist/ssg.js +1255 -777
- package/dist/state-management.js +4 -1
- package/dist/store-loader.d.ts +0 -11
- package/dist/store-loader.js +27 -3
- package/dist/strict-lint.d.ts +9 -6
- package/dist/strict-lint.js +2 -21
- package/dist/stx.d.ts +125 -22
- package/dist/types/config-types.d.ts +1 -0
- package/dist/unresolved-identifiers.d.ts +50 -0
- package/dist/unresolved-identifiers.js +146 -0
- package/dist/utils.js +3 -3
- package/dist/variable-extractor.js +17 -1
- package/dist/x-element.js +1 -1
- package/package.json +5 -5
- package/stx.d.ts +125 -22
package/dist/plugin-system.d.ts
CHANGED
|
@@ -89,7 +89,7 @@ export declare interface StxPlugin {
|
|
|
89
89
|
registerFilters?: () => Record<string, (value: unknown, ...args: unknown[]) => unknown>
|
|
90
90
|
onRegister?: (options: StxOptions) => void | Promise<void>
|
|
91
91
|
onUnregister?: () => void | Promise<void>
|
|
92
|
-
components?: string
|
|
92
|
+
components?: string | string[]
|
|
93
93
|
functions?: string
|
|
94
94
|
stores?: string
|
|
95
95
|
pages?: string
|
package/dist/process.js
CHANGED
|
@@ -7,7 +7,7 @@ import { processTemplateBindings } from "./reactive-bindings.js";
|
|
|
7
7
|
import { injectAnalytics } from "./analytics.js";
|
|
8
8
|
import { injectHeatmap } from "./heatmap.js";
|
|
9
9
|
import { processAnimationDirectives } from "./animation.js";
|
|
10
|
-
import { processEventDirectives } from "./events.js";
|
|
10
|
+
import { generateRuntimeScript, processEventDirectives } from "./events.js";
|
|
11
11
|
import { extractBridgeData, processClientScript } from "./client-script.js";
|
|
12
12
|
import { processReactiveDirectives } from "./reactive.js";
|
|
13
13
|
import { processMarkdownFileDirectives } from "./assets.js";
|
|
@@ -36,8 +36,9 @@ import { processServerBindings } from "./server-bindings.js";
|
|
|
36
36
|
import { processVueTemplate } from "./vue-template.js";
|
|
37
37
|
import { processDynamicComponents } from "./dynamic-components.js";
|
|
38
38
|
import { dedupeScopedStyles, processScopedStyles } from "./style-scoping.js";
|
|
39
|
-
import { injectColorModeBootScript } from "./color-mode-boot.js";
|
|
40
|
-
import {
|
|
39
|
+
import { injectColorModeBootScript, normalizeCriticalHeadOrder } from "./color-mode-boot.js";
|
|
40
|
+
import { injectBuildId } from "./build-id.js";
|
|
41
|
+
import { applyHtmlAttrs, ensureDocumentShell, hasDocumentShell, injectCloakStyle, injectConfigHeadTags, mergeHtmlAttrs, startsDocument } from "./document-shell.js";
|
|
41
42
|
import { hasSignalsSyntax, convertSignalDirectivesToAttributes, convertSignalLoopsToAttributes, preEvalLiteralReactiveIfs, processSignals } from "./signal-processing.js";
|
|
42
43
|
import { processComponents } from "./component-renderer.js";
|
|
43
44
|
import { processInlineAssets } from "./inline-assets.js";
|
|
@@ -50,6 +51,7 @@ import { deriveLayoutGroup } from "stx-router/layout-metadata";
|
|
|
50
51
|
import { initializeComponentClientFactories, injectComponentClientFactories } from "./component-client-factories.js";
|
|
51
52
|
import { importOnce } from "./lazy-module.js";
|
|
52
53
|
export { injectRouterScript } from "./runtime-injection.js";
|
|
54
|
+
import { injectSignalsRuntime, outputNeedsSignalsRuntime, pageShipsSignalsRuntime } from "./runtime-injection.js";
|
|
53
55
|
export { processJsonDirective, processOnceDirective } from "./misc-directives.js";
|
|
54
56
|
export { validateClientScript } from "./script-validation.js";
|
|
55
57
|
const PARENT_PLACEHOLDER = "<!--PARENT_CONTENT_PLACEHOLDER-->";
|
|
@@ -245,6 +247,8 @@ function placeSignalsRuntimeBeforeScripts(html) {
|
|
|
245
247
|
export async function processDirectives(template, context, filePath, options, dependencies) {
|
|
246
248
|
if (options.ssr === !1 && !options.autoShell && options.buildMode === "spa")
|
|
247
249
|
return template;
|
|
250
|
+
if (context.__stx_signals_gate === void 0)
|
|
251
|
+
context.__stx_signals_gate = usesSignalsInScript(template);
|
|
248
252
|
const isTopLevel = !context.__stxProcessingDepth;
|
|
249
253
|
if (isTopLevel)
|
|
250
254
|
initializeComponentClientFactories(context);
|
|
@@ -268,7 +272,7 @@ export async function processDirectives(template, context, filePath, options, de
|
|
|
268
272
|
pageHeadTitle = rawTitleMatch[1].trim();
|
|
269
273
|
pageHeadRaw = pageHeadRaw.replace(rawTitleMatch[0], "").trim();
|
|
270
274
|
}
|
|
271
|
-
const sectionTitle = context.__sections?.title, pageTitle = runtimeHead.title || pageHeadTitle || sectionTitle, headConfig = {
|
|
275
|
+
const sectionTitle = context.__sections?.title, pageTitle = runtimeHead.title || pageHeadTitle || sectionTitle, titleIsHtml = !runtimeHead.title && (!!pageHeadTitle || !!sectionTitle), headConfig = {
|
|
272
276
|
...baseHeadConfig,
|
|
273
277
|
...pageTitle && { title: pageTitle },
|
|
274
278
|
meta: [...baseHeadConfig.meta || [], ...runtimeHead.meta || []],
|
|
@@ -276,18 +280,21 @@ export async function processDirectives(template, context, filePath, options, de
|
|
|
276
280
|
script: [...baseHeadConfig.script || [], ...runtimeHead.script || []],
|
|
277
281
|
headRaw: [baseHeadConfig.headRaw, pageHeadRaw].filter(Boolean).join(`
|
|
278
282
|
`),
|
|
279
|
-
...runtimeHead.htmlAttrs && { htmlAttrs:
|
|
283
|
+
...runtimeHead.htmlAttrs && { htmlAttrs: mergeHtmlAttrs(baseHeadConfig.htmlAttrs, runtimeHead.htmlAttrs) },
|
|
280
284
|
...runtimeHead.bodyAttrs && { bodyAttrs: { ...baseHeadConfig.bodyAttrs || {}, ...runtimeHead.bodyAttrs } }
|
|
281
285
|
}, alreadyShelled = hasDocumentShell(result);
|
|
282
286
|
result = ensureDocumentShell(result, headConfig, {
|
|
287
|
+
...titleIsHtml && { titleIsHtml: !0 },
|
|
283
288
|
...options.app?.colorMode && { colorMode: options.app.colorMode }
|
|
284
289
|
});
|
|
285
|
-
if (alreadyShelled)
|
|
290
|
+
if (alreadyShelled) {
|
|
286
291
|
result = injectConfigHeadTags(result, baseHeadConfig);
|
|
292
|
+
result = applyHtmlAttrs(result, headConfig.htmlAttrs);
|
|
293
|
+
}
|
|
287
294
|
const layoutComment = result.match(/<!-- stx-layout: ([^ ]+) -->/);
|
|
288
295
|
if (layoutComment && result.includes("<head")) {
|
|
289
296
|
const layoutName = layoutComment[1], layoutGroup = deriveLayoutGroup(layoutName);
|
|
290
|
-
result = result.replace(
|
|
297
|
+
result = result.replace(/<head\b[^>]*>/i, (match) => `${match}
|
|
291
298
|
<meta name="stx-layout" content="${escapeHtmlAttribute(layoutName)}">
|
|
292
299
|
<meta name="stx-layout-group" content="${escapeHtmlAttribute(layoutGroup)}">`);
|
|
293
300
|
}
|
|
@@ -303,6 +310,7 @@ export async function processDirectives(template, context, filePath, options, de
|
|
|
303
310
|
const colorModeConfig = options.app?.colorMode;
|
|
304
311
|
if (colorModeConfig)
|
|
305
312
|
result = injectColorModeBootScript(result, colorModeConfig);
|
|
313
|
+
result = injectBuildId(result);
|
|
306
314
|
result = placeSignalsRuntimeBeforeScripts(result);
|
|
307
315
|
}
|
|
308
316
|
if (isTopLevel)
|
|
@@ -315,6 +323,16 @@ export async function processDirectives(template, context, filePath, options, de
|
|
|
315
323
|
` + storeTag + result.slice(runtime.end);
|
|
316
324
|
}
|
|
317
325
|
} catch {}
|
|
326
|
+
if (isTopLevel)
|
|
327
|
+
try {
|
|
328
|
+
const { getFrameworkComposableScript } = await importOnce("stx/framework-composables", () => import("./framework-composables.js")), frameworkScript = await getFrameworkComposableScript(result);
|
|
329
|
+
if (frameworkScript) {
|
|
330
|
+
const anchor = findScriptBlockByAttribute(result, "data-stx-stores") || findScriptBlockByAttribute(result, "data-stx-runtime");
|
|
331
|
+
if (anchor)
|
|
332
|
+
result = result.slice(0, anchor.end) + `
|
|
333
|
+
` + frameworkScript + result.slice(anchor.end);
|
|
334
|
+
}
|
|
335
|
+
} catch {}
|
|
318
336
|
if (isTopLevel)
|
|
319
337
|
try {
|
|
320
338
|
const { getComposableScript } = await importOnce("stx/composable-loader", () => import("./composable-loader.js")), resolvedComposablesDir = options.composablesDir, composableCode = await getComposableScript(resolvedComposablesDir);
|
|
@@ -325,6 +343,8 @@ export async function processDirectives(template, context, filePath, options, de
|
|
|
325
343
|
` + composableTag + result.slice(anchor.end);
|
|
326
344
|
}
|
|
327
345
|
} catch {}
|
|
346
|
+
if (isTopLevel)
|
|
347
|
+
result = normalizeCriticalHeadOrder(result);
|
|
328
348
|
if (isTopLevel && context.__stx_inject_css !== !1)
|
|
329
349
|
result = await injectCrosswindCSS(result, void 0, options.buildMode === "serve");
|
|
330
350
|
if (isTopLevel)
|
|
@@ -380,8 +400,8 @@ async function processDirectivesInternal(template, context, filePath, options, d
|
|
|
380
400
|
output = output.replace(/@(?:layout|extends)\(\s*['"]([^'"]+)['"]\s*\)/g, "");
|
|
381
401
|
}
|
|
382
402
|
if (!layoutPath && !hasNoLayout && opts.defaultLayout) {
|
|
383
|
-
const
|
|
384
|
-
if (!
|
|
403
|
+
const isDocument = startsDocument(output), hasSections = /@section\s*\(/.test(output);
|
|
404
|
+
if (!isDocument || hasSections) {
|
|
385
405
|
let autoLayoutPath = "", searchDir = path.dirname(filePath);
|
|
386
406
|
const rootDir = opts.layoutsDir ? path.dirname(opts.layoutsDir) : process.cwd();
|
|
387
407
|
for (let i = 0;i < 20; i++) {
|
|
@@ -598,8 +618,8 @@ async function processOtherDirectives(template, context, filePath, options, depe
|
|
|
598
618
|
const { processStreamDirectives } = await importOnce("stx/streaming", () => import("./streaming.js"));
|
|
599
619
|
output = processStreamDirectives(output, context);
|
|
600
620
|
output = processLoops(output, context, filePath, opts);
|
|
601
|
-
output = await processComponents(output, context, filePath, opts, dependencies);
|
|
602
621
|
output = await processDynamicComponents(output, context, filePath, opts, dependencies);
|
|
622
|
+
output = await processComponents(output, context, filePath, opts, dependencies);
|
|
603
623
|
output = processAnimationDirectives(output, context, filePath, opts);
|
|
604
624
|
const { processDeferDirectives } = await importOnce("stx/defer", () => import("./defer.js"));
|
|
605
625
|
output = processDeferDirectives(output, context, filePath);
|
|
@@ -735,7 +755,7 @@ ${snippet}
|
|
|
735
755
|
}
|
|
736
756
|
const hasClientScripts = /<script\b(?![^>]*\bserver\b)[^>]*>[\s\S]*?<\/script>/i.test(output), hasStxUsage = /\bSTX\.\w+/.test(output), alreadyHasRuntime = /window\.STX\s*=/.test(output);
|
|
737
757
|
if (hasClientScripts && hasStxUsage && !alreadyHasRuntime) {
|
|
738
|
-
const runtimeScript = `<script data-stx-scoped>
|
|
758
|
+
const runtimeScript = `<script data-stx-scoped data-stx-run="once">
|
|
739
759
|
${generateLifecycleRuntime()}
|
|
740
760
|
</script>`;
|
|
741
761
|
if (output.includes("</head>")) {
|
|
@@ -785,12 +805,26 @@ ${runtimeScript}`);
|
|
|
785
805
|
for (const { match, attrs, content } of clientScriptMatches) {
|
|
786
806
|
clientScriptsTransformed = !0;
|
|
787
807
|
let processedContent = content;
|
|
788
|
-
validateClientScript(content, filePath, options.strict);
|
|
808
|
+
validateClientScript(content, filePath, options.strict, context.__originalFilePath);
|
|
789
809
|
const scriptResult = await processClientScript(content, { eventBindings, attrs, hasColonDirectives, templateContent: template, filePath, projectRoot: process.cwd(), production: options.buildMode === "compile", serverData });
|
|
790
810
|
output = output.replace(match, () => scriptResult);
|
|
791
811
|
}
|
|
792
812
|
if (clientScriptsTransformed)
|
|
793
813
|
context.__stx_event_bindings = [];
|
|
814
|
+
if (!clientScriptsTransformed && context.__stxProcessingDepth === 1) {
|
|
815
|
+
const orphaned = context.__stx_event_bindings || [];
|
|
816
|
+
if (orphaned.length > 0) {
|
|
817
|
+
const script = generateRuntimeScript(orphaned);
|
|
818
|
+
if (script) {
|
|
819
|
+
const bodyIdx = output.lastIndexOf("</body>");
|
|
820
|
+
output = bodyIdx === -1 ? output + script : output.slice(0, bodyIdx) + script + `
|
|
821
|
+
` + output.slice(bodyIdx);
|
|
822
|
+
}
|
|
823
|
+
context.__stx_event_bindings = [];
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
if (!pageShipsSignalsRuntime(output) && outputNeedsSignalsRuntime(output))
|
|
827
|
+
output = await injectSignalsRuntime(output, opts);
|
|
794
828
|
if (opts.csp?.enabled && opts.csp.useNonce && typeof context.cspNonce === "string")
|
|
795
829
|
output = addNonceToInlineContent(output, context.cspNonce);
|
|
796
830
|
return output;
|
|
@@ -5,7 +5,7 @@ import { buildRuntimeAsset, buildRouterAsset } from "./build-assets.js";
|
|
|
5
5
|
import { compileTemplate } from "./template-compiler.js";
|
|
6
6
|
import { generateManifest, writeManifest } from "./manifest.js";
|
|
7
7
|
import { injectColorModeBootScript } from "./color-mode-boot.js";
|
|
8
|
-
import { ensureDocumentShell } from "./document-shell.js";
|
|
8
|
+
import { applyHtmlAttrs, ensureDocumentShell } from "./document-shell.js";
|
|
9
9
|
import { extractContainerContent } from "./app-shell.js";
|
|
10
10
|
import { injectCrosswindCSS } from "./dev-server/crosswind.js";
|
|
11
11
|
import { loadStxConfig } from "./config.js";
|
|
@@ -88,6 +88,8 @@ export async function buildForProduction(options = {}) {
|
|
|
88
88
|
});
|
|
89
89
|
if (colorModeConfig)
|
|
90
90
|
compiled.html = injectColorModeBootScript(compiled.html, colorModeConfig);
|
|
91
|
+
if (headConfigDefault.htmlAttrs)
|
|
92
|
+
compiled.html = applyHtmlAttrs(compiled.html, headConfigDefault.htmlAttrs);
|
|
91
93
|
if (!/<body[^>]*\bdata-stx=/.test(compiled.html)) {
|
|
92
94
|
const dataStxMatch = compiled.html.match(/<(?!body\b)[a-zA-Z][a-zA-Z0-9-]*\b[^>]*?\s(data-stx="[^"]+")[^>]*>/);
|
|
93
95
|
if (dataStxMatch && dataStxMatch[1]) {
|
|
@@ -4,6 +4,7 @@ import { serve } from "bun";
|
|
|
4
4
|
import { loadManifest } from "./manifest.js";
|
|
5
5
|
import { hydrateTemplateStream, hydrateFragment } from "./template-hydrator.js";
|
|
6
6
|
import { extractLayoutMetadata } from "./app-shell.js";
|
|
7
|
+
import { pageShipsSignalsRuntime } from "./runtime-injection.js";
|
|
7
8
|
import { patternToRegex } from "stx-router";
|
|
8
9
|
const MIME_TYPES = {
|
|
9
10
|
".js": "application/javascript",
|
|
@@ -41,12 +42,13 @@ export async function startProductionServer(options = {}) {
|
|
|
41
42
|
process.exit(1);
|
|
42
43
|
}
|
|
43
44
|
console.log(`[stx] Production server loading ${manifest.routes.length} routes...`);
|
|
44
|
-
const compiledTemplates = new Map, fragmentCache = new Map, layoutMetadataCache = new Map;
|
|
45
|
+
const compiledTemplates = new Map, fragmentCache = new Map, layoutMetadataCache = new Map, runtimeCache = new Map;
|
|
45
46
|
for (const route of manifest.routes)
|
|
46
47
|
try {
|
|
47
48
|
const compiledPath = path.join(outputDir, route.compiledPath), compiled = JSON.parse(await Bun.file(compiledPath).text());
|
|
48
49
|
compiledTemplates.set(route.pattern, compiled);
|
|
49
50
|
layoutMetadataCache.set(route.pattern, extractLayoutMetadata(compiled.html));
|
|
51
|
+
runtimeCache.set(route.pattern, pageShipsSignalsRuntime(compiled.html));
|
|
50
52
|
const fragmentPath = path.join(outputDir, route.fragmentPath);
|
|
51
53
|
if (await Bun.file(fragmentPath).exists())
|
|
52
54
|
fragmentCache.set(route.pattern, await Bun.file(fragmentPath).text());
|
|
@@ -129,6 +131,7 @@ export async function startProductionServer(options = {}) {
|
|
|
129
131
|
headers: {
|
|
130
132
|
"Content-Type": "text/html",
|
|
131
133
|
"X-STX-Fragment": "true",
|
|
134
|
+
...runtimeCache.has(matchedRoute.pattern) ? { "X-STX-Runtime": runtimeCache.get(matchedRoute.pattern) ? "true" : "false" } : {},
|
|
132
135
|
...layoutMetadata ? {
|
|
133
136
|
"X-STX-Layout": layoutMetadata.layout,
|
|
134
137
|
"X-STX-Layout-Group": layoutMetadata.group
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Is this value the bare-boolean-attribute marker? */
|
|
2
|
+
export declare function isBooleanAttributeSentinel(value: unknown): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Last-resort guard for anything about to be written into a response.
|
|
5
|
+
*
|
|
6
|
+
* Nothing should reach output carrying a NUL, but the cost of one escaping is
|
|
7
|
+
* an invalid document and a silent grep, which is far worse than the cost of
|
|
8
|
+
* this check.
|
|
9
|
+
*/
|
|
10
|
+
export declare function stripControlChars(value: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Sentinel values used while resolving component props.
|
|
13
|
+
*
|
|
14
|
+
* A leaf module on purpose: `component-renderer.ts` imports `./builtins`, so a
|
|
15
|
+
* builtin importing the renderer back would be a cycle. Both sides import this
|
|
16
|
+
* instead.
|
|
17
|
+
*
|
|
18
|
+
* @module prop-sentinels
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Marks a prop that was written as a bare HTML boolean attribute — `<X open>`
|
|
22
|
+
* rather than `<X open="true">`.
|
|
23
|
+
*
|
|
24
|
+
* It carries a leading NUL precisely so it cannot collide with an author-written
|
|
25
|
+
* value, which also means it must never survive into a response: a NUL byte
|
|
26
|
+
* makes the document invalid UTF-8, and tools treat the file as binary. `grep`
|
|
27
|
+
* in particular goes SILENT on it — not zero matches, no output at all — so a
|
|
28
|
+
* verification step that greps rendered HTML returns an empty string and reads
|
|
29
|
+
* as a pass (stacksjs/stx#1816).
|
|
30
|
+
*/
|
|
31
|
+
export declare const BOOLEAN_ATTRIBUTE_SENTINEL: '\0stx-boolean-attribute';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const BOOLEAN_ATTRIBUTE_SENTINEL = "\x00stx-boolean-attribute";
|
|
2
|
+
export function isBooleanAttributeSentinel(value) {
|
|
3
|
+
return value === BOOLEAN_ATTRIBUTE_SENTINEL;
|
|
4
|
+
}
|
|
5
|
+
export function stripControlChars(value) {
|
|
6
|
+
return value.indexOf("\x00") === -1 ? value : value.replace(/\0/g, "");
|
|
7
|
+
}
|