site-config-stack 1.6.7 → 2.0.0
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/index.cjs +46 -39
- package/dist/index.d.cts +25 -54
- package/dist/index.d.mts +25 -54
- package/dist/index.d.ts +25 -54
- package/dist/index.mjs +46 -39
- package/dist/urls.cjs +30 -0
- package/dist/urls.d.cts +10 -0
- package/dist/urls.d.mts +10 -0
- package/dist/urls.d.ts +10 -0
- package/dist/urls.mjs +27 -0
- package/package.json +13 -2
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,44 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const vue = require('vue');
|
|
3
4
|
const ufo = require('ufo');
|
|
4
5
|
|
|
6
|
+
function normalizeSiteConfig(config) {
|
|
7
|
+
if (typeof config.indexable !== "undefined")
|
|
8
|
+
config.indexable = String(config.indexable) !== "false";
|
|
9
|
+
if (typeof config.trailingSlash !== "undefined" && !config.trailingSlash)
|
|
10
|
+
config.trailingSlash = String(config.trailingSlash) !== "false";
|
|
11
|
+
if (config.url && !ufo.hasProtocol(config.url, { acceptRelative: true, strict: false }))
|
|
12
|
+
config.url = ufo.withHttps(config.url);
|
|
13
|
+
const keys = Object.keys(config).sort((a, b) => a.localeCompare(b));
|
|
14
|
+
const newConfig = {};
|
|
15
|
+
for (const k of keys)
|
|
16
|
+
newConfig[k] = config[k];
|
|
17
|
+
return newConfig;
|
|
18
|
+
}
|
|
19
|
+
function validateSiteConfigStack(stack) {
|
|
20
|
+
const resolved = normalizeSiteConfig(stack.get({
|
|
21
|
+
// we need the context
|
|
22
|
+
debug: true
|
|
23
|
+
}));
|
|
24
|
+
const errors = [];
|
|
25
|
+
if (resolved.url) {
|
|
26
|
+
const val = resolved.url;
|
|
27
|
+
const context = resolved._context?.url || "unknown";
|
|
28
|
+
const url = ufo.parseURL(val);
|
|
29
|
+
if (!url.host)
|
|
30
|
+
errors.push(`url "${val}" from ${context} is not absolute`);
|
|
31
|
+
else if (url.pathname && url.pathname !== "/")
|
|
32
|
+
errors.push(`url "${val}" from ${context} should not contain a path`);
|
|
33
|
+
else if (url.hash)
|
|
34
|
+
errors.push(`url "${val}" from ${context} should not contain a hash`);
|
|
35
|
+
else if (Object.keys(ufo.getQuery(val)).length > 0)
|
|
36
|
+
errors.push(`url "${val}" from ${context} should not contain a query`);
|
|
37
|
+
else if (url.host === "localhost")
|
|
38
|
+
errors.push(`url "${val}" from ${context} should not be localhost`);
|
|
39
|
+
}
|
|
40
|
+
return errors;
|
|
41
|
+
}
|
|
5
42
|
function createSiteConfigStack(options) {
|
|
6
43
|
const debug = options?.debug || false;
|
|
7
44
|
const stack = [];
|
|
@@ -32,13 +69,13 @@ function createSiteConfigStack(options) {
|
|
|
32
69
|
const key = k;
|
|
33
70
|
const val = stack[o][k];
|
|
34
71
|
if (!k.startsWith("_")) {
|
|
35
|
-
siteConfig[k] = val;
|
|
72
|
+
siteConfig[k] = options2?.resolveRefs ? vue.toValue(val) : val;
|
|
36
73
|
if (options2?.debug)
|
|
37
74
|
siteConfig._context[key] = stack[o]._context?.[key] || stack[o]._context || "anonymous";
|
|
38
75
|
}
|
|
39
76
|
}
|
|
40
77
|
}
|
|
41
|
-
return normalizeSiteConfig(siteConfig);
|
|
78
|
+
return options2?.skipNormalize ? siteConfig : normalizeSiteConfig(siteConfig);
|
|
42
79
|
}
|
|
43
80
|
return {
|
|
44
81
|
stack,
|
|
@@ -47,44 +84,14 @@ function createSiteConfigStack(options) {
|
|
|
47
84
|
};
|
|
48
85
|
}
|
|
49
86
|
|
|
50
|
-
function
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (config.url && !ufo.hasProtocol(config.url, { acceptRelative: true, strict: false }))
|
|
56
|
-
config.url = ufo.withHttps(config.url);
|
|
57
|
-
const keys = Object.keys(config).sort((a, b) => a.localeCompare(b));
|
|
58
|
-
const newConfig = {};
|
|
59
|
-
for (const k of keys)
|
|
60
|
-
newConfig[k] = config[k];
|
|
61
|
-
return newConfig;
|
|
62
|
-
}
|
|
63
|
-
function resolveSitePath(pathOrUrl, options) {
|
|
64
|
-
let path = pathOrUrl;
|
|
65
|
-
if (ufo.hasProtocol(pathOrUrl, { strict: false, acceptRelative: true })) {
|
|
66
|
-
const parsed = ufo.parseURL(pathOrUrl);
|
|
67
|
-
path = parsed.pathname;
|
|
68
|
-
}
|
|
69
|
-
const base = ufo.withLeadingSlash(options.base || "/");
|
|
70
|
-
if (base !== "/" && path.startsWith(base)) {
|
|
71
|
-
path = path.slice(base.length);
|
|
72
|
-
}
|
|
73
|
-
const origin = options.absolute ? options.siteUrl : "";
|
|
74
|
-
const baseWithOrigin = options.withBase ? ufo.withBase(base, origin || "/") : origin;
|
|
75
|
-
const resolvedUrl = ufo.withBase(path, baseWithOrigin);
|
|
76
|
-
return path === "/" && !options.withBase ? ufo.withTrailingSlash(resolvedUrl) : fixSlashes(options.trailingSlash, resolvedUrl);
|
|
77
|
-
}
|
|
78
|
-
function fixSlashes(trailingSlash, pathOrUrl) {
|
|
79
|
-
const $url = ufo.parseURL(pathOrUrl);
|
|
80
|
-
const isFileUrl = $url.pathname.includes(".");
|
|
81
|
-
if (isFileUrl)
|
|
82
|
-
return pathOrUrl;
|
|
83
|
-
const fixedPath = trailingSlash ? ufo.withTrailingSlash($url.pathname) : ufo.withoutTrailingSlash($url.pathname);
|
|
84
|
-
return `${$url.protocol ? `${$url.protocol}//` : ""}${$url.host || ""}${fixedPath}${$url.search || ""}${$url.hash || ""}`;
|
|
87
|
+
function envSiteConfig(env) {
|
|
88
|
+
return Object.fromEntries(Object.entries(env).filter(([k]) => k.startsWith("NUXT_SITE_") || k.startsWith("NUXT_PUBLIC_SITE_")).map(([k, v]) => [
|
|
89
|
+
k.replace(/^NUXT_(PUBLIC_)?SITE_/, "").split("_").map((s, i) => i === 0 ? s.toLowerCase() : s[0].toUpperCase() + s.slice(1).toLowerCase()).join(""),
|
|
90
|
+
v
|
|
91
|
+
]));
|
|
85
92
|
}
|
|
86
93
|
|
|
87
94
|
exports.createSiteConfigStack = createSiteConfigStack;
|
|
88
|
-
exports.
|
|
95
|
+
exports.envSiteConfig = envSiteConfig;
|
|
89
96
|
exports.normalizeSiteConfig = normalizeSiteConfig;
|
|
90
|
-
exports.
|
|
97
|
+
exports.validateSiteConfigStack = validateSiteConfigStack;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComputedRef, Ref } from 'vue';
|
|
2
2
|
|
|
3
|
-
interface
|
|
3
|
+
interface SiteConfigResolved {
|
|
4
4
|
/**
|
|
5
5
|
* The canonical Site URL.
|
|
6
6
|
*
|
|
@@ -19,91 +19,62 @@ interface SiteConfig {
|
|
|
19
19
|
*
|
|
20
20
|
* Used by: nuxt-schema-org, nuxt-seo-kit
|
|
21
21
|
*/
|
|
22
|
-
name
|
|
22
|
+
name?: string;
|
|
23
23
|
/**
|
|
24
24
|
* Whether the site is indexable by search engines.
|
|
25
|
+
*
|
|
26
|
+
* @deprecated we should only rely on `env`
|
|
25
27
|
*/
|
|
26
|
-
indexable
|
|
28
|
+
indexable?: boolean;
|
|
27
29
|
/**
|
|
28
30
|
* The environment of the site. Comparable to `process.env.NODE_ENV`.
|
|
29
31
|
*/
|
|
30
|
-
env
|
|
32
|
+
env?: 'production' | 'staging' | 'development' | 'preview' | 'uat' | string;
|
|
31
33
|
/**
|
|
32
34
|
* Whether the site uses trailing slash.
|
|
33
35
|
*/
|
|
34
|
-
trailingSlash
|
|
35
|
-
/**
|
|
36
|
-
* Current locale, set with `@nuxt/i18n`.
|
|
37
|
-
*
|
|
38
|
-
* Falls back to the defaultLocale.
|
|
39
|
-
*/
|
|
40
|
-
currentLocale?: string;
|
|
41
|
-
/**
|
|
42
|
-
* The default locale of the site.
|
|
43
|
-
*/
|
|
44
|
-
defaultLocale: string;
|
|
45
|
-
/**
|
|
46
|
-
* The description of the site.
|
|
47
|
-
*
|
|
48
|
-
* @default `process.env.NUXT_PUBLIC_SITE_DESCRIPTION`
|
|
49
|
-
*
|
|
50
|
-
* Used by: nuxt-schema-org, nuxt-seo-kit
|
|
51
|
-
*/
|
|
52
|
-
description?: string;
|
|
36
|
+
trailingSlash?: boolean;
|
|
53
37
|
/**
|
|
54
|
-
*
|
|
55
|
-
*/
|
|
56
|
-
identity?: {
|
|
57
|
-
/**
|
|
58
|
-
* Use Organization for when the site is a company, business, etc.
|
|
59
|
-
* Use Person for when the site is a personal blog, portfolio, etc.
|
|
60
|
-
*/
|
|
61
|
-
type: 'Organization' | 'Person';
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Twitter (X) profile ID.
|
|
65
|
-
*
|
|
66
|
-
* Used for Schema.org sameAs and `<meta profile>`.
|
|
67
|
-
*
|
|
68
|
-
* @example `@harlan_zw`
|
|
38
|
+
* The mapping of the context of each site config value being set.
|
|
69
39
|
*/
|
|
70
|
-
|
|
40
|
+
_context?: Record<string, string>;
|
|
71
41
|
/**
|
|
72
|
-
*
|
|
42
|
+
* Support any keys as site config.
|
|
73
43
|
*/
|
|
74
|
-
|
|
75
|
-
[key: (string & Record<never, never>)]: any;
|
|
44
|
+
[key: string]: any;
|
|
76
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* @deprecated use SiteConfigResolved
|
|
48
|
+
*/
|
|
49
|
+
type SiteConfig = SiteConfigResolved;
|
|
77
50
|
type MaybeComputedRef<T> = T | (() => T) | ComputedRef<T> | Ref<T>;
|
|
78
51
|
type MaybeComputedRefEntries<T> = {
|
|
79
52
|
[key in keyof T]?: MaybeComputedRef<T[key]>;
|
|
80
53
|
};
|
|
81
|
-
type SiteConfigInput = Omit<MaybeComputedRefEntries<Partial<
|
|
54
|
+
type SiteConfigInput = Omit<MaybeComputedRefEntries<Partial<SiteConfigResolved>>, '_context' | 'indexable'> & {
|
|
82
55
|
_context?: string;
|
|
83
56
|
_priority?: number;
|
|
84
57
|
indexable?: MaybeComputedRef<string | boolean>;
|
|
85
58
|
};
|
|
86
59
|
interface GetSiteConfigOptions {
|
|
87
60
|
debug?: boolean;
|
|
61
|
+
skipNormalize?: boolean;
|
|
62
|
+
resolveRefs?: boolean;
|
|
88
63
|
}
|
|
89
64
|
interface SiteConfigStack {
|
|
90
65
|
stack: Partial<SiteConfigInput>[];
|
|
91
66
|
push: (config: SiteConfigInput) => void;
|
|
92
|
-
get: (options?: GetSiteConfigOptions) =>
|
|
67
|
+
get: (options?: GetSiteConfigOptions) => SiteConfigResolved;
|
|
93
68
|
}
|
|
94
69
|
|
|
70
|
+
declare function normalizeSiteConfig(config: SiteConfigResolved): SiteConfigResolved;
|
|
71
|
+
declare function validateSiteConfigStack(stack: SiteConfigStack): string[];
|
|
95
72
|
declare function createSiteConfigStack(options?: {
|
|
96
73
|
debug: boolean;
|
|
97
74
|
}): SiteConfigStack;
|
|
98
75
|
|
|
99
|
-
declare function
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
trailingSlash: boolean;
|
|
103
|
-
base?: string;
|
|
104
|
-
absolute?: boolean;
|
|
105
|
-
withBase?: boolean;
|
|
106
|
-
}): string;
|
|
107
|
-
declare function fixSlashes(trailingSlash: boolean, pathOrUrl: string): string;
|
|
76
|
+
declare function envSiteConfig(env: Record<string, any>): {
|
|
77
|
+
[k: string]: any;
|
|
78
|
+
};
|
|
108
79
|
|
|
109
|
-
export { type GetSiteConfigOptions, type MaybeComputedRef, type MaybeComputedRefEntries, type SiteConfig, type SiteConfigInput, type SiteConfigStack, createSiteConfigStack,
|
|
80
|
+
export { type GetSiteConfigOptions, type MaybeComputedRef, type MaybeComputedRefEntries, type SiteConfig, type SiteConfigInput, type SiteConfigResolved, type SiteConfigStack, createSiteConfigStack, envSiteConfig, normalizeSiteConfig, validateSiteConfigStack };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComputedRef, Ref } from 'vue';
|
|
2
2
|
|
|
3
|
-
interface
|
|
3
|
+
interface SiteConfigResolved {
|
|
4
4
|
/**
|
|
5
5
|
* The canonical Site URL.
|
|
6
6
|
*
|
|
@@ -19,91 +19,62 @@ interface SiteConfig {
|
|
|
19
19
|
*
|
|
20
20
|
* Used by: nuxt-schema-org, nuxt-seo-kit
|
|
21
21
|
*/
|
|
22
|
-
name
|
|
22
|
+
name?: string;
|
|
23
23
|
/**
|
|
24
24
|
* Whether the site is indexable by search engines.
|
|
25
|
+
*
|
|
26
|
+
* @deprecated we should only rely on `env`
|
|
25
27
|
*/
|
|
26
|
-
indexable
|
|
28
|
+
indexable?: boolean;
|
|
27
29
|
/**
|
|
28
30
|
* The environment of the site. Comparable to `process.env.NODE_ENV`.
|
|
29
31
|
*/
|
|
30
|
-
env
|
|
32
|
+
env?: 'production' | 'staging' | 'development' | 'preview' | 'uat' | string;
|
|
31
33
|
/**
|
|
32
34
|
* Whether the site uses trailing slash.
|
|
33
35
|
*/
|
|
34
|
-
trailingSlash
|
|
35
|
-
/**
|
|
36
|
-
* Current locale, set with `@nuxt/i18n`.
|
|
37
|
-
*
|
|
38
|
-
* Falls back to the defaultLocale.
|
|
39
|
-
*/
|
|
40
|
-
currentLocale?: string;
|
|
41
|
-
/**
|
|
42
|
-
* The default locale of the site.
|
|
43
|
-
*/
|
|
44
|
-
defaultLocale: string;
|
|
45
|
-
/**
|
|
46
|
-
* The description of the site.
|
|
47
|
-
*
|
|
48
|
-
* @default `process.env.NUXT_PUBLIC_SITE_DESCRIPTION`
|
|
49
|
-
*
|
|
50
|
-
* Used by: nuxt-schema-org, nuxt-seo-kit
|
|
51
|
-
*/
|
|
52
|
-
description?: string;
|
|
36
|
+
trailingSlash?: boolean;
|
|
53
37
|
/**
|
|
54
|
-
*
|
|
55
|
-
*/
|
|
56
|
-
identity?: {
|
|
57
|
-
/**
|
|
58
|
-
* Use Organization for when the site is a company, business, etc.
|
|
59
|
-
* Use Person for when the site is a personal blog, portfolio, etc.
|
|
60
|
-
*/
|
|
61
|
-
type: 'Organization' | 'Person';
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Twitter (X) profile ID.
|
|
65
|
-
*
|
|
66
|
-
* Used for Schema.org sameAs and `<meta profile>`.
|
|
67
|
-
*
|
|
68
|
-
* @example `@harlan_zw`
|
|
38
|
+
* The mapping of the context of each site config value being set.
|
|
69
39
|
*/
|
|
70
|
-
|
|
40
|
+
_context?: Record<string, string>;
|
|
71
41
|
/**
|
|
72
|
-
*
|
|
42
|
+
* Support any keys as site config.
|
|
73
43
|
*/
|
|
74
|
-
|
|
75
|
-
[key: (string & Record<never, never>)]: any;
|
|
44
|
+
[key: string]: any;
|
|
76
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* @deprecated use SiteConfigResolved
|
|
48
|
+
*/
|
|
49
|
+
type SiteConfig = SiteConfigResolved;
|
|
77
50
|
type MaybeComputedRef<T> = T | (() => T) | ComputedRef<T> | Ref<T>;
|
|
78
51
|
type MaybeComputedRefEntries<T> = {
|
|
79
52
|
[key in keyof T]?: MaybeComputedRef<T[key]>;
|
|
80
53
|
};
|
|
81
|
-
type SiteConfigInput = Omit<MaybeComputedRefEntries<Partial<
|
|
54
|
+
type SiteConfigInput = Omit<MaybeComputedRefEntries<Partial<SiteConfigResolved>>, '_context' | 'indexable'> & {
|
|
82
55
|
_context?: string;
|
|
83
56
|
_priority?: number;
|
|
84
57
|
indexable?: MaybeComputedRef<string | boolean>;
|
|
85
58
|
};
|
|
86
59
|
interface GetSiteConfigOptions {
|
|
87
60
|
debug?: boolean;
|
|
61
|
+
skipNormalize?: boolean;
|
|
62
|
+
resolveRefs?: boolean;
|
|
88
63
|
}
|
|
89
64
|
interface SiteConfigStack {
|
|
90
65
|
stack: Partial<SiteConfigInput>[];
|
|
91
66
|
push: (config: SiteConfigInput) => void;
|
|
92
|
-
get: (options?: GetSiteConfigOptions) =>
|
|
67
|
+
get: (options?: GetSiteConfigOptions) => SiteConfigResolved;
|
|
93
68
|
}
|
|
94
69
|
|
|
70
|
+
declare function normalizeSiteConfig(config: SiteConfigResolved): SiteConfigResolved;
|
|
71
|
+
declare function validateSiteConfigStack(stack: SiteConfigStack): string[];
|
|
95
72
|
declare function createSiteConfigStack(options?: {
|
|
96
73
|
debug: boolean;
|
|
97
74
|
}): SiteConfigStack;
|
|
98
75
|
|
|
99
|
-
declare function
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
trailingSlash: boolean;
|
|
103
|
-
base?: string;
|
|
104
|
-
absolute?: boolean;
|
|
105
|
-
withBase?: boolean;
|
|
106
|
-
}): string;
|
|
107
|
-
declare function fixSlashes(trailingSlash: boolean, pathOrUrl: string): string;
|
|
76
|
+
declare function envSiteConfig(env: Record<string, any>): {
|
|
77
|
+
[k: string]: any;
|
|
78
|
+
};
|
|
108
79
|
|
|
109
|
-
export { type GetSiteConfigOptions, type MaybeComputedRef, type MaybeComputedRefEntries, type SiteConfig, type SiteConfigInput, type SiteConfigStack, createSiteConfigStack,
|
|
80
|
+
export { type GetSiteConfigOptions, type MaybeComputedRef, type MaybeComputedRefEntries, type SiteConfig, type SiteConfigInput, type SiteConfigResolved, type SiteConfigStack, createSiteConfigStack, envSiteConfig, normalizeSiteConfig, validateSiteConfigStack };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComputedRef, Ref } from 'vue';
|
|
2
2
|
|
|
3
|
-
interface
|
|
3
|
+
interface SiteConfigResolved {
|
|
4
4
|
/**
|
|
5
5
|
* The canonical Site URL.
|
|
6
6
|
*
|
|
@@ -19,91 +19,62 @@ interface SiteConfig {
|
|
|
19
19
|
*
|
|
20
20
|
* Used by: nuxt-schema-org, nuxt-seo-kit
|
|
21
21
|
*/
|
|
22
|
-
name
|
|
22
|
+
name?: string;
|
|
23
23
|
/**
|
|
24
24
|
* Whether the site is indexable by search engines.
|
|
25
|
+
*
|
|
26
|
+
* @deprecated we should only rely on `env`
|
|
25
27
|
*/
|
|
26
|
-
indexable
|
|
28
|
+
indexable?: boolean;
|
|
27
29
|
/**
|
|
28
30
|
* The environment of the site. Comparable to `process.env.NODE_ENV`.
|
|
29
31
|
*/
|
|
30
|
-
env
|
|
32
|
+
env?: 'production' | 'staging' | 'development' | 'preview' | 'uat' | string;
|
|
31
33
|
/**
|
|
32
34
|
* Whether the site uses trailing slash.
|
|
33
35
|
*/
|
|
34
|
-
trailingSlash
|
|
35
|
-
/**
|
|
36
|
-
* Current locale, set with `@nuxt/i18n`.
|
|
37
|
-
*
|
|
38
|
-
* Falls back to the defaultLocale.
|
|
39
|
-
*/
|
|
40
|
-
currentLocale?: string;
|
|
41
|
-
/**
|
|
42
|
-
* The default locale of the site.
|
|
43
|
-
*/
|
|
44
|
-
defaultLocale: string;
|
|
45
|
-
/**
|
|
46
|
-
* The description of the site.
|
|
47
|
-
*
|
|
48
|
-
* @default `process.env.NUXT_PUBLIC_SITE_DESCRIPTION`
|
|
49
|
-
*
|
|
50
|
-
* Used by: nuxt-schema-org, nuxt-seo-kit
|
|
51
|
-
*/
|
|
52
|
-
description?: string;
|
|
36
|
+
trailingSlash?: boolean;
|
|
53
37
|
/**
|
|
54
|
-
*
|
|
55
|
-
*/
|
|
56
|
-
identity?: {
|
|
57
|
-
/**
|
|
58
|
-
* Use Organization for when the site is a company, business, etc.
|
|
59
|
-
* Use Person for when the site is a personal blog, portfolio, etc.
|
|
60
|
-
*/
|
|
61
|
-
type: 'Organization' | 'Person';
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Twitter (X) profile ID.
|
|
65
|
-
*
|
|
66
|
-
* Used for Schema.org sameAs and `<meta profile>`.
|
|
67
|
-
*
|
|
68
|
-
* @example `@harlan_zw`
|
|
38
|
+
* The mapping of the context of each site config value being set.
|
|
69
39
|
*/
|
|
70
|
-
|
|
40
|
+
_context?: Record<string, string>;
|
|
71
41
|
/**
|
|
72
|
-
*
|
|
42
|
+
* Support any keys as site config.
|
|
73
43
|
*/
|
|
74
|
-
|
|
75
|
-
[key: (string & Record<never, never>)]: any;
|
|
44
|
+
[key: string]: any;
|
|
76
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* @deprecated use SiteConfigResolved
|
|
48
|
+
*/
|
|
49
|
+
type SiteConfig = SiteConfigResolved;
|
|
77
50
|
type MaybeComputedRef<T> = T | (() => T) | ComputedRef<T> | Ref<T>;
|
|
78
51
|
type MaybeComputedRefEntries<T> = {
|
|
79
52
|
[key in keyof T]?: MaybeComputedRef<T[key]>;
|
|
80
53
|
};
|
|
81
|
-
type SiteConfigInput = Omit<MaybeComputedRefEntries<Partial<
|
|
54
|
+
type SiteConfigInput = Omit<MaybeComputedRefEntries<Partial<SiteConfigResolved>>, '_context' | 'indexable'> & {
|
|
82
55
|
_context?: string;
|
|
83
56
|
_priority?: number;
|
|
84
57
|
indexable?: MaybeComputedRef<string | boolean>;
|
|
85
58
|
};
|
|
86
59
|
interface GetSiteConfigOptions {
|
|
87
60
|
debug?: boolean;
|
|
61
|
+
skipNormalize?: boolean;
|
|
62
|
+
resolveRefs?: boolean;
|
|
88
63
|
}
|
|
89
64
|
interface SiteConfigStack {
|
|
90
65
|
stack: Partial<SiteConfigInput>[];
|
|
91
66
|
push: (config: SiteConfigInput) => void;
|
|
92
|
-
get: (options?: GetSiteConfigOptions) =>
|
|
67
|
+
get: (options?: GetSiteConfigOptions) => SiteConfigResolved;
|
|
93
68
|
}
|
|
94
69
|
|
|
70
|
+
declare function normalizeSiteConfig(config: SiteConfigResolved): SiteConfigResolved;
|
|
71
|
+
declare function validateSiteConfigStack(stack: SiteConfigStack): string[];
|
|
95
72
|
declare function createSiteConfigStack(options?: {
|
|
96
73
|
debug: boolean;
|
|
97
74
|
}): SiteConfigStack;
|
|
98
75
|
|
|
99
|
-
declare function
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
trailingSlash: boolean;
|
|
103
|
-
base?: string;
|
|
104
|
-
absolute?: boolean;
|
|
105
|
-
withBase?: boolean;
|
|
106
|
-
}): string;
|
|
107
|
-
declare function fixSlashes(trailingSlash: boolean, pathOrUrl: string): string;
|
|
76
|
+
declare function envSiteConfig(env: Record<string, any>): {
|
|
77
|
+
[k: string]: any;
|
|
78
|
+
};
|
|
108
79
|
|
|
109
|
-
export { type GetSiteConfigOptions, type MaybeComputedRef, type MaybeComputedRefEntries, type SiteConfig, type SiteConfigInput, type SiteConfigStack, createSiteConfigStack,
|
|
80
|
+
export { type GetSiteConfigOptions, type MaybeComputedRef, type MaybeComputedRefEntries, type SiteConfig, type SiteConfigInput, type SiteConfigResolved, type SiteConfigStack, createSiteConfigStack, envSiteConfig, normalizeSiteConfig, validateSiteConfigStack };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { toValue } from 'vue';
|
|
2
|
+
import { hasProtocol, withHttps, parseURL, getQuery } from 'ufo';
|
|
2
3
|
|
|
4
|
+
function normalizeSiteConfig(config) {
|
|
5
|
+
if (typeof config.indexable !== "undefined")
|
|
6
|
+
config.indexable = String(config.indexable) !== "false";
|
|
7
|
+
if (typeof config.trailingSlash !== "undefined" && !config.trailingSlash)
|
|
8
|
+
config.trailingSlash = String(config.trailingSlash) !== "false";
|
|
9
|
+
if (config.url && !hasProtocol(config.url, { acceptRelative: true, strict: false }))
|
|
10
|
+
config.url = withHttps(config.url);
|
|
11
|
+
const keys = Object.keys(config).sort((a, b) => a.localeCompare(b));
|
|
12
|
+
const newConfig = {};
|
|
13
|
+
for (const k of keys)
|
|
14
|
+
newConfig[k] = config[k];
|
|
15
|
+
return newConfig;
|
|
16
|
+
}
|
|
17
|
+
function validateSiteConfigStack(stack) {
|
|
18
|
+
const resolved = normalizeSiteConfig(stack.get({
|
|
19
|
+
// we need the context
|
|
20
|
+
debug: true
|
|
21
|
+
}));
|
|
22
|
+
const errors = [];
|
|
23
|
+
if (resolved.url) {
|
|
24
|
+
const val = resolved.url;
|
|
25
|
+
const context = resolved._context?.url || "unknown";
|
|
26
|
+
const url = parseURL(val);
|
|
27
|
+
if (!url.host)
|
|
28
|
+
errors.push(`url "${val}" from ${context} is not absolute`);
|
|
29
|
+
else if (url.pathname && url.pathname !== "/")
|
|
30
|
+
errors.push(`url "${val}" from ${context} should not contain a path`);
|
|
31
|
+
else if (url.hash)
|
|
32
|
+
errors.push(`url "${val}" from ${context} should not contain a hash`);
|
|
33
|
+
else if (Object.keys(getQuery(val)).length > 0)
|
|
34
|
+
errors.push(`url "${val}" from ${context} should not contain a query`);
|
|
35
|
+
else if (url.host === "localhost")
|
|
36
|
+
errors.push(`url "${val}" from ${context} should not be localhost`);
|
|
37
|
+
}
|
|
38
|
+
return errors;
|
|
39
|
+
}
|
|
3
40
|
function createSiteConfigStack(options) {
|
|
4
41
|
const debug = options?.debug || false;
|
|
5
42
|
const stack = [];
|
|
@@ -30,13 +67,13 @@ function createSiteConfigStack(options) {
|
|
|
30
67
|
const key = k;
|
|
31
68
|
const val = stack[o][k];
|
|
32
69
|
if (!k.startsWith("_")) {
|
|
33
|
-
siteConfig[k] = val;
|
|
70
|
+
siteConfig[k] = options2?.resolveRefs ? toValue(val) : val;
|
|
34
71
|
if (options2?.debug)
|
|
35
72
|
siteConfig._context[key] = stack[o]._context?.[key] || stack[o]._context || "anonymous";
|
|
36
73
|
}
|
|
37
74
|
}
|
|
38
75
|
}
|
|
39
|
-
return normalizeSiteConfig(siteConfig);
|
|
76
|
+
return options2?.skipNormalize ? siteConfig : normalizeSiteConfig(siteConfig);
|
|
40
77
|
}
|
|
41
78
|
return {
|
|
42
79
|
stack,
|
|
@@ -45,41 +82,11 @@ function createSiteConfigStack(options) {
|
|
|
45
82
|
};
|
|
46
83
|
}
|
|
47
84
|
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (config.url && !hasProtocol(config.url, { acceptRelative: true, strict: false }))
|
|
54
|
-
config.url = withHttps(config.url);
|
|
55
|
-
const keys = Object.keys(config).sort((a, b) => a.localeCompare(b));
|
|
56
|
-
const newConfig = {};
|
|
57
|
-
for (const k of keys)
|
|
58
|
-
newConfig[k] = config[k];
|
|
59
|
-
return newConfig;
|
|
60
|
-
}
|
|
61
|
-
function resolveSitePath(pathOrUrl, options) {
|
|
62
|
-
let path = pathOrUrl;
|
|
63
|
-
if (hasProtocol(pathOrUrl, { strict: false, acceptRelative: true })) {
|
|
64
|
-
const parsed = parseURL(pathOrUrl);
|
|
65
|
-
path = parsed.pathname;
|
|
66
|
-
}
|
|
67
|
-
const base = withLeadingSlash(options.base || "/");
|
|
68
|
-
if (base !== "/" && path.startsWith(base)) {
|
|
69
|
-
path = path.slice(base.length);
|
|
70
|
-
}
|
|
71
|
-
const origin = options.absolute ? options.siteUrl : "";
|
|
72
|
-
const baseWithOrigin = options.withBase ? withBase(base, origin || "/") : origin;
|
|
73
|
-
const resolvedUrl = withBase(path, baseWithOrigin);
|
|
74
|
-
return path === "/" && !options.withBase ? withTrailingSlash(resolvedUrl) : fixSlashes(options.trailingSlash, resolvedUrl);
|
|
75
|
-
}
|
|
76
|
-
function fixSlashes(trailingSlash, pathOrUrl) {
|
|
77
|
-
const $url = parseURL(pathOrUrl);
|
|
78
|
-
const isFileUrl = $url.pathname.includes(".");
|
|
79
|
-
if (isFileUrl)
|
|
80
|
-
return pathOrUrl;
|
|
81
|
-
const fixedPath = trailingSlash ? withTrailingSlash($url.pathname) : withoutTrailingSlash($url.pathname);
|
|
82
|
-
return `${$url.protocol ? `${$url.protocol}//` : ""}${$url.host || ""}${fixedPath}${$url.search || ""}${$url.hash || ""}`;
|
|
85
|
+
function envSiteConfig(env) {
|
|
86
|
+
return Object.fromEntries(Object.entries(env).filter(([k]) => k.startsWith("NUXT_SITE_") || k.startsWith("NUXT_PUBLIC_SITE_")).map(([k, v]) => [
|
|
87
|
+
k.replace(/^NUXT_(PUBLIC_)?SITE_/, "").split("_").map((s, i) => i === 0 ? s.toLowerCase() : s[0].toUpperCase() + s.slice(1).toLowerCase()).join(""),
|
|
88
|
+
v
|
|
89
|
+
]));
|
|
83
90
|
}
|
|
84
91
|
|
|
85
|
-
export { createSiteConfigStack,
|
|
92
|
+
export { createSiteConfigStack, envSiteConfig, normalizeSiteConfig, validateSiteConfigStack };
|
package/dist/urls.cjs
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const ufo = require('ufo');
|
|
4
|
+
|
|
5
|
+
function resolveSitePath(pathOrUrl, options) {
|
|
6
|
+
let path = pathOrUrl;
|
|
7
|
+
if (ufo.hasProtocol(pathOrUrl, { strict: false, acceptRelative: true })) {
|
|
8
|
+
const parsed = ufo.parseURL(pathOrUrl);
|
|
9
|
+
path = parsed.pathname;
|
|
10
|
+
}
|
|
11
|
+
const base = ufo.withLeadingSlash(options.base || "/");
|
|
12
|
+
if (base !== "/" && path.startsWith(base)) {
|
|
13
|
+
path = path.slice(base.length);
|
|
14
|
+
}
|
|
15
|
+
const origin = options.absolute ? options.siteUrl : "";
|
|
16
|
+
const baseWithOrigin = options.withBase ? ufo.withBase(base, origin || "/") : origin;
|
|
17
|
+
const resolvedUrl = ufo.withBase(path, baseWithOrigin);
|
|
18
|
+
return path === "/" && !options.withBase ? ufo.withTrailingSlash(resolvedUrl) : fixSlashes(options.trailingSlash, resolvedUrl);
|
|
19
|
+
}
|
|
20
|
+
function fixSlashes(trailingSlash, pathOrUrl) {
|
|
21
|
+
const $url = ufo.parseURL(pathOrUrl);
|
|
22
|
+
const isFileUrl = $url.pathname.includes(".");
|
|
23
|
+
if (isFileUrl)
|
|
24
|
+
return pathOrUrl;
|
|
25
|
+
const fixedPath = trailingSlash ? ufo.withTrailingSlash($url.pathname) : ufo.withoutTrailingSlash($url.pathname);
|
|
26
|
+
return `${$url.protocol ? `${$url.protocol}//` : ""}${$url.host || ""}${fixedPath}${$url.search || ""}${$url.hash || ""}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.fixSlashes = fixSlashes;
|
|
30
|
+
exports.resolveSitePath = resolveSitePath;
|
package/dist/urls.d.cts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare function resolveSitePath(pathOrUrl: string, options: {
|
|
2
|
+
siteUrl: string;
|
|
3
|
+
trailingSlash?: boolean;
|
|
4
|
+
base?: string;
|
|
5
|
+
absolute?: boolean;
|
|
6
|
+
withBase?: boolean;
|
|
7
|
+
}): string;
|
|
8
|
+
declare function fixSlashes(trailingSlash: boolean | undefined, pathOrUrl: string): string;
|
|
9
|
+
|
|
10
|
+
export { fixSlashes, resolveSitePath };
|
package/dist/urls.d.mts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare function resolveSitePath(pathOrUrl: string, options: {
|
|
2
|
+
siteUrl: string;
|
|
3
|
+
trailingSlash?: boolean;
|
|
4
|
+
base?: string;
|
|
5
|
+
absolute?: boolean;
|
|
6
|
+
withBase?: boolean;
|
|
7
|
+
}): string;
|
|
8
|
+
declare function fixSlashes(trailingSlash: boolean | undefined, pathOrUrl: string): string;
|
|
9
|
+
|
|
10
|
+
export { fixSlashes, resolveSitePath };
|
package/dist/urls.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare function resolveSitePath(pathOrUrl: string, options: {
|
|
2
|
+
siteUrl: string;
|
|
3
|
+
trailingSlash?: boolean;
|
|
4
|
+
base?: string;
|
|
5
|
+
absolute?: boolean;
|
|
6
|
+
withBase?: boolean;
|
|
7
|
+
}): string;
|
|
8
|
+
declare function fixSlashes(trailingSlash: boolean | undefined, pathOrUrl: string): string;
|
|
9
|
+
|
|
10
|
+
export { fixSlashes, resolveSitePath };
|
package/dist/urls.mjs
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { hasProtocol, parseURL, withLeadingSlash, withBase, withTrailingSlash, withoutTrailingSlash } from 'ufo';
|
|
2
|
+
|
|
3
|
+
function resolveSitePath(pathOrUrl, options) {
|
|
4
|
+
let path = pathOrUrl;
|
|
5
|
+
if (hasProtocol(pathOrUrl, { strict: false, acceptRelative: true })) {
|
|
6
|
+
const parsed = parseURL(pathOrUrl);
|
|
7
|
+
path = parsed.pathname;
|
|
8
|
+
}
|
|
9
|
+
const base = withLeadingSlash(options.base || "/");
|
|
10
|
+
if (base !== "/" && path.startsWith(base)) {
|
|
11
|
+
path = path.slice(base.length);
|
|
12
|
+
}
|
|
13
|
+
const origin = options.absolute ? options.siteUrl : "";
|
|
14
|
+
const baseWithOrigin = options.withBase ? withBase(base, origin || "/") : origin;
|
|
15
|
+
const resolvedUrl = withBase(path, baseWithOrigin);
|
|
16
|
+
return path === "/" && !options.withBase ? withTrailingSlash(resolvedUrl) : fixSlashes(options.trailingSlash, resolvedUrl);
|
|
17
|
+
}
|
|
18
|
+
function fixSlashes(trailingSlash, pathOrUrl) {
|
|
19
|
+
const $url = parseURL(pathOrUrl);
|
|
20
|
+
const isFileUrl = $url.pathname.includes(".");
|
|
21
|
+
if (isFileUrl)
|
|
22
|
+
return pathOrUrl;
|
|
23
|
+
const fixedPath = trailingSlash ? withTrailingSlash($url.pathname) : withoutTrailingSlash($url.pathname);
|
|
24
|
+
return `${$url.protocol ? `${$url.protocol}//` : ""}${$url.host || ""}${fixedPath}${$url.search || ""}${$url.hash || ""}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { fixSlashes, resolveSitePath };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "site-config-stack",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "2.0.0",
|
|
5
5
|
"description": "Shared site configuration utilities.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"funding": "https://github.com/sponsors/harlan-zw",
|
|
@@ -19,6 +19,16 @@
|
|
|
19
19
|
"types": "./dist/index.d.ts",
|
|
20
20
|
"import": "./dist/index.mjs",
|
|
21
21
|
"require": "./dist/index.cjs"
|
|
22
|
+
},
|
|
23
|
+
"./urls": {
|
|
24
|
+
"types": "./dist/urls.d.ts",
|
|
25
|
+
"import": "./dist/urls.mjs",
|
|
26
|
+
"require": "./dist/urls.cjs"
|
|
27
|
+
},
|
|
28
|
+
"./dist/urls": {
|
|
29
|
+
"types": "./dist/urls.d.ts",
|
|
30
|
+
"import": "./dist/urls.mjs",
|
|
31
|
+
"require": "./dist/urls.cjs"
|
|
22
32
|
}
|
|
23
33
|
},
|
|
24
34
|
"main": "./dist/index.cjs",
|
|
@@ -38,6 +48,7 @@
|
|
|
38
48
|
"scripts": {
|
|
39
49
|
"lint": "eslint . --fix",
|
|
40
50
|
"build": "unbuild",
|
|
41
|
-
"stub": "unbuild --stub"
|
|
51
|
+
"stub": "unbuild --stub",
|
|
52
|
+
"typecheck": "tsc --noEmit"
|
|
42
53
|
}
|
|
43
54
|
}
|