@openelement/ssg 0.41.0-alpha.1
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/LICENSE +21 -0
- package/README.md +21 -0
- package/package.json +30 -0
- package/src/build-postprocess.d.ts +24 -0
- package/src/build-postprocess.js +74 -0
- package/src/cem-compat.js +226 -0
- package/src/entry-generators.d.ts +3 -0
- package/src/entry-generators.js +126 -0
- package/src/entry-render-helpers.js +307 -0
- package/src/entry-render-runtime.js +94 -0
- package/src/entry-render-ssg.js +169 -0
- package/src/entry-renderer.d.ts +87 -0
- package/src/entry-renderer.js +555 -0
- package/src/external-resolver.d.ts +62 -0
- package/src/external-resolver.js +285 -0
- package/src/index.d.ts +31 -0
- package/src/index.js +28 -0
- package/src/island-manifest.d.ts +27 -0
- package/src/island-manifest.js +78 -0
- package/src/postprocess.d.ts +73 -0
- package/src/postprocess.js +376 -0
- package/src/route-scanner-fs.js +29 -0
- package/src/route-scanner.d.ts +132 -0
- package/src/route-scanner.js +497 -0
- package/src/route-type-generator.d.ts +29 -0
- package/src/route-type-generator.js +99 -0
- package/src/ssg-dynamic.js +66 -0
- package/src/ssg-helpers.d.ts +8 -0
- package/src/ssg-helpers.js +96 -0
- package/src/ssg-i18n.js +78 -0
- package/src/ssg-render.d.ts +3 -0
- package/src/ssg-render.js +162 -0
- package/src/ssg-report.js +172 -0
- package/src/ssr-polyfills.d.ts +15 -0
- package/src/ssr-polyfills.js +26 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zhi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# @openelement/ssg
|
|
2
|
+
|
|
3
|
+
Adapter-agnostic static site generation engine for openElement.
|
|
4
|
+
|
|
5
|
+
This package owns the build-time SSG pipeline:
|
|
6
|
+
|
|
7
|
+
- Route scanning and island metadata extraction.
|
|
8
|
+
- Entry descriptor construction and Hono server-entry code generation.
|
|
9
|
+
- Parallel/sequential static page rendering.
|
|
10
|
+
- HTML post-processing, island manifest generation, and SSR admission planning.
|
|
11
|
+
|
|
12
|
+
`@openelement/ssg` depends on `@openelement/core`, `hono`, and `typescript` — it has no Vite dependency. Generated server entries may import optional packages such as `@openelement/content`, `@openelement/router`, and `@openelement/app` when the consuming project uses those features. Build adapters such as `@openelement/adapter-vite` delegate SSG orchestration to this engine and provide only adapter-specific glue.
|
|
13
|
+
|
|
14
|
+
Most users should not import this package directly; use the framework entry
|
|
15
|
+
`@openelement/app` or the adapter CLI instead.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @openelement/ssg
|
|
21
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openelement/ssg",
|
|
3
|
+
"version": "0.41.0-alpha.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./src/index.js",
|
|
6
|
+
"types": "./src/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./src/index.d.ts",
|
|
10
|
+
"import": "./src/index.js",
|
|
11
|
+
"default": "./src/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/open-element/openelement.git"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"openelement",
|
|
20
|
+
"web-components",
|
|
21
|
+
"ssg",
|
|
22
|
+
"framework",
|
|
23
|
+
"deno"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@openelement/protocol": "^0.41.0-alpha.1",
|
|
27
|
+
"@openelement/core": "^0.41.0-alpha.1",
|
|
28
|
+
"@openelement/content": "^0.41.0-alpha.1"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { HydrationStrategy } from '@openelement/protocol/framework';
|
|
2
|
+
import type { IslandDecl } from '@openelement/protocol/ssg';
|
|
3
|
+
/** Narrow view of OpenElementBuildContext used by the SSG post-processor. */ export interface BuildContextView {
|
|
4
|
+
phase3: {
|
|
5
|
+
root: string;
|
|
6
|
+
outDir: string;
|
|
7
|
+
base: string;
|
|
8
|
+
upgradeStrategy: HydrationStrategy;
|
|
9
|
+
};
|
|
10
|
+
phase1: {
|
|
11
|
+
islandTagNames: string[];
|
|
12
|
+
packageIslandDecls: IslandDecl[];
|
|
13
|
+
islandMeta: Record<string, Partial<IslandDecl>>;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Inject the island client script and generate per-page island manifests.
|
|
18
|
+
* Must only run after Phase 2 (client island build) has completed.
|
|
19
|
+
*/ export declare function postProcessClientIslandBuild(ctx: BuildContextView, scriptSrc: string): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Clean Phase 1 SSR artifacts from the public dist directory.
|
|
22
|
+
* The SSR virtual entry bundle and its source map are build-time only
|
|
23
|
+
* and must not be deployed to static hosting.
|
|
24
|
+
*/ export declare function cleanSsrArtifacts(ctx: BuildContextView): Promise<void>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/ssg - Adapter-agnostic SSG build post-processing.
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates client-script injection, island chunk/strategy/layer map
|
|
5
|
+
* construction, and SSR artifact cleanup. This module has zero Vite
|
|
6
|
+
* dependency and only reads/writes files.
|
|
7
|
+
*/ import { join } from 'node:path';
|
|
8
|
+
import process from 'node:process';
|
|
9
|
+
import { readdir, unlink } from 'node:fs/promises';
|
|
10
|
+
import { createLogger } from '@openelement/core/logger';
|
|
11
|
+
import { buildIslandChunkMap, injectClientScript } from './postprocess.js';
|
|
12
|
+
import { generateIslandManifests, writeIslandManifests } from './island-manifest.js';
|
|
13
|
+
const log = createLogger('core');
|
|
14
|
+
/**
|
|
15
|
+
* Inject the island client script and generate per-page island manifests.
|
|
16
|
+
* Must only run after Phase 2 (client island build) has completed.
|
|
17
|
+
*/ export async function postProcessClientIslandBuild(ctx, scriptSrc) {
|
|
18
|
+
const root = ctx.phase3.root || process.cwd();
|
|
19
|
+
const outDir = ctx.phase3.outDir || 'dist';
|
|
20
|
+
const base = ctx.phase3.base || '/';
|
|
21
|
+
const outputDir = join(root, outDir);
|
|
22
|
+
injectClientScript(outputDir, scriptSrc);
|
|
23
|
+
const islandTagNames = [
|
|
24
|
+
...ctx.phase1.islandTagNames || [],
|
|
25
|
+
...(ctx.phase1.packageIslandDecls || []).map((island)=>island.tagName)
|
|
26
|
+
];
|
|
27
|
+
const chunkMap = buildIslandChunkMap(root, outDir, islandTagNames, base);
|
|
28
|
+
const strategyMap = Object.fromEntries([
|
|
29
|
+
...Object.entries(ctx.phase1.islandMeta || {}).map(([tag, meta])=>[
|
|
30
|
+
tag,
|
|
31
|
+
meta.hydrate || ctx.phase3.upgradeStrategy || 'idle'
|
|
32
|
+
]),
|
|
33
|
+
...(ctx.phase1.packageIslandDecls || []).map((island)=>[
|
|
34
|
+
island.tagName,
|
|
35
|
+
island.hydrate || ctx.phase3.upgradeStrategy || 'idle'
|
|
36
|
+
])
|
|
37
|
+
]);
|
|
38
|
+
const layerMap = Object.fromEntries([
|
|
39
|
+
...Object.entries(ctx.phase1.islandMeta || {}).map(([tag, meta])=>[
|
|
40
|
+
tag,
|
|
41
|
+
meta.hydrate === 'only' || meta.ssr === false ? 'pure-island' : 'dsd-interactive'
|
|
42
|
+
]),
|
|
43
|
+
...(ctx.phase1.packageIslandDecls || []).map((island)=>[
|
|
44
|
+
island.tagName,
|
|
45
|
+
island.hydrate === 'only' || island.ssr === false ? 'pure-island' : 'dsd-interactive'
|
|
46
|
+
])
|
|
47
|
+
]);
|
|
48
|
+
const pageManifests = generateIslandManifests(outputDir, chunkMap, strategyMap, layerMap);
|
|
49
|
+
await writeIslandManifests(outputDir, pageManifests);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Clean Phase 1 SSR artifacts from the public dist directory.
|
|
53
|
+
* The SSR virtual entry bundle and its source map are build-time only
|
|
54
|
+
* and must not be deployed to static hosting.
|
|
55
|
+
*/ export async function cleanSsrArtifacts(ctx) {
|
|
56
|
+
const root = ctx.phase3.root || process.cwd();
|
|
57
|
+
const outDir = ctx.phase3.outDir || 'dist';
|
|
58
|
+
try {
|
|
59
|
+
const assetsDir = join(root, outDir, 'assets');
|
|
60
|
+
const entries = await readdir(assetsDir).catch(()=>[]);
|
|
61
|
+
const toDelete = entries.filter((f)=>f.startsWith('_virtual_open-hono-entry') || f.startsWith('src-') && f.endsWith('.js') && !f.includes('client'));
|
|
62
|
+
for (const f of toDelete){
|
|
63
|
+
const p = join(assetsDir, f);
|
|
64
|
+
await unlink(p).catch(()=>{});
|
|
65
|
+
log.info(`Cleaned SSR artifact: ${f}`);
|
|
66
|
+
}
|
|
67
|
+
if (toDelete.length > 0) {
|
|
68
|
+
log.info(`Removed ${toDelete.length} unreferenced SSR artifact(s) from dist/assets/`);
|
|
69
|
+
}
|
|
70
|
+
} catch {
|
|
71
|
+
// Non-critical - assets dir may not exist in some configs
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9zc2cvc3JjL2J1aWxkLXBvc3Rwcm9jZXNzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQG9wZW5lbGVtZW50L3NzZyAtIEFkYXB0ZXItYWdub3N0aWMgU1NHIGJ1aWxkIHBvc3QtcHJvY2Vzc2luZy5cbiAqXG4gKiBPcmNoZXN0cmF0ZXMgY2xpZW50LXNjcmlwdCBpbmplY3Rpb24sIGlzbGFuZCBjaHVuay9zdHJhdGVneS9sYXllciBtYXBcbiAqIGNvbnN0cnVjdGlvbiwgYW5kIFNTUiBhcnRpZmFjdCBjbGVhbnVwLiBUaGlzIG1vZHVsZSBoYXMgemVybyBWaXRlXG4gKiBkZXBlbmRlbmN5IGFuZCBvbmx5IHJlYWRzL3dyaXRlcyBmaWxlcy5cbiAqL1xuXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCBwcm9jZXNzIGZyb20gJ25vZGU6cHJvY2Vzcyc7XG5pbXBvcnQgeyByZWFkZGlyLCB1bmxpbmsgfSBmcm9tICdub2RlOmZzL3Byb21pc2VzJztcbmltcG9ydCB0eXBlIHsgQ29tcG9uZW50TGF5ZXIsIEh5ZHJhdGlvblN0cmF0ZWd5IH0gZnJvbSAnQG9wZW5lbGVtZW50L3Byb3RvY29sL2ZyYW1ld29yayc7XG5pbXBvcnQgdHlwZSB7IElzbGFuZERlY2wgfSBmcm9tICdAb3BlbmVsZW1lbnQvcHJvdG9jb2wvc3NnJztcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJ0BvcGVuZWxlbWVudC9jb3JlL2xvZ2dlcic7XG5pbXBvcnQgeyBidWlsZElzbGFuZENodW5rTWFwLCBpbmplY3RDbGllbnRTY3JpcHQgfSBmcm9tICcuL3Bvc3Rwcm9jZXNzLmpzJztcbmltcG9ydCB7IGdlbmVyYXRlSXNsYW5kTWFuaWZlc3RzLCB3cml0ZUlzbGFuZE1hbmlmZXN0cyB9IGZyb20gJy4vaXNsYW5kLW1hbmlmZXN0LmpzJztcblxuY29uc3QgbG9nID0gY3JlYXRlTG9nZ2VyKCdjb3JlJyk7XG5cbi8qKiBOYXJyb3cgdmlldyBvZiBPcGVuRWxlbWVudEJ1aWxkQ29udGV4dCB1c2VkIGJ5IHRoZSBTU0cgcG9zdC1wcm9jZXNzb3IuICovXG5leHBvcnQgaW50ZXJmYWNlIEJ1aWxkQ29udGV4dFZpZXcge1xuICBwaGFzZTM6IHtcbiAgICByb290OiBzdHJpbmc7XG4gICAgb3V0RGlyOiBzdHJpbmc7XG4gICAgYmFzZTogc3RyaW5nO1xuICAgIHVwZ3JhZGVTdHJhdGVneTogSHlkcmF0aW9uU3RyYXRlZ3k7XG4gIH07XG4gIHBoYXNlMToge1xuICAgIGlzbGFuZFRhZ05hbWVzOiBzdHJpbmdbXTtcbiAgICBwYWNrYWdlSXNsYW5kRGVjbHM6IElzbGFuZERlY2xbXTtcbiAgICBpc2xhbmRNZXRhOiBSZWNvcmQ8c3RyaW5nLCBQYXJ0aWFsPElzbGFuZERlY2w+PjtcbiAgfTtcbn1cblxuLyoqXG4gKiBJbmplY3QgdGhlIGlzbGFuZCBjbGllbnQgc2NyaXB0IGFuZCBnZW5lcmF0ZSBwZXItcGFnZSBpc2xhbmQgbWFuaWZlc3RzLlxuICogTXVzdCBvbmx5IHJ1biBhZnRlciBQaGFzZSAyIChjbGllbnQgaXNsYW5kIGJ1aWxkKSBoYXMgY29tcGxldGVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcG9zdFByb2Nlc3NDbGllbnRJc2xhbmRCdWlsZChcbiAgY3R4OiBCdWlsZENvbnRleHRWaWV3LFxuICBzY3JpcHRTcmM6IHN0cmluZyxcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCByb290ID0gY3R4LnBoYXNlMy5yb290IHx8IHByb2Nlc3MuY3dkKCk7XG4gIGNvbnN0IG91dERpciA9IGN0eC5waGFzZTMub3V0RGlyIHx8ICdkaXN0JztcbiAgY29uc3QgYmFzZSA9IGN0eC5waGFzZTMuYmFzZSB8fCAnLyc7XG4gIGNvbnN0IG91dHB1dERpciA9IGpvaW4ocm9vdCwgb3V0RGlyKTtcblxuICBpbmplY3RDbGllbnRTY3JpcHQob3V0cHV0RGlyLCBzY3JpcHRTcmMpO1xuXG4gIGNvbnN0IGlzbGFuZFRhZ05hbWVzID0gW1xuICAgIC4uLihjdHgucGhhc2UxLmlzbGFuZFRhZ05hbWVzIHx8IFtdKSxcbiAgICAuLi4oY3R4LnBoYXNlMS5wYWNrYWdlSXNsYW5kRGVjbHMgfHwgW10pLm1hcCgoaXNsYW5kKSA9PiBpc2xhbmQudGFnTmFtZSksXG4gIF07XG5cbiAgY29uc3QgY2h1bmtNYXAgPSBidWlsZElzbGFuZENodW5rTWFwKHJvb3QsIG91dERpciwgaXNsYW5kVGFnTmFtZXMsIGJhc2UpO1xuXG4gIGNvbnN0IHN0cmF0ZWd5TWFwID0gT2JqZWN0LmZyb21FbnRyaWVzKFtcbiAgICAuLi5PYmplY3QuZW50cmllcyhjdHgucGhhc2UxLmlzbGFuZE1ldGEgfHwge30pLm1hcCgoW3RhZywgbWV0YV0pID0+IFtcbiAgICAgIHRhZyxcbiAgICAgIG1ldGEuaHlkcmF0ZSB8fCBjdHgucGhhc2UzLnVwZ3JhZGVTdHJhdGVneSB8fCAnaWRsZScsXG4gICAgXSksXG4gICAgLi4uKGN0eC5waGFzZTEucGFja2FnZUlzbGFuZERlY2xzIHx8IFtdKS5tYXAoKGlzbGFuZCkgPT4gW1xuICAgICAgaXNsYW5kLnRhZ05hbWUsXG4gICAgICBpc2xhbmQuaHlkcmF0ZSB8fCBjdHgucGhhc2UzLnVwZ3JhZGVTdHJhdGVneSB8fCAnaWRsZScsXG4gICAgXSksXG4gIF0pIGFzIFJlY29yZDxzdHJpbmcsIEh5ZHJhdGlvblN0cmF0ZWd5PjtcblxuICBjb25zdCBsYXllck1hcCA9IE9iamVjdC5mcm9tRW50cmllcyhbXG4gICAgLi4uT2JqZWN0LmVudHJpZXMoY3R4LnBoYXNlMS5pc2xhbmRNZXRhIHx8IHt9KS5tYXAoKFt0YWcsIG1ldGFdKSA9PiBbXG4gICAgICB0YWcsXG4gICAgICBtZXRhLmh5ZHJhdGUgPT09ICdvbmx5JyB8fCBtZXRhLnNzciA9PT0gZmFsc2UgPyAncHVyZS1pc2xhbmQnIDogJ2RzZC1pbnRlcmFjdGl2ZScsXG4gICAgXSksXG4gICAgLi4uKGN0eC5waGFzZTEucGFja2FnZUlzbGFuZERlY2xzIHx8IFtdKS5tYXAoKGlzbGFuZCkgPT4gW1xuICAgICAgaXNsYW5kLnRhZ05hbWUsXG4gICAgICBpc2xhbmQuaHlkcmF0ZSA9PT0gJ29ubHknIHx8IGlzbGFuZC5zc3IgPT09IGZhbHNlID8gJ3B1cmUtaXNsYW5kJyA6ICdkc2QtaW50ZXJhY3RpdmUnLFxuICAgIF0pLFxuICBdKSBhcyBSZWNvcmQ8c3RyaW5nLCBDb21wb25lbnRMYXllcj47XG5cbiAgY29uc3QgcGFnZU1hbmlmZXN0cyA9IGdlbmVyYXRlSXNsYW5kTWFuaWZlc3RzKG91dHB1dERpciwgY2h1bmtNYXAsIHN0cmF0ZWd5TWFwLCBsYXllck1hcCk7XG4gIGF3YWl0IHdyaXRlSXNsYW5kTWFuaWZlc3RzKG91dHB1dERpciwgcGFnZU1hbmlmZXN0cyk7XG59XG5cbi8qKlxuICogQ2xlYW4gUGhhc2UgMSBTU1IgYXJ0aWZhY3RzIGZyb20gdGhlIHB1YmxpYyBkaXN0IGRpcmVjdG9yeS5cbiAqIFRoZSBTU1IgdmlydHVhbCBlbnRyeSBidW5kbGUgYW5kIGl0cyBzb3VyY2UgbWFwIGFyZSBidWlsZC10aW1lIG9ubHlcbiAqIGFuZCBtdXN0IG5vdCBiZSBkZXBsb3llZCB0byBzdGF0aWMgaG9zdGluZy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFuU3NyQXJ0aWZhY3RzKGN0eDogQnVpbGRDb250ZXh0Vmlldyk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCByb290ID0gY3R4LnBoYXNlMy5yb290IHx8IHByb2Nlc3MuY3dkKCk7XG4gIGNvbnN0IG91dERpciA9IGN0eC5waGFzZTMub3V0RGlyIHx8ICdkaXN0JztcblxuICB0cnkge1xuICAgIGNvbnN0IGFzc2V0c0RpciA9IGpvaW4ocm9vdCwgb3V0RGlyLCAnYXNzZXRzJyk7XG4gICAgY29uc3QgZW50cmllcyA9IGF3YWl0IHJlYWRkaXIoYXNzZXRzRGlyKS5jYXRjaCgoKSA9PiBbXSBhcyBzdHJpbmdbXSk7XG4gICAgY29uc3QgdG9EZWxldGUgPSBlbnRyaWVzLmZpbHRlcihcbiAgICAgIChmKSA9PlxuICAgICAgICBmLnN0YXJ0c1dpdGgoJ192aXJ0dWFsX29wZW4taG9uby1lbnRyeScpIHx8XG4gICAgICAgIChmLnN0YXJ0c1dpdGgoJ3NyYy0nKSAmJiBmLmVuZHNXaXRoKCcuanMnKSAmJiAhZi5pbmNsdWRlcygnY2xpZW50JykpLFxuICAgICk7XG4gICAgZm9yIChjb25zdCBmIG9mIHRvRGVsZXRlKSB7XG4gICAgICBjb25zdCBwID0gam9pbihhc3NldHNEaXIsIGYpO1xuICAgICAgYXdhaXQgdW5saW5rKHApLmNhdGNoKCgpID0+IHt9KTtcbiAgICAgIGxvZy5pbmZvKGBDbGVhbmVkIFNTUiBhcnRpZmFjdDogJHtmfWApO1xuICAgIH1cbiAgICBpZiAodG9EZWxldGUubGVuZ3RoID4gMCkge1xuICAgICAgbG9nLmluZm8oYFJlbW92ZWQgJHt0b0RlbGV0ZS5sZW5ndGh9IHVucmVmZXJlbmNlZCBTU1IgYXJ0aWZhY3QocykgZnJvbSBkaXN0L2Fzc2V0cy9gKTtcbiAgICB9XG4gIH0gY2F0Y2gge1xuICAgIC8vIE5vbi1jcml0aWNhbCAtIGFzc2V0cyBkaXIgbWF5IG5vdCBleGlzdCBpbiBzb21lIGNvbmZpZ3NcbiAgfVxufVxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Q0FNQyxHQUVELFNBQVMsSUFBSSxRQUFRLFlBQVk7QUFDakMsT0FBTyxhQUFhLGVBQWU7QUFDbkMsU0FBUyxPQUFPLEVBQUUsTUFBTSxRQUFRLG1CQUFtQjtBQUduRCxTQUFTLFlBQVksUUFBUSwyQkFBMkI7QUFDeEQsU0FBUyxtQkFBbUIsRUFBRSxrQkFBa0IsUUFBUSxtQkFBbUI7QUFDM0UsU0FBUyx1QkFBdUIsRUFBRSxvQkFBb0IsUUFBUSx1QkFBdUI7QUFFckYsTUFBTSxNQUFNLGFBQWE7QUFpQnpCOzs7Q0FHQyxHQUNELE9BQU8sZUFBZSw2QkFDcEIsR0FBcUIsRUFDckIsU0FBaUI7RUFFakIsTUFBTSxPQUFP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
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { isValidTagName } from '@openelement/core';
|
|
2
|
+
import { formatError } from '@openelement/core/errors';
|
|
3
|
+
function isCemCustomElement(declaration) {
|
|
4
|
+
return declaration.kind === 'custom-element';
|
|
5
|
+
}
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
function toCemBaseArray(value) {
|
|
10
|
+
if (!Array.isArray(value)) return undefined;
|
|
11
|
+
return value.filter(isRecord);
|
|
12
|
+
}
|
|
13
|
+
function toCemExports(value) {
|
|
14
|
+
if (!Array.isArray(value)) return undefined;
|
|
15
|
+
return value.filter(isRecord).map((entry)=>({
|
|
16
|
+
declaration: entry.declaration
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
function toCemModule(value) {
|
|
20
|
+
if (!isRecord(value)) return undefined;
|
|
21
|
+
return {
|
|
22
|
+
kind: typeof value.kind === 'string' ? value.kind : undefined,
|
|
23
|
+
path: typeof value.path === 'string' ? value.path : '',
|
|
24
|
+
declarations: toCemBaseArray(value.declarations),
|
|
25
|
+
exports: toCemExports(value.exports)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function parseCem(json) {
|
|
29
|
+
const errors = [];
|
|
30
|
+
const warnings = [];
|
|
31
|
+
let parsed;
|
|
32
|
+
try {
|
|
33
|
+
parsed = JSON.parse(json);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
errors.push({
|
|
36
|
+
code: 'CEM_PARSE_ERROR',
|
|
37
|
+
message: `Invalid JSON: ${formatError(error)}`
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
success: false,
|
|
41
|
+
errors,
|
|
42
|
+
warnings
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (!isRecord(parsed)) {
|
|
46
|
+
errors.push({
|
|
47
|
+
code: 'CEM_INVALID_ROOT',
|
|
48
|
+
message: 'Manifest root must be an object'
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
errors,
|
|
53
|
+
warnings
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const root = parsed;
|
|
57
|
+
if (!root.schemaVersion) {
|
|
58
|
+
warnings.push({
|
|
59
|
+
code: 'CEM_NO_SCHEMA_VERSION',
|
|
60
|
+
message: 'Missing schemaVersion field, assuming legacy format'
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (!Array.isArray(root.modules)) {
|
|
64
|
+
errors.push({
|
|
65
|
+
code: 'CEM_NO_MODULES',
|
|
66
|
+
message: 'Manifest must have a modules array'
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
errors,
|
|
71
|
+
warnings
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const manifest = {
|
|
75
|
+
...root,
|
|
76
|
+
schemaVersion: typeof root.schemaVersion === 'string' ? root.schemaVersion : undefined,
|
|
77
|
+
packageName: typeof root.packageName === 'string' ? root.packageName : undefined,
|
|
78
|
+
version: typeof root.version === 'string' ? root.version : undefined,
|
|
79
|
+
modules: root.modules.map((module)=>toCemModule(module) ?? {
|
|
80
|
+
path: ''
|
|
81
|
+
})
|
|
82
|
+
};
|
|
83
|
+
const seenTagNames = new Set();
|
|
84
|
+
for(let i = 0; i < manifest.modules.length; i++){
|
|
85
|
+
const module = manifest.modules[i];
|
|
86
|
+
const modulePath = `modules[${i}]`;
|
|
87
|
+
if (!module.kind) {
|
|
88
|
+
warnings.push({
|
|
89
|
+
code: 'CEM_MODULE_NO_KIND',
|
|
90
|
+
message: `Module at index ${i} has no kind field`,
|
|
91
|
+
path: modulePath
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (!module.path) {
|
|
95
|
+
errors.push({
|
|
96
|
+
code: 'CEM_MODULE_NO_PATH',
|
|
97
|
+
message: `Module at index ${i} has no path field`,
|
|
98
|
+
path: modulePath
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
for (const [j, declaration] of (module.declarations ?? []).entries()){
|
|
102
|
+
if (!isCemCustomElement(declaration)) continue;
|
|
103
|
+
const declarationPath = `${modulePath}.declarations[${j}]`;
|
|
104
|
+
const tagName = declaration.tagName;
|
|
105
|
+
if (!tagName) {
|
|
106
|
+
errors.push({
|
|
107
|
+
code: 'CEM_CE_NO_TAG_NAME',
|
|
108
|
+
message: `Custom element at ${declarationPath} has no tagName`,
|
|
109
|
+
path: declarationPath
|
|
110
|
+
});
|
|
111
|
+
} else if (!isValidTagName(tagName)) {
|
|
112
|
+
errors.push({
|
|
113
|
+
code: 'CEM_CE_INVALID_TAG_NAME',
|
|
114
|
+
message: `Invalid tag name: ${tagName} (must contain a hyphen and match HTML spec)`,
|
|
115
|
+
path: declarationPath
|
|
116
|
+
});
|
|
117
|
+
} else if (seenTagNames.has(tagName)) {
|
|
118
|
+
errors.push({
|
|
119
|
+
code: 'CEM_CE_DUPLICATE_TAG',
|
|
120
|
+
message: `Duplicate tag name: ${tagName}`,
|
|
121
|
+
path: declarationPath
|
|
122
|
+
});
|
|
123
|
+
} else {
|
|
124
|
+
seenTagNames.add(tagName);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
for (const [j, exported] of (module.exports ?? []).entries()){
|
|
128
|
+
if (!exported.declaration) {
|
|
129
|
+
errors.push({
|
|
130
|
+
code: 'CEM_EXPORT_NO_DECLARATION',
|
|
131
|
+
message: `Export at ${modulePath}.exports[${j}] has no declaration reference`,
|
|
132
|
+
path: `${modulePath}.exports[${j}]`
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
success: errors.length === 0,
|
|
139
|
+
manifest: errors.length === 0 ? manifest : undefined,
|
|
140
|
+
errors,
|
|
141
|
+
warnings
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
export function classifyCemManifest(manifest) {
|
|
145
|
+
const classifications = [];
|
|
146
|
+
const seenTags = new Map();
|
|
147
|
+
for (const module of manifest.modules){
|
|
148
|
+
for (const declaration of module.declarations ?? []){
|
|
149
|
+
if (!isCemCustomElement(declaration) || !declaration.tagName) continue;
|
|
150
|
+
if (seenTags.has(declaration.tagName)) {
|
|
151
|
+
classifications.push({
|
|
152
|
+
tagName: declaration.tagName,
|
|
153
|
+
tier: 'rejected',
|
|
154
|
+
reason: `Duplicate tag name: ${declaration.tagName}`,
|
|
155
|
+
source: 'package',
|
|
156
|
+
modulePath: module.path,
|
|
157
|
+
ssr: false,
|
|
158
|
+
dsd: false,
|
|
159
|
+
hydrate: 'idle'
|
|
160
|
+
});
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const classification = classifyCemDeclaration(manifest, module, declaration);
|
|
164
|
+
classifications.push(classification);
|
|
165
|
+
seenTags.set(declaration.tagName, classification);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const rejectedTags = [];
|
|
169
|
+
const ssrCapableTags = [];
|
|
170
|
+
const clientOnlyTags = [];
|
|
171
|
+
const experimentalDomTags = [];
|
|
172
|
+
// ponytail: bucket lookup replaces 4-case switch
|
|
173
|
+
const buckets = {
|
|
174
|
+
rejected: rejectedTags,
|
|
175
|
+
'ssr-capable': ssrCapableTags,
|
|
176
|
+
'client-only': clientOnlyTags,
|
|
177
|
+
'experimental-dom': experimentalDomTags
|
|
178
|
+
};
|
|
179
|
+
for (const classification of classifications){
|
|
180
|
+
buckets[classification.tier]?.push(classification.tagName);
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
classifications,
|
|
184
|
+
rejectedTags,
|
|
185
|
+
ssrCapableTags,
|
|
186
|
+
clientOnlyTags,
|
|
187
|
+
experimentalDomTags,
|
|
188
|
+
stats: {
|
|
189
|
+
totalComponents: classifications.length,
|
|
190
|
+
ssrCapableCount: ssrCapableTags.length,
|
|
191
|
+
clientOnlyCount: clientOnlyTags.length,
|
|
192
|
+
rejectedCount: rejectedTags.length,
|
|
193
|
+
experimentalDomCount: experimentalDomTags.length
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function classifyCemDeclaration(manifest, module, declaration) {
|
|
198
|
+
const openElement = declaration.openElement;
|
|
199
|
+
const ssr = openElement?.ssr ?? false;
|
|
200
|
+
const dsd = openElement?.dsd ?? false;
|
|
201
|
+
const hydrate = openElement?.hydrate ?? 'idle';
|
|
202
|
+
let tier = 'client-only';
|
|
203
|
+
let reason = manifest.packageName ? `CEM-only package ${manifest.packageName} (no openElement SSR declaration)` : 'CEM-only package (no openElement SSR declaration)';
|
|
204
|
+
if (openElement?.ssr === true) {
|
|
205
|
+
if (openElement.layer) {
|
|
206
|
+
tier = 'ssr-capable';
|
|
207
|
+
reason = `ssr: true with layer: ${openElement.layer}`;
|
|
208
|
+
} else {
|
|
209
|
+
tier = 'client-only';
|
|
210
|
+
reason = 'ssr: true but no adapter/layer declared';
|
|
211
|
+
}
|
|
212
|
+
} else if (openElement?.ssr === false) {
|
|
213
|
+
reason = 'ssr: false (explicit client-only)';
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
tagName: declaration.tagName,
|
|
217
|
+
tier,
|
|
218
|
+
reason,
|
|
219
|
+
source: 'package',
|
|
220
|
+
modulePath: module.path,
|
|
221
|
+
ssr,
|
|
222
|
+
dsd,
|
|
223
|
+
hydrate
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9zc2cvc3JjL2NlbS1jb21wYXQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUge1xuICBDb21wYXRpYmlsaXR5Q2xhc3NpZmljYXRpb24sXG4gIENvbXBhdGliaWxpdHlUaWVyLFxuICBIeWRyYXRpb25TdHJhdGVneSxcbn0gZnJvbSAnQG9wZW5lbGVtZW50L3Byb3RvY29sL2ZyYW1ld29yayc7XG5pbXBvcnQgeyBpc1ZhbGlkVGFnTmFtZSB9IGZyb20gJ0BvcGVuZWxlbWVudC9jb3JlJztcbmltcG9ydCB7IGZvcm1hdEVycm9yIH0gZnJvbSAnQG9wZW5lbGVtZW50L2NvcmUvZXJyb3JzJztcblxuZXhwb3J0IGludGVyZmFjZSBPcGVuRWxlbWVudEV4dGVuc2lvbnMge1xuICBzc3I/OiBib29sZWFuO1xuICBkc2Q/OiBib29sZWFuO1xuICBsYXllcj86IHN0cmluZztcbiAgaHlkcmF0ZT86IEh5ZHJhdGlvblN0cmF0ZWd5O1xuICBtb2R1bGU/OiBzdHJpbmc7XG4gIGV4cG9ydD86IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIENlbUJhc2Uge1xuICBraW5kPzogc3RyaW5nO1xuICBba2V5OiBzdHJpbmddOiB1bmtub3duO1xufVxuXG5pbnRlcmZhY2UgQ2VtQ3VzdG9tRWxlbWVudCBleHRlbmRzIENlbUJhc2Uge1xuICBraW5kOiAnY3VzdG9tLWVsZW1lbnQnO1xuICB0YWdOYW1lPzogc3RyaW5nO1xuICBzdXBlckNsYXNzPzogeyBuYW1lPzogc3RyaW5nIH07XG4gIG9wZW5FbGVtZW50PzogT3BlbkVsZW1lbnRFeHRlbnNpb25zO1xufVxuXG5pbnRlcmZhY2UgQ2VtTW9kdWxlIHtcbiAga2luZD86IHN0cmluZztcbiAgcGF0aDogc3RyaW5nO1xuICBkZWNsYXJhdGlvbnM/OiBDZW1CYXNlW107XG4gIGV4cG9ydHM/OiB7IGRlY2xhcmF0aW9uPzogdW5rbm93biB9W107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3VzdG9tRWxlbWVudHNNYW5pZmVzdCB7XG4gIHNjaGVtYVZlcnNpb24/OiBzdHJpbmc7XG4gIHBhY2thZ2VOYW1lPzogc3RyaW5nO1xuICB2ZXJzaW9uPzogc3RyaW5nO1xuICBtb2R1bGVzOiBDZW1Nb2R1bGVbXTtcbiAgW2tleTogc3RyaW5nXTogdW5rbm93bjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDZW1QYXJzZUVycm9yIHtcbiAgY29kZTogc3RyaW5nO1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIHBhdGg/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2VtUGFyc2VXYXJuaW5nIHtcbiAgY29kZTogc3RyaW5nO1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIHBhdGg/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2VtUGFyc2VSZXN1bHQge1xuICBzdWNjZXNzOiBib29sZWFuO1xuICBtYW5pZmVzdD86IEN1c3RvbUVsZW1lbnRzTWFuaWZlc3Q7XG4gIGVycm9yczogQ2VtUGFyc2VFcnJvcltdO1xuICB3YXJuaW5nczogQ2VtUGFyc2VXYXJuaW5nW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2VtQ2xhc3NpZmljYXRpb25SZXN1bHQge1xuICBjbGFzc2lmaWNhdGlvbnM6IENvbXBhdGliaWxpdHlDbGFzc2lmaWNhdGlvbltdO1xuICByZWplY3RlZFRhZ3M6IHN0cmluZ1tdO1xuICBzc3JDYXBhYmxlVGFnczogc3RyaW5nW107XG4gIGNsaWVudE9ubHlUYWdzOiBzdHJpbmdbXTtcbiAgZXhwZXJpbWVudGFsRG9tVGFnczogc3RyaW5nW107XG4gIHN0YXRzOiB7XG4gICAgdG90YWxDb21wb25lbnRzOiBudW1iZXI7XG4gICAgc3NyQ2FwYWJsZUNvdW50OiBudW1iZXI7XG4gICAgY2xpZW50T25seUNvdW50OiBudW1iZXI7XG4gICAgcmVqZWN0ZWRDb3VudDogbnVtYmVyO1xuICAgIGV4cGVyaW1lbnRhbERvbUNvdW50OiBudW1iZXI7XG4gIH07XG59XG5cbmZ1bmN0aW9uIGlzQ2VtQ3VzdG9tRWxlbWVudChkZWNsYXJhdGlvbjogQ2VtQmFzZSk6IGRlY2xhcmF0aW9uIGlzIENlbUN1c3RvbUVsZW1lbnQge1xuICByZXR1cm4gZGVjbGFyYXRpb24ua2luZCA9PT0gJ2N1c3RvbS1lbGVtZW50Jztcbn1cblxuZnVuY3Rpb24gaXNSZWNvcmQodmFsdWU6IHVua25vd24pOiB2YWx1ZSBpcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIHJldHVybiAhIXZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkodmFsdWUpO1xufVxuXG5mdW5jdGlvbiB0b0NlbUJhc2VBcnJheSh2YWx1ZTogdW5rbm93bik6IENlbUJhc2VbXSB8IHVuZGVmaW5lZCB7XG4gIGlmICghQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHJldHVybiB1bmRlZmluZWQ7XG4gIHJldHVybiB2YWx1ZS5maWx0ZXIoaXNSZWNvcmQpO1xufVxuXG5mdW5jdGlvbiB0b0NlbUV4cG9ydHModmFsdWU6IHVua25vd24pOiB7IGRlY2xhcmF0aW9uPzogdW5rbm93biB9W10gfCB1bmRlZmluZWQge1xuICBpZiAoIUFycmF5LmlzQXJyYXkodmFsdWUpKSByZXR1cm4gdW5kZWZpbmVkO1xuICByZXR1cm4gdmFsdWUuZmlsdGVyKGlzUmVjb3JkKS5tYXAoKGVudHJ5KSA9PiAoeyBkZWNsYXJhdGlvbjogZW50cnkuZGVjbGFyYXRpb24gfSkpO1xufVxuXG5mdW5jdGlvbiB0b0NlbU1vZHVsZSh2YWx1ZTogdW5rbm93bik6IENlbU1vZHVsZSB8IHVuZGVmaW5lZCB7XG4gIGlmICghaXNSZWNvcmQodmFsdWUpKSByZXR1cm4gdW5kZWZpbmVkO1xuICByZXR1cm4ge1xuICAgIGtpbmQ6IHR5cGVvZiB2YWx1ZS5raW5kID09PSAnc3RyaW5nJyA/IHZhbHVlLmtpbmQgOiB1bmRlZmluZWQsXG4gICAgcGF0aDogdHlwZW9mIHZhbHVlLnBhdGggPT09ICdzdHJpbmcnID8gdmFsdWUucGF0aCA6ICcnLFxuICAgIGRlY2xhcmF0aW9uczogdG9DZW1CYXNlQXJyYXkodmFsdWUuZGVjbGFyYXRpb25zKSxcbiAgICBleHBvcnRzOiB0b0NlbUV4cG9ydHModmFsdWUuZXhwb3J0cyksXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUNlbShqc29uOiBzdHJpbmcpOiBDZW1QYXJzZVJlc3VsdCB7XG4gIGNvbnN0IGVycm9yczogQ2VtUGFyc2VFcnJvcltdID0gW107XG4gIGNvbnN0IHdhcm5pbmdzOiBDZW1QYXJzZVdhcm5pbmdbXSA9IFtdO1xuXG4gIGxldCBwYXJzZWQ6IHVua25vd247XG4gIHRyeSB7XG4gICAgcGFyc2VkID0gSlNPTi5wYXJzZShqc29uKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBlcnJvcnMucHVzaCh7XG4gICAgICBjb2RlOiAnQ0VNX1BBUlNFX0VSUk9SJyxcbiAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIEpTT046ICR7Zm9ybWF0RXJyb3IoZXJyb3IpfWAsXG4gICAgfSk7XG4gICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UsIGVycm9ycywgd2FybmluZ3MgfTtcbiAgfVxuXG4gIGlmICghaXNSZWNvcmQocGFyc2VkKSkge1xuICAgIGVycm9ycy5wdXNoKHsgY29kZTogJ0NFTV9JTlZBTElEX1JPT1QnLCBtZXNzYWdlOiAnTWFuaWZlc3Qgcm9vdCBtdXN0IGJlIGFuIG9iamVjdCcgfSk7XG4gICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UsIGVycm9ycywgd2FybmluZ3MgfTtcbiAgfVxuXG4gIGNvbnN0IHJvb3QgPSBwYXJzZWQ7XG4gIGlmICghcm9vdC5zY2hlbWFWZXJzaW9uKSB7XG4gICAgd2FybmluZ3MucHVzaCh7XG4gICAgICBjb2RlOiAnQ0VNX05PX1NDSEVNQV9WRVJTSU9OJyxcbiAgICAgIG1lc3NhZ2U6ICdNaXNzaW5nIHNjaGVtYVZlcnNpb24gZmllbGQsIGFzc3VtaW5nIGxlZ2FjeSBmb3JtYXQnLFxuICAgIH0pO1xuICB9XG4gIGlmICghQXJyYXkuaXNBcnJheShyb290Lm1vZHVsZXMpKSB7XG4gICAgZXJyb3JzLnB1c2goeyBjb2RlOiAnQ0VNX05PX01PRFVMRVMnLCBtZXNzYWdlOiAnTWFuaWZlc3QgbXVzdCBoYXZlIGEgbW9kdWxlcyBhcnJheScgfSk7XG4gICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UsIGVycm9ycywgd2FybmluZ3MgfTtcbiAgfVxuXG4gIGNvbnN0IG1hbmlmZXN0OiBDdXN0b21FbGVtZW50c01hbmlmZXN0ID0ge1xuICAgIC4uLnJvb3QsXG4gICAgc2NoZW1hVmVyc2lvbjogdHlwZW9mIHJvb3Quc2NoZW1hVmVyc2lvbiA9PT0gJ3N0cmluZycgPyByb290LnNjaGVtYVZlcnNpb24gOiB1bmRlZmluZWQsXG4gICAgcGFja2FnZU5hbWU6IHR5cGVvZiByb290LnBhY2thZ2VOYW1lID09PSAnc3RyaW5nJyA/IHJvb3QucGFja2FnZU5hbWUgOiB1bmRlZmluZWQsXG4gICAgdmVyc2lvbjogdHlwZW9mIHJvb3QudmVyc2lvbiA9PT0gJ3N0cmluZycgPyByb290LnZlcnNpb24gOiB1bmRlZmluZWQsXG4gICAgbW9kdWxlczogcm9vdC5tb2R1bGVzLm1hcCgobW9kdWxlKSA9PlxuICAgICAgdG9DZW1Nb2R1bGUobW9kdWxlKSA/PyB7XG4gICAgICAgIHBhdGg6ICcnLFxuICAgICAgfVxuICAgICksXG4gIH07XG4gIGNvbnN0IHNlZW5UYWdOYW1lcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbWFuaWZlc3QubW9kdWxlcy5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IG1vZHVsZSA9IG1hbmlmZXN0Lm1vZHVsZXNbaV07XG4gICAgY29uc3QgbW9kdWxlUGF0aCA9IGBtb2R1bGVzWyR7aX1dYDtcblxuICAgIGlmICghbW9kdWxlLmtpbmQpIHtcbiAgICAgIHdhcm5pbmdzLnB1c2goe1xuICAgICAgICBjb2RlOiAnQ0VNX01PRFVMRV9OT19LSU5EJyxcbiAgICAgICAgbWVzc2FnZTogYE1vZHVsZSBhdCBpbmRleCAke2l9IGhhcyBubyBraW5kIGZpZWxkYCxcbiAgICAgICAgcGF0aDogbW9kdWxlUGF0aCxcbiAgICAgIH0pO1xuICAgIH1cbiAgICBpZiAoIW1vZHVsZS5wYXRoKSB7XG4gICAgICBlcnJvcnMucHVzaCh7XG4gICAgICAgIGNvZGU6ICdDRU1fTU9EVUxFX05PX1BBVEgnLFxuICAgICAgICBtZXNzYWdlOiBgTW9kdWxlIGF0IGluZGV4ICR7aX0gaGFzIG5vIHBhdGggZmllbGRgLFxuICAgICAgICBwYXRoOiBtb2R1bGVQYXRoLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbaiwgZGVjbGFyYXRpb25dIG9mIChtb2R1bGUuZGVjbGFyYXRpb25zID8/IFtdKS5lbnRyaWVzKCkpIHtcbiAgICAgIGlmICghaXNDZW1DdXN0b21FbGVtZW50KGRlY2xhcmF0aW9uKSkgY29udGludWU7XG4gICAgICBjb25zdCBkZWNsYXJhdGlvblBhdGggPSBgJHttb2R1bGVQYXRofS5kZWNsYXJhdGlvbnNbJHtqfV1gO1xuICAgICAgY29uc3QgdGFnTmFtZSA9IGRlY2xhcmF0aW9uLnRhZ05hbWU7XG4gICAgICBpZiAoIXRhZ05hbWUpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goe1xuICAgICAgICAgIGNvZGU6ICdDRU1fQ0VfTk9fVEFHX05BTUUnLFxuICAgICAgICAgIG1lc3NhZ2U6IGBDdXN0b20gZWxlbWVudCBhdCAke2RlY2xhcmF0aW9uUGF0aH0gaGFzIG5vIHRhZ05hbWVgLFxuICAgICAgICAgIHBhdGg6IGRlY2xhcmF0aW9uUGF0aCxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKCFpc1ZhbGlkVGFnTmFtZSh0YWdOYW1lKSkge1xuICAgICAgICBlcnJvcnMucHVzaCh7XG4gICAgICAgICAgY29kZTogJ0NFTV9DRV9JTlZBTElEX1RBR19OQU1FJyxcbiAgICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB0YWcgbmFtZTogJHt0YWdOYW1lfSAobXVzdCBjb250YWluIGEgaHlwaGVuIGFuZCBtYXRjaCBIVE1MIHNwZWMpYCxcbiAgICAgICAgICBwYXRoOiBkZWNsYXJhdGlvblBhdGgsXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmIChzZWVuVGFnTmFtZXMuaGFzKHRhZ05hbWUpKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKHtcbiAgICAgICAgICBjb2RlOiAnQ0VNX0NFX0RVUExJQ0FURV9UQUcnLFxuICAgICAgICAgIG1lc3NhZ2U6IGBEdXBsaWNhdGUgdGFnIG5hbWU6ICR7dGFnTmFtZX1gLFxuICAgICAgICAgIHBhdGg6IGRlY2xhcmF0aW9uUGF0aCxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzZWVuVGFnTmFtZXMuYWRkKHRhZ05hbWUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZvciAoY29uc3QgW2osIGV4cG9ydGVkXSBvZiAobW9kdWxlLmV4cG9ydHMgPz8gW10pLmVudHJpZXMoKSkge1xuICAgICAgaWYgKCFleHBvcnRlZC5kZWNsYXJhdGlvbikge1xuICAgICAgICBlcnJvcnMucHVzaCh7XG4gICAgICAgICAgY29kZTogJ0NFTV9FWFBPUlRfTk9fREVDTEFSQVRJT04nLFxuICAgICAgICAgIG1lc3NhZ2U6IGBFeHBvcnQgYXQgJHttb2R1bGVQYXRofS5leHBvcnRzWyR7an1dIGhhcyBubyBkZWNsYXJhdGlvbiByZWZlcmVuY2VgLFxuICAgICAgICAgIHBhdGg6IGAke21vZHVsZVBhdGh9LmV4cG9ydHNbJHtqfV1gLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHN1Y2Nlc3M6IGVycm9ycy5sZW5ndGggPT09IDAsXG4gICAgbWFuaWZlc3Q6IGVycm9ycy5sZW5ndGggPT09IDAgPyBtYW5pZmVzdCA6IHVuZGVmaW5lZCxcbiAgICBlcnJvcnMsXG4gICAgd2FybmluZ3MsXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjbGFzc2lmeUNlbU1hbmlmZXN0KG1hbmlmZXN0OiBDdXN0b21FbGVtZW50c01hbmlmZXN0KTogQ2VtQ2xhc3NpZmljYXRpb25SZXN1bHQge1xuICBjb25zdCBjbGFzc2lmaWNhdGlvbnM6IENvbXBhdGliaWxpdHlDbGFzc2lmaWNhdGlvbltdID0gW107XG4gIGNvbnN0IHNlZW5UYWdzID0gbmV3IE1hcDxzdHJpbmcsIENvbXBhdGliaWxpdHlDbGFzc2lmaWNhdGlvbj4oKTtcblxuICBmb3IgKGNvbnN0IG1vZHVsZSBvZiBtYW5pZmVzdC5tb2R1bGVzKSB7XG4gICAgZm9yIChjb25zdCBkZWNsYXJhdGlvbiBvZiBtb2R1bGUuZGVjbGFyYXRpb25zID8/IFtdKSB7XG4gICAgICBpZiAoIWlzQ2VtQ3VzdG9tRWxlbWVudChkZWNsYXJhdGlvbikgfHwgIWRlY2xhcmF0aW9uLnRhZ05hbWUpIGNvbnRpbnVlO1xuXG4gICAgICBpZiAoc2VlblRhZ3MuaGFzKGRlY2xhcmF0aW9uLnRhZ05hbWUpKSB7XG4gICAgICAgIGNsYXNzaWZpY2F0aW9ucy5wdXNoKHtcbiAgICAgICAgICB0YWdOYW1lOiBkZWNsYXJhdGlvbi50YWdOYW1lLFxuICAgICAgICAgIHRpZXI6ICdyZWplY3RlZCcsXG4gICAgICAgICAgcmVhc29uOiBgRHVwbGljYXRlIHRhZyBuYW1lOiAke2RlY2xhcmF0aW9uLnRhZ05hbWV9YCxcbiAgICAgICAgICBzb3VyY2U6ICdwYWNrYWdlJyxcbiAgICAgICAgICBtb2R1bGVQYXRoOiBtb2R1bGUucGF0aCxcbiAgICAgICAgICBzc3I6IGZhbHNlLFxuICAgICAgICAgIGRzZDogZmFsc2UsXG4gICAgICAgICAgaHlkcmF0ZTogJ2lkbGUnLFxuICAgICAgICB9KTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNsYXNzaWZpY2F0aW9uID0gY2xhc3NpZnlDZW1EZWNsYXJhdGlvbihtYW5pZmVzdCwgbW9kdWxlLCBkZWNsYXJhdGlvbik7XG4gICAgICBjbGFzc2lmaWNhdGlvbnMucHVzaChjbGFzc2lmaWNhdGlvbik7XG4gICAgICBzZWVuVGFncy5zZXQoZGVjbGFyYXRpb24udGFnTmFtZSwgY2xhc3NpZmljYXRpb24pO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHJlamVjdGVkVGFnczogc3RyaW5nW10gPSBbXTtcbiAgY29uc3Qgc3NyQ2FwYWJsZVRhZ3M6IHN0cmluZ1tdID0gW107XG4gIGNvbnN0IGNsaWVudE9ubHlUYWdzOiBzdHJpbmdbXSA9IFtdO1xuICBjb25zdCBleHBlcmltZW50YWxEb21UYWdzOiBzdHJpbmdbXSA9IFtdO1xuXG4gIC8vIHBvbnl0YWlsOiBidWNrZXQgbG9va3VwIHJlcGxhY2VzIDQtY2FzZSBzd2l0Y2hcbiAgY29uc3QgYnVja2V0czogUmVjb3JkPHN0cmluZywgc3RyaW5nW10+ID0ge1xuICAgIHJlamVjdGVkOiByZWplY3RlZFRhZ3MsXG4gICAgJ3Nzci1jYXBhYmxlJzogc3NyQ2FwYWJsZVRhZ3MsXG4gICAgJ2NsaWVudC1vbmx5JzogY2xpZW50T25seVRhZ3MsXG4gICAgJ2V4cGVyaW1lbnRhbC1kb20nOiBleHBlcmltZW50YWxEb21UYWdzLFxuICB9O1xuXG4gIGZvciAoY29uc3QgY2xhc3NpZmljYXRpb24gb2YgY2xhc3NpZmljYXRpb25zKSB7XG4gICAgYnVja2V0c1tjbGFzc2lmaWNhdGlvbi50aWVyXT8ucHVzaChjbGFzc2lmaWNhdGlvbi50YWdOYW1lKTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgY2xhc3NpZmljYXRpb25zLFxuICAgIHJlamVjdGVkVGFncyxcbiAgICBzc3JDYXBhYmxlVGFncyxcbiAgICBjbGllbnRPbmx5VGFncyxcbiAgICBleHBlcmltZW50YWxEb21UYWdzLFxuICAgIHN0YXRzOiB7XG4gICAgICB0b3RhbENvbXBvbmVudHM6IGNsYXNzaWZpY2F0aW9ucy5sZW5ndGgsXG4gICAgICBzc3JDYXBhYmxlQ291bnQ6IHNzckNhcGFibGVUYWdzLmxlbmd0aCxcbiAgICAgIGNsaWVudE9ubHlDb3VudDogY2xpZW50T25seVRhZ3MubGVuZ3RoLFxuICAgICAgcmVqZWN0ZWRDb3VudDogcmVqZWN0ZWRUYWdzLmxlbmd0aCxcbiAgICAgIGV4cGVyaW1lbnRhbERvbUNvdW50OiBleHBlcmltZW50YWxEb21UYWdzLmxlbmd0aCxcbiAgICB9LFxuICB9O1xufVxuXG5mdW5jdGlvbiBjbGFzc2lmeUNlbURlY2xhcmF0aW9uKFxuICBtYW5pZmVzdDogQ3VzdG9tRWxlbWVudHNNYW5pZmVzdCxcbiAgbW9kdWxlOiBDZW1Nb2R1bGUsXG4gIGRlY2xhcmF0aW9uOiBDZW1DdXN0b21FbGVtZW50LFxuKTogQ29tcGF0aWJpbGl0eUNsYXNzaWZpY2F0aW9uIHtcbiAgY29uc3Qgb3BlbkVsZW1lbnQgPSBkZWNsYXJhdGlvbi5vcGVuRWxlbWVudDtcbiAgY29uc3Qgc3NyID0gb3BlbkVsZW1lbnQ/LnNzciA/PyBmYWxzZTtcbiAgY29uc3QgZHNkID0gb3BlbkVsZW1lbnQ/LmRzZCA/PyBmYWxzZTtcbiAgY29uc3QgaHlkcmF0ZSA9IG9wZW5FbGVtZW50Py5oeWRyYXRlID8/ICdpZGxlJztcblxuICBsZXQgdGllcjogQ29tcGF0aWJpbGl0eVRpZXIgPSAnY2xpZW50LW9ubHknO1xuICBsZXQgcmVhc29uID0gbWFuaWZlc3QucGFja2FnZU5hbWVcbiAgICA/IGBDRU0tb25seSBwYWNrYWdlICR7bWFuaWZlc3QucGFja2FnZU5hbWV9IChubyBvcGVuRWxlbWVudCBTU1IgZGVjbGFyYXRpb24pYFxuICAgIDogJ0NFTS1vbmx5IHBhY2thZ2UgKG5vIG9wZW5FbGVtZW50IFNTUiBkZWNsYXJhdGlvbiknO1xuXG4gIGlmIChvcGVuRWxlbWVudD8uc3NyID09PSB0cnVlKSB7XG4gICAgaWYgKG9wZW5FbGVtZW50LmxheWVyKSB7XG4gICAgICB0aWVyID0gJ3Nzci1jYXBhYmxlJztcbiAgICAgIHJlYXNvbiA9IGBzc3I6IHRydWUgd2l0aCBsYXllcjogJHtvcGVuRWxlbWVudC5sYXllcn1gO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aWVyID0gJ2NsaWVudC1vbmx5JztcbiAgICAgIHJlYXNvbiA9ICdzc3I6IHRydWUgYnV0IG5vIGFkYXB0ZXIvbGF5ZXIgZGVjbGFyZWQnO1xuICAgIH1cbiAgfSBlbHNlIGlmIChvcGVuRWxlbWVudD8uc3NyID09PSBmYWxzZSkge1xuICAgIHJlYXNvbiA9ICdzc3I6IGZhbHNlIChleHBsaWNpdCBjbGllbnQtb25seSknO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICB0YWdOYW1lOiBkZWNsYXJhdGlvbi50YWdOYW1lISxcbiAgICB0aWVyLFxuICAgIHJlYXNvbixcbiAgICBzb3VyY2U6ICdwYWNrYWdlJyxcbiAgICBtb2R1bGVQYXRoOiBtb2R1bGUucGF0aCxcbiAgICBzc3IsXG4gICAgZHNkLFxuICAgIGh5ZHJhdGUsXG4gIH07XG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBS0EsU0FBUyxjQUFjLFFBQVEsb0JBQW9CO0FBQ25ELFNBQVMsV0FBVyxRQUFRLDJCQUEyQjtBQXdFdkQsU0FBUyxtQkFBbUIsV0FBb0I7RUFDOUMsT0FBTyxZQUFZLElBQUksS0FBSztBQUM5QjtBQUVBLFNBQVMsU0FBUyxLQUFjO0VBQzlCLE9BQU8sQ0FBQyxDQUFDLFNBQVMsT0FBTyxVQUFVLFlBQVksQ0FBQyxNQUFNLE9BQU8sQ0FBQztBQUNoRTtBQUVBLFNBQVMsZUFBZSxLQUFjO0VBQ3BDLElBQUksQ0FBQyxNQUFNLE9BQU8sQ0FBQyxRQUFRLE9BQU87RUFDbEMsT0FBTyxNQUFNLE1BQU0sQ0FBQztBQUN0QjtBQUVBLFNBQVMsYUFBYSxLQUFjO0VBQ2xDLElBQUksQ0FBQyxNQUFNLE9BQU8sQ0FBQyxRQUFRLE9BQU87RUFDbEMsT0FBTyxNQUFNLE1BQU0sQ0FBQyxVQUFVLEdBQUcsQ0FBQyxDQUFDLFFBQVUsQ0FBQztNQUFFLGFBQWEsTUFBTSxXQUFXO0lBQUMsQ0FBQztBQUNsRjtBQUVBLFNBQVMsWUFBWSxLQUFjO0VBQ2pDLElBQUksQ0FBQyxTQUFTLFFBQVEsT0FBTztFQUM3QixPQUFPO0lB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
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/core - Entry Generators
|
|
3
|
+
*
|
|
4
|
+
* v0.21.0: manifest-driven hydration strategies.
|
|
5
|
+
* Zero DOM interaction - cannot interfere with DSD rendering.
|
|
6
|
+
*/ const CUSTOM_ELEMENT_NAME_RE = /^[a-z][.0-9_a-z]*-[\-.0-9_a-z]*$/;
|
|
7
|
+
const UNSAFE_IMPORT_PROTOCOL_RE = /^(?:javascript|data|vbscript|node):/i;
|
|
8
|
+
const VALID_STRATEGIES = new Set([
|
|
9
|
+
'load',
|
|
10
|
+
'idle',
|
|
11
|
+
'visible',
|
|
12
|
+
'only'
|
|
13
|
+
]);
|
|
14
|
+
function hasControlCharacter(value) {
|
|
15
|
+
for(let i = 0; i < value.length; i++){
|
|
16
|
+
const code = value.charCodeAt(i);
|
|
17
|
+
if (code <= 0x1f || code === 0x7f) return true;
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
export function validateClientIslandEntry(entry) {
|
|
22
|
+
if (!CUSTOM_ELEMENT_NAME_RE.test(entry.tagName)) {
|
|
23
|
+
throw new Error(`Invalid island tagName: ${entry.tagName}`);
|
|
24
|
+
}
|
|
25
|
+
if (!entry.modulePath || hasControlCharacter(entry.modulePath) || /[\r\n]/.test(entry.modulePath) || UNSAFE_IMPORT_PROTOCOL_RE.test(entry.modulePath)) {
|
|
26
|
+
throw new Error(`Invalid island modulePath for ${entry.tagName}: ${entry.modulePath}`);
|
|
27
|
+
}
|
|
28
|
+
if (!VALID_STRATEGIES.has(entry.strategy)) {
|
|
29
|
+
throw new Error(`Invalid island strategy for ${entry.tagName}: ${String(entry.strategy)}. ` + 'Use one of: load, idle, visible, only.');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function generateClientEntry(islands) {
|
|
33
|
+
islands.forEach(validateClientIslandEntry);
|
|
34
|
+
if (islands.length === 0) {
|
|
35
|
+
return '// openElement Client Entry - No islands detected, zero client JS needed\n';
|
|
36
|
+
}
|
|
37
|
+
const islandMap = islands.map((i)=>` ${JSON.stringify(i.tagName)}: () => import(${JSON.stringify(i.modulePath)})`).join(',\n');
|
|
38
|
+
const tags = islands.map((i)=>JSON.stringify(i.tagName)).join(', ');
|
|
39
|
+
const loadTags = islands.filter((i)=>i.strategy === 'load').map((i)=>JSON.stringify(i.tagName)).join(', ');
|
|
40
|
+
const visibleTags = islands.filter((i)=>i.strategy === 'visible').map((i)=>JSON.stringify(i.tagName)).join(', ');
|
|
41
|
+
const idleTags = islands.filter((i)=>i.strategy === 'idle').map((i)=>JSON.stringify(i.tagName)).join(', ');
|
|
42
|
+
const onlyTags = islands.filter((i)=>i.strategy === 'only').map((i)=>JSON.stringify(i.tagName)).join(', ');
|
|
43
|
+
return `// openElement Client Entry (v0.21 - load/idle/visible/only)
|
|
44
|
+
// load islands import immediately.
|
|
45
|
+
// idle islands import during browser idle time.
|
|
46
|
+
// visible islands import when their host enters the viewport.
|
|
47
|
+
// only islands are client-only and import immediately (no DSD/SSR).
|
|
48
|
+
// Zero DOM interaction - safe with DSD rendering.
|
|
49
|
+
|
|
50
|
+
var log = {
|
|
51
|
+
warn: function() { var a = ['[openElement]']; a.push.apply(a, arguments); console.warn.apply(console, a); },
|
|
52
|
+
error: function() { var a = ['[openElement]']; a.push.apply(a, arguments); console.error.apply(console, a); },
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
var __map = {
|
|
56
|
+
${islandMap}
|
|
57
|
+
};
|
|
58
|
+
var __tags = [${tags}];
|
|
59
|
+
|
|
60
|
+
function __load(tag) {
|
|
61
|
+
if (__map[tag]) {
|
|
62
|
+
__map[tag]().catch(function(e) { log.warn(tag, e); });
|
|
63
|
+
__map[tag] = null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function __onReady(fn) {
|
|
68
|
+
if (document.readyState === 'loading') {
|
|
69
|
+
document.addEventListener('DOMContentLoaded', fn, { once: true });
|
|
70
|
+
} else {
|
|
71
|
+
fn();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function __dispatchReady(strategy, tags) {
|
|
76
|
+
document.dispatchEvent(new CustomEvent('open:ready', {
|
|
77
|
+
detail: { strategy: strategy, islands: tags }
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// client:load islands - import immediately
|
|
82
|
+
[${loadTags || ''}].filter(Boolean).forEach(__load);
|
|
83
|
+
|
|
84
|
+
// client:only islands - import immediately, no DSD/SSR expected
|
|
85
|
+
${onlyTags ? `var __onlyTags = [${onlyTags || ''}];\n__onlyTags.forEach(__load);\n` : '// No client:only islands\n'}
|
|
86
|
+
// client:visible islands - load when their element enters viewport
|
|
87
|
+
${visibleTags ? `var __visibleTags = [${visibleTags || ''}];
|
|
88
|
+
var __observedTags = [];
|
|
89
|
+
function __observeVisible() {
|
|
90
|
+
if (!('IntersectionObserver' in window)) {
|
|
91
|
+
__visibleTags.forEach(__load);
|
|
92
|
+
__dispatchReady('visible', __visibleTags);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
__visibleTags.forEach(function(tag) {
|
|
96
|
+
var els = document.querySelectorAll(tag);
|
|
97
|
+
if (els.length > 0 && __observedTags.indexOf(tag) === -1) {
|
|
98
|
+
__observedTags.push(tag);
|
|
99
|
+
els.forEach(function(el) {
|
|
100
|
+
var obs = new IntersectionObserver(function(entries) {
|
|
101
|
+
entries.forEach(function(entry) {
|
|
102
|
+
if (entry.isIntersecting) {
|
|
103
|
+
__load(tag);
|
|
104
|
+
__dispatchReady('visible', [tag]);
|
|
105
|
+
obs.disconnect();
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}, { rootMargin: '200px' });
|
|
109
|
+
obs.observe(el);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
__onReady(__observeVisible);` : '// No client:visible islands'}
|
|
115
|
+
|
|
116
|
+
// client:idle islands - defer to browser idle
|
|
117
|
+
${idleTags ? `var __idleTags = [${idleTags || ''}];
|
|
118
|
+
var __deferred = function() {
|
|
119
|
+
__idleTags.forEach(__load);
|
|
120
|
+
__dispatchReady('idle', __idleTags);
|
|
121
|
+
};
|
|
122
|
+
var __schedule = window.requestIdleCallback || window.requestAnimationFrame || function(fn) { setTimeout(fn, 50); };
|
|
123
|
+
__schedule(__deferred);` : '// No client:idle islands'}
|
|
124
|
+
`;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9zc2cvc3JjL2VudHJ5LWdlbmVyYXRvcnMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAb3BlbmVsZW1lbnQvY29yZSAtIEVudHJ5IEdlbmVyYXRvcnNcbiAqXG4gKiB2MC4yMS4wOiBtYW5pZmVzdC1kcml2ZW4gaHlkcmF0aW9uIHN0cmF0ZWdpZXMuXG4gKiBaZXJvIERPTSBpbnRlcmFjdGlvbiAtIGNhbm5vdCBpbnRlcmZlcmUgd2l0aCBEU0QgcmVuZGVyaW5nLlxuICovXG5cbmltcG9ydCB0eXBlIHsgSHlkcmF0aW9uU3RyYXRlZ3kgfSBmcm9tICdAb3BlbmVsZW1lbnQvcHJvdG9jb2wvZnJhbWV3b3JrJztcbmltcG9ydCB0eXBlIHsgQ2xpZW50SXNsYW5kRW50cnkgfSBmcm9tICdAb3BlbmVsZW1lbnQvcHJvdG9jb2wvc3NnJztcblxuY29uc3QgQ1VTVE9NX0VMRU1FTlRfTkFNRV9SRSA9IC9eW2Etel1bLjAtOV9hLXpdKi1bXFwtLjAtOV9hLXpdKiQvO1xuY29uc3QgVU5TQUZFX0lNUE9SVF9QUk9UT0NPTF9SRSA9IC9eKD86amF2YXNjcmlwdHxkYXRhfHZic2NyaXB0fG5vZGUpOi9pO1xuY29uc3QgVkFMSURfU1RSQVRFR0lFUyA9IG5ldyBTZXQ8SHlkcmF0aW9uU3RyYXRlZ3k+KFsnbG9hZCcsICdpZGxlJywgJ3Zpc2libGUnLCAnb25seSddKTtcblxuZnVuY3Rpb24gaGFzQ29udHJvbENoYXJhY3Rlcih2YWx1ZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdmFsdWUubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBjb2RlID0gdmFsdWUuY2hhckNvZGVBdChpKTtcbiAgICBpZiAoY29kZSA8PSAweDFmIHx8IGNvZGUgPT09IDB4N2YpIHJldHVybiB0cnVlO1xuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlQ2xpZW50SXNsYW5kRW50cnkoZW50cnk6IENsaWVudElzbGFuZEVudHJ5KTogdm9pZCB7XG4gIGlmICghQ1VTVE9NX0VMRU1FTlRfTkFNRV9SRS50ZXN0KGVudHJ5LnRhZ05hbWUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGlzbGFuZCB0YWdOYW1lOiAke2VudHJ5LnRhZ05hbWV9YCk7XG4gIH1cbiAgaWYgKFxuICAgICFlbnRyeS5tb2R1bGVQYXRoIHx8XG4gICAgaGFzQ29udHJvbENoYXJhY3RlcihlbnRyeS5tb2R1bGVQYXRoKSB8fFxuICAgIC9bXFxyXFxuXS8udGVzdChlbnRyeS5tb2R1bGVQYXRoKSB8fFxuICAgIFVOU0FGRV9JTVBPUlRfUFJPVE9DT0xfUkUudGVzdChlbnRyeS5tb2R1bGVQYXRoKVxuICApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgaXNsYW5kIG1vZHVsZVBhdGggZm9yICR7ZW50cnkudGFnTmFtZX06ICR7ZW50cnkubW9kdWxlUGF0aH1gKTtcbiAgfVxuICBpZiAoIVZBTElEX1NUUkFURUdJRVMuaGFzKGVudHJ5LnN0cmF0ZWd5KSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBJbnZhbGlkIGlzbGFuZCBzdHJhdGVneSBmb3IgJHtlbnRyeS50YWdOYW1lfTogJHtTdHJpbmcoZW50cnkuc3RyYXRlZ3kpfS4gYCArXG4gICAgICAgICdVc2Ugb25lIG9mOiBsb2FkLCBpZGxlLCB2aXNpYmxlLCBvbmx5LicsXG4gICAgKTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVDbGllbnRFbnRyeShcbiAgaXNsYW5kczogQ2xpZW50SXNsYW5kRW50cnlbXSxcbik6IHN0cmluZyB7XG4gIGlzbGFuZHMuZm9yRWFjaCh2YWxpZGF0ZUNsaWVudElzbGFuZEVudHJ5KTtcblxuICBpZiAoaXNsYW5kcy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gJy8vIG9wZW5FbGVtZW50IENsaWVudCBFbnRyeSAtIE5vIGlzbGFuZHMgZGV0ZWN0ZWQsIHplcm8gY2xpZW50IEpTIG5lZWRlZFxcbic7XG4gIH1cblxuICBjb25zdCBpc2xhbmRNYXAgPSBpc2xhbmRzXG4gICAgLm1hcCgoaSkgPT4gYCAgJHtKU09OLnN0cmluZ2lmeShpLnRhZ05hbWUpfTogKCkgPT4gaW1wb3J0KCR7SlNPTi5zdHJpbmdpZnkoaS5tb2R1bGVQYXRoKX0pYClcbiAgICAuam9pbignLFxcbicpO1xuXG4gIGNvbnN0IHRhZ3MgPSBpc2xhbmRzLm1hcCgoaSkgPT4gSlNPTi5zdHJpbmdpZnkoaS50YWdOYW1lKSkuam9pbignLCAnKTtcbiAgY29uc3QgbG9hZFRhZ3MgPSBpc2xhbmRzXG4gICAgLmZpbHRlcigoaSkgPT4gaS5zdHJhdGVneSA9PT0gJ2xvYWQnKVxuICAgIC5tYXAoKGkpID0+IEpTT04uc3RyaW5naWZ5KGkudGFnTmFtZSkpXG4gICAgLmpvaW4oJywgJyk7XG4gIGNvbnN0IHZpc2libGVUYWdzID0gaXNsYW5kc1xuICAgIC5maWx0ZXIoKGkpID0+IGkuc3RyYXRlZ3kgPT09ICd2aXNpYmxlJylcbiAgICAubWFwKChpKSA9PiBKU09OLnN0cmluZ2lmeShpLnRhZ05hbWUpKVxuICAgIC5qb2luKCcsICcpO1xuICBjb25zdCBpZGxlVGFncyA9IGlzbGFuZHNcbiAgICAuZmlsdGVyKChpKSA9PiBpLnN0cmF0ZWd5ID09PSAnaWRsZScpXG4gICAgLm1hcCgoaSkgPT4gSlNPTi5zdHJpbmdpZnkoaS50YWdOYW1lKSlcbiAgICAuam9pbignLCAnKTtcbiAgY29uc3Qgb25seVRhZ3MgPSBpc2xhbmRzXG4gICAgLmZpbHRlcigoaSkgPT4gaS5zdHJhdGVneSA9PT0gJ29ubHknKVxuICAgIC5tYXAoKGkpID0+IEpTT04uc3RyaW5naWZ5KGkudGFnTmFtZSkpXG4gICAgLmpvaW4oJywgJyk7XG5cbiAgcmV0dXJuIGAvLyBvcGVuRWxlbWVudCBDbGllbnQgRW50cnkgKHYwLjIxIC0gbG9hZC9pZGxlL3Zpc2libGUvb25seSlcbi8vIGxvYWQgaXNsYW5kcyBpbXBvcnQgaW1tZWRpYXRlbHkuXG4vLyBpZGxlIGlzbGFuZHMgaW1wb3J0IGR1cmluZyBicm93c2VyIGlkbGUgdGltZS5cbi8vIHZpc2libGUgaXNsYW5kcyBpbXBvcnQgd2hlbiB0aGVpciBob3N0IGVudGVycyB0aGUgdmlld3BvcnQuXG4vLyBvbmx5IGlzbGFuZHMgYXJlIGNsaWVudC1vbmx5IGFuZCBpbXBvcnQgaW1tZWRpYXRlbHkgKG5vIERTRC9TU1IpLlxuLy8gWmVybyBET00gaW50ZXJhY3Rpb24gLSBzYWZlIHdpdGggRFNEIHJlbmRlcmluZy5cblxudmFyIGxvZyA9IHtcbiAgd2FybjogZnVuY3Rpb24oKSB7IHZhciBhID0gWydbb3BlbkVsZW1lbnRdJ107IGEucHVzaC5hcHBseShhLCBhcmd1bWVudHMpOyBjb25zb2xlLndhcm4uYXBwbHkoY29uc29sZSwgYSk7IH0sXG4gIGVycm9yOiBmdW5jdGlvbigpIHsgdmFyIGEgPSBbJ1tvcGVuRWxlbWVudF0nXTsgYS5wdXNoLmFwcGx5KGEsIGFyZ3VtZW50cyk7IGNvbnNvbGUuZXJyb3IuYXBwbHkoY29uc29sZSwgYSk7IH0sXG59O1xuXG52YXIgX19tYXAgPSB7XG4ke2lzbGFuZE1hcH1cbn07XG52YXIgX190YWdzID0gWyR7dGFnc31dO1xuXG5mdW5jdGlvbiBfX2xvYWQodGFnKSB7XG4gIGlmIChfX21hcFt0YWddKSB7XG4gICAgX19tYXBbdGFnXSgpLmNhdGNoKGZ1bmN0aW9uKGUpIHsgbG9nLndhcm4odGFnLCBlKTsgfSk7XG4gICAgX19tYXBbdGFnXSA9IG51bGw7XG4gIH1cbn1cblxuZnVuY3Rpb24gX19vblJlYWR5KGZuKSB7XG4gIGlmIChkb2N1bWVudC5yZWFkeVN0YXRlID09PSAnbG9hZGluZycpIHtcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgZm4sIHsgb25jZTogdHJ1ZSB9KTtcbiAgfSBlbHNlIHtcbiAgICBmbigpO1xuICB9XG59XG5cbmZ1bmN0aW9uIF9fZGlzcGF0Y2hSZWFkeShzdHJhdGVneSwgdGFncykge1xuICBkb2N1bWVudC5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudCgnb3BlbjpyZWFkeScsIHtcbiAgICBkZXRhaWw6IHsgc3RyYXRlZ3k6IHN0cmF0ZWd5LCBpc2xhbmRzOiB0YWdzIH1cbiAgfSkpO1xufVxuXG4vLyBjbGllbnQ6bG9hZCBpc2xhbmRzIC0gaW1wb3J0IGltbWVkaWF0ZWx5XG5bJHtsb2FkVGFncyB8fCAnJ31dLmZpbHRlcihCb29sZWFuKS5mb3JFYWNoKF9fbG9hZCk7XG5cbi8vIGNsaWVudDpvbmx5IGlzbGFuZHMgLSBpbXBvcnQgaW1tZWRpYXRlbHksIG5vIERTRC9TU1IgZXhwZWN0ZWRcbiR7XG4gICAgb25seVRhZ3NcbiAgICAgID8gYHZhciBfX29ubHlUYWdzID0gWyR7b25seVRhZ3MgfHwgJyd9XTtcXG5fX29ubHlUYWdzLmZvckVhY2goX19sb2FkKTtcXG5gXG4gICAgICA6ICcvLyBObyBjbGllbnQ6b25seSBpc2xhbmRzXFxuJ1xuICB9XG4vLyBjbGllbnQ6dmlzaWJsZSBpc2xhbmRzIC0gbG9hZCB3aGVuIHRoZWlyIGVsZW1lbnQgZW50ZXJzIHZpZXdwb3J0XG4ke1xuICAgIHZpc2libGVUYWdzXG4gICAgICA/IGB2YXIgX192aXNpYmxlVGFncyA9IFske3Zpc2libGVUYWdzIHx8ICcnfV07XG52YXIgX19vYnNlcnZlZFRhZ3MgPSBbXTtcbmZ1bmN0aW9uIF9fb2JzZXJ2ZVZpc2libGUoKSB7XG4gIGlmICghKCdJbnRlcnNlY3Rpb25PYnNlcnZlcicgaW4gd2luZG93KSkge1xuICAgIF9fdmlzaWJsZVRhZ3MuZm9yRWFjaChfX2xvYWQpO1xuICAgIF9fZGlzcGF0Y2hSZWFkeSgndmlzaWJsZScsIF9fdmlzaWJsZVRhZ3MpO1xuICAgIHJldHVybjtcbiAgfVxuICBfX3Zpc2libGVUYWdzLmZvckVhY2goZnVuY3Rpb24odGFnKSB7XG4gICAgdmFyIGVscyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwodGFnKTtcbiAgICBpZiAoZWxzLmxlbmd0aCA+IDAgJiYgX19vYnNlcnZlZFRhZ3MuaW5kZXhPZih0YWcpID09PSAtMSkge1xuICAgICAgX19vYnNlcnZlZFRhZ3MucHVzaCh0YWcpO1xuICAgICAgZWxzLmZvckVhY2goZnVuY3Rpb24oZWwpIHtcbiAgICAgICAgdmFyIG9icyA9IG5ldyBJbnRlcnNlY3Rpb25PYnNlcnZlcihmdW5jdGlvbihlbnRyaWVzKSB7XG4gICAgICAgICAgZW50cmllcy5mb3JFYWNoKGZ1bmN0aW9uKGVudHJ5KSB7XG4gICAgICAgICAgICBpZiAoZW50cnkuaXNJbnRlcnNlY3RpbmcpIHtcbiAgICAgICAgICAgICAgX19sb2FkKHRhZyk7XG4gICAgICAgICAgICAgIF9fZGlzcGF0Y2hSZWFkeSgndmlzaWJsZScsIFt0YWddKTtcbiAgICAgICAgICAgICAgb2JzLmRpc2Nvbm5lY3QoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSwgeyByb290TWFyZ2luOiAnMjAwcHgnIH0pO1xuICAgICAgICBvYnMub2JzZXJ2ZShlbCk7XG4gICAgICB9KTtcbiAgICB9XG4gIH0pO1xufVxuX19vblJlYWR5KF9fb2JzZXJ2ZVZpc2libGUpO2BcbiAgICAgIDogJy8vIE5vIGNsaWVudDp2aXNpYmxlIGlzbGFuZHMnXG4gIH1cblxuLy8gY2xpZW50OmlkbGUgaXNsYW5kcyAtIGRlZmVyIHRvIGJyb3dzZXIgaWRsZVxuJHtcbiAgICBpZGxlVGFnc1xuICAgICAgPyBgdmFyIF9faWRsZVRhZ3MgPSBbJHtpZGxlVGFncyB8fCAnJ31dO1xudmFyIF9fZGVmZXJyZWQgPSBmdW5jdGlvbigpIHtcbiAgX19pZGxlVGFncy5mb3JFYWNoKF9fbG9hZCk7XG4gIF9fZGlzcGF0Y2hSZWFkeSgnaWRsZScsIF9faWRsZVRhZ3MpO1xufTtcbnZhciBfX3NjaGVkdWxlID0gd2luZG93LnJlcXVlc3RJZGxlQ2FsbGJhY2sgfHwgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSB8fCBmdW5jdGlvbihmbikgeyBzZXRUaW1lb3V0KGZuLCA1MCk7IH07XG5fX3NjaGVkdWxlKF9fZGVmZXJyZWQpO2BcbiAgICAgIDogJy8vIE5vIGNsaWVudDppZGxlIGlzbGFuZHMnXG4gIH1cbmA7XG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0NBS0MsR0FLRCxNQUFNLHlCQUF5QjtBQUMvQixNQUFNLDRCQUE0QjtBQUNsQyxNQUFNLG1CQUFtQixJQUFJLElBQXVCO0VBQUM7RUFBUTtFQUFRO0VBQVc7Q0FBTztBQUV2RixTQUFTLG9CQUFvQixLQUFhO0VBQ3hDLElBQUssSUFBSSxJQUFJLEdBQUcsSUFBSSxNQUFNLE1BQU0sRUFBRSxJQUFLO0lBQ3JDLE1BQU0sT0FBTyxNQUFNLFVBQVUsQ0FBQztJQUM5QixJQUFJLFFBQVEsUUFBUSxTQUFTLE1BQU0sT0FBTztFQUM1QztFQUNBLE9BQU87QUFDVDtBQUVBLE9BQU8sU0FBUywwQkFBMEIsS0FBd0I7RUFDaEUsSUFBSSxDQUFDLHVCQUF1QixJQUFJLENBQUMsTUFBTSxPQUFPLEdBQUc7SUFDL0MsTUFBTSxJQUFJLE1BQU0sQ0FBQyx3QkFBd0IsRUFBRSxNQUFNLE9BQU8sRUFBRTtFQUM1RDtFQUNBLElBQ0UsQ0FBQyxNQUFNLFVBQVUsSUFDakIsb0JBQW9CLE1BQU0sVUFBVSxLQUNwQyxTQUFTLElBQUksQ0FBQyxNQUFNLFVBQVUsS0FDOUIsMEJBQTBCLElBQUksQ0FBQyxNQUFNLFVBQVUsR0FDL0M7SUFDQSxNQUFNLElBQUksTUFBTSxDQUFDLDhCQUE4QixFQUFFLE1BQU0sT0FBTyxDQUFDLEVBQUUsRUFBRSxNQUFNLFVBQVUsRUFBRTtFQUN2RjtFQUNBLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxDQUFDLE1BQU0sUUFBUSxHQUFHO0lBQ3pDLE1BQU0sSUFBSSxNQUNSLENBQUMsNEJBQTRCLEVBQUUsTUFBTSxPQUFPLENBQUMsRUFBRSxFQUFFLE9BQU8sTUFBTSxRQUFRLEVBQUUsRUFBRSxDQUFDLEdBQ3pFO0VBRU47QUFDRjtBQUVBLE9BQU8sU0FBUyxvQkFDZCxPQUE0QjtFQUU1QixRQUFRLE9BQU8sQ0FBQztFQUVoQixJQUFJLFFBQVEsTUFBTSxLQUFLLEdBQUc7SUFDeEIsT0FBTztFQUNUO0VBRUEsTUFBTSxZQUFZLFFBQ2YsR0FBRyxDQUFDLENBQUMsSUFBTSxDQUFDLEVBQUUsRUFBRSxLQUFLLFNBQVMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxlQUFlLEVBQUUsS0FBSyxTQUFTLENBQUMsRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDLEVBQzFGLElBQUksQ0FBQztFQUVSLE1BQU0sT0FBTyxRQUFRLEdBQUcsQ0FBQyxDQUFDLElBQU0sS0FBSyxTQUFTLENBQUMsRUFBRSxPQUFPLEdBQUcsSUFBSSxDQUFDO0VBQ2hFLE1BQU0sV0FBVyxRQUNkLE1BQU0sQ0FBQyxDQUFDLElBQU0sRUFBRSxRQUFRLEtBQUssUUFDN0IsR0FBRyxDQUFDLENBQUMsSUFBTSxLQUFLLFNBQVMsQ0FBQyxFQUFFLE9BQU8sR0FDbkMsSUFBSSxDQUFDO0VBQ1IsTUFBTSxjQUFjLFFBQ2pCLE1BQU0sQ0FBQyxDQUFDLElBQU0sRUFBRSxRQUFRLEtBQUssV0FDN0IsR0FBRyxDQUFDLENBQUMsSUFBTSxLQUFLLFNBQVMsQ0FBQyxFQUFFLE9BQU8sR0FDbkMsSUFBSSxDQUFDO0VBQ1IsTUFBTSxXQUFXLFFBQ2QsTUFBTSxDQUFDLENBQUMsSUFBTSxFQUFFLFFBQVEsS0FBSyxRQUM3QixHQUFHLENBQUMsQ0FBQyxJQUFNLEtBQUssU0FBUyxDQUFDLEVBQUUsT0FBTyxHQUNuQyxJQUFJLENBQUM7RUFDUixNQUFNLFdBQVcsUUFDZCxNQUFNLENBQUMsQ0FBQyxJQUFNLEVBQUUsUUFBUSxLQUFLLFFBQzdCLEdBQUcsQ0FBQyxDQUFDLElBQU0sS0FBSyxTQUFTLENBQUMsRUFBRSxPQUFPLEdBQ25DLElBQUksQ0FBQztFQUVSLE9BQU8sQ0FBQzs7Ozs7Ozs7Ozs7OztBQWFWLEVBQUUsVUFBVTs7Y0FFRSxFQUFFLEtBQUs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztDQXdCcEIsRUFBRSxZQUFZLEdBQUc7OztBQUdsQixFQUNJLFdBQ0ksQ0FBQyxrQkFBa0IsRUFBRSxZQUFZLEdBQUcsaUNBQWlDLENBQUMsR0FDdEUsOEJBQ0w7O0FBRUgsRUFDSSxjQUNJLENBQUMscUJBQXFCLEVBQUUsZUFBZSxHQUFHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7NEJBMkJ0QixDQUFDLEdBQ3JCLCtCQUNMOzs7QUFHSCxFQUNJLFdBQ0ksQ0FBQyxrQkFBa0IsRUFBRSxZQUFZLEdBQUc7Ozs7Ozt1QkFNckIsQ0FBQyxHQUNoQiw0QkFDTDtBQUNILENBQUM7QUFDRCJ9
|