@absolutejs/absolute 0.20.0-beta.169 → 0.20.0-beta.170
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/CHANGELOG.md +80 -0
- package/README.md +232 -0
- package/changelog.json +228 -0
- package/dist/angular/browser.js +7 -8
- package/dist/angular/browser.js.map +6 -5
- package/dist/angular/components/core/streamingSlotRegistrar.js +6 -2
- package/dist/angular/components/core/streamingSlotRegistry.js +7 -3
- package/dist/angular/index.js +555 -156
- package/dist/angular/index.js.map +29 -23
- package/dist/angular/server.js +555 -156
- package/dist/angular/server.js.map +29 -23
- package/dist/build/buildWorker.js +14 -8
- package/dist/build.js +4949 -1941
- package/dist/build.js.map +72 -42
- package/dist/cli/{add-7azr0c83.js → add-6a7pjkn9.js} +11 -7
- package/dist/cli/{analyze-3cyek6v3.js → analyze-606fshwa.js} +1 -1
- package/dist/cli/{build-25rz8v25.js → build-g81xqbb9.js} +1 -1
- package/dist/cli/{compile-4jnfxts9.js → compile-9y1w9zpj.js} +3 -3
- package/dist/cli/config/server.js +10699 -1538
- package/dist/cli/{dev-9tk5hn2e.js → dev-hyeb89hp.js} +5 -1
- package/dist/cli/{doctor-4nv2c2j3.js → doctor-h55y9hj1.js} +1 -1
- package/dist/cli/{generate-v75p2fct.js → generate-20x1pkf7.js} +4 -4
- package/dist/cli/{htmx-427swtdz.js → htmx-6mz2h7k1.js} +2 -2
- package/dist/cli/{index-bhbs6d5z.js → index-32ge2w1f.js} +12 -4
- package/dist/cli/{index-a4ws2jwd.js → index-3wz3mktm.js} +1 -1
- package/dist/cli/{index-b7hjgknf.js → index-9sksd8c8.js} +13 -4
- package/dist/cli/{index-eyzwc7gz.js → index-qbrzvmh9.js} +4 -2
- package/dist/cli/index-qw98g1p6.js +269 -0
- package/dist/cli/{index-434b7j4a.js → index-vtp20gwf.js} +69 -1
- package/dist/cli/{index-h7qhz02e.js → index-wk0pyxrg.js} +3 -0
- package/dist/cli/{index-k3y8cb6c.js → index-z6f43b20.js} +1 -1
- package/dist/cli/index.js +16 -16
- package/dist/cli/{islands-8sgky9gh.js → islands-dc54e5y1.js} +1 -1
- package/dist/cli/{ls-4m4yqwww.js → ls-b6zz24nt.js} +1 -1
- package/dist/cli/{mobile-hcxjr2gf.js → mobile-ajnnvqtv.js} +3 -3
- package/dist/cli/prerender-fqpp0m1j.js +10 -0
- package/dist/cli/{remove-1ycjx85k.js → remove-t8x1mrxg.js} +4 -4
- package/dist/cli/{start-mbaejxhm.js → start-d6p831ny.js} +3 -3
- package/dist/cli/{typecheck-dr068pmh.js → typecheck-stbt0qt5.js} +6 -1
- package/dist/cli/{workspace-1sycp9g1.js → workspace-61hh6jq1.js} +1 -1
- package/dist/client/chunks/index-6b66nzyf.js +381 -0
- package/dist/client/chunks/index-6b66nzyf.js.map +11 -0
- package/dist/client/chunks/{islands-rc28k5sx.js → islands-s2ta5ajb.js} +5 -2
- package/dist/client/chunks/{islands-rc28k5sx.js.map → islands-s2ta5ajb.js.map} +7 -6
- package/dist/client/index.js +160 -3
- package/dist/client/index.js.map +6 -4
- package/dist/client/navigation.js +764 -0
- package/dist/client/navigation.js.map +10 -0
- package/dist/client/prefetch.js +33 -375
- package/dist/client/prefetch.js.map +3 -4
- package/dist/core/streamingSlotRegistrar.js +5 -2
- package/dist/core/streamingSlotRegistrar.js.map +5 -4
- package/dist/core/streamingSlotRegistry.js +5 -2
- package/dist/core/streamingSlotRegistry.js.map +5 -4
- package/dist/dev/client/cspNonce.ts +28 -0
- package/dist/dev/client/handlers/html.ts +4 -3
- package/dist/dev/client/handlers/htmx.ts +3 -2
- package/dist/dev/client/handlers/svelte.ts +15 -90
- package/dist/dev/client/syncDevtools.ts +2 -1
- package/dist/dev/serverBootstrap.js +11 -4
- package/dist/i18n/index.js +543 -0
- package/dist/i18n/index.js.map +15 -0
- package/dist/index.js +6339 -2233
- package/dist/index.js.map +89 -54
- package/dist/islands/index.js +282 -40
- package/dist/islands/index.js.map +14 -10
- package/dist/mobile/browser.js +7 -2
- package/dist/mobile/browser.js.map +5 -4
- package/dist/mobile/index.js +7 -2
- package/dist/mobile/index.js.map +5 -4
- package/dist/mobile/remoteMacAgentEntry.js +1 -1
- package/dist/react/components/browser/index.js +94 -4
- package/dist/react/components/index.js +150 -10
- package/dist/react/components/index.js.map +15 -10
- package/dist/react/hooks/index.js +479 -13
- package/dist/react/hooks/index.js.map +12 -4
- package/dist/react/index.js +769 -166
- package/dist/react/index.js.map +32 -21
- package/dist/react/router/browser.js +21 -4
- package/dist/react/router/browser.js.map +5 -4
- package/dist/react/router/index.js +21 -4
- package/dist/react/router/index.js.map +5 -4
- package/dist/react/server.js +597 -203
- package/dist/react/server.js.map +25 -15
- package/dist/src/angular/zoneRuntime.d.ts +5 -0
- package/dist/src/build/buildReactServerComponents.d.ts +22 -0
- package/dist/src/build/downlevelAsyncForZone.d.ts +1 -0
- package/dist/src/build/fileRoutes.d.ts +65 -0
- package/dist/src/build/fonts/buildFonts.d.ts +25 -0
- package/dist/src/build/fonts/fallbackMetrics.d.ts +13 -0
- package/dist/src/build/fonts/googleFonts.d.ts +18 -0
- package/dist/src/build/fonts/injectFontTags.d.ts +7 -0
- package/dist/src/build/fonts/parseFontMetrics.d.ts +4 -0
- package/dist/src/build/generateReactIndexes.d.ts +7 -1
- package/dist/src/build/htmlIncludes.d.ts +16 -0
- package/dist/src/build/inlineSourceMapComment.d.ts +1 -0
- package/dist/src/build/scanConventions.d.ts +3 -0
- package/dist/src/build/vitals.d.ts +21 -0
- package/dist/src/client/formActions.d.ts +29 -0
- package/dist/src/client/index.d.ts +2 -0
- package/dist/src/client/navigation.d.ts +16 -0
- package/dist/src/client/prefetch.d.ts +2 -30
- package/dist/src/core/build.d.ts +2 -2
- package/dist/src/core/cspNonce.d.ts +12 -0
- package/dist/src/core/fileRouteAdapter.d.ts +15 -0
- package/dist/src/core/fileRoutes.d.ts +5 -0
- package/dist/src/core/formActionFlash.d.ts +25 -0
- package/dist/src/core/formActions.d.ts +249 -0
- package/dist/src/core/index.d.ts +5 -0
- package/dist/src/core/partialPrerender.d.ts +28 -0
- package/dist/src/core/partialPrerenderServe.d.ts +24 -0
- package/dist/src/core/precompressed.d.ts +11 -1
- package/dist/src/core/prerenderNonce.d.ts +9 -0
- package/dist/src/core/productionRuntime.d.ts +4 -2
- package/dist/src/core/serverOnlyStaticFiles.d.ts +8 -0
- package/dist/src/core/staticHtmlNonce.d.ts +2 -0
- package/dist/src/core/vitals.d.ts +108 -0
- package/dist/src/dev/angular/fastHmrCompiler.d.ts +1 -1
- package/dist/src/dev/client/cspNonce.d.ts +2 -0
- package/dist/src/dev/fileRouteRefresher.d.ts +5 -0
- package/dist/src/dev/importCost/instrument.d.ts +1 -1
- package/dist/src/dev/reactServerComponentsRebuild.d.ts +3 -0
- package/dist/src/i18n/defineMessages.d.ts +5 -0
- package/dist/src/i18n/formatMessage.d.ts +26 -0
- package/dist/src/i18n/index.d.ts +6 -0
- package/dist/src/i18n/intlCache.d.ts +5 -0
- package/dist/src/i18n/routing.d.ts +28 -0
- package/dist/src/i18n/translator.d.ts +11 -0
- package/dist/src/mobile/androidRelease.d.ts +2 -2
- package/dist/src/mobile/iosRelease.d.ts +4 -4
- package/dist/src/mobile/materializedBundle.d.ts +1 -1
- package/dist/src/mobile/mobileInspect.d.ts +1 -1
- package/dist/src/mobile/releaseArtifact.d.ts +2 -2
- package/dist/src/mobile/remoteMacProtocol.d.ts +2 -2
- package/dist/src/plugins/i18n.d.ts +30 -0
- package/dist/src/plugins/index.d.ts +2 -1
- package/dist/src/plugins/secureHeaders.d.ts +48 -0
- package/dist/src/react/components/Head.d.ts +1 -1
- package/dist/src/react/components/StreamSlot.browser.d.ts +1 -0
- package/dist/src/react/components/StreamSlot.d.ts +5 -1
- package/dist/src/react/components/SuspenseSlot.browser.d.ts +2 -0
- package/dist/src/react/components/SuspenseSlot.d.ts +12 -0
- package/dist/src/react/fileRoute.d.ts +18 -0
- package/dist/src/react/hooks/index.d.ts +4 -0
- package/dist/src/react/hooks/useFormAction.d.ts +42 -0
- package/dist/src/react/hooks/useI18n.d.ts +15 -0
- package/dist/src/react/index.d.ts +2 -0
- package/dist/src/react/server.d.ts +2 -0
- package/dist/src/react/serverComponents/constants.d.ts +11 -0
- package/dist/src/react/serverComponents/flightPayload.d.ts +2 -0
- package/dist/src/react/serverComponents/pageHandler.d.ts +14 -0
- package/dist/src/svelte/browser.d.ts +1 -0
- package/dist/src/svelte/fileRoute.d.ts +15 -0
- package/dist/src/svelte/i18n.d.ts +8 -0
- package/dist/src/svelte/index.d.ts +2 -0
- package/dist/src/svelte/lowerAwaitSlotSyntax.d.ts +5 -1
- package/dist/src/svelte/renderToReadableStream.d.ts +10 -2
- package/dist/src/svelte/router/browser.d.ts +3 -1
- package/dist/src/svelte/router/goto.d.ts +13 -10
- package/dist/src/svelte/router/guards.d.ts +43 -0
- package/dist/src/svelte/router/index.d.ts +3 -1
- package/dist/src/svelte/router/lazy.d.ts +17 -0
- package/dist/src/svelte/router/lazyModule.d.ts +29 -0
- package/dist/src/svelte/router/navigation.d.ts +55 -0
- package/dist/src/svelte/router/pushState.d.ts +4 -2
- package/dist/src/svelte/router/scroll.d.ts +34 -0
- package/dist/src/svelte/routerSsr.d.ts +9 -0
- package/dist/src/svelte/server.d.ts +1 -0
- package/dist/src/utils/cspNonceRef.d.ts +8 -0
- package/dist/src/utils/fontAssets.d.ts +17 -0
- package/dist/src/utils/formActionProtocol.d.ts +10 -0
- package/dist/src/utils/generateHeadElement.d.ts +1 -1
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/inlinePageCss.d.ts +18 -0
- package/dist/src/utils/loadConfig.d.ts +5 -0
- package/dist/src/utils/localeRef.d.ts +10 -0
- package/dist/src/utils/resolveConvention.d.ts +6 -1
- package/dist/src/utils/streamingSlots.d.ts +5 -0
- package/dist/src/vue/browser.d.ts +2 -0
- package/dist/src/vue/components/Image.d.ts +2 -2
- package/dist/src/vue/index.d.ts +2 -0
- package/dist/src/vue/serverDataPayload.d.ts +32 -0
- package/dist/src/vue/serverDataState.d.ts +9 -0
- package/dist/src/vue/useServerData.browser.d.ts +6 -0
- package/dist/src/vue/useServerData.d.ts +24 -0
- package/dist/svelte/browser.js +330 -3
- package/dist/svelte/browser.js.map +8 -4
- package/dist/svelte/components/AwaitSlot.svelte +5 -0
- package/dist/svelte/components/Head.svelte +50 -0
- package/dist/svelte/components/JsonLd.svelte +9 -1
- package/dist/svelte/components/StreamSlot.svelte +5 -0
- package/dist/svelte/index.js +1017 -117
- package/dist/svelte/index.js.map +38 -24
- package/dist/svelte/router/Link.svelte +40 -8
- package/dist/svelte/router/Route.svelte +157 -12
- package/dist/svelte/router/Route.svelte.d.ts +39 -5
- package/dist/svelte/router/Router.svelte +140 -25
- package/dist/svelte/router/Router.svelte.d.ts +5 -1
- package/dist/svelte/router/browser.ts +10 -0
- package/dist/svelte/router/goto.ts +15 -86
- package/dist/svelte/router/guards.ts +112 -0
- package/dist/svelte/router/index.ts +10 -0
- package/dist/svelte/router/lazy.ts +82 -0
- package/dist/svelte/router/lazyModule.ts +74 -0
- package/dist/svelte/router/navigation.ts +412 -0
- package/dist/svelte/router/pushState.ts +7 -4
- package/dist/svelte/router/scroll.ts +286 -0
- package/dist/svelte/server.js +747 -252
- package/dist/svelte/server.js.map +30 -20
- package/dist/types/angular.d.ts +2 -0
- package/dist/types/build.d.ts +37 -0
- package/dist/types/conventions.d.ts +3 -0
- package/dist/types/fileRoutes.d.ts +72 -0
- package/dist/types/fonts.d.ts +86 -0
- package/dist/types/formAction.d.ts +54 -0
- package/dist/types/globals.d.ts +10 -0
- package/dist/types/i18n.d.ts +185 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/metadata.d.ts +11 -0
- package/dist/types/navigation.d.ts +37 -0
- package/dist/types/prefetch.d.ts +10 -0
- package/dist/types/sitemap.d.ts +4 -0
- package/dist/types/svelteRouter.d.ts +89 -2
- package/dist/types/svelteRouter.ts +112 -2
- package/dist/types/vue.d.ts +46 -1
- package/dist/utils/iconVersion.ts +34 -0
- package/dist/vue/browser.js +107 -11
- package/dist/vue/browser.js.map +7 -4
- package/dist/vue/components/index.js +5 -2
- package/dist/vue/components/index.js.map +5 -4
- package/dist/vue/index.js +712 -158
- package/dist/vue/index.js.map +32 -23
- package/dist/vue/server.js +310 -79
- package/dist/vue/server.js.map +20 -15
- package/package.json +9 -1
- package/dist/cli/prerender-mfnwsvyt.js +0 -7
- package/dist/src/plugins/pageRouter.d.ts +0 -1
- /package/dist/cli/{index-j7m8pq48.js → index-rervww4p.js} +0 -0
|
@@ -35,7 +35,10 @@ import {
|
|
|
35
35
|
} from "./index-71gchbzt.js";
|
|
36
36
|
import {
|
|
37
37
|
loadConfig
|
|
38
|
-
} from "./index-
|
|
38
|
+
} from "./index-wk0pyxrg.js";
|
|
39
|
+
import {
|
|
40
|
+
ensureFileRouteModule
|
|
41
|
+
} from "./index-qw98g1p6.js";
|
|
39
42
|
import {
|
|
40
43
|
TUNNEL_CONTROL_PATH,
|
|
41
44
|
TUNNEL_FORWARDED_HOST_HEADER,
|
|
@@ -2467,6 +2470,7 @@ var dev = async (serverEntry, configPath, options = {}) => {
|
|
|
2467
2470
|
} catch {
|
|
2468
2471
|
return;
|
|
2469
2472
|
}
|
|
2473
|
+
ensureFileRouteModule(cfg);
|
|
2470
2474
|
const refreshedDevConfig = resolveDevConfig(cfg?.dev);
|
|
2471
2475
|
if (options.androidDevice && ["localhost", "127.0.0.1", "::1"].includes(refreshedDevConfig.host)) {
|
|
2472
2476
|
refreshedDevConfig.host = "0.0.0.0";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import"./index-
|
|
2
|
+
import"./index-wk0pyxrg.js";
|
|
3
3
|
import {
|
|
4
4
|
frameworks,
|
|
5
5
|
resolveProject,
|
|
6
6
|
selectFramework,
|
|
7
7
|
toModuleSpecifier
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-qbrzvmh9.js";
|
|
9
9
|
import"./index-fgz435qn.js";
|
|
10
10
|
import {
|
|
11
11
|
wirePluginUse
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-3wz3mktm.js";
|
|
13
13
|
import {
|
|
14
14
|
isValidName,
|
|
15
15
|
toCamelCase,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
toTitleCase,
|
|
19
19
|
emptyOutcome,
|
|
20
20
|
generatePage
|
|
21
|
-
} from "./index-
|
|
21
|
+
} from "./index-9sksd8c8.js";
|
|
22
22
|
import {
|
|
23
23
|
colors
|
|
24
24
|
} from "./index-xw1byvzp.js";
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
createElysiaOpenApiTypeboxPlugin,
|
|
21
21
|
createOptionalPeerPlugin,
|
|
22
22
|
resolveServerBundleExternals
|
|
23
|
-
} from "./index-
|
|
23
|
+
} from "./index-rervww4p.js";
|
|
24
24
|
import {
|
|
25
25
|
normalizeAbsoluteMobileConfig2
|
|
26
26
|
} from "./index-t7yf3vxs.js";
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
} from "./index-pch0v1z6.js";
|
|
30
30
|
import {
|
|
31
31
|
loadConfig
|
|
32
|
-
} from "./index-
|
|
32
|
+
} from "./index-wk0pyxrg.js";
|
|
33
33
|
import {
|
|
34
34
|
stripStringsAndComments
|
|
35
35
|
} from "./index-prs14ys9.js";
|
|
@@ -76,6 +76,7 @@ var RUNTIME_KEYS = [
|
|
|
76
76
|
"static",
|
|
77
77
|
"svelteDirectory",
|
|
78
78
|
"telemetry",
|
|
79
|
+
"vitals",
|
|
79
80
|
"vueDirectory"
|
|
80
81
|
];
|
|
81
82
|
var productionRuntimeConfigOf = (config) => {
|
|
@@ -83,6 +84,8 @@ var productionRuntimeConfigOf = (config) => {
|
|
|
83
84
|
for (const key of RUNTIME_KEYS)
|
|
84
85
|
if (config[key] !== undefined)
|
|
85
86
|
picked[key] = config[key];
|
|
87
|
+
if (config.angular?.changeDetection)
|
|
88
|
+
picked.angular = { changeDetection: config.angular.changeDetection };
|
|
86
89
|
const runtime = JSON.parse(JSON.stringify(picked));
|
|
87
90
|
return runtime;
|
|
88
91
|
};
|
|
@@ -178,7 +181,7 @@ var jsxDevRuntimeCompatPath = resolveJsxDevRuntimeCompatPath();
|
|
|
178
181
|
var prerenderStaticPages = async (outputPath, prerenderPort, resolvedOutdir, staticConfig, absoluteVersion, configPath) => {
|
|
179
182
|
const prerenderStart = performance.now();
|
|
180
183
|
process.stdout.write(cliTag("\x1B[36m", "Pre-rendering static pages"));
|
|
181
|
-
const { prerenderWithServer } = await import("./prerender-
|
|
184
|
+
const { prerenderWithServer } = await import("./prerender-fqpp0m1j.js");
|
|
182
185
|
try {
|
|
183
186
|
killStaleProcesses(prerenderPort);
|
|
184
187
|
const result = await prerenderWithServer(outputPath, prerenderPort, resolvedOutdir, staticConfig, {
|
|
@@ -436,10 +439,14 @@ var start2 = async (serverEntry, outdir, configPath, options = {}) => {
|
|
|
436
439
|
};
|
|
437
440
|
const islandRegistrySpec = buildConfig.islands?.registry;
|
|
438
441
|
const islandRegistryPlugin = islandRegistrySpec ? createIslandRegistryDefinitionPlugin(await loadIslandRegistryBuildInfo(resolve(islandRegistrySpec))) : undefined;
|
|
442
|
+
const sharedPageRuntimes = buildConfig.svelteDirectory ? ["svelte", "svelte/*"] : [];
|
|
439
443
|
const serverBundle = await Bun.build({
|
|
440
444
|
define: { "process.env.NODE_ENV": '"production"' },
|
|
441
445
|
entrypoints: [resolve(serverEntry)],
|
|
442
|
-
external:
|
|
446
|
+
external: [
|
|
447
|
+
...resolveServerBundleExternals(buildConfig),
|
|
448
|
+
...sharedPageRuntimes
|
|
449
|
+
],
|
|
443
450
|
outdir: resolvedOutdir,
|
|
444
451
|
plugins: [
|
|
445
452
|
createOptionalPeerPlugin(),
|
|
@@ -453,6 +460,7 @@ var start2 = async (serverEntry, outdir, configPath, options = {}) => {
|
|
|
453
460
|
stubPlugin,
|
|
454
461
|
createBunStringRawUnicodePlugin()
|
|
455
462
|
],
|
|
463
|
+
sourcemap: "linked",
|
|
456
464
|
target: "bun",
|
|
457
465
|
throw: false
|
|
458
466
|
});
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
frameworks,
|
|
4
4
|
sharedDirFor,
|
|
5
5
|
toModuleSpecifier
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-qbrzvmh9.js";
|
|
7
7
|
import {
|
|
8
8
|
findRoutingFile,
|
|
9
9
|
wireRoute
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-3wz3mktm.js";
|
|
11
11
|
|
|
12
12
|
// src/cli/generate/naming.ts
|
|
13
13
|
var tokenize = (raw) => raw.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").split(/[^a-zA-Z0-9]+/).filter((token) => token.length > 0).map((token) => token.toLowerCase());
|
|
@@ -314,13 +314,22 @@ var vuePage = (ctx) => `<script setup lang="ts">
|
|
|
314
314
|
</main>
|
|
315
315
|
</template>
|
|
316
316
|
`;
|
|
317
|
+
var angularNavItems = (items) => items.length === 0 ? "[]" : `[
|
|
318
|
+
${items.map((item) => ` { href: ${JSON.stringify(item.href)}, label: ${JSON.stringify(item.label)} }`).join(`,
|
|
319
|
+
`)}
|
|
320
|
+
]`;
|
|
317
321
|
var angularPage = (ctx) => `import { Component } from '@angular/core';
|
|
318
|
-
import { navData } from '${ctx.navImportPath}';
|
|
319
322
|
|
|
320
323
|
// This page has no per-request DI context, so the SSR handler's
|
|
321
324
|
// \`requestContext\` is an empty object.
|
|
322
325
|
export type Context = Record<string, never>;
|
|
323
326
|
|
|
327
|
+
type NavItem = { href: string; label: string };
|
|
328
|
+
|
|
329
|
+
// The site's pages when this one was generated. Edit freely; generating
|
|
330
|
+
// another page doesn't rewrite this list.
|
|
331
|
+
const navItems: NavItem[] = ${angularNavItems(ctx.navItems)};
|
|
332
|
+
|
|
324
333
|
@Component({
|
|
325
334
|
imports: [],
|
|
326
335
|
selector: '${ctx.kebab}-page',
|
|
@@ -337,7 +346,7 @@ export type Context = Record<string, never>;
|
|
|
337
346
|
\`
|
|
338
347
|
})
|
|
339
348
|
export class ${ctx.pascal}Component {
|
|
340
|
-
navItems =
|
|
349
|
+
navItems = navItems;
|
|
341
350
|
}
|
|
342
351
|
`;
|
|
343
352
|
var htmlHead = (ctx, extraHead) => `<!doctype html>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
loadConfig
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-wk0pyxrg.js";
|
|
5
5
|
import {
|
|
6
6
|
isRecord
|
|
7
7
|
} from "./index-tx0kx9zx.js";
|
|
@@ -419,7 +419,9 @@ var findConfigObject = (sourceFile) => {
|
|
|
419
419
|
if (ts2.isExportAssignment(node) && ts2.isObjectLiteralExpression(node.expression)) {
|
|
420
420
|
return node.expression;
|
|
421
421
|
}
|
|
422
|
-
node.forEachChild((child) =>
|
|
422
|
+
node.forEachChild((child) => {
|
|
423
|
+
pending.push(child);
|
|
424
|
+
});
|
|
423
425
|
}
|
|
424
426
|
return null;
|
|
425
427
|
};
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/build/fileRoutes.ts
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
4
|
+
import {
|
|
5
|
+
dirname,
|
|
6
|
+
extname,
|
|
7
|
+
isAbsolute,
|
|
8
|
+
join,
|
|
9
|
+
relative,
|
|
10
|
+
resolve,
|
|
11
|
+
sep
|
|
12
|
+
} from "path";
|
|
13
|
+
var {Glob } = globalThis.Bun;
|
|
14
|
+
var DEFAULT_DIRECTORY = "routes";
|
|
15
|
+
var DEFAULT_OUTPUT = join("src", "routes.gen.ts");
|
|
16
|
+
var HASH_LENGTH = 6;
|
|
17
|
+
var HASH_RADIX = 36;
|
|
18
|
+
var PAGE_GLOBS = {
|
|
19
|
+
react: "**/*.{tsx,jsx}",
|
|
20
|
+
svelte: "**/*.svelte"
|
|
21
|
+
};
|
|
22
|
+
var PAGE_EXTENSIONS = {
|
|
23
|
+
react: [".tsx", ".jsx"],
|
|
24
|
+
svelte: [".svelte"]
|
|
25
|
+
};
|
|
26
|
+
var SERVER_EXTENSIONS = [".server.ts", ".server.js"];
|
|
27
|
+
var CONVENTION_RE = /^(?:.+\.)?(?:error|loading|not-found)\.[^.]+$/;
|
|
28
|
+
var TEST_RE = /\.(?:test|spec)\.[^.]+$/;
|
|
29
|
+
var PARAM_RE = /^\[([A-Za-z_$][\w$]*)\]$/;
|
|
30
|
+
var STATIC_SEGMENT_RE = /^[A-Za-z0-9._~-]+$/;
|
|
31
|
+
var REGISTRY_KEY = Symbol.for("absolutejs.fileRoutes.registry");
|
|
32
|
+
var isRegistry = (value) => typeof value === "object" && value !== null && ("bySource" in value) && value.bySource instanceof Map && ("roots" in value) && Array.isArray(value.roots);
|
|
33
|
+
var registry = () => {
|
|
34
|
+
const existing = Reflect.get(globalThis, REGISTRY_KEY);
|
|
35
|
+
if (isRegistry(existing))
|
|
36
|
+
return existing;
|
|
37
|
+
const created = { bySource: new Map, roots: [] };
|
|
38
|
+
Reflect.set(globalThis, REGISTRY_KEY, created);
|
|
39
|
+
return created;
|
|
40
|
+
};
|
|
41
|
+
var toPosix = (path) => path.split(sep).join("/");
|
|
42
|
+
var optionsOf = (config) => {
|
|
43
|
+
const { fileRoutes } = config;
|
|
44
|
+
if (!fileRoutes)
|
|
45
|
+
return;
|
|
46
|
+
const options = fileRoutes === true ? {} : fileRoutes;
|
|
47
|
+
return options;
|
|
48
|
+
};
|
|
49
|
+
var resolveFileRoutes = (config, root = process.cwd()) => {
|
|
50
|
+
const options = optionsOf(config);
|
|
51
|
+
if (!options)
|
|
52
|
+
return;
|
|
53
|
+
const directory = options.directory ?? DEFAULT_DIRECTORY;
|
|
54
|
+
const roots = [];
|
|
55
|
+
if (config.reactDirectory)
|
|
56
|
+
roots.push({
|
|
57
|
+
dir: resolve(root, config.reactDirectory, directory),
|
|
58
|
+
framework: "react"
|
|
59
|
+
});
|
|
60
|
+
if (config.svelteDirectory)
|
|
61
|
+
roots.push({
|
|
62
|
+
dir: resolve(root, config.svelteDirectory, directory),
|
|
63
|
+
framework: "svelte"
|
|
64
|
+
});
|
|
65
|
+
const resolved = {
|
|
66
|
+
output: resolve(root, options.output ?? DEFAULT_OUTPUT),
|
|
67
|
+
roots
|
|
68
|
+
};
|
|
69
|
+
return resolved;
|
|
70
|
+
};
|
|
71
|
+
var pageExtensionOf = (framework, file) => PAGE_EXTENSIONS[framework].find((extension) => file.endsWith(extension));
|
|
72
|
+
var isIgnoredSegment = (segment) => segment.startsWith("_") || segment.startsWith(".");
|
|
73
|
+
var isRouteCandidate = (relativePath) => {
|
|
74
|
+
const segments = relativePath.split("/");
|
|
75
|
+
const fileName = segments[segments.length - 1] ?? "";
|
|
76
|
+
return !segments.some(isIgnoredSegment) && !CONVENTION_RE.test(fileName) && !TEST_RE.test(fileName) && !fileName.includes(".server.");
|
|
77
|
+
};
|
|
78
|
+
var segmentToPath = (segment) => {
|
|
79
|
+
const param = PARAM_RE.exec(segment);
|
|
80
|
+
if (param)
|
|
81
|
+
return { path: `:${param[1]}` };
|
|
82
|
+
if (segment.startsWith("[") || segment.startsWith("(")) {
|
|
83
|
+
return {
|
|
84
|
+
error: `"${segment}" is not supported yet \u2014 only static segments and [param] segments are (catch-all, optional and group segments come later).`
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
if (!STATIC_SEGMENT_RE.test(segment)) {
|
|
88
|
+
return {
|
|
89
|
+
error: `"${segment}" has characters a URL path segment cannot hold unescaped.`
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return { path: segment };
|
|
93
|
+
};
|
|
94
|
+
var stripPageExtension = (framework, relativePath) => {
|
|
95
|
+
const extension = pageExtensionOf(framework, relativePath) ?? "";
|
|
96
|
+
return relativePath.slice(0, relativePath.length - extension.length);
|
|
97
|
+
};
|
|
98
|
+
var fileRoutePath = (framework, relativePath) => {
|
|
99
|
+
const segments = stripPageExtension(framework, relativePath).split("/");
|
|
100
|
+
const last = segments[segments.length - 1];
|
|
101
|
+
const routeSegments = last === "index" ? segments.slice(0, -1) : segments;
|
|
102
|
+
const parts = [];
|
|
103
|
+
for (const segment of routeSegments) {
|
|
104
|
+
const result = segmentToPath(segment);
|
|
105
|
+
if ("error" in result)
|
|
106
|
+
return result;
|
|
107
|
+
parts.push(result.path);
|
|
108
|
+
}
|
|
109
|
+
return { path: `/${parts.join("/")}` };
|
|
110
|
+
};
|
|
111
|
+
var pascalSegment = (segment) => {
|
|
112
|
+
const words = segment.split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
113
|
+
return words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
114
|
+
};
|
|
115
|
+
var fileRoutePageName = (framework, relativePath) => {
|
|
116
|
+
const stem = stripPageExtension(framework, relativePath);
|
|
117
|
+
const readable = stem.split("/").map(pascalSegment).join("");
|
|
118
|
+
const hash = Bun.hash(`${framework}:${stem}`).toString(HASH_RADIX).slice(-HASH_LENGTH).padStart(HASH_LENGTH, "0");
|
|
119
|
+
return `Route${readable}${hash}`;
|
|
120
|
+
};
|
|
121
|
+
var findServerModule = (framework, source) => {
|
|
122
|
+
const extension = pageExtensionOf(framework, source) ?? extname(source);
|
|
123
|
+
const stem = source.slice(0, source.length - extension.length);
|
|
124
|
+
return SERVER_EXTENSIONS.map((suffix) => `${stem}${suffix}`).find((candidate) => existsSync(candidate));
|
|
125
|
+
};
|
|
126
|
+
var routeFromFile = (root, relativePath, problems) => {
|
|
127
|
+
const source = join(root.dir, relativePath);
|
|
128
|
+
const mapped = fileRoutePath(root.framework, relativePath);
|
|
129
|
+
if ("error" in mapped) {
|
|
130
|
+
problems.push(`${toPosix(relative(process.cwd(), source))}: ${mapped.error}`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const route = {
|
|
134
|
+
framework: root.framework,
|
|
135
|
+
name: fileRoutePageName(root.framework, relativePath),
|
|
136
|
+
path: mapped.path,
|
|
137
|
+
server: findServerModule(root.framework, source),
|
|
138
|
+
source
|
|
139
|
+
};
|
|
140
|
+
return route;
|
|
141
|
+
};
|
|
142
|
+
var scanRoot = (root, problems) => {
|
|
143
|
+
if (!existsSync(root.dir))
|
|
144
|
+
return [];
|
|
145
|
+
const glob = new Glob(PAGE_GLOBS[root.framework]);
|
|
146
|
+
const files = [...glob.scanSync({ cwd: root.dir })].map(toPosix).filter(isRouteCandidate).sort();
|
|
147
|
+
return files.map((file) => routeFromFile(root, file, problems)).filter((route) => route !== undefined);
|
|
148
|
+
};
|
|
149
|
+
var conflictMessage = (route, existing) => `${toPosix(relative(process.cwd(), route.source))} and ${toPosix(relative(process.cwd(), existing.source))} both serve ${route.path}; keep one.`;
|
|
150
|
+
var reportConflicts = (routes, problems) => {
|
|
151
|
+
const byPath = new Map;
|
|
152
|
+
for (const route of routes) {
|
|
153
|
+
const existing = byPath.get(route.path);
|
|
154
|
+
if (existing)
|
|
155
|
+
problems.push(conflictMessage(route, existing));
|
|
156
|
+
else
|
|
157
|
+
byPath.set(route.path, route);
|
|
158
|
+
}
|
|
159
|
+
return [...byPath.values()];
|
|
160
|
+
};
|
|
161
|
+
var compareRoutes = (left, right) => left.path.localeCompare(right.path) || left.framework.localeCompare(right.framework);
|
|
162
|
+
var remember = (roots, routes) => {
|
|
163
|
+
const state = registry();
|
|
164
|
+
state.roots = roots;
|
|
165
|
+
state.bySource = new Map(routes.map((route) => [route.source, route]));
|
|
166
|
+
};
|
|
167
|
+
var scanFileRoutes = (config) => {
|
|
168
|
+
const resolved = resolveFileRoutes(config);
|
|
169
|
+
const problems = [];
|
|
170
|
+
if (!resolved) {
|
|
171
|
+
remember([], []);
|
|
172
|
+
const empty = { problems, routes: [] };
|
|
173
|
+
return empty;
|
|
174
|
+
}
|
|
175
|
+
const scanned = resolved.roots.flatMap((root) => scanRoot(root, problems));
|
|
176
|
+
const routes = reportConflicts(scanned, problems).sort(compareRoutes);
|
|
177
|
+
remember(resolved.roots, routes);
|
|
178
|
+
const scan = { problems, routes };
|
|
179
|
+
return scan;
|
|
180
|
+
};
|
|
181
|
+
var quote = (value) => `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
182
|
+
var importSpecifier = (outputDir, target) => {
|
|
183
|
+
const extension = extname(target);
|
|
184
|
+
const keepsExtension = extension === ".svelte";
|
|
185
|
+
const withoutExtension = keepsExtension ? target : target.slice(0, target.length - extension.length);
|
|
186
|
+
const path = toPosix(relative(outputDir, withoutExtension));
|
|
187
|
+
return path.startsWith(".") ? path : `./${path}`;
|
|
188
|
+
};
|
|
189
|
+
var ADAPTERS = {
|
|
190
|
+
react: {
|
|
191
|
+
name: "reactFileRoute",
|
|
192
|
+
specifier: "@absolutejs/absolute/react/server"
|
|
193
|
+
},
|
|
194
|
+
svelte: {
|
|
195
|
+
name: "svelteFileRoute",
|
|
196
|
+
specifier: "@absolutejs/absolute/svelte/server"
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
var renderRoute = (route, outputDir) => {
|
|
200
|
+
const page = quote(importSpecifier(outputDir, route.source));
|
|
201
|
+
const server = route.server ? quote(importSpecifier(outputDir, route.server)) : undefined;
|
|
202
|
+
const serverType = server ? `typeof import(${server})` : "undefined";
|
|
203
|
+
const source = quote(toPosix(relative(process.cwd(), route.source)));
|
|
204
|
+
const lines = [
|
|
205
|
+
` ${ADAPTERS[route.framework].name}<`,
|
|
206
|
+
` ${quote(route.path)},`,
|
|
207
|
+
` typeof import(${page}),`,
|
|
208
|
+
` ${serverType}`,
|
|
209
|
+
` >({`,
|
|
210
|
+
` name: ${quote(route.name)},`,
|
|
211
|
+
...route.framework === "react" ? [` page: () => import(${page}),`] : [],
|
|
212
|
+
` path: ${quote(route.path)},`,
|
|
213
|
+
...server ? [` server: () => import(${server}),`] : [],
|
|
214
|
+
` source: ${source}`,
|
|
215
|
+
` })`
|
|
216
|
+
];
|
|
217
|
+
return lines.join(`
|
|
218
|
+
`);
|
|
219
|
+
};
|
|
220
|
+
var renderFileRouteModule = (routes, output) => {
|
|
221
|
+
const outputDir = dirname(output);
|
|
222
|
+
const frameworks = [...new Set(routes.map((route) => route.framework))].sort().map((framework) => ADAPTERS[framework]);
|
|
223
|
+
const imports = [
|
|
224
|
+
`import type { FileRouteDefinition } from '@absolutejs/absolute';`,
|
|
225
|
+
...frameworks.map((adapter) => `import { ${adapter.name} } from '${adapter.specifier}';`)
|
|
226
|
+
];
|
|
227
|
+
const body = routes.length === 0 ? "export const routeTree: readonly FileRouteDefinition[] = [];" : [
|
|
228
|
+
"export const routeTree: readonly FileRouteDefinition[] = [",
|
|
229
|
+
routes.map((route) => renderRoute(route, outputDir)).join(`,
|
|
230
|
+
`),
|
|
231
|
+
"];"
|
|
232
|
+
].join(`
|
|
233
|
+
`);
|
|
234
|
+
return [
|
|
235
|
+
"// Generated by AbsoluteJS from your route files (`fileRoutes` in",
|
|
236
|
+
"// absolute.config.ts). Do not edit: it is rewritten whenever a route",
|
|
237
|
+
"// file is added, renamed or removed.",
|
|
238
|
+
...imports,
|
|
239
|
+
"",
|
|
240
|
+
body,
|
|
241
|
+
""
|
|
242
|
+
].join(`
|
|
243
|
+
`);
|
|
244
|
+
};
|
|
245
|
+
var writeIfChanged = (path, contents) => {
|
|
246
|
+
const current = existsSync(path) ? readFileSync(path, "utf-8") : undefined;
|
|
247
|
+
if (current === contents)
|
|
248
|
+
return false;
|
|
249
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
250
|
+
writeFileSync(path, contents);
|
|
251
|
+
return true;
|
|
252
|
+
};
|
|
253
|
+
var ensureFileRouteModule = (config) => {
|
|
254
|
+
try {
|
|
255
|
+
syncFileRoutes(config);
|
|
256
|
+
} catch {}
|
|
257
|
+
};
|
|
258
|
+
var syncFileRoutes = (config) => {
|
|
259
|
+
const resolved = resolveFileRoutes(config);
|
|
260
|
+
if (!resolved) {
|
|
261
|
+
remember([], []);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const scan = scanFileRoutes(config);
|
|
265
|
+
const written = writeIfChanged(resolved.output, renderFileRouteModule(scan.routes, resolved.output));
|
|
266
|
+
return { ...scan, output: resolved.output, written };
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
export { ensureFileRouteModule };
|
|
@@ -2,6 +2,70 @@
|
|
|
2
2
|
// src/core/prerender.ts
|
|
3
3
|
import { mkdirSync, readFileSync } from "fs";
|
|
4
4
|
import { join } from "path";
|
|
5
|
+
|
|
6
|
+
// src/core/partialPrerender.ts
|
|
7
|
+
import { rm } from "fs/promises";
|
|
8
|
+
var PARTIAL_HOLES_HEADER = "X-Absolute-Partial-Holes";
|
|
9
|
+
var PARTIAL_SHELL_HEADER = "X-Absolute-Partial-Shell";
|
|
10
|
+
var SINK_STORAGE_KEY = Symbol.for("absolutejs.partialPrerenderHolesSink");
|
|
11
|
+
var decodePartialHoles = (value) => value ? value.split(",").filter(Boolean).map((id) => decodeURIComponent(id)) : [];
|
|
12
|
+
var encodePartialHoles = (ids) => ids.map((id) => encodeURIComponent(id)).join(",");
|
|
13
|
+
var holesPath = (htmlPath) => htmlPath.replace(/\.html$/, ".holes");
|
|
14
|
+
var writePartialHoles = async (htmlPath, response) => {
|
|
15
|
+
const ids = decodePartialHoles(response.headers.get(PARTIAL_HOLES_HEADER));
|
|
16
|
+
if (ids.length > 0) {
|
|
17
|
+
await Bun.write(holesPath(htmlPath), `${encodePartialHoles(ids).split(",").join(`
|
|
18
|
+
`)}
|
|
19
|
+
`);
|
|
20
|
+
} else {
|
|
21
|
+
await rm(holesPath(htmlPath), { force: true });
|
|
22
|
+
}
|
|
23
|
+
return ids;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// src/core/prerenderNonce.ts
|
|
27
|
+
import { rm as rm2 } from "fs/promises";
|
|
28
|
+
|
|
29
|
+
// src/utils/logger.ts
|
|
30
|
+
var colors = {
|
|
31
|
+
blue: "\x1B[34m",
|
|
32
|
+
bold: "\x1B[1m",
|
|
33
|
+
cyan: "\x1B[36m",
|
|
34
|
+
dim: "\x1B[2m",
|
|
35
|
+
green: "\x1B[32m",
|
|
36
|
+
magenta: "\x1B[35m",
|
|
37
|
+
red: "\x1B[31m",
|
|
38
|
+
reset: "\x1B[0m",
|
|
39
|
+
white: "\x1B[37m",
|
|
40
|
+
yellow: "\x1B[33m"
|
|
41
|
+
};
|
|
42
|
+
var frameworkColors = {
|
|
43
|
+
angular: colors.magenta,
|
|
44
|
+
assets: colors.dim,
|
|
45
|
+
css: colors.cyan,
|
|
46
|
+
html: colors.white,
|
|
47
|
+
htmx: colors.white,
|
|
48
|
+
react: colors.blue,
|
|
49
|
+
svelte: colors.yellow,
|
|
50
|
+
vue: colors.green
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// src/core/prerenderNonce.ts
|
|
54
|
+
var CSP_HEADERS = [
|
|
55
|
+
"content-security-policy",
|
|
56
|
+
"content-security-policy-report-only"
|
|
57
|
+
];
|
|
58
|
+
var noncePath = (htmlPath) => htmlPath.replace(/\.html$/, ".nonce");
|
|
59
|
+
var renderedNonce = (response) => CSP_HEADERS.map((name) => response.headers.get(name)).map((policy) => policy?.match(/'nonce-([^']+)'/)?.[1]).find((nonce) => nonce !== undefined);
|
|
60
|
+
var writeRenderedNonce = async (htmlPath, nonce) => {
|
|
61
|
+
if (nonce)
|
|
62
|
+
await Bun.write(noncePath(htmlPath), nonce);
|
|
63
|
+
else
|
|
64
|
+
await rm2(noncePath(htmlPath), { force: true });
|
|
65
|
+
};
|
|
66
|
+
var warned = new Set;
|
|
67
|
+
|
|
68
|
+
// src/core/prerender.ts
|
|
5
69
|
var SERVER_OUTPUT_LIMIT = 4000;
|
|
6
70
|
var STARTUP_POLL_INTERVAL_MS = 100;
|
|
7
71
|
var DEFAULT_STARTUP_TIMEOUT_MS = 30000;
|
|
@@ -62,6 +126,7 @@ var crawlRoutes = async (baseUrl) => {
|
|
|
62
126
|
};
|
|
63
127
|
var prerenderRoute = async (baseUrl, route, prerenderDir, result, log) => {
|
|
64
128
|
const res = await fetchWithTimeout(`${baseUrl}${route}`, {
|
|
129
|
+
headers: { [PARTIAL_SHELL_HEADER]: "1" },
|
|
65
130
|
redirect: "manual"
|
|
66
131
|
}).catch(() => null);
|
|
67
132
|
if (!res) {
|
|
@@ -85,9 +150,12 @@ var prerenderRoute = async (baseUrl, route, prerenderDir, result, log) => {
|
|
|
85
150
|
const fileName = routeToFilename(route);
|
|
86
151
|
const filePath = join(prerenderDir, fileName);
|
|
87
152
|
await Bun.write(filePath, html);
|
|
153
|
+
await writeRenderedNonce(filePath, renderedNonce(res));
|
|
154
|
+
const holes = await writePartialHoles(filePath, res);
|
|
88
155
|
await writeTimestamp(filePath);
|
|
89
156
|
result.routes.set(route, filePath);
|
|
90
|
-
|
|
157
|
+
const partial = holes.length > 0 ? `, partial: ${holes.length} dynamic slot${holes.length === 1 ? "" : "s"}` : "";
|
|
158
|
+
log?.(` Pre-rendered ${route} \u2192 ${fileName} (${html.length} bytes${partial})`);
|
|
91
159
|
};
|
|
92
160
|
var prerender = async (port, outDir, staticConfig, log) => {
|
|
93
161
|
const prerenderDir = join(outDir, "_prerendered");
|
|
@@ -14,8 +14,10 @@ var RESERVED_TOP_LEVEL_KEYS = new Set([
|
|
|
14
14
|
"emberDirectory",
|
|
15
15
|
"entry",
|
|
16
16
|
"env",
|
|
17
|
+
"fileRoutes",
|
|
17
18
|
"htmlDirectory",
|
|
18
19
|
"htmxDirectory",
|
|
20
|
+
"fonts",
|
|
19
21
|
"images",
|
|
20
22
|
"incrementalFiles",
|
|
21
23
|
"islands",
|
|
@@ -34,6 +36,7 @@ var RESERVED_TOP_LEVEL_KEYS = new Set([
|
|
|
34
36
|
"tailwind",
|
|
35
37
|
"ready",
|
|
36
38
|
"visibility",
|
|
39
|
+
"vitals",
|
|
37
40
|
"vueDirectory"
|
|
38
41
|
]);
|
|
39
42
|
var isObject = (value) => typeof value === "object" && value !== null;
|