@apleasantview/eleventy-plugin-baseline 0.1.0-next.22 → 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
package/README.md CHANGED
@@ -5,11 +5,13 @@ An experimental Swiss army knife toolkit for Eleventy. Bundles handy helpers for
5
5
  ## Install
6
6
 
7
7
  If you already have Eleventy and eleventy-img installed:
8
+
8
9
  ```bash
9
10
  npm install @apleasantview/eleventy-plugin-baseline
10
11
  ```
11
12
 
12
13
  For a fresh project (install Eleventy and eleventy-img too):
14
+
13
15
  ```bash
14
16
  npm install @11ty/eleventy @11ty/eleventy-img @apleasantview/eleventy-plugin-baseline
15
17
  ```
@@ -19,7 +21,7 @@ npm install @11ty/eleventy @11ty/eleventy-img @apleasantview/eleventy-plugin-bas
19
21
  In your Eleventy config (ESM):
20
22
 
21
23
  ```js
22
- import baseline, { config as baselineConfig } from "@apleasantview/eleventy-plugin-baseline";
24
+ import baseline, { config as baselineConfig } from '@apleasantview/eleventy-plugin-baseline';
23
25
 
24
26
  export default function (eleventyConfig) {
25
27
  eleventyConfig.addPlugin(baseline, {
package/core/debug.js CHANGED
@@ -1,20 +1,20 @@
1
- import { inspect as utilInspect } from "node:util";
1
+ import { inspect as utilInspect } from 'node:util';
2
2
 
3
3
  // Adapted from pdehaan - https://github.com/pdehaan/eleventy-plugin-debug
4
4
  const debugOptions = Object.assign({
5
- space: 0
5
+ space: 0
6
6
  });
7
7
 
8
8
  function inspect(obj, options = {}) {
9
- return utilInspect(obj, options);
9
+ return utilInspect(obj, options);
10
10
  }
11
11
 
12
12
  function json(obj, space = debugOptions.space) {
13
- return JSON.stringify(obj, null, space);
13
+ return JSON.stringify(obj, null, space);
14
14
  }
15
15
 
16
16
  function keys(obj) {
17
- return Object.keys(obj).sort();
17
+ return Object.keys(obj).sort();
18
18
  }
19
19
 
20
20
  export default { inspect, json, keys };
@@ -1,3 +1,3 @@
1
1
  export default function isStringFilter(object) {
2
- return typeof object === "string";
2
+ return typeof object === 'string';
3
3
  }
@@ -1,10 +1,8 @@
1
- // see https://jeremias.codes/2025/02/markdown-filters-eleventy/
1
+ // See https://jeremias.codes/2025/02/markdown-filters-eleventy/
2
2
  import markdownit from 'markdown-it';
3
3
 
4
- const md = markdownit({
5
- html: true
6
- });
4
+ const md = markdownit();
7
5
 
8
6
  export const markdownFilter = (string) => {
9
- return md.renderInline(string);
7
+ return md.renderInline(string);
10
8
  };
@@ -1,6 +1,5 @@
1
1
  export default function relatedPostsFilter(collection = []) {
2
- const page = this.ctx.page;
3
- return collection.filter(post => {
4
- return post.url !== page.url;
5
- })
6
- }
2
+ const page = this?.ctx?.page;
3
+ if (!page?.url) return collection;
4
+ return collection.filter((post) => post.url !== page.url);
5
+ }
package/core/filters.js CHANGED
@@ -1,9 +1,9 @@
1
- import { markdownFilter } from "./filters/markdown.js";
2
- import relatedPostsFilter from "./filters/related-posts.js";
3
- import isStringFilter from "./filters/isString.js";
1
+ import { markdownFilter } from './filters/markdown.js';
2
+ import relatedPostsFilter from './filters/related-posts.js';
3
+ import isStringFilter from './filters/isString.js';
4
4
 
5
5
  export default {
6
6
  markdownFilter,
7
7
  relatedPostsFilter,
8
8
  isStringFilter
9
- }
9
+ };
@@ -1,4 +1,4 @@
1
- import { DateTime } from "luxon";
1
+ import { DateTime } from 'luxon';
2
2
 
3
3
  /**
4
4
  * Register Nunjucks global "date" with helper methods.
@@ -7,11 +7,11 @@ import { DateTime } from "luxon";
7
7
  * @param {import("@11ty/eleventy").UserConfig} eleventyConfig
8
8
  */
9
9
  export function registerDateGlobal(eleventyConfig) {
10
- eleventyConfig.addNunjucksGlobal("date", {
10
+ eleventyConfig.addNunjucksGlobal('date', {
11
11
  toUTCISO(value) {
12
- if (!value) return "";
12
+ if (!value) return '';
13
13
  const jsDate = value instanceof Date ? value : new Date(value);
14
- if (Number.isNaN(jsDate.getTime())) return "";
14
+ if (Number.isNaN(jsDate.getTime())) return '';
15
15
  return DateTime.fromJSDate(jsDate).toUTC().toISO({ suppressMilliseconds: true });
16
16
  }
17
17
  });
package/core/globals.js CHANGED
@@ -1,4 +1,4 @@
1
- import { registerDateGlobal } from "./globals/date.js";
1
+ import { registerDateGlobal } from './globals/date.js';
2
2
 
3
3
  /** @param {import("@11ty/eleventy").UserConfig} eleventyConfig */
4
4
  export default function registerGlobals(eleventyConfig) {
package/core/helpers.js CHANGED
@@ -1,5 +1,5 @@
1
- import path from "node:path";
2
- import { TemplatePath } from "@11ty/eleventy-utils";
1
+ import path from 'node:path';
2
+ import { TemplatePath } from '@11ty/eleventy-utils';
3
3
 
4
4
  /**
5
5
  * Helper function to add trailing slash to a path
@@ -7,10 +7,10 @@ import { TemplatePath } from "@11ty/eleventy-utils";
7
7
  * @returns {string}
8
8
  */
9
9
  export function addTrailingSlash(path) {
10
- if (path.slice(-1) === "/") {
10
+ if (path.slice(-1) === '/') {
11
11
  return path;
12
12
  }
13
- return path + "/";
13
+ return path + '/';
14
14
  }
15
15
 
16
16
  /**
@@ -22,15 +22,15 @@ export function addTrailingSlash(path) {
22
22
  */
23
23
  export function resolveAssetsDir(inputDir, outputDir, rawDir) {
24
24
  // Join input/output with assets subdir and normalize
25
- const joinedInput = TemplatePath.join(inputDir, rawDir || "");
26
- const joinedOutput = TemplatePath.join(outputDir, rawDir || "");
25
+ const joinedInput = TemplatePath.join(inputDir, rawDir || '');
26
+ const joinedOutput = TemplatePath.join(outputDir, rawDir || '');
27
27
 
28
28
  const assetsDir = addTrailingSlash(TemplatePath.standardizeFilePath(joinedInput));
29
29
  const assetsOutputDir = addTrailingSlash(TemplatePath.standardizeFilePath(joinedOutput));
30
30
 
31
31
  return {
32
32
  assetsDir,
33
- assetsOutputDir,
33
+ assetsOutputDir
34
34
  };
35
35
  }
36
36
 
@@ -41,13 +41,11 @@ export function resolveAssetsDir(inputDir, outputDir, rawDir) {
41
41
  * @returns {string[]} Absolute glob patterns
42
42
  */
43
43
  export function buildGlobPatterns(patterns, assetsDir) {
44
- const assetsDirAbsolute = TemplatePath.absolutePath(
45
- TemplatePath.stripLeadingDotSlash(assetsDir)
46
- );
47
-
44
+ const assetsDirAbsolute = TemplatePath.absolutePath(TemplatePath.stripLeadingDotSlash(assetsDir));
45
+
48
46
  return patterns.map((pattern) => {
49
47
  const normalized = TemplatePath.standardizeFilePath(pattern);
50
- return normalized.startsWith("/") || path.isAbsolute(normalized)
48
+ return normalized.startsWith('/') || path.isAbsolute(normalized)
51
49
  ? normalized
52
50
  : TemplatePath.join(assetsDirAbsolute, normalized);
53
51
  });
@@ -60,7 +58,7 @@ export function buildGlobPatterns(patterns, assetsDir) {
60
58
  */
61
59
  export function extractFileMetadata(filePath) {
62
60
  const ext = path.extname(filePath); // Returns extension with dot (e.g., ".css") or ""
63
- const inputFileExtension = ext && ext.length > 0 ? ext.slice(1) : "";
61
+ const inputFileExtension = ext && ext.length > 0 ? ext.slice(1) : '';
64
62
  const basename = TemplatePath.getLastPathSegment(filePath, false);
65
63
  const fileSlug = ext ? basename.slice(0, -ext.length) : basename;
66
64
 
@@ -90,41 +88,31 @@ export function createCollectionItem(
90
88
  // Get path relative to input directory
91
89
  // e.g., inputPath = "./src/assets/css/index.css", inputDir = "./src/"
92
90
  // relToInput = "assets/css/index.css"
93
- const relToInput = TemplatePath.stripLeadingSubPath(
94
- inputPath,
95
- TemplatePath.addLeadingDotSlash(inputDir)
96
- );
91
+ const relToInput = TemplatePath.stripLeadingSubPath(inputPath, TemplatePath.addLeadingDotSlash(inputDir));
97
92
 
98
93
  // outputPath: prepend output directory (with leading ./)
99
94
  // e.g., relToInput = "assets/css/index.css", outputDir = "./dist/"
100
95
  // outputPath = "./dist/assets/css/index.css"
101
96
  const outputPath = TemplatePath.addLeadingDotSlash(
102
- TemplatePath.normalize(
103
- TemplatePath.join(
104
- TemplatePath.addLeadingDotSlash(outputDir),
105
- relToInput
106
- )
107
- )
97
+ TemplatePath.normalize(TemplatePath.join(TemplatePath.addLeadingDotSlash(outputDir), relToInput))
108
98
  );
109
99
 
110
100
  // relToAssets: path relative to assets directory for URL generation
111
101
  // e.g., inputPath = "./src/assets/css/index.css", assetsDirRelative = "assets"
112
102
  // relToAssets = "css/index.css"
113
- const assetsDirPath = TemplatePath.addLeadingDotSlash(
114
- TemplatePath.join(inputDir, assetsDirRelative)
115
- );
103
+ const assetsDirPath = TemplatePath.addLeadingDotSlash(TemplatePath.join(inputDir, assetsDirRelative));
116
104
  const relToAssets = TemplatePath.stripLeadingSubPath(inputPath, assetsDirPath);
117
105
 
118
- const url = passthrough
119
- ? TemplatePath.join(passthroughOutput, relToAssets).replace(/\/$/, "")
120
- : undefined;
106
+ const url = passthrough ? TemplatePath.join(passthroughOutput, relToAssets).replace(/\/$/, '') : undefined;
121
107
 
122
108
  // filePathStem: path relative to input without extension, with leading slash
123
109
  // e.g., relToInput = "assets/css/index.css"
124
110
  // filePathStem = "/assets/css/index"
125
- const filePathStem = "/" + (inputFileExtension
126
- ? relToInput.slice(0, -inputFileExtension.length - 1) // Remove extension and dot
127
- : relToInput);
111
+ const filePathStem =
112
+ '/' +
113
+ (inputFileExtension
114
+ ? relToInput.slice(0, -inputFileExtension.length - 1) // Remove extension and dot
115
+ : relToInput);
128
116
 
129
117
  return {
130
118
  inputPath,
@@ -134,6 +122,6 @@ export function createCollectionItem(
134
122
  inputFileExtension,
135
123
  filePathStem,
136
124
  dir: TemplatePath.getDirFromFilePath(inputPath),
137
- url,
125
+ url
138
126
  };
139
127
  }
package/core/modules.js CHANGED
@@ -1,14 +1,14 @@
1
1
  // Eleventy plugins
2
- import { EleventyHtmlBasePlugin } from "@11ty/eleventy";
2
+ import { EleventyHtmlBasePlugin } from '@11ty/eleventy';
3
3
 
4
4
  // Custom plugins
5
- import multilangCore from "../modules/multilang-core/plugins/multilang-core.js";
6
- import navigatorCore from "../modules/navigator-core/plugins/navigator-core.js";
7
- import assetsCore from "../modules/assets-core/plugins/assets-core.js";
8
- import assetsPostCSS from "../modules/assets-postcss/plugins/assets-postcss.js";
9
- import assetsESBuild from "../modules/assets-esbuild/plugins/assets-esbuild.js";
10
- import headCore from "../modules/head-core/plugins/head-core.js";
11
- import sitemapCore from "../modules/sitemap-core/plugins/sitemap-core.js";
5
+ import multilangCore from '../modules/multilang-core/plugins/multilang-core.js';
6
+ import navigatorCore from '../modules/navigator-core/plugins/navigator-core.js';
7
+ import assetsCore from '../modules/assets-core/plugins/assets-core.js';
8
+ import assetsPostCSS from '../modules/assets-postcss/plugins/assets-postcss.js';
9
+ import assetsESBuild from '../modules/assets-esbuild/plugins/assets-esbuild.js';
10
+ import headCore from '../modules/head-core/plugins/head-core.js';
11
+ import sitemapCore from '../modules/sitemap-core/plugins/sitemap-core.js';
12
12
 
13
13
  export default {
14
14
  EleventyHtmlBasePlugin,
@@ -1,14 +1,9 @@
1
- import path from "node:path";
2
- import Image from "@11ty/eleventy-img";
3
- import { eleventyImageOnRequestDuringServePlugin } from "@11ty/eleventy-img";
1
+ import path from 'node:path';
2
+ import Image from '@11ty/eleventy-img';
4
3
 
5
4
  const DEFAULT_WIDTHS = [320, 640, 960, 1280];
6
- const DEFAULT_FORMATS = ["avif", "webp", "jpeg"];
7
- const DEFAULT_SIZES = "(max-width: 768px) 100vw, 768px";
8
- const DEFAULT_OUTPUT = {
9
- outputDir: "./dist/media/",
10
- urlPath: "/media/",
11
- };
5
+ const DEFAULT_FORMATS = ['avif', 'webp', 'jpeg'];
6
+ const DEFAULT_SIZES = '(max-width: 768px) 100vw, 768px';
12
7
 
13
8
  function pickRenditions(metadata) {
14
9
  // Use the first available format; first entry is smallest, last is largest.
@@ -31,52 +26,48 @@ function pickRenditions(metadata) {
31
26
  * @param {Array<number|string>} [options.widths=DEFAULT_WIDTHS] Widths passed to eleventy-img.
32
27
  * @param {string} [options.sizes=DEFAULT_SIZES] Sizes attribute used on sources.
33
28
  * @param {string[]} [options.formats=DEFAULT_FORMATS] Output formats (order matters).
34
- * @param {string} [options.outputDir=DEFAULT_OUTPUT.outputDir] Output directory for generated assets.
35
- * @param {string} [options.urlPath=DEFAULT_OUTPUT.urlPath] Public URL base for generated assets.
29
+ * @param {string} [options.outputDir] Output directory for generated assets (defaults to `./dist/media/` or `./<dir.output>/media/` when set).
30
+ * @param {string} [options.urlPath="/media/"] Public URL base for generated assets.
36
31
  * @param {Object} [options.attrs={}] Extra attributes applied to <img>; `class` merges with imageClass.
37
32
  * @param {string} [options.style] Inline style applied to <img> (alias for attrs.style).
38
33
  * @param {boolean} [options.figure=true] Wrap in <figure> when caption is provided.
39
34
  * @param {boolean} [options.setDimensions=true] When false, omit width/height on <img>.
40
35
  */
41
36
  export async function imageShortcode(options = {}) {
37
+ const outputBase = this?.eleventy?.directories?.output || 'dist';
42
38
  const {
43
39
  src,
44
40
  alt,
45
- caption = "",
46
- loading = "lazy",
47
- containerClass = "",
48
- imageClass = "",
41
+ caption = '',
42
+ loading = 'lazy',
43
+ containerClass = '',
44
+ imageClass = '',
49
45
  style,
50
46
  widths = DEFAULT_WIDTHS,
51
47
  sizes = DEFAULT_SIZES,
52
48
  formats = DEFAULT_FORMATS,
53
- outputDir = DEFAULT_OUTPUT.outputDir,
54
- urlPath = DEFAULT_OUTPUT.urlPath,
49
+ outputDir = path.join('.', outputBase, 'media'),
50
+ urlPath = '/media/',
55
51
  attrs = {},
56
52
  figure = true,
57
- setDimensions = true,
53
+ setDimensions = true
58
54
  } = options;
59
-
60
55
  const hasImageTransformPlugin = this.ctx._baseline.hasImageTransformPlugin;
61
56
 
62
- if (!src) throw new Error("imageShortcode: src is required");
57
+ if (!src) throw new Error('imageShortcode: src is required');
63
58
  if (alt === undefined) {
64
- throw new Error(
65
- "imageShortcode: alt is required (use empty string for decorative images)",
66
- );
59
+ throw new Error('imageShortcode: alt is required (use empty string for decorative images)');
67
60
  }
68
61
 
69
- const normalizedCaption = caption == null ? "" : String(caption);
70
- const normalizedAlt = alt == null ? "" : String(alt);
62
+ const normalizedCaption = caption == null ? '' : String(caption);
63
+ const normalizedAlt = alt == null ? '' : String(alt);
71
64
 
72
65
  const inputDir = this?.eleventy?.directories?.input;
73
66
  const isRemote = /^https?:\/\//i.test(src);
74
- const resolvedSrc = !isRemote && inputDir
75
- ? path.join(inputDir, src.replace(/^\//, ""))
76
- : src;
67
+ const resolvedSrc = !isRemote && inputDir ? path.join(inputDir, src.replace(/^\//, '')) : src;
77
68
 
78
69
  const metadata = await Image(resolvedSrc, {
79
- transformOnRequest: process.env.ELEVENTY_RUN_MODE === "serve",
70
+ transformOnRequest: process.env.ELEVENTY_RUN_MODE === 'serve',
80
71
  widths: [...widths],
81
72
  formats: [...formats],
82
73
  outputDir,
@@ -85,7 +76,7 @@ export async function imageShortcode(options = {}) {
85
76
  const extension = path.extname(srcPath);
86
77
  const name = path.basename(srcPath, extension);
87
78
  return `${name}-${width}w.${format}`;
88
- },
79
+ }
89
80
  });
90
81
 
91
82
  const { lowsrc, highsrc } = pickRenditions(metadata);
@@ -96,32 +87,32 @@ export async function imageShortcode(options = {}) {
96
87
  const sourceTags = Object.values(metadata)
97
88
  .map((formatEntries) => {
98
89
  const type = formatEntries[0].sourceType;
99
- const srcset = formatEntries.map((entry) => entry.srcset).join(", ");
90
+ const srcset = formatEntries.map((entry) => entry.srcset).join(', ');
100
91
  return `<source type="${type}" srcset="${srcset}" sizes="${sizes}">`;
101
92
  })
102
- .join("\n");
93
+ .join('\n');
103
94
 
104
95
  const { class: attrClass, ...restAttrs } = attrs;
105
- const combinedClass = [imageClass, attrClass].filter(Boolean).join(" ").trim() || undefined;
96
+ const combinedClass = [imageClass, attrClass].filter(Boolean).join(' ').trim() || undefined;
106
97
 
107
98
  const imageAttributes = {
108
99
  src: lowsrc.url,
109
100
  alt: normalizedAlt,
110
101
  loading,
111
- decoding: loading === "eager" ? "sync" : "async",
102
+ decoding: loading === 'eager' ? 'sync' : 'async',
112
103
  class: combinedClass,
113
104
  style,
114
105
  ...(setDimensions ? { width: highsrc.width, height: highsrc.height } : {}),
115
106
  ...restAttrs,
116
- ...(hasImageTransformPlugin ? { "eleventy:ignore": true } : {})
107
+ ...(hasImageTransformPlugin ? { 'eleventy:ignore': true } : {})
117
108
  };
118
109
 
119
110
  const imgAttrString = Object.entries(imageAttributes)
120
- .filter(([, value]) => value !== undefined && value !== null && value !== "")
121
- .map(([key, value]) => value === true ? key : `${key}="${value}"`)
122
- .join(" ");
111
+ .filter(([, value]) => value !== undefined && value !== null && value !== '')
112
+ .map(([key, value]) => (value === true ? key : `${key}="${value}"`))
113
+ .join(' ');
123
114
 
124
- const pictureClass = containerClass && containerClass.trim() ? ` class="${containerClass.trim()}"` : "";
115
+ const pictureClass = containerClass && containerClass.trim() ? ` class="${containerClass.trim()}"` : '';
125
116
 
126
117
  const picture = `<picture${pictureClass}>
127
118
  ${sourceTags}
@@ -1,3 +1,3 @@
1
- import { imageShortcode } from "./shortcodes/image.js";
1
+ import { imageShortcode } from './shortcodes/image.js';
2
2
 
3
3
  export default { imageShortcode };
@@ -1,15 +1,15 @@
1
- import "dotenv/config";
2
- import globals from "./core/globals.js";
3
- import debug from "./core/debug.js";
4
- import filters from "./core/filters.js";
5
- import modules from "./core/modules.js";
6
- import shortcodes from "./core/shortcodes.js";
7
- import { eleventyImageOnRequestDuringServePlugin } from "@11ty/eleventy-img";
8
-
9
- import { createRequire } from "node:module";
1
+ import 'dotenv/config';
2
+ import globals from './core/globals.js';
3
+ import debug from './core/debug.js';
4
+ import filters from './core/filters.js';
5
+ import modules from './core/modules.js';
6
+ import shortcodes from './core/shortcodes.js';
7
+ import { eleventyImageOnRequestDuringServePlugin } from '@11ty/eleventy-img';
8
+
9
+ import { createRequire } from 'node:module';
10
10
  const __require = createRequire(import.meta.url);
11
11
 
12
- const { name, version } = __require("./package.json");
12
+ const { name, version } = __require('./package.json');
13
13
 
14
14
  /**
15
15
  * Eleventy Plugin Baseline.
@@ -31,12 +31,12 @@ export default function baseline(options = {}) {
31
31
  const plugin = async function (eleventyConfig) {
32
32
  try {
33
33
  // Emit a warning message if the application is not using Eleventy 3.0 or newer (including prereleases).
34
- eleventyConfig.versionCheck(">=3.0");
34
+ eleventyConfig.versionCheck('>=3.0');
35
35
  } catch (e) {
36
36
  console.log(`[eleventy-plugin-baseline] WARN Eleventy plugin compatibility: ${e.message}`);
37
37
  }
38
38
 
39
- const hasImageTransformPlugin = eleventyConfig.hasPlugin("eleventyImageTransformPlugin");
39
+ const hasImageTransformPlugin = eleventyConfig.hasPlugin('eleventyImageTransformPlugin');
40
40
 
41
41
  const userOptions = {
42
42
  version,
@@ -45,28 +45,47 @@ export default function baseline(options = {}) {
45
45
  hasImageTransformPlugin,
46
46
  enableNavigatorTemplate: options.enableNavigatorTemplate ?? false,
47
47
  enableSitemapTemplate: options.enableSitemapTemplate ?? true,
48
+ filterAllCollection: options.filterAllCollection ?? true,
48
49
  assets: {
49
- esbuild: options.assetsESBuild ?? { minify: true, target: "es2020" }
50
+ esbuild: options.assetsESBuild ?? { minify: true, target: 'es2020' }
50
51
  },
51
52
  multilingual: options.multilingual ?? false,
52
53
  ...options
53
54
  };
54
55
 
55
56
  // Core functions.
56
- // Languages are expected as an object map; if missing or invalid, skip.
57
- const languages = userOptions.languages && typeof userOptions.languages === "object"
58
- ? userOptions.languages : null;
57
+
58
+ // Normalize languages to an object map; if missing or invalid, use null.
59
+ const normalizedLanguages = Array.isArray(userOptions.languages)
60
+ ? Object.fromEntries(
61
+ userOptions.languages
62
+ .filter((lang) => typeof lang === 'string' && lang.trim())
63
+ .map((lang) => [lang.trim(), {}])
64
+ )
65
+ : userOptions.languages && typeof userOptions.languages === 'object'
66
+ ? userOptions.languages
67
+ : null;
68
+
69
+ if (userOptions.verbose && Array.isArray(userOptions.languages)) {
70
+ const normalizedCount = normalizedLanguages ? Object.keys(normalizedLanguages).length : 0;
71
+ if (normalizedCount !== userOptions.languages.length) {
72
+ console.warn('[baseline] Some languages entries were invalid and were dropped.');
73
+ }
74
+ }
75
+
76
+ userOptions.languages = normalizedLanguages;
77
+ const languages = normalizedLanguages;
59
78
  const hasLanguages = languages && Object.keys(languages).length > 0;
60
79
  const isMultilingual = userOptions.multilingual === true && userOptions.defaultLanguage && hasLanguages;
61
80
 
62
- eleventyConfig.addGlobalData("_baseline", userOptions);
81
+ eleventyConfig.addGlobalData('_baseline', userOptions);
63
82
  globals(eleventyConfig);
64
- eleventyConfig.addPassthroughCopy({ "./src/static": "/" }, { failOnError: true });
83
+ eleventyConfig.addPassthroughCopy({ './src/static': '/' });
65
84
 
66
85
  // Prevents double-registering the preprocessor, user config wins.
67
86
  if (!eleventyConfig.preprocessors.drafts) {
68
- eleventyConfig.addPreprocessor("drafts", "*", (data, content) => {
69
- if (data.draft && process.env.ELEVENTY_RUN_MODE === "build") {
87
+ eleventyConfig.addPreprocessor('drafts', '*', (data) => {
88
+ if (data.draft && process.env.ELEVENTY_RUN_MODE === 'build') {
70
89
  return false;
71
90
  }
72
91
  });
@@ -80,45 +99,59 @@ export default function baseline(options = {}) {
80
99
  }
81
100
 
82
101
  // Modules.
83
- eleventyConfig.addPlugin(modules.EleventyHtmlBasePlugin, { baseHref: process.env.URL || eleventyConfig.pathPrefix });
102
+ eleventyConfig.addPlugin(modules.EleventyHtmlBasePlugin, {
103
+ baseHref: process.env.URL || eleventyConfig.pathPrefix
104
+ });
84
105
  eleventyConfig.addPlugin(modules.assetsCore);
85
106
  eleventyConfig.addPlugin(modules.assetsPostCSS);
86
107
  eleventyConfig.addPlugin(modules.assetsESBuild, userOptions.assets.esbuild);
108
+
109
+ if (userOptions.filterAllCollection) {
110
+ // Override the default collection behavior. Adding js as template format collects 11tydata.js files.
111
+ eleventyConfig.addCollection('all', (collectionApi) =>
112
+ collectionApi.getAll().filter((item) => !item.inputPath.endsWith('11tydata.js'))
113
+ );
114
+ }
115
+
87
116
  eleventyConfig.addPlugin(modules.headCore);
88
- eleventyConfig.addPlugin(modules.sitemapCore, { enableSitemapTemplate: userOptions.enableSitemapTemplate, multilingual: isMultilingual, languages });
117
+ eleventyConfig.addPlugin(modules.sitemapCore, {
118
+ enableSitemapTemplate: userOptions.enableSitemapTemplate,
119
+ multilingual: isMultilingual,
120
+ languages
121
+ });
89
122
 
90
123
  // Filters — Module filters might move to their respective module.
91
- eleventyConfig.addFilter("markdownify", filters.markdownFilter);
92
- eleventyConfig.addFilter("relatedPosts", filters.relatedPostsFilter);
93
- eleventyConfig.addFilter("isString", filters.isStringFilter);
124
+ eleventyConfig.addFilter('markdownify', filters.markdownFilter);
125
+ eleventyConfig.addFilter('relatedPosts', filters.relatedPostsFilter);
126
+ eleventyConfig.addFilter('isString', filters.isStringFilter);
94
127
 
95
128
  // Shortcodes.
96
- eleventyConfig.addShortcode("image", shortcodes.imageShortcode);
129
+ eleventyConfig.addShortcode('image', shortcodes.imageShortcode);
97
130
 
98
131
  // Add the dev server middleware for images.
99
132
  eleventyConfig.addPlugin(eleventyImageOnRequestDuringServePlugin);
100
133
 
101
134
  // Debug filters and navigators.
102
- eleventyConfig.addFilter("_inspect", debug.inspect);
103
- eleventyConfig.addFilter("_json", debug.json);
104
- eleventyConfig.addFilter("_keys", debug.keys);
135
+ eleventyConfig.addFilter('_inspect', debug.inspect);
136
+ eleventyConfig.addFilter('_json', debug.json);
137
+ eleventyConfig.addFilter('_keys', debug.keys);
105
138
  eleventyConfig.addPlugin(modules.navigatorCore, { enableNavigatorTemplate: userOptions.enableNavigatorTemplate });
106
139
  };
107
140
 
108
141
  // Set plugin name so `eleventyConfig.hasPlugin()` can detect it.
109
- Object.defineProperty(plugin, "name", { value: `${name}` });
142
+ Object.defineProperty(plugin, 'name', { value: `${name}` });
110
143
  return plugin;
111
144
  }
112
145
 
113
146
  export const config = {
114
147
  dir: {
115
- input: "src",
116
- output: "dist",
117
- data: "_data",
118
- includes: "_includes",
119
- assets: "assets"
148
+ input: 'src',
149
+ output: 'dist',
150
+ data: '_data',
151
+ includes: '_includes',
152
+ assets: 'assets'
120
153
  },
121
- htmlTemplateEngine: "njk",
122
- markdownTemplateEngine: "njk",
123
- templateFormats: ["html", "njk", "md"]
154
+ htmlTemplateEngine: 'njk',
155
+ markdownTemplateEngine: 'njk',
156
+ templateFormats: ['html', 'njk', 'md']
124
157
  };