{"_id":"@eleventy-plugin-themer/core","_rev":"4-04d78823fc4170d4eacf782af36a1c72","name":"@eleventy-plugin-themer/core","dist-tags":{"latest":"0.5.1"},"versions":{"0.1.0":{"name":"@eleventy-plugin-themer/core","version":"0.1.0","keywords":["eleventy","eleventy-theme","11ty","cascade","theme-system","build-agnostic"],"author":{"name":"Artis Lismanis"},"license":"MIT","_id":"@eleventy-plugin-themer/core@0.1.0","maintainers":[{"name":"artislismanis","email":"artis@lismanis.uk"}],"homepage":"https://github.com/artislismanis/eleventy-plugin-themer/tree/main/packages/core#readme","bugs":{"url":"https://github.com/artislismanis/eleventy-plugin-themer/issues"},"dist":{"shasum":"3a94f4ccb9592cfb2dc1c2623e44c591cccb5271","tarball":"https://registry.npmjs.org/@eleventy-plugin-themer/core/-/core-0.1.0.tgz","fileCount":21,"integrity":"sha512-+fPqLjsKsPHdZACfqQ2blpeu4Buwrvq+aX00vxyWNQHsKBAp4oLtV5tWKu/8TltYSmAA+DeL0t4kjQjOmcWFOQ==","signatures":[{"sig":"MEUCIAOvS6RW6NKY6baXNsW06qKht0LCg7fKmcSwjM8Z/vzPAiEAhkUu45YBO1M1nNTGdf8klpYW/x0VoR3TgAQmRQZ0E+Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":71153},"main":"lib/index.mjs","type":"module","engines":{"node":">=22"},"exports":{".":"./lib/index.mjs","./types":"./lib/types.mjs","./logger":"./lib/logger.mjs","./internal/api":"./lib/internal/api.mjs","./internal/defaults":"./lib/defaults.mjs","./internal/safe-keys":"./lib/internal/safe-keys.mjs"},"gitHead":"ca19d933936453a503e5cd1aba78acea7dcb8696","scripts":{"lint":"eslint .","test":"vitest run","test:watch":"vitest"},"_npmUser":{"name":"artislismanis","email":"artis@lismanis.uk"},"repository":{"url":"git+https://github.com/artislismanis/eleventy-plugin-themer.git","type":"git","directory":"packages/core"},"_npmVersion":"10.9.8","description":"Build-agnostic core cascade system for Eleventy themes","directories":{},"_nodeVersion":"22.22.3","dependencies":{"zod":"^4.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"nunjucks":"^3.2.0","@11ty/eleventy":"^3.1.0"},"_npmOperationalInternal":{"tmp":"tmp/core_0.1.0_1781953227707_0.04085721295376854","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@eleventy-plugin-themer/core","version":"0.4.0","keywords":["eleventy","eleventy-theme","11ty","cascade","theme-system","build-agnostic"],"author":{"name":"Artis Lismanis"},"license":"MIT","_id":"@eleventy-plugin-themer/core@0.4.0","maintainers":[{"name":"artislismanis","email":"artis@lismanis.uk"}],"homepage":"https://github.com/artislismanis/eleventy-plugin-themer/tree/main/packages/core#readme","bugs":{"url":"https://github.com/artislismanis/eleventy-plugin-themer/issues"},"dist":{"shasum":"a37332dc79d8cfffe439b0f929f81b136cd679ac","tarball":"https://registry.npmjs.org/@eleventy-plugin-themer/core/-/core-0.4.0.tgz","fileCount":22,"integrity":"sha512-Zm6K9Zwuuuep4uAyQJg6O0YWAPW83aWXYwiggcqXUlo43BW0GtBkO0WR3reOdn0aGsr9KNQHtWRZawZLiln4Pw==","signatures":[{"sig":"MEQCIACeyg2WPtgksu/YE7OH6lRpg4VsimwiIb5WXS8pqxguAiB+fG+QvoBvZ6jIVoinZ5mp1U3BVTcfmcQOpXPuuL1u9g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":85189},"main":"lib/index.mjs","type":"module","engines":{"node":">=22"},"exports":{".":"./lib/index.mjs","./types":"./lib/types.mjs","./logger":"./lib/logger.mjs","./internal/api":"./lib/internal/api.mjs","./internal/defaults":"./lib/defaults.mjs","./internal/safe-keys":"./lib/internal/safe-keys.mjs"},"gitHead":"bcc252ea28916abc6fb22670b6de7463adf42673","scripts":{"lint":"eslint .","test":"vitest run","test:watch":"vitest"},"_npmUser":{"name":"artislismanis","email":"artis@lismanis.uk"},"repository":{"url":"git+https://github.com/artislismanis/eleventy-plugin-themer.git","type":"git","directory":"packages/core"},"_npmVersion":"10.9.8","description":"Build-agnostic core cascade system for Eleventy themes","directories":{},"_nodeVersion":"22.22.3","dependencies":{"zod":"^4.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"nunjucks":"^3.2.0","@11ty/eleventy":"^3.1.0"},"_npmOperationalInternal":{"tmp":"tmp/core_0.4.0_1782058955238_0.7289935587178815","host":"s3://npm-registry-packages-npm-production"}},"0.4.3":{"name":"@eleventy-plugin-themer/core","version":"0.4.3","keywords":["eleventy","eleventy-theme","11ty","cascade","theme-system","build-agnostic"],"author":{"name":"Artis Lismanis"},"license":"MIT","_id":"@eleventy-plugin-themer/core@0.4.3","maintainers":[{"name":"artislismanis","email":"artis@lismanis.uk"}],"homepage":"https://github.com/artislismanis/eleventy-plugin-themer/tree/main/packages/core#readme","bugs":{"url":"https://github.com/artislismanis/eleventy-plugin-themer/issues"},"dist":{"shasum":"9a79dd2b3e972ecfa7cf2c1487032a5cac061994","tarball":"https://registry.npmjs.org/@eleventy-plugin-themer/core/-/core-0.4.3.tgz","fileCount":22,"integrity":"sha512-h63IVrW9TzBWNHStns5LVlhjGrQZ6RRuPWzVa34v6W0j69yJkUxVrc275rpFyBsw2rs19DlObLDWPXelXqomeQ==","signatures":[{"sig":"MEUCIQCJ/GiWJ1ezXlmutqFq6Alplt/wdENKTfH8SUECIHSk5AIgO4ZWRFImQgvLqr0hDtZ2ZYYd21EjonkC7AJ7q/12Gmw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":85521},"main":"lib/index.mjs","type":"module","engines":{"node":">=22"},"exports":{".":"./lib/index.mjs","./types":"./lib/types.mjs","./logger":"./lib/logger.mjs","./internal/api":"./lib/internal/api.mjs","./internal/defaults":"./lib/defaults.mjs","./internal/safe-keys":"./lib/internal/safe-keys.mjs"},"gitHead":"a91eefdfd604b0979d6f9c9e9093b9260141dc57","scripts":{"lint":"eslint .","test":"vitest run","test:watch":"vitest"},"_npmUser":{"name":"artislismanis","email":"artis@lismanis.uk"},"repository":{"url":"git+https://github.com/artislismanis/eleventy-plugin-themer.git","type":"git","directory":"packages/core"},"_npmVersion":"10.9.8","description":"Build-agnostic core cascade system for Eleventy themes","directories":{},"_nodeVersion":"22.23.1","dependencies":{"zod":"^4.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"nunjucks":"^3.2.0","@11ty/eleventy":"^3.1.0"},"_npmOperationalInternal":{"tmp":"tmp/core_0.4.3_1783273809370_0.5016413266100024","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"_id":"@eleventy-plugin-themer/core@0.5.1","bugs":{"url":"https://github.com/artislismanis/eleventy-plugin-themer/issues"},"dist":{"shasum":"b77f257988cbba0e72dd3790d672c629f2bd59ea","tarball":"https://registry.npmjs.org/@eleventy-plugin-themer/core/-/core-0.5.1.tgz","fileCount":22,"integrity":"sha512-8HrpOB0214tqJO/z3SdjW9pQyctTAWyRzILfsm1TB40yIVbuqUwMYQg5Z2c6XEdamXAwTLxkkCMx1Ijf2ypMtw==","signatures":[{"sig":"MEUCIQDG6IxjNK1Htqr7/NMoOThw3ygesoIneCmRNkJvOpBM/QIgSrNJvqytTHhLWR9qdHqMzURfGmbHtM7BmyCoMr+TsQY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDfZuFvWKNRwqPOgr98ZL9YApMrpR+QYpixMHA+eZpAFgIhAPaizB8VUgpx46+cprapPS9brUuVz0LZPPEv2yh8mQap"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eleventy-plugin-themer%2fcore@0.5.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":85582},"main":"lib/index.mjs","name":"@eleventy-plugin-themer/core","type":"module","author":{"name":"Artis Lismanis"},"engines":{"node":">=22"},"exports":{".":"./lib/index.mjs","./types":"./lib/types.mjs","./logger":"./lib/logger.mjs","./internal/api":"./lib/internal/api.mjs","./internal/defaults":"./lib/defaults.mjs","./internal/safe-keys":"./lib/internal/safe-keys.mjs"},"gitHead":"ebacf6fe6076746447f82cf3ddefea56c9947acb","license":"MIT","scripts":{"lint":"eslint .","test":"vitest run","test:watch":"vitest"},"version":"0.5.1","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:24fc7786-04e1-4ef3-b7d9-73bf2ee082c6"}},"homepage":"https://github.com/artislismanis/eleventy-plugin-themer/tree/main/packages/core#readme","keywords":["eleventy","eleventy-theme","11ty","cascade","theme-system","build-agnostic"],"repository":{"url":"git+https://github.com/artislismanis/eleventy-plugin-themer.git","type":"git","directory":"packages/core"},"_npmVersion":"11.19.0","description":"Build-agnostic core cascade system for Eleventy themes","directories":{},"maintainers":[{"name":"artislismanis","email":"artis@lismanis.uk"}],"_nodeVersion":"24.20.0","dependencies":{"zod":"^4.6.5"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"peerDependencies":{"nunjucks":"^3.2.0","@11ty/eleventy":"^3.1.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/core_0.5.1_1789850877620_0.6572806857570932"}}},"time":{"created":"2026-06-20T11:00:27.562Z","modified":"2026-09-19T20:47:58.003Z","0.1.0":"2026-06-20T11:00:27.841Z","0.4.0":"2026-06-21T16:22:35.407Z","0.4.3":"2026-07-05T17:50:09.493Z","0.5.1":"2026-09-19T20:47:57.703Z"},"bugs":{"url":"https://github.com/artislismanis/eleventy-plugin-themer/issues"},"author":{"name":"Artis Lismanis"},"license":"MIT","homepage":"https://github.com/artislismanis/eleventy-plugin-themer/tree/main/packages/core#readme","keywords":["eleventy","eleventy-theme","11ty","cascade","theme-system","build-agnostic"],"repository":{"url":"git+https://github.com/artislismanis/eleventy-plugin-themer.git","type":"git","directory":"packages/core"},"description":"Build-agnostic core cascade system for Eleventy themes","maintainers":[{"name":"artislismanis","email":"artis@lismanis.uk"}],"readme":"# @eleventy-plugin-themer/core\n\nBuild-agnostic cascade system for Eleventy themes. Works with any build tool or no build tool at all.\n\n## Features\n\n- **Template Loading** - ThemeAwareLoader with `@theme/` alias for Nunjucks\n- **Data Cascade** - User data files override theme defaults via Eleventy's native data cascade\n- **Static Assets Cascade** - User assets override theme assets by filename\n- **Feature Resolution** - Discover and resolve features from user or theme directories\n- **Theme Configuration** - Deep-merged theme config accessible in templates as `{{ theme.* }}`\n- **Theme Validation** - Helpful errors with suggested fixes\n\n## Installation\n\n```bash\nnpm install @eleventy-plugin-themer/core\n```\n\nRequires Node.js 22+.\n\n## Usage\n\n### Using a Theme (Content Site)\n\n```js\n// eleventy.config.mjs\nimport { createThemerProject } from '@eleventy-plugin-themer/core';\nimport { eleventyPluginThemerVite } from '@eleventy-plugin-themer/build-vite';\n\nconst THEME_NAME = '@eleventy-plugin-themer/theme-base';\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n// Bind `{ theme, projectRoot }` once and reuse across the Eleventy plugin,\n// the Vite adapter, and `postcss.config.mjs`.\nconst themer = createThemerProject({ theme: THEME_NAME, projectRoot: __dirname });\n\nexport default async function (eleventyConfig) {\n  // Direct call: returns the computed `dir` so it can be spread into the config-function\n  // return value (Eleventy defers `addPlugin` until after the function returns).\n  const { dir } = await themer.eleventyPlugin(eleventyConfig, {\n    input: 'content',\n    output: '_site',\n  });\n\n  eleventyConfig.addPlugin(\n    eleventyPluginThemerVite,\n    themer.viteOptions({ optimizations: { purgeCSS: true } }),\n  );\n\n  return { dir };\n}\n```\n\nYou can also call `eleventyPluginThemer(eleventyConfig, { theme, projectRoot, ... })` directly without the project handle — the handle is purely an ergonomic wrapper that removes repetition.\n\n### Why `eleventyDataSchema.js` is a manual step\n\nThe plugin can't auto-register `eleventyDataSchema` because Eleventy resolves `_data` files **before** the async config function (and therefore the plugin) finishes. Add a one-line file in your content data directory:\n\n```js\n// content/_data/eleventyDataSchema.js\nexport { themerDataSchema as default } from '@eleventy-plugin-themer/core';\n```\n\n`themerDataSchema` reads the cached themer context lazily on first call, so it sees the right theme and feature set regardless of which invocation style you used.\n\n### Override Paths\n\nBy default, user overrides are expected at these locations:\n\n| Resource | Default Path         |\n| -------- | -------------------- |\n| layouts  | `overrides/layouts`  |\n| features | `overrides/features` |\n| styles   | `overrides/styles`   |\n| scripts  | `overrides/scripts`  |\n| data     | `content/_data`      |\n| public   | `public`             |\n\nOverride with custom paths:\n\n```js\nawait eleventyConfig.addPlugin(eleventyPluginThemer, {\n  theme: THEME_NAME,\n  projectRoot: __dirname,\n  overridePaths: {\n    layouts: 'my-layouts',\n    data: 'src/_data',\n  },\n});\n```\n\n## Public API\n\n### `createThemerProject({ theme, projectRoot })`\n\nBind the two values you'd otherwise pass to four different call sites (`eleventyPluginThemer`, `eleventyPluginThemerVite`, `resolveThemeMetadata`, `createPostcssConfig`). Returns a project handle:\n\n| Field / Method                          | Purpose                                                                                |\n| --------------------------------------- | -------------------------------------------------------------------------------------- |\n| `theme`, `projectRoot`, `themeMetadata` | Eagerly-resolved values for ad-hoc use                                                 |\n| `eleventyPlugin(eleventyConfig, extra)` | Pre-bound `eleventyPluginThemer` — pass `{ input, output, overridePaths }` if needed   |\n| `viteOptions(extra)`                    | Options object for `addPlugin(eleventyPluginThemerVite, ...)` — append `optimizations` |\n| `postcssOptions(extra)`                 | Options object for `createPostcssConfig({ ... })` — append `userPlugins`               |\n\n### `defineThemeConfig(config)`\n\nIdentity helper for `theme.config.mjs` that types the argument as `ThemeUserConfig` via JSDoc. No runtime cost; pure editor ergonomics.\n\n```js\nimport { defineThemeConfig } from '@eleventy-plugin-themer/core';\nexport default defineThemeConfig({ themeToggle: { defaultTheme: 'auto' } });\n```\n\n### `eleventyPluginThemer(eleventyConfig, options)`\n\nEleventy plugin that handles theme registration. Sets up:\n\n- Theme metadata resolution from `package.json` + `theme.json`\n- Filter, shortcode, and paired shortcode registration from the theme module\n- Nunjucks template engine with `@theme/` prefix support\n- Layout alias registration with cascade resolution\n- Theme metadata available as `themeMetadata` global data\n\n**Options:**\n\n- `theme` (string, required) - Theme package name\n- `projectRoot` (string, required) - Path to content repo root\n- `overridePaths` (Object) - Override paths configuration\n\n**Returns:** `{ themeMetadata, resolvedOverridePaths, discoveredFeatures, dir }`\n\nWhen `input` and `output` are passed, the returned `dir` is `{ input, output, includes }` ready to spread into the Eleventy config-function return value. The same `dir` is also stashed in the themer context — retrieve it later via `getThemerDir(eleventyConfig)`.\n\n### `resolveThemeMetadata(projectRoot, themeName)`\n\nLoad theme metadata by merging `package.json` and `theme.json` from the theme package.\n\n### `getAvailableFeatures(projectRoot, themeMetadata, resolvedOverridePaths?)`\n\nDiscover all available features (theme + user) with source tracking.\n\n**Returns:** `Map<string, { name, source, path }>` where source is `'theme'`, `'user'`, or `'override'`\n\n### Schema helpers (zod-based runtime validation)\n\n```js\nimport {\n  themeConfigSchema, // strict-key schema for theme.config.mjs\n  featuresFrontMatterSchema, // validates page front-matter `features` field\n  formatZodIssues, // pretty-print zod errors\n} from '@eleventy-plugin-themer/core';\n```\n\n`themeConfigSchema(themeMetadata)` rejects unknown top-level keys (typo-catching) but is permissive about inner shapes. `featuresFrontMatterSchema(projectRoot, themeMetadata, overridePaths?)` validates feature names against features actually available in the cascade — useful in `eleventyDataSchema.js`.\n\n### Subpath exports\n\n| Subpath                                           | Stability    | Purpose                                                               |\n| ------------------------------------------------- | ------------ | --------------------------------------------------------------------- |\n| `@eleventy-plugin-themer/core`                    | public       | Main API                                                              |\n| `@eleventy-plugin-themer/core/logger`             | public       | Shared logger (used by build adapters)                                |\n| `@eleventy-plugin-themer/core/internal/safe-keys` | **internal** | Cross-package `UNSAFE_KEYS` constant — may change without notice      |\n| `@eleventy-plugin-themer/core/internal/defaults`  | **internal** | Framework defaults (`DEFAULT_ASSET_ENTRIES`, etc.) for build adapters |\n\n`internal/*` subpaths are not part of the public SemVer surface. See the root README for the full SemVer policy.\n\n## Creating a Theme\n\nA theme package needs:\n\n1. **`package.json`** - Standard npm package with `name` and `version`\n2. **`theme.json`** - Theme metadata (features, assets, config defaults)\n3. **`lib/index.mjs`** - Default export with `filters`, `shortcodes`, `pairedShortcodes`\n4. **`layouts/`** - Nunjucks layout templates\n5. **`styles/`** - SCSS/CSS stylesheets\n6. **`scripts/`** - JavaScript entry points\n7. **`features/`** - Optional feature subdirectories with `index.js` / `index.auto.js`\n\n### theme.json\n\n```json\n{\n  \"$schema\": \"../../core/theme.schema.json\",\n  \"themeFeatures\": [\n    { \"name\": \"code-highlighting\", \"entry\": \"features/code-highlighting/index.js\" }\n  ],\n  \"assets\": {\n    \"styles\": { \"entry\": \"styles/main.scss\" },\n    \"scripts\": { \"entry\": \"scripts/main.js\" }\n  },\n  \"config\": {\n    \"colors\": { \"light\": { \"primary\": \"#172c51\" } },\n    \"typography\": { \"fontFamily\": \"system-ui, sans-serif\" }\n  }\n}\n```\n\nThe `config` section provides defaults accessible in templates as `{{ theme.colors.light.primary }}`. Users override via `theme.config.mjs`.\n\n## Cascade Resolution\n\nAll resources follow the same priority: **user files win over theme files**.\n\n- Layouts: user's `overrides/layouts/post.njk` overrides theme's `layouts/post.njk`\n- Data: user's `content/_data/site.mjs` overrides theme's `data/site.js`\n- Features: user's `overrides/features/code-highlighting/` overrides theme's `features/code-highlighting/`\n- Assets: user's `public/favicon.svg` overrides theme's `public/favicon.svg`\n\nSee [@eleventy-plugin-themer/theme-base](../themes/base/README.md) for a complete theme example.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}