@apleasantview/eleventy-plugin-baseline 0.1.0-next.32 → 0.1.0-next.39

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 (65) hide show
  1. package/README.md +48 -23
  2. package/core/content-map-store.js +51 -0
  3. package/core/filters/index.js +4 -0
  4. package/core/filters/isString.js +6 -1
  5. package/core/filters/markdown.js +6 -0
  6. package/core/filters/related-posts.js +7 -1
  7. package/core/global-functions/index.js +6 -0
  8. package/core/logging.js +25 -25
  9. package/core/page-context.js +310 -0
  10. package/core/registry.js +110 -0
  11. package/core/schema.js +37 -0
  12. package/core/shortcodes/image.js +167 -144
  13. package/core/shortcodes/index.js +2 -0
  14. package/core/slug-index.js +61 -0
  15. package/core/translation-map-store.js +46 -0
  16. package/core/types.js +73 -0
  17. package/core/utils/helpers.js +75 -0
  18. package/core/utils/pick.js +7 -0
  19. package/core/virtual-dir.js +111 -0
  20. package/core/wikilinks.js +152 -0
  21. package/index.js +364 -0
  22. package/modules/assets/index.js +162 -0
  23. package/modules/assets/processors/esbuild-process.js +35 -0
  24. package/modules/assets/processors/postcss-process.js +52 -0
  25. package/modules/assets/schema.js +14 -0
  26. package/modules/head/drivers/capo-adapter.js +72 -0
  27. package/modules/head/drivers/posthtml-head-elements.js +140 -0
  28. package/modules/head/index.js +106 -0
  29. package/modules/head/schema.js +42 -0
  30. package/modules/head/utils/alternates.js +11 -0
  31. package/modules/head/utils/dedupe.js +47 -0
  32. package/modules/multilang/index.js +149 -0
  33. package/modules/navigator/index.js +140 -0
  34. package/modules/navigator/schema.js +13 -0
  35. package/modules/{navigator-core → navigator}/templates/navigator-core.html +14 -8
  36. package/modules/navigator/utils/debug.js +41 -0
  37. package/modules/sitemap/index.js +121 -0
  38. package/modules/sitemap/templates/sitemap-core.html +34 -0
  39. package/modules/{sitemap-core → sitemap}/templates/sitemap-index.html +2 -2
  40. package/modules.js +6 -0
  41. package/package.json +15 -6
  42. package/core/debug.js +0 -20
  43. package/core/filters.js +0 -9
  44. package/core/globals.js +0 -6
  45. package/core/helpers.js +0 -127
  46. package/core/modules.js +0 -22
  47. package/core/shortcodes.js +0 -3
  48. package/eleventy.config.js +0 -157
  49. package/modules/assets-core/plugins/assets-core.js +0 -84
  50. package/modules/assets-esbuild/filters/inline-esbuild.js +0 -24
  51. package/modules/assets-esbuild/plugins/assets-esbuild.js +0 -71
  52. package/modules/assets-postcss/filters/inline-postcss.js +0 -38
  53. package/modules/assets-postcss/plugins/assets-postcss.js +0 -75
  54. package/modules/head-core/drivers/posthtml-head-elements.js +0 -132
  55. package/modules/head-core/plugins/head-core.js +0 -57
  56. package/modules/head-core/utils/head-utils.js +0 -183
  57. package/modules/multilang-core/plugins/multilang-core.js +0 -101
  58. package/modules/navigator-core/plugins/navigator-core.js +0 -39
  59. package/modules/sitemap-core/plugins/sitemap-core.js +0 -65
  60. package/modules/sitemap-core/templates/sitemap-core.html +0 -25
  61. /package/core/{globals → global-functions}/date.js +0 -0
  62. /package/modules/{assets-postcss/fallback → assets/configs}/postcss.config.js +0 -0
  63. /package/modules/{multilang-core → multilang}/filters/i18n-default-translation.js +0 -0
  64. /package/modules/{multilang-core → multilang}/filters/i18n-translation-in.js +0 -0
  65. /package/modules/{multilang-core → multilang}/filters/i18n-translations-for.js +0 -0
@@ -0,0 +1,149 @@
1
+ import { I18nPlugin } from '@11ty/eleventy';
2
+ import { DeepCopy } from '@11ty/eleventy-utils';
3
+ import { normalizeLanguages } from '../../core/utils/helpers.js';
4
+ import i18nTranslationsFor from './filters/i18n-translations-for.js';
5
+ import i18nTranslationIn from './filters/i18n-translation-in.js';
6
+ import i18nDefaultTranslation from './filters/i18n-default-translation.js';
7
+
8
+ /**
9
+ * Multilang (module)
10
+ *
11
+ * Language infrastructure. Normalises language config, builds translation
12
+ * relationships, attaches per-page locale data, and exposes cross-language
13
+ * lookup filters. Active only when options.multilingual is true and both
14
+ * defaultLanguage and at least one languages entry are set; otherwise the
15
+ * module exits early.
16
+ *
17
+ * Architecture layer:
18
+ * module
19
+ *
20
+ * System role:
21
+ * Wraps Eleventy's I18nPlugin and feeds the translation-map store that
22
+ * head reads at transform-time. Sitemap reuses the same normalised
23
+ * language map.
24
+ *
25
+ * Lifecycle:
26
+ * build-time → normalise languages, attach I18nPlugin, register filters
27
+ * and computed page.locale
28
+ * cascade-time → translationsMap and translations collections build the
29
+ * per-translationKey map and write it to the store
30
+ *
31
+ * Why this exists:
32
+ * I18nPlugin handles locale-aware routing but not translation
33
+ * relationships. Head needs a transform-time-readable hreflang map; the
34
+ * collection populates it once and the store carries it across the
35
+ * lifecycle boundary.
36
+ *
37
+ * Scope:
38
+ * Owns language normalisation, page.locale computation, the translations
39
+ * and translationsMap collections, and the i18n filters
40
+ * (i18nTranslationsFor, i18nTranslationIn, i18nDefaultTranslation).
41
+ * Does not own URL routing (I18nPlugin) or hreflang rendering (head).
42
+ *
43
+ * Data flow:
44
+ * settings.languages + page.lang/translationKey → normalisation +
45
+ * I18nPlugin → collections + computed page.locale + translation-map
46
+ * store → head, sitemap
47
+ *
48
+ * @param {import("@11ty/eleventy/src/UserConfig.js").default} eleventyConfig
49
+ * @param {Object} moduleContext
50
+ */
51
+ export function multilangCore(eleventyConfig, moduleContext) {
52
+ const { state, runtime, log } = moduleContext;
53
+ const { settings, options } = state;
54
+
55
+ // --- Language normalization ---
56
+ // Accept languages as array or object; normalize to object map.
57
+ // Drives collection building, locale data, and sitemap-core language config.
58
+ const normalizeLanguageCode = (lang) => (lang || '').toLowerCase().trim();
59
+ const defaultLanguage = normalizeLanguageCode(settings.defaultLanguage);
60
+ const languages = normalizeLanguages(settings, log);
61
+ const hasLanguages = languages && Object.keys(languages).length > 0;
62
+
63
+ const isMultilingual = options.multilang === true && defaultLanguage && hasLanguages;
64
+
65
+ if (!isMultilingual) {
66
+ log.info('inactive: requires options.multilingual + settings.defaultLanguage + languages');
67
+ return;
68
+ }
69
+
70
+ // Register Eleventy's built-in I18nPlugin for locale-aware URL resolution.
71
+ eleventyConfig.addPlugin(I18nPlugin, {
72
+ defaultLanguage: defaultLanguage,
73
+ errorMode: 'allow-fallback'
74
+ });
75
+
76
+ // Computed locale data: every page gets a page.locale object with its
77
+ // resolved lang, translationKey, and whether it's the default language.
78
+ eleventyConfig.addGlobalData('eleventyComputed.page.locale', () => {
79
+ return (data) => {
80
+ const translationKey = data.translationKey;
81
+ const lang = normalizeLanguageCode(data.lang || data.language || defaultLanguage);
82
+ const isDefaultLang = lang === defaultLanguage;
83
+
84
+ return {
85
+ translationKey,
86
+ lang,
87
+ isDefaultLang
88
+ };
89
+ };
90
+ });
91
+
92
+ // Build a set of allowed language codes for validation during collection building.
93
+ const allowedLanguages = new Set(Object.keys(languages).map(normalizeLanguageCode));
94
+
95
+ // Build both the map (keyed by translationKey → lang) and the flat list.
96
+ // Shared logic for both collections — called once per collection registration.
97
+ const buildTranslations = (collection) => {
98
+ const map = {};
99
+ const list = [];
100
+
101
+ for (const page of collection.getAll()) {
102
+ const translationKey = page.data.translationKey;
103
+ if (!translationKey) continue;
104
+
105
+ const lang = page.data.lang || page.data.language || defaultLanguage;
106
+ if (!lang) continue;
107
+
108
+ if (allowedLanguages.size && !allowedLanguages.has(lang)) {
109
+ log.info(`Unknown lang "${lang}" in ${page.inputPath}`);
110
+ continue;
111
+ }
112
+
113
+ const locale = { locale: { translationKey, lang, isDefaultLang: lang === defaultLanguage } };
114
+ const safeCopy = DeepCopy(page, locale);
115
+ list.push(safeCopy);
116
+
117
+ if (!map[translationKey]) map[translationKey] = {};
118
+ map[translationKey][lang] = {
119
+ title: page.data.title,
120
+ url: page.url,
121
+ lang,
122
+ isDefaultLang: lang === defaultLanguage,
123
+ data: page.data
124
+ };
125
+ }
126
+
127
+ return { map, list };
128
+ };
129
+
130
+ // --- Collections ---
131
+
132
+ // Map form: translationsMap[translationKey][lang] → page metadata.
133
+ eleventyConfig.addCollection('translationsMap', (collection) => {
134
+ const map = buildTranslations(collection).map;
135
+ runtime.translationMap.set(map);
136
+ return map;
137
+ });
138
+
139
+ // Flat list: all translatable pages with locale data attached.
140
+ eleventyConfig.addCollection('translations', (collection) => {
141
+ return buildTranslations(collection).list;
142
+ });
143
+
144
+ // --- Filters ---
145
+ // Relational helpers for cross-language lookups in templates.
146
+ eleventyConfig.addFilter('i18nTranslationsFor', i18nTranslationsFor);
147
+ eleventyConfig.addFilter('i18nTranslationIn', i18nTranslationIn);
148
+ eleventyConfig.addFilter('i18nDefaultTranslation', i18nDefaultTranslation);
149
+ }
@@ -0,0 +1,140 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import debug from './utils/debug.js';
5
+ import { optionsSchema } from './schema.js';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ /**
11
+ * Navigator (module)
12
+ *
13
+ * Debug surface. Exposes Eleventy and Baseline runtime state to templates so
14
+ * developers can inspect data shape, scope contents, and lifecycle output
15
+ * without leaving the page.
16
+ *
17
+ * Architecture layer:
18
+ * module
19
+ *
20
+ * System role:
21
+ * Read-only window into the runtime substrate. Pulls snapshots from the
22
+ * page-context registry and content-map store via the module context;
23
+ * does not write back.
24
+ *
25
+ * Lifecycle:
26
+ * build-time → register Nunjucks globals, debug filters, and the
27
+ * optional virtual debug page
28
+ * cascade-time → eleventyComputed `_snapshot` resolves contentMap and
29
+ * pageContext on each page
30
+ *
31
+ * Why this exists:
32
+ * Render-time inspection of cascade state has no built-in surface.
33
+ * Centralising globals and filters under a debug-only module keeps the
34
+ * inspection vocabulary stable and out of feature modules.
35
+ *
36
+ * Scope:
37
+ * Owns the `_runtime` and `_ctx` Nunjucks globals, computed `_snapshot`,
38
+ * debug filters (`_inspect`, `_json`, `_keys`), and the optional virtual
39
+ * page at /navigator-core.html.
40
+ * Does not own the data it surfaces (page-context registry, content-map
41
+ * store).
42
+ *
43
+ * Data flow:
44
+ * snapshots (contentMap, pageContext) + this.ctx → globals + computed
45
+ * `_snapshot` + virtual page → developer
46
+ *
47
+ * Note: `_snapshot.contentMap` is null on the navigator template itself
48
+ * because it renders before `eleventy.contentMap` fires. Read `_snapshot`
49
+ * from any ordinary page for a populated contentMap.
50
+ *
51
+ * @param {import("@11ty/eleventy").UserConfig} eleventyConfig
52
+ * @param {Object} moduleContext
53
+ * @param {Object} moduleContext.state - Resolved plugin state.
54
+ * @param {Object} moduleContext.snapshots - Thunks: { contentMap, pageContext }.
55
+ */
56
+ export function navigatorCore(eleventyConfig, moduleContext) {
57
+ const { state, snapshots, log, env } = moduleContext;
58
+ const { settings, options } = state;
59
+
60
+ // Structural-only options check: log on mismatch, do not throw.
61
+ const parsed = optionsSchema.safeParse(options.navigator);
62
+ if (!parsed.success) {
63
+ for (const issue of parsed.error.issues) {
64
+ log.info('options:', `${issue.path.join('.')} — ${issue.message}`);
65
+ }
66
+ }
67
+
68
+ // Boolean shorthand activates the virtual page; object form lets users tune.
69
+ const navigatorOpts = options.navigator && typeof options.navigator === 'object' ? options.navigator : {};
70
+ const renderTemplate = env.mode === 'development' ?? navigatorOpts.template ?? Boolean(options.navigator);
71
+ const inspectorDepth = navigatorOpts.inspectorDepth ?? 4;
72
+
73
+ eleventyConfig.addGlobalData('eleventyComputed._snapshot', () => {
74
+ return () => ({
75
+ contentMap: snapshots.contentMap(),
76
+ pageContext: snapshots.pageContext()
77
+ });
78
+ });
79
+
80
+ /**
81
+ * Nunjucks Global: _runtime
82
+ *
83
+ * Exposes internal Nunjucks runtime state:
84
+ * - env → environment instance
85
+ * - ctx → current render context
86
+ * - globals → registered global values
87
+ */
88
+ eleventyConfig.addNunjucksGlobal('_runtime', function () {
89
+ return {
90
+ env: this.env,
91
+ ctx: this.ctx,
92
+ globals: this.env?.globals
93
+ };
94
+ });
95
+
96
+ /**
97
+ * Nunjucks Global: _ctx
98
+ *
99
+ * Direct reference to the template execution context.
100
+ * Useful for debugging data shape at render time.
101
+ */
102
+ eleventyConfig.addNunjucksGlobal('_ctx', function () {
103
+ return this.ctx;
104
+ });
105
+
106
+ /**
107
+ * Virtual Debug Template
108
+ *
109
+ * Registers a synthetic Eleventy page that dumps runtime context.
110
+ * This is only enabled when explicitly configured via options.
111
+ */
112
+ if (renderTemplate) {
113
+ const templatePath = path.join(__dirname, './templates/navigator-core.html');
114
+ const virtualTemplateContent = fs.readFileSync(templatePath, 'utf-8');
115
+
116
+ eleventyConfig.addTemplate('navigator-core.html', virtualTemplateContent, {
117
+ permalink: '/navigator-core.html',
118
+ title: 'Navigator Core',
119
+ description: 'Eleventy + Baseline internals',
120
+ layout: null,
121
+ eleventyExcludeFromCollections: true,
122
+ _internal: false,
123
+
124
+ // Debug control surface
125
+ inspectorDepth
126
+ });
127
+
128
+ log.info('Navigator template registered at /navigator-core.html');
129
+ }
130
+
131
+ /**
132
+ * Debug Filters
133
+ *
134
+ * Lightweight helpers for inspecting values in templates.
135
+ * These are intentionally prefixed to avoid collisions.
136
+ */
137
+ eleventyConfig.addFilter('_inspect', debug.inspect);
138
+ eleventyConfig.addFilter('_json', debug.json);
139
+ eleventyConfig.addFilter('_keys', debug.keys);
140
+ }
@@ -0,0 +1,13 @@
1
+ import * as z from 'zod';
2
+
3
+ // Structural schema for the `options.navigator` slice. Accepts boolean
4
+ // shorthand or object form; permissive on unknown keys, typed on the keys
5
+ // the module reads. Non-throwing at the call site.
6
+
7
+ export const optionsSchema = z.union([
8
+ z.boolean(),
9
+ z.looseObject({
10
+ template: z.boolean().optional(),
11
+ inspectorDepth: z.number().int().min(0).optional()
12
+ })
13
+ ]).optional();
@@ -4,7 +4,7 @@ permalink: /navigator-core.html
4
4
  ---
5
5
 
6
6
  <!DOCTYPE html>
7
- <html lang="{{ lang | default(site.defaultLanguage) }}">
7
+ <html lang="{{ lang | default(settings.defaultLanguage) }}">
8
8
 
9
9
  <head>
10
10
  <baseline-head></baseline-head>
@@ -28,9 +28,9 @@ permalink: /navigator-core.html
28
28
  </a>
29
29
  <header>
30
30
  <div class="_navigator__wrapper">
31
- <h1>{{ site.title }} Navigator</h1>
31
+ <h1>{{ settings.title }} Navigator</h1>
32
32
  <div>
33
- <p>{{ site.tagline }}</p>
33
+ <p>{{ settings.tagline }}</p>
34
34
  </div>
35
35
  </div>
36
36
  </header>
@@ -38,11 +38,17 @@ permalink: /navigator-core.html
38
38
  <div class="_navigator__wrapper">
39
39
  <p><a id="go-back" href=""><span style="vertical-align: text-bottom;">&#8592;</span>&nbsp;Go back</a></p>
40
40
  <h2><u>Navigator</u></h2>
41
- {% for key, value in _navigator() %}
41
+ <details>
42
+ <summary><strong>Page Context</strong></summary>
43
+ <pre>
44
+ {{- _snapshot.pageContext | _inspect({ depth: null }) -}}
45
+ </pre>
46
+ </details>
47
+ {% for key, value in _runtime() %}
42
48
  <details>
43
49
  <summary><strong>{{ key }}</strong></summary>
44
50
  {% if value | isString %}
45
- <pre>{{ value | safe }}</pre>
51
+ <pre>{{ value }}</pre>
46
52
  {% else %}
47
53
  <pre>{{ value | _inspect({ depth: inspectorDepth }) }}</pre>
48
54
  {% endif %}
@@ -56,9 +62,9 @@ permalink: /navigator-core.html
56
62
  history.back();
57
63
  });
58
64
  </script>
65
+ <footer>
66
+ <div class="_navigator__wrapper"><small>Navigator Core — Eleventy Plugin Baseline</small></div>
67
+ </footer>
59
68
  </body>
60
- <footer>
61
- <div class="_navigator__wrapper"><small>Navigator Core — Eleventy Plugin Baseline</small></div>
62
- </footer>
63
69
 
64
70
  </html>
@@ -0,0 +1,41 @@
1
+ import { inspect as utilInspect } from 'node:util';
2
+
3
+ // Adapted from pdehaan - https://github.com/pdehaan/eleventy-plugin-debug
4
+ const debugOptions = { space: 0 };
5
+
6
+ /**
7
+ * Pretty-print an object using Node's util.inspect.
8
+ * @param {*} obj - Value to inspect.
9
+ * @param {Object} [options={}] - Options forwarded to util.inspect.
10
+ * @returns {string}
11
+ */
12
+ function inspect(obj, options = {}) {
13
+ return utilInspect(obj, {
14
+ depth: 4,
15
+ maxArrayLength: 10,
16
+ breakLength: 80,
17
+ compact: true,
18
+ ...options
19
+ });
20
+ }
21
+
22
+ /**
23
+ * Serialize an object to JSON.
24
+ * @param {*} obj - Value to serialize.
25
+ * @param {number} [space] - Indentation level (default 0, compact).
26
+ * @returns {string}
27
+ */
28
+ function json(obj, space = debugOptions.space) {
29
+ return JSON.stringify(obj, null, space);
30
+ }
31
+
32
+ /**
33
+ * Return an object's own keys, sorted alphabetically.
34
+ * @param {Object} obj
35
+ * @returns {string[]}
36
+ */
37
+ function keys(obj) {
38
+ return Object.keys(obj).sort();
39
+ }
40
+
41
+ export default { inspect, json, keys };
@@ -0,0 +1,121 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { normalizeLanguages } from '../../core/utils/helpers.js';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ /**
10
+ * Sitemap (module)
11
+ *
12
+ * Sitemap generation and per-page sitemap metadata. Layers on Eleventy
13
+ * collections rather than rendering independently. In multilingual mode it
14
+ * partitions per-language sitemaps and emits a sitemap index; otherwise it
15
+ * emits a single flat sitemap.
16
+ *
17
+ * Architecture layer:
18
+ * module
19
+ *
20
+ * System role:
21
+ * Reads the same normalised language map as multilang (via
22
+ * core/utils/helpers.js) and emits virtual templates that Eleventy
23
+ * renders to XML. Pages opt out via `noindex` in the cascade.
24
+ *
25
+ * Lifecycle:
26
+ * build-time → register virtual sitemap templates (single, per-lang,
27
+ * or index)
28
+ * cascade-time → eleventyComputed `page.sitemap` resolves ignore /
29
+ * changefreq / priority on each page
30
+ *
31
+ * Why this exists:
32
+ * Eleventy has no built-in sitemap. Multilingual sites also need
33
+ * partitioning plus an index, which only makes sense once language config
34
+ * is normalised the same way multilang sees it.
35
+ *
36
+ * Scope:
37
+ * Owns computed page.sitemap and the virtual sitemap templates
38
+ * (single-language /sitemap.xml, or per-lang /{lang}/sitemap.xml plus a
39
+ * /sitemap.xml index).
40
+ * Does not own language normalisation (core/utils/helpers.js) or noindex
41
+ * propagation through the cascade.
42
+ *
43
+ * Data flow:
44
+ * settings.languages + page data → computed page.sitemap + virtual
45
+ * templates → /sitemap.xml or per-language + index
46
+ *
47
+ * @param {import("@11ty/eleventy").UserConfig} eleventyConfig
48
+ * @param {Object} moduleContext
49
+ */
50
+ export function sitemapCore(eleventyConfig, moduleContext) {
51
+ const { state, log } = moduleContext;
52
+ const { settings, options } = state;
53
+
54
+ // --- Language normalization ---
55
+ // Accept languages as array or object; normalize to object map.
56
+ // Drives collection building, locale data, and sitemap-core language config.
57
+ const normalizeLanguageCode = (lang) => (lang || '').toLowerCase().trim();
58
+ const defaultLanguage = normalizeLanguageCode(settings.defaultLanguage);
59
+ const languages = normalizeLanguages(settings, log);
60
+ const hasLanguages = languages && Object.keys(languages).length > 0;
61
+ const isMultilingual = options.multilang === true && defaultLanguage && hasLanguages;
62
+
63
+ // Computed sitemap data: every page gets a page.sitemap object.
64
+ // Pages set noindex in frontmatter or site data to be excluded.
65
+ eleventyConfig.addGlobalData('eleventyComputed.page.sitemap', () => {
66
+ return (data) => ({
67
+ ignore: data.noindex ?? data.page?.noindex ?? data.settings?.noindex ?? false,
68
+ changefreq: '',
69
+ priority: -1
70
+ });
71
+ });
72
+
73
+ // --- Virtual sitemap templates ---
74
+ // Read template sources synchronously (same constraint as navigator-core).
75
+ // In multilingual mode: one sitemap per language + a sitemap index.
76
+ // In single-language mode: one flat sitemap at /sitemap.xml.
77
+ // Activation gate lives in the composition root via features.sitemap;
78
+ // the module is only registered when enabled.
79
+ const templatePath = path.join(__dirname, './templates/sitemap-core.html');
80
+ const indexTemplatePath = path.join(__dirname, './templates/sitemap-index.html');
81
+ const baseContent = fs.readFileSync(templatePath, 'utf-8');
82
+ const indexContent = fs.readFileSync(indexTemplatePath, 'utf-8');
83
+
84
+ const langKeys = Object.keys(languages || {});
85
+ const multilingual = isMultilingual;
86
+
87
+ if (multilingual && langKeys.length > 1) {
88
+ for (const lang of langKeys) {
89
+ eleventyConfig.addTemplate(`_baseline/sitemap-core-${lang}.html`, baseContent, {
90
+ permalink: `${lang}/sitemap.xml`,
91
+ title: '',
92
+ description: '',
93
+ layout: null,
94
+ eleventyExcludeFromCollections: true,
95
+ isMultilingual: multilingual,
96
+ sitemapLang: lang,
97
+ _internal: true
98
+ });
99
+ }
100
+
101
+ eleventyConfig.addTemplate('_baseline/sitemap-index.html', indexContent, {
102
+ permalink: '/sitemap.xml',
103
+ title: '',
104
+ description: '',
105
+ layout: null,
106
+ eleventyExcludeFromCollections: true,
107
+ isMultilingual: multilingual,
108
+ languages: languages,
109
+ _internal: true
110
+ });
111
+ } else {
112
+ eleventyConfig.addTemplate('_baseline/sitemap-core.html', baseContent, {
113
+ permalink: '/sitemap.xml',
114
+ title: '',
115
+ description: '',
116
+ layout: null,
117
+ eleventyExcludeFromCollections: true,
118
+ _internal: true
119
+ });
120
+ }
121
+ }
@@ -0,0 +1,34 @@
1
+ <?xml version="1.0" encoding="utf-8" standalone="yes"?>
2
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
3
+ {%- if not settings.noindex %}
4
+ {%- for item in collections.all %}
5
+ {%- if not item.data.eleventyExcludeFromCollections and (not item.data.sitemap or item.data.sitemap.ignore != true) and item.data.noindex != true %}
6
+ {%- set pageLang = item.data.lang or settings.defaultLanguage %}
7
+ {%- if (not isMultilingual) or (not sitemapLang) or (pageLang == sitemapLang) %}
8
+ {%- set absoluteUrl = item.url | htmlBaseUrl %}
9
+ {%- set lastmod = item.data.sitemap and item.data.sitemap.lastmod or item.date %}
10
+ <url>
11
+ <loc>{{ absoluteUrl }}</loc>
12
+ {%- if lastmod %}
13
+ <lastmod>{{ date.toUTCISO(lastmod) }}</lastmod>
14
+ {%- endif %}
15
+ {%- if item.data.sitemap and item.data.sitemap.changefreq %}
16
+ <changefreq>{{ item.data.sitemap.changefreq }}</changefreq>
17
+ {%- endif %}
18
+ {%- if item.data.sitemap and item.data.sitemap.priority is defined %}
19
+ <priority>{{ item.data.sitemap.priority }}</priority>
20
+ {%- endif %}
21
+ {%- if item.data.translationKey and collections.translationsMap and collections.translationsMap[item.data.translationKey] %}
22
+ {%- for language, entry in collections.translationsMap[item.data.translationKey] %}
23
+ <xhtml:link rel="alternate" hreflang="{{ entry.lang }}" href="{{ entry.url | htmlBaseUrl }}" />
24
+ {%- if entry.isDefaultLang %}
25
+ <xhtml:link rel="alternate" hreflang="x-default" href="{{ entry.url | htmlBaseUrl }}" />
26
+ {%- endif %}
27
+ {%- endfor %}
28
+ {%- endif %}
29
+ </url>
30
+ {%- endif %}
31
+ {%- endif %}
32
+ {%- endfor %}
33
+ {%- endif %}
34
+ </urlset>
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0" encoding="utf-8" standalone="yes"?>
2
2
  <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3
- {%- if not site.noindex %}
4
- {%- set langs = _baseline.languages or _i18n.languages %}
3
+ {%- if not settings.noindex %}
4
+ {%- set langs = languages %}
5
5
  {%- if langs %}
6
6
  {%- for lang, cfg in langs %}
7
7
  <sitemap>
package/modules.js ADDED
@@ -0,0 +1,6 @@
1
+ // Modules barrel.
2
+ export { assetsCore } from './modules/assets/index.js';
3
+ export { headCore } from './modules/head/index.js';
4
+ export { multilangCore } from './modules/multilang/index.js';
5
+ export { navigatorCore } from './modules/navigator/index.js';
6
+ export { sitemapCore } from './modules/sitemap/index.js';
package/package.json CHANGED
@@ -1,19 +1,21 @@
1
1
  {
2
2
  "name": "@apleasantview/eleventy-plugin-baseline",
3
- "version": "0.1.0-next.32",
3
+ "version": "0.1.0-next.39",
4
4
  "description": "An experimental Swiss army knife toolkit for Eleventy",
5
5
  "type": "module",
6
- "main": "eleventy.config.js",
7
6
  "exports": {
8
- ".": "./eleventy.config.js",
7
+ ".": "./index.js",
9
8
  "./package.json": "./package.json"
10
9
  },
11
10
  "files": [
12
- "eleventy.config.js",
11
+ "index.js",
12
+ "modules.js",
13
13
  "core/**",
14
14
  "modules/**",
15
15
  "README.md",
16
- "LICENSE"
16
+ "LICENSE",
17
+ "!**/__tests__/**",
18
+ "!**/*.test.js"
17
19
  ],
18
20
  "engines": {
19
21
  "node": ">=20"
@@ -38,14 +40,21 @@
38
40
  "@11ty/eleventy-img": "^6.0.4"
39
41
  },
40
42
  "dependencies": {
43
+ "@11ty/eleventy-utils": "^2.0.7",
44
+ "@rviscomi/capo.js": "^2.1.0",
41
45
  "cssnano": "^7.1.2",
42
46
  "dotenv": "^17.2.3",
43
47
  "esbuild": "0.27.0",
48
+ "kleur": "^4.1.5",
49
+ "luxon": "^3.7.2",
50
+ "markdown-it": "^14.1.1",
44
51
  "postcss": "^8.5.6",
45
52
  "postcss-import": "^16.1.1",
46
53
  "postcss-import-ext-glob": "^2.1.1",
47
54
  "postcss-load-config": "^6.0.1",
48
- "postcss-preset-env": "^10.4.0"
55
+ "postcss-preset-env": "^10.4.0",
56
+ "slugify": "^1.6.6",
57
+ "zod": "^4.3.6"
49
58
  },
50
59
  "sideEffects": false
51
60
  }
package/core/debug.js DELETED
@@ -1,20 +0,0 @@
1
- import { inspect as utilInspect } from 'node:util';
2
-
3
- // Adapted from pdehaan - https://github.com/pdehaan/eleventy-plugin-debug
4
- const debugOptions = Object.assign({
5
- space: 0
6
- });
7
-
8
- function inspect(obj, options = {}) {
9
- return utilInspect(obj, options);
10
- }
11
-
12
- function json(obj, space = debugOptions.space) {
13
- return JSON.stringify(obj, null, space);
14
- }
15
-
16
- function keys(obj) {
17
- return Object.keys(obj).sort();
18
- }
19
-
20
- export default { inspect, json, keys };
package/core/filters.js DELETED
@@ -1,9 +0,0 @@
1
- import { markdownFilter } from './filters/markdown.js';
2
- import relatedPostsFilter from './filters/related-posts.js';
3
- import isStringFilter from './filters/isString.js';
4
-
5
- export default {
6
- markdownFilter,
7
- relatedPostsFilter,
8
- isStringFilter
9
- };
package/core/globals.js DELETED
@@ -1,6 +0,0 @@
1
- import { registerDateGlobal } from './globals/date.js';
2
-
3
- /** @param {import("@11ty/eleventy").UserConfig} eleventyConfig */
4
- export default function registerGlobals(eleventyConfig) {
5
- registerDateGlobal(eleventyConfig);
6
- }