@apleasantview/eleventy-plugin-baseline 0.1.0-next.21 → 0.1.0-next.27

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.
Files changed (31) hide show
  1. package/README.md +3 -1
  2. package/core/debug.js +5 -5
  3. package/core/filters/isString.js +1 -1
  4. package/core/filters/markdown.js +3 -5
  5. package/core/filters/related-posts.js +4 -5
  6. package/core/filters.js +4 -4
  7. package/core/globals/date.js +4 -4
  8. package/core/globals.js +1 -1
  9. package/core/helpers.js +21 -33
  10. package/core/modules.js +8 -8
  11. package/core/shortcodes/image.js +30 -39
  12. package/core/shortcodes.js +1 -1
  13. package/eleventy.config.js +71 -38
  14. package/modules/assets-core/plugins/assets-core.js +12 -12
  15. package/modules/assets-esbuild/filters/inline-esbuild.js +3 -3
  16. package/modules/assets-esbuild/plugins/assets-esbuild.js +22 -25
  17. package/modules/assets-postcss/fallback/postcss.config.js +9 -11
  18. package/modules/assets-postcss/filters/inline-postcss.js +7 -7
  19. package/modules/assets-postcss/plugins/assets-postcss.js +19 -19
  20. package/modules/head-core/drivers/posthtml-head-elements.js +106 -122
  21. package/modules/head-core/plugins/head-core.js +14 -17
  22. package/modules/head-core/utils/head-utils.js +57 -67
  23. package/modules/multilang-core/filters/i18n-default-translation.js +14 -0
  24. package/modules/multilang-core/filters/i18n-translation-in.js +16 -0
  25. package/modules/multilang-core/filters/i18n-translations-for.js +10 -0
  26. package/modules/multilang-core/plugins/multilang-core.js +78 -12
  27. package/modules/navigator-core/plugins/navigator-core.js +16 -14
  28. package/modules/navigator-core/templates/navigator-core.html +33 -17
  29. package/modules/sitemap-core/plugins/sitemap-core.js +21 -21
  30. package/modules/sitemap-core/templates/sitemap-core.html +4 -4
  31. package/package.json +1 -1
@@ -1,23 +1,22 @@
1
- import Merge from "@11ty/eleventy-utils/src/Merge.js";
2
- import { TemplatePath } from "@11ty/eleventy-utils";
1
+ import Merge from '@11ty/eleventy-utils/src/Merge.js';
2
+ import { TemplatePath } from '@11ty/eleventy-utils';
3
3
 
4
4
  const pick = (...values) => values.find((v) => v !== undefined && v !== null);
5
5
 
6
- const normalizePathPrefix = (pathPrefix = "") => {
6
+ const normalizePathPrefix = (pathPrefix = '') => {
7
7
  // Align with Eleventy’s normalizeUrlPath behavior
8
- const normalized = TemplatePath.normalizeUrlPath("/", pathPrefix);
9
- return normalized === "/" ? "" : normalized; // empty means root
8
+ const normalized = TemplatePath.normalizeUrlPath('/', pathPrefix);
9
+ return normalized === '/' ? '' : normalized; // empty means root
10
10
  };
11
11
 
12
- const isAbsoluteUrl = (url = "") =>
13
- /^[a-z][a-z\d+\-.]*:\/\//i.test(url) || url.startsWith("//");
12
+ const isAbsoluteUrl = (url = '') => /^[a-z][a-z\d+\-.]*:\/\//i.test(url) || url.startsWith('//');
14
13
 
15
14
  const absoluteUrl = (siteUrl, pathPrefix, url) => {
16
15
  if (!url) return url;
17
16
  if (isAbsoluteUrl(url)) return url;
18
17
  const prefix = normalizePathPrefix(pathPrefix);
19
- const joined = TemplatePath.normalizeUrlPath(prefix || "/", url);
20
- return siteUrl ? `${siteUrl.replace(/\/+$/, "")}${joined}` : joined;
18
+ const joined = TemplatePath.normalizeUrlPath(prefix || '/', url);
19
+ return siteUrl ? `${siteUrl.replace(/\/+$/, '')}${joined}` : joined;
21
20
  };
22
21
 
23
22
  const mergeBaseHead = (site, user, page, title, description, noindex, url) => {
@@ -26,47 +25,52 @@ const mergeBaseHead = (site, user, page, title, description, noindex, url) => {
26
25
  {
27
26
  title,
28
27
  meta: [
29
- { charset: "UTF-8" },
30
- { name: "viewport", content: "width=device-width, initial-scale=1.0" },
31
- { name: "description", content: description },
32
- { name: "robots", content: noindex ? "noindex, nofollow" : "index, follow" },
28
+ { charset: 'UTF-8' },
29
+ { name: 'viewport', content: 'width=device-width, initial-scale=1.0' },
30
+ { name: 'description', content: description },
31
+ { name: 'robots', content: noindex ? 'noindex, nofollow' : 'index, follow' }
33
32
  ],
34
33
  link: [],
35
34
  script: [],
36
35
  style: [],
37
36
  hreflang: [],
38
37
  openGraph: {
39
- "og:title": title,
40
- "og:description": description,
41
- "og:type": "website",
42
- "og:url": url || "",
43
- "og:image": "",
38
+ 'og:title': title,
39
+ 'og:description': description,
40
+ 'og:type': 'website',
41
+ 'og:url': url || '',
42
+ 'og:image': ''
44
43
  },
45
44
  twitter: {
46
- "twitter:card": "summary_large_image",
47
- "twitter:title": title,
48
- "twitter:description": description,
49
- "twitter:image": "",
45
+ 'twitter:card': 'summary_large_image',
46
+ 'twitter:title': title,
47
+ 'twitter:description': description,
48
+ 'twitter:image': ''
50
49
  },
51
50
  miscMeta: [],
52
- structuredData: null,
51
+ structuredData: null
53
52
  },
54
53
  user
55
54
  );
56
55
  };
57
56
 
58
57
  const resolveCanonical = (head, page, contentMap, env = {}) => {
59
- const { siteUrl, pathPrefix = "", pageUrlOverride } = env;
58
+ const { siteUrl, pathPrefix = '', pageUrlOverride, verbose } = env;
60
59
  const explicit = pick(head.canonical);
61
- if (explicit) return absoluteUrl(siteUrl, pathPrefix, explicit);
60
+ if (explicit) {
61
+ if (!siteUrl && verbose) {
62
+ console.warn('[baseline] site.url is missing; canonical will be relative.');
63
+ }
64
+ return absoluteUrl(siteUrl, pathPrefix, explicit);
65
+ }
62
66
 
63
- const url = pick(
64
- pageUrlOverride,
65
- page?.url,
66
- page?.inputPath && contentMap?.inputPathToUrl?.[page.inputPath]?.[0]
67
- );
67
+ const url = pick(pageUrlOverride, page?.url, page?.inputPath && contentMap?.inputPathToUrl?.[page.inputPath]?.[0]);
68
68
  if (!url) return undefined;
69
69
 
70
+ if (!siteUrl && verbose) {
71
+ console.warn('[baseline] site.url is missing; canonical will be relative.');
72
+ }
73
+
70
74
  return absoluteUrl(siteUrl, pathPrefix, url);
71
75
  };
72
76
 
@@ -75,16 +79,15 @@ const dedupeMeta = (arr = []) => {
75
79
  const out = [];
76
80
  for (let i = arr.length - 1; i >= 0; i--) {
77
81
  const m = arr[i];
78
- const key =
79
- m.charset
80
- ? "charset"
81
- : m.name
82
+ const key = m.charset
83
+ ? 'charset'
84
+ : m.name
82
85
  ? `name:${m.name}`
83
86
  : m.property
84
- ? `prop:${m.property}`
85
- : m["http-equiv"]
86
- ? `http:${m["http-equiv"]}`
87
- : null;
87
+ ? `prop:${m.property}`
88
+ : m['http-equiv']
89
+ ? `http:${m['http-equiv']}`
90
+ : null;
88
91
  if (!key || seen.has(key)) continue;
89
92
  seen.add(key);
90
93
  out.push(m);
@@ -119,61 +122,55 @@ const flattenHead = (head = {}, canonical) => {
119
122
  ? Object.entries(head.twitter)
120
123
  .filter(([, v]) => v)
121
124
  .map(([k, v]) => ({ name: k, content: v }))
122
- : []),
125
+ : [])
123
126
  ]);
124
127
 
125
128
  const style = [...(head.style || [])];
126
129
 
127
- const linkCanonical = canonical ? [{ rel: "canonical", href: canonical }] : [];
130
+ const linkCanonical = canonical ? [{ rel: 'canonical', href: canonical }] : [];
128
131
  const link = dedupeLink([...(head.link || []), ...(head.hreflang || [])].filter(Boolean));
129
132
 
130
133
  const script = [...(head.script || [])];
131
134
  if (head.structuredData) {
132
135
  script.unshift({
133
- type: "application/ld+json",
134
- content: JSON.stringify(head.structuredData),
136
+ type: 'application/ld+json',
137
+ content: JSON.stringify(head.structuredData)
135
138
  });
136
139
  }
137
140
 
138
141
  // Key order matters for posthtml-head-elements.
139
142
  return {
140
143
  meta: baseMeta,
141
- title: head.title || "",
144
+ title: head.title || '',
142
145
  linkCanonical,
143
146
  style,
144
147
  link,
145
148
  script,
146
- meta_social: socialMeta,
149
+ meta_social: socialMeta
147
150
  };
148
151
  };
149
152
 
150
153
  const buildHead = (data = {}, env = {}) => {
151
- const { userKey = "head", contentMap = {}, siteUrl, pathPrefix } = env;
154
+ const { userKey = 'head', contentMap = {}, siteUrl, pathPrefix } = env;
152
155
  const site = data.site || {};
153
156
  const user = userKey ? data[userKey] || {} : {};
154
157
  const page = data.page || {};
155
158
  const resolvedSiteUrl =
156
- siteUrl ||
157
- site.url ||
158
- process.env.URL ||
159
- process.env.DEPLOY_URL ||
160
- process.env.DEPLOY_PRIME_URL;
161
-
162
- const siteTitle = site.title || "";
163
- const pageTitle = pick(data.title, user.title, site.title, "");
159
+ siteUrl || site.url || process.env.URL || process.env.DEPLOY_URL || process.env.DEPLOY_PRIME_URL;
160
+
161
+ const siteTitle = site.title || '';
162
+ const pageTitle = pick(data.title, user.title, site.title, '');
164
163
  const title =
165
- siteTitle && pageTitle && siteTitle !== pageTitle
166
- ? `${pageTitle} | ${siteTitle}`
167
- : pageTitle || siteTitle || "";
164
+ siteTitle && pageTitle && siteTitle !== pageTitle ? `${pageTitle} | ${siteTitle}` : pageTitle || siteTitle || '';
168
165
 
169
- const description = pick(data.description, user.description, site.tagline, "");
170
- const noindex = pick(page.noindex, user.noindex, site.noindex, false);
166
+ const description = pick(data.description, user.description, site.tagline, '');
167
+ const noindex = pick(data.noindex, page.noindex, user.noindex, site.noindex, false);
171
168
 
172
169
  const canonical = resolveCanonical(
173
170
  { canonical: absoluteUrl(resolvedSiteUrl, pathPrefix, user.canonical) },
174
171
  page,
175
172
  contentMap,
176
- { ...env, siteUrl: resolvedSiteUrl }
173
+ { ...env, siteUrl: resolvedSiteUrl, verbose: env.verbose }
177
174
  );
178
175
  const merged = mergeBaseHead(site, user, page, title, description, noindex, canonical);
179
176
  return flattenHead(merged, canonical);
@@ -183,11 +180,4 @@ const buildHeadSpec = (context, contentMap, env = {}) => {
183
180
  return buildHead(context, { ...env, contentMap });
184
181
  };
185
182
 
186
- export {
187
- pick,
188
- resolveCanonical,
189
- flattenHead,
190
- buildHead,
191
- buildHeadSpec,
192
- absoluteUrl,
193
- };
183
+ export { pick, resolveCanonical, flattenHead, buildHead, buildHeadSpec, absoluteUrl };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Get the default-language variant for the current page.
3
+ * @param {object} page
4
+ * @param {Array<object>} collection
5
+ * @returns {object|null}
6
+ */
7
+ export default function i18nDefaultTranslation(page, collection) {
8
+ if (!page?.locale?.translationKey) return null;
9
+ return (
10
+ collection.find(
11
+ (p) => p.locale && p.locale.translationKey === page.locale.translationKey && p.locale.isDefaultLang
12
+ ) || null
13
+ );
14
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Get a specific language variant for the current page.
3
+ * @param {object} page
4
+ * @param {Array<object>} collection
5
+ * @param {string} lang
6
+ * @returns {object|null}
7
+ */
8
+ export default function i18nTranslationIn(page, collection, lang) {
9
+ if (!page?.locale?.translationKey) return null;
10
+
11
+ return (
12
+ collection.find(
13
+ (p) => p.locale && p.locale.translationKey === page.locale.translationKey && p.locale.lang === lang
14
+ ) || null
15
+ );
16
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Get all translations for the current page.
3
+ * @param {object} page
4
+ * @param {Array<object>} collection
5
+ * @returns {Array<object>}
6
+ */
7
+ export default function i18nTranslationsFor(page, collection) {
8
+ if (!page?.locale?.translationKey) return [];
9
+ return collection.filter((p) => p.locale && p.locale.translationKey === page.locale.translationKey);
10
+ }
@@ -1,35 +1,101 @@
1
- import { I18nPlugin } from "@11ty/eleventy";
1
+ import { I18nPlugin } from '@11ty/eleventy';
2
+ import { DeepCopy } from '@11ty/eleventy-utils';
3
+ import i18nTranslationsFor from '../filters/i18n-translations-for.js';
4
+ import i18nTranslationIn from '../filters/i18n-translation-in.js';
5
+ import i18nDefaultTranslation from '../filters/i18n-default-translation.js';
2
6
 
3
- /** @param { import("@11ty/eleventy/src/UserConfig.js").default } eleventyConfig */
7
+ /**
8
+ * Baseline – multilang-core
9
+ *
10
+ * Responsibilities:
11
+ * - Normalize language metadata
12
+ * - Annotate translatable pages
13
+ * - Expose relational helpers for translations
14
+ *
15
+ * @param { import("@11ty/eleventy/src/UserConfig.js").default } eleventyConfig
16
+ */
4
17
  export default function multilangCore(eleventyConfig, options = {}) {
5
18
  const userOptions = {
6
- defaultLanguage: "en",
19
+ defaultLanguage: 'en',
7
20
  languages: [],
21
+ verbose: false,
8
22
  ...options
9
- }
23
+ };
10
24
 
11
25
  eleventyConfig.addPlugin(I18nPlugin, {
12
26
  defaultLanguage: userOptions.defaultLanguage,
13
- errorMode: "allow-fallback"
27
+ errorMode: 'allow-fallback'
14
28
  });
15
29
 
16
- // Add translations collection
17
- eleventyConfig.addCollection("translations", function (collection) {
18
- const translations = {};
30
+ // Normalize allowed languages (optionally lower/trim)
31
+ const normalizeLang = (lang) => (lang || '').toLowerCase().trim();
32
+ const allowedLanguages = new Set(
33
+ Array.isArray(userOptions.languages)
34
+ ? userOptions.languages.map(normalizeLang)
35
+ : Object.keys(userOptions.languages || {}).map(normalizeLang)
36
+ );
37
+
38
+ eleventyConfig.addGlobalData('eleventyComputed.page.locale', () => {
39
+ return (data) => {
40
+ const lang = normalizeLang(data.lang || data.language || userOptions.defaultLanguage);
41
+ const translationKey = data.translationKey;
42
+ const isDefaultLang = lang === normalizeLang(userOptions.defaultLanguage);
43
+
44
+ return {
45
+ translationKey,
46
+ lang,
47
+ isDefaultLang
48
+ };
49
+ };
50
+ });
51
+
52
+ const buildTranslations = (collection) => {
53
+ const map = {};
54
+ const list = [];
55
+
19
56
  for (const page of collection.getAll()) {
20
57
  const translationKey = page.data.translationKey;
21
58
  if (!translationKey) continue;
59
+
22
60
  const lang = page.data.lang || page.data.language || userOptions.defaultLanguage;
23
61
  if (!lang) continue;
24
- if (!translations[translationKey]) translations[translationKey] = {};
25
- translations[translationKey][lang] = {
62
+
63
+ if (allowedLanguages.size && !allowedLanguages.has(lang)) {
64
+ if (userOptions.verbose) {
65
+ console.warn(`[baseline:multilang-core] Unknown lang "${lang}" in ${page.inputPath}`);
66
+ }
67
+ continue;
68
+ }
69
+
70
+ const locale = { locale: { translationKey, lang, isDefaultLang: lang === userOptions.defaultLanguage } };
71
+ const safeCopy = DeepCopy(page, locale);
72
+ list.push(safeCopy);
73
+
74
+ if (!map[translationKey]) map[translationKey] = {};
75
+ map[translationKey][lang] = {
26
76
  title: page.data.title,
27
77
  url: page.url,
28
78
  lang,
29
- isDefault: lang === userOptions.defaultLanguage,
79
+ isDefaultLang: lang === userOptions.defaultLanguage,
30
80
  data: page.data
31
81
  };
32
82
  }
33
- return translations;
83
+
84
+ return { map, list };
85
+ };
86
+
87
+ // Map form for direct lookups
88
+ eleventyConfig.addCollection('translationsMap', (collection) => {
89
+ return buildTranslations(collection).map;
90
+ });
91
+
92
+ // Canonical translations collection
93
+ eleventyConfig.addCollection('translations', (collection) => {
94
+ return buildTranslations(collection).list;
34
95
  });
96
+
97
+ // Filters – relational helpers
98
+ eleventyConfig.addFilter('i18nTranslationsFor', i18nTranslationsFor);
99
+ eleventyConfig.addFilter('i18nTranslationIn', i18nTranslationIn);
100
+ eleventyConfig.addFilter('i18nDefaultTranslation', i18nDefaultTranslation);
35
101
  }
@@ -1,6 +1,6 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { fileURLToPath } from "node:url";
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
4
 
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
@@ -8,9 +8,7 @@ const __dirname = path.dirname(__filename);
8
8
  /** @param {import("@11ty/eleventy").UserConfig} eleventyConfig */
9
9
  export default function navigatorCore(eleventyConfig, options = {}) {
10
10
  const raw = options.enableNavigatorTemplate;
11
- const [enableNavigatorTemplate, inspectorDepth] = Array.isArray(raw)
12
- ? [raw[0], raw[1]]
13
- : [raw, undefined];
11
+ const [enableNavigatorTemplate, inspectorDepth] = Array.isArray(raw) ? [raw[0], raw[1]] : [raw, undefined];
14
12
 
15
13
  const userOptions = {
16
14
  ...options,
@@ -18,17 +16,21 @@ export default function navigatorCore(eleventyConfig, options = {}) {
18
16
  inspectorDepth: inspectorDepth ?? 2
19
17
  };
20
18
 
21
- eleventyConfig.addNunjucksGlobal("_navigator", function () { return this; });
22
- eleventyConfig.addNunjucksGlobal("_context", function () { return this.ctx; });
19
+ eleventyConfig.addNunjucksGlobal('_navigator', function () {
20
+ return this;
21
+ });
22
+ eleventyConfig.addNunjucksGlobal('_context', function () {
23
+ return this.ctx;
24
+ });
23
25
 
24
26
  if (userOptions.enableNavigatorTemplate) {
25
27
  // Read virtual template synchronously; Nunjucks pipeline here is sync-only.
26
- const templatePath = path.join(__dirname, "../templates/navigator-core.html");
27
- const virtualTemplateContent = fs.readFileSync(templatePath, "utf-8");
28
- eleventyConfig.addTemplate("navigator-core.html", virtualTemplateContent, {
29
- permalink: "/navigator-core.html",
30
- title: "Navigator Core",
31
- description: "",
28
+ const templatePath = path.join(__dirname, '../templates/navigator-core.html');
29
+ const virtualTemplateContent = fs.readFileSync(templatePath, 'utf-8');
30
+ eleventyConfig.addTemplate('navigator-core.html', virtualTemplateContent, {
31
+ permalink: '/navigator-core.html',
32
+ title: 'Navigator Core',
33
+ description: '',
32
34
  layout: null,
33
35
  eleventyExcludeFromCollections: true,
34
36
  inspectorDepth: userOptions.inspectorDepth
@@ -4,10 +4,22 @@ permalink: /navigator-core.html
4
4
  ---
5
5
 
6
6
  <!DOCTYPE html>
7
- <html lang="{{ site.defaultLanguage }}">
7
+ <html lang="{{ lang | default(site.defaultLanguage) }}">
8
8
 
9
9
  <head>
10
10
  <baseline-head></baseline-head>
11
+ <style>
12
+ ._navigator__wrapper:not(#\#):not(#\#) {
13
+ box-sizing: content-box;
14
+ max-width: 60rem;
15
+ padding-inline: clamp(1rem, 0.2083rem + 3.5185vw, 3.375rem);
16
+ margin-inline: auto;
17
+ }
18
+
19
+ ._navigator__wrapper:not(#\#):not(#\#) > * + * {
20
+ margin-block-start: 1.25rem;
21
+ }
22
+ </style>
11
23
  </head>
12
24
 
13
25
  <body>
@@ -15,24 +27,28 @@ permalink: /navigator-core.html
15
27
  Skip to main content
16
28
  </a>
17
29
  <header>
18
- <h1>{{ site.title }} Navigator</h1>
19
- <div>
20
- <p>{{ site.tagline }}</p>
30
+ <div class="_navigator__wrapper">
31
+ <h1>{{ site.title }} Navigator</h1>
32
+ <div>
33
+ <p>{{ site.tagline }}</p>
34
+ </div>
21
35
  </div>
22
36
  </header>
23
37
  <main id="main" tabindex="-1">
24
- <p><a id="go-back" href=""><span style="vertical-align: text-bottom;">&#8592;</span>&nbsp;Go back</a></p>
25
- <h2><u>Navigator</u></h2>
26
- {% for key, value in _navigator() %}
27
- <details name="navigator-item">
28
- <summary><strong>{{ key }}</strong></summary>
29
- {% if value | isString %}
30
- <pre>{{ value | safe }}</pre>
31
- {% else %}
32
- <pre>{{ value | _inspect({ depth: inspectorDepth }) }}</pre>
33
- {% endif %}
34
- </details>
35
- {% endfor %}
38
+ <div class="_navigator__wrapper">
39
+ <p><a id="go-back" href=""><span style="vertical-align: text-bottom;">&#8592;</span>&nbsp;Go back</a></p>
40
+ <h2><u>Navigator</u></h2>
41
+ {% for key, value in _navigator() %}
42
+ <details>
43
+ <summary><strong>{{ key }}</strong></summary>
44
+ {% if value | isString %}
45
+ <pre>{{ value | safe }}</pre>
46
+ {% else %}
47
+ <pre>{{ value | _inspect({ depth: inspectorDepth }) }}</pre>
48
+ {% endif %}
49
+ </details>
50
+ {% endfor %}
51
+ </div>
36
52
  </main>
37
53
  <script>
38
54
  document.getElementById("go-back").addEventListener("click", (event) => {
@@ -42,7 +58,7 @@ permalink: /navigator-core.html
42
58
  </script>
43
59
  </body>
44
60
  <footer>
45
- <small>Navigator Core — Eleventy Plugin Baseline</small>
61
+ <div class="_navigator__wrapper"><small>Navigator Core — Eleventy Plugin Baseline</small></div>
46
62
  </footer>
47
63
 
48
64
  </html>
@@ -1,6 +1,6 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { fileURLToPath } from "node:url";
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
4
 
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
@@ -13,30 +13,30 @@ export default function sitemapCore(eleventyConfig, options = {}) {
13
13
  languages: options.languages
14
14
  };
15
15
 
16
- eleventyConfig.addGlobalData("eleventyComputed.page.sitemap", () => {
16
+ eleventyConfig.addGlobalData('eleventyComputed.page.sitemap', () => {
17
17
  return (data) => ({
18
- ignore: data.site?.noindex ?? false,
19
- changefreq: "",
18
+ ignore: data.noindex ?? data.page?.noindex ?? data.site?.noindex ?? false,
19
+ changefreq: '',
20
20
  priority: -1
21
21
  });
22
22
  });
23
23
 
24
24
  if (userOptions.enableSitemapTemplate) {
25
- const templatePath = path.join(__dirname, "../templates/sitemap-core.html");
26
- const indexTemplatePath = path.join(__dirname, "../templates/sitemap-index.html");
27
- const baseContent = fs.readFileSync(templatePath, "utf-8");
28
- const indexContent = fs.readFileSync(indexTemplatePath, "utf-8");
25
+ const templatePath = path.join(__dirname, '../templates/sitemap-core.html');
26
+ const indexTemplatePath = path.join(__dirname, '../templates/sitemap-index.html');
27
+ const baseContent = fs.readFileSync(templatePath, 'utf-8');
28
+ const indexContent = fs.readFileSync(indexTemplatePath, 'utf-8');
29
29
 
30
30
  const languages = userOptions.languages || {};
31
31
  const langKeys = Array.isArray(languages) ? languages : Object.keys(languages);
32
- const multilingual = typeof userOptions.multilingual === "boolean" ? userOptions.multilingual : langKeys.length > 1;
32
+ const multilingual = typeof userOptions.multilingual === 'boolean' ? userOptions.multilingual : langKeys.length > 1;
33
33
 
34
34
  if (multilingual && langKeys.length > 1) {
35
35
  for (const lang of langKeys) {
36
36
  eleventyConfig.addTemplate(`_baseline/sitemap-core-${lang}.html`, baseContent, {
37
37
  permalink: `${lang}/sitemap.xml`,
38
- title: "",
39
- description: "",
38
+ title: '',
39
+ description: '',
40
40
  layout: null,
41
41
  eleventyExcludeFromCollections: true,
42
42
  isMultilingual: multilingual,
@@ -44,19 +44,19 @@ export default function sitemapCore(eleventyConfig, options = {}) {
44
44
  });
45
45
  }
46
46
 
47
- eleventyConfig.addTemplate("_baseline/sitemap-index.html", indexContent, {
48
- permalink: "/sitemap.xml",
49
- title: "",
50
- description: "",
47
+ eleventyConfig.addTemplate('_baseline/sitemap-index.html', indexContent, {
48
+ permalink: '/sitemap.xml',
49
+ title: '',
50
+ description: '',
51
51
  layout: null,
52
52
  eleventyExcludeFromCollections: true,
53
53
  isMultilingual: multilingual
54
54
  });
55
55
  } else {
56
- eleventyConfig.addTemplate("_baseline/sitemap-core.html", baseContent, {
57
- permalink: "/sitemap.xml",
58
- title: "",
59
- description: "",
56
+ eleventyConfig.addTemplate('_baseline/sitemap-core.html', baseContent, {
57
+ permalink: '/sitemap.xml',
58
+ title: '',
59
+ description: '',
60
60
  layout: null,
61
61
  eleventyExcludeFromCollections: true
62
62
  });
@@ -2,7 +2,7 @@
2
2
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
3
3
  {%- if not site.noindex -%}
4
4
  {%- for item in collections.all -%}
5
- {%- if not item.data.eleventyExcludeFromCollections and (not item.data.sitemap or item.data.sitemap.ignore != true) -%}
5
+ {%- if not item.data.eleventyExcludeFromCollections and (not item.data.sitemap or item.data.sitemap.ignore != true) and item.data.noindex != true -%}
6
6
  {%- set pageLang = item.data.lang or site.defaultLanguage -%}
7
7
  {%- if (not isMultilingual) or (not sitemapLang) or (pageLang == sitemapLang) -%}
8
8
  {%- set absoluteUrl = item.url | htmlBaseUrl -%}
@@ -12,9 +12,9 @@
12
12
  {%- if lastmod -%}<lastmod>{{ date.toUTCISO(lastmod) }}</lastmod>{%- endif -%}
13
13
  {%- if item.data.sitemap and item.data.sitemap.changefreq -%}<changefreq>{{ item.data.sitemap.changefreq }}</changefreq>{%- endif -%}
14
14
  {%- if item.data.sitemap and item.data.sitemap.priority is defined -%}<priority>{{ item.data.sitemap.priority }}</priority>{%- endif -%}
15
- {%- if item.data.translationKey and collections.translations and collections.translations[item.data.translationKey] -%}
16
- {%- for language, item in collections.translations[item.data.translationKey] -%}
17
- <xhtml:link rel="alternate" hreflang="{{ item.lang }}" href="{{ item.url | htmlBaseUrl }}" />
15
+ {%- if item.data.translationKey and collections.translationsMap and collections.translationsMap[item.data.translationKey] -%}
16
+ {%- for language, entry in collections.translationsMap[item.data.translationKey] -%}
17
+ <xhtml:link rel="alternate" hreflang="{{ entry.lang }}" href="{{ entry.url | htmlBaseUrl }}" />
18
18
  {%- endfor -%}
19
19
  {%- endif -%}
20
20
  </url>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apleasantview/eleventy-plugin-baseline",
3
- "version": "0.1.0-next.21",
3
+ "version": "0.1.0-next.27",
4
4
  "description": "An experimental Swiss army knife toolkit for Eleventy",
5
5
  "type": "module",
6
6
  "main": "eleventy.config.js",