mirror of https://github.com/theNewDynamic/gohugo-theme-ananke.git

Patrick Kollitsch
yesterday 1832a681026ac3db6e62aa90cb5ed75886ea69ac
build(deps): onboard dnbhq configurations and linting fixes
21 files modified
3 files deleted
5 files added
1364 ■■■■■ changed files
.github/dependabot.yml 64 ●●●●● patch | view | raw | blame | history
.github/rulesets/protect-development.json patch | view | raw | blame | history
.github/rulesets/protect-main.json patch | view | raw | blame | history
.github/scripts/posterboy.mjs 59 ●●●●● patch | view | raw | blame | history
.lintstagedrc.js 28 ●●●●● patch | view | raw | blame | history
.markdownlint.jsonc 133 ●●●●● patch | view | raw | blame | history
.release-it.ts 128 ●●●●● patch | view | raw | blame | history
.vscode/instructions/shortcodes.instructions.md 17 ●●●●● patch | view | raw | blame | history
.vscode/prompts/test-hugo-versions.prompt.md 300 ●●●●● patch | view | raw | blame | history
.vscode/settings.json 6 ●●●●● patch | view | raw | blame | history
ananke.code-workspace patch | view | raw | blame | history
assets/ananke/css/_code.css 7 ●●●●● patch | view | raw | blame | history
assets/ananke/css/_hugo-internal-templates.css 8 ●●●●● patch | view | raw | blame | history
assets/ananke/css/_social-icons.css 2 ●●●●● patch | view | raw | blame | history
assets/ananke/css/_styles.css 3 ●●●●● patch | view | raw | blame | history
biome.json 11 ●●●●● patch | view | raw | blame | history
lint-staged.config.ts 22 ●●●●● patch | view | raw | blame | history
package-lock.json 490 ●●●●● patch | view | raw | blame | history
package.json 37 ●●●●● patch | view | raw | blame | history
playwright.config.ts patch | view | raw | blame | history
renovate.json5 7 ●●●●● patch | view | raw | blame | history
scripts/synch-social-icons.ts patch | view | raw | blame | history
scripts/test-hugo-quickstart.ts 16 ●●●●● patch | view | raw | blame | history
tests/coverage-gate.mjs patch | view | raw | blame | history
tests/e2e/accessibility.spec.ts patch | view | raw | blame | history
tests/e2e/copy-button.spec.ts patch | view | raw | blame | history
tests/support/dev-server.mjs patch | view | raw | blame | history
tests/support/prepare-site.mjs patch | view | raw | blame | history
tsconfig.json 26 ●●●●● patch | view | raw | blame | history
.github/dependabot.yml
File was deleted
.github/rulesets/protect-development.json
.github/rulesets/protect-main.json
.github/scripts/posterboy.mjs
@@ -1,14 +1,14 @@
import { readFile, writeFile, access, mkdir } from 'node:fs/promises';
import path from 'node:path';
import fs from 'node:fs';
import dotenv from 'dotenv';
import { homedir } from 'node:os';
import fs from "node:fs";
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
import { homedir } from "node:os";
import path from "node:path";
import dotenv from "dotenv";
const userHomeDir = homedir();
// Load .env files
const GLOBAL_ENV_PATH = path.join(userHomeDir, '.env');
const LOCAL_ENV_PATH = path.resolve('.env');
const GLOBAL_ENV_PATH = path.join(userHomeDir, ".env");
const LOCAL_ENV_PATH = path.resolve(".env");
/**
 * Load environment variables from a file if it exists.
@@ -28,13 +28,14 @@
process.env = { ...globalEnv, ...process.env, ...localEnv };
// Configurable values
const DISCORD_WEBHOOK = process.env.DISCORD_WEBHOOK || '';
const GITHUB_DEV_TOKEN = process.env.GITHUB_DEV_TOKEN || '';
const GITHUB_REPO = process.env.GITHUB_REPO || 'gohugo-ananke/ananke';
const DEFAULT_MESSAGE_TEMPLATE = 'New release: {{tag_name}} - {{html_url}}';
const MESSAGE_TEMPLATE = process.env.MESSAGE_TEMPLATE || DEFAULT_MESSAGE_TEMPLATE;
const CACHE_DIR = './cache';
const CACHE_FILE = 'github-releases.json';
const DISCORD_WEBHOOK = process.env.DISCORD_WEBHOOK || "";
const GITHUB_DEV_TOKEN = process.env.GITHUB_DEV_TOKEN || "";
const GITHUB_REPO = process.env.GITHUB_REPO || "gohugo-ananke/ananke";
const DEFAULT_MESSAGE_TEMPLATE = "New release: {{tag_name}} - {{html_url}}";
const MESSAGE_TEMPLATE =
  process.env.MESSAGE_TEMPLATE || DEFAULT_MESSAGE_TEMPLATE;
const CACHE_DIR = "./cache";
const CACHE_FILE = "github-releases.json";
const CACHE_FILE_PATH = path.join(CACHE_DIR, CACHE_FILE);
/**
@@ -60,7 +61,7 @@
 */
async function readCache() {
  try {
    const data = await readFile(CACHE_FILE_PATH, 'utf8');
    const data = await readFile(CACHE_FILE_PATH, "utf8");
    return JSON.parse(data) || [];
  } catch {
    return [];
@@ -81,11 +82,14 @@
 */
async function fetchLatestRelease() {
  try {
    const response = await fetch('https://api.github.com/repos/' + GITHUB_REPO + '/releases', {
    const response = await fetch(
      "https://api.github.com/repos/" + GITHUB_REPO + "/releases",
      {
      headers: {
        Authorization: `token ${GITHUB_DEV_TOKEN}`,
      },
    });
      },
    );
    if (!response.ok) {
      throw new Error(`GitHub API request failed: ${response.statusText}`);
@@ -93,13 +97,13 @@
    const releases = await response.json();
    if (!Array.isArray(releases) || releases.length === 0) {
      console.log('No releases found.');
      console.log("No releases found.");
      return null;
    }
    return releases[0];
  } catch (err) {
    console.error('Failed to fetch releases:', err.message);
    console.error("Failed to fetch releases:", err.message);
    return null;
  }
}
@@ -111,8 +115,8 @@
async function postToDiscord(message) {
  try {
    const response = await fetch(DISCORD_WEBHOOK, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ content: message }),
    });
@@ -120,9 +124,9 @@
      throw new Error(`Failed to post to Discord: ${response.statusText}`);
    }
    console.log('Posted to Discord successfully.');
    console.log("Posted to Discord successfully.");
  } catch (err) {
    console.error('Failed to post to Discord:', err.message);
    console.error("Failed to post to Discord:", err.message);
  }
}
@@ -132,7 +136,10 @@
 * @returns {string}
 */
function formatMessage(releaseData) {
  return MESSAGE_TEMPLATE.replace(/{{\s*(\w+)\s*}}/g, (_, key) => releaseData[key] || '');
  return MESSAGE_TEMPLATE.replace(
    /{{\s*(\w+)\s*}}/g,
    (_, key) => releaseData[key] || "",
  );
}
/**
@@ -152,10 +159,10 @@
      cachedIds.push(latestRelease.tag_name);
      await writeCache(cachedIds);
    } else {
      console.log('No new releases to post.');
      console.log("No new releases to post.");
    }
  } catch (err) {
    console.error('Error:', err.message);
    console.error("Error:", err.message);
  }
}
.lintstagedrc.js
File was deleted
.markdownlint.jsonc
File was deleted
.release-it.ts
@@ -1,11 +1,7 @@
import { execSync } from "node:child_process";
import { createReleaseConfig } from "@dnbhq/release-config";
import type { Config } from "release-it";
interface ConventionalCommitLike {
    type?: string;
    notes?: unknown[];
}
function getCurrentBranch(): string {
    try {
        return execSync("git rev-parse --abbrev-ref HEAD", {
@@ -47,77 +43,11 @@
    process.exit(1);
}
const config = {
    npm: {
        publish: false,
    },
    git: {
        requireCleanWorkingDir: true,
        requireBranch: currentBranch,
        commit: true,
        commitMessage: "chore(release): v${version}",
        commitArgs: ["--no-verify"],
        tag: true,
        tagName: "v${version}",
        push: true,
        pushArgs: ["--follow-tags"],
    },
    github: {
        release: true,
        releaseName: "Release v${version}",
        skipChecks: true,
        tokenRef: "GITHUB_ANANKE_TOKEN_ADMIN_PRIVATE",
        comments: {
            submit: true,
        },
        discussionCategoryName: "1-release-notes",
    },
    plugins: {
        "@release-it/conventional-changelog": {
            infile: "CHANGELOG.md",
            preset: {
                name: "conventionalcommits",
                commitUrlFormat:
                    "https://github.com/gohugo-ananke/ananke/commit/{{hash}}",
                compareUrlFormat:
                    "https://github.com/gohugo-ananke/ananke/compare/{{previousTag}}...{{currentTag}}",
                types: [
                    { type: "feat", section: "Features" },
                    { type: "fix", section: "Bug Fixes" },
                    { type: "build", section: "Build" },
                    { type: "chore", section: "Chores" },
                    { type: "ci", section: "CI" },
                    { type: "docs", section: "Documentation" },
                    { type: "perf", section: "Performance" },
                    { type: "refactor", section: "Refactoring" },
                    { type: "revert", section: "Reverts" },
                    { type: "style", section: "Styles" },
                    { type: "test", section: "Tests" },
                    { type: "ai", section: "AI Instruction Files" },
                ],
            },
            whatBump(commits: ConventionalCommitLike[]) {
                let level: 2 | 1 | 0 | null = null;
                for (const commit of commits) {
                    const notes = Array.isArray(commit.notes) ? commit.notes : [];
                    const type = typeof commit.type === "string" ? commit.type : "";
                    if (notes.length > 0) {
                        return {
                            level: 0,
                            reason: "There are BREAKING CHANGES.",
                        };
                    }
                    if (type === "feat") {
                        level = 1;
                        continue;
                    }
                    if (
                        level === null &&
                        [
const config: Config = createReleaseConfig({
  githubTokenRef: "GITHUB_ANANKE_TOKEN_ADMIN_PRIVATE",
  scopes: {
    minorTypes: ["feat"],
    patchTypes: [
                            "fix",
                            "build",
                            "chore",
@@ -129,26 +59,34 @@
                            "style",
                            "test",
                            "ai",
                        ].includes(type)
                    ) {
                        level = 2;
                    }
                }
                if (level === null) {
                    return false;
                }
                return {
                    level,
                    reason:
                        level === 1
                            ? "There are feature commits."
                            : "There are patch-level changes.",
                };
    ],
  },
  overrides: {
    git: {
      requireCleanWorkingDir: true,
      requireBranch: currentBranch,
      commit: true,
      // biome-ignore lint/suspicious/noTemplateCurlyInString: release-it expands this placeholder.
      commitMessage: "chore(release): v${version}",
      commitArgs: ["--no-verify"],
      tag: true,
      // biome-ignore lint/suspicious/noTemplateCurlyInString: release-it expands this placeholder.
      tagName: "v${version}",
      push: true,
      pushArgs: ["--follow-tags"],
    },
    github: {
      release: true,
      // biome-ignore lint/suspicious/noTemplateCurlyInString: release-it expands this placeholder.
      releaseName: "Release v${version}",
      skipChecks: true,
      tokenRef: "GITHUB_ANANKE_TOKEN_ADMIN_PRIVATE",
      comments: {
        submit: true,
      },
      discussionCategoryName: "1-release-notes",
            },
        },
    },
} satisfies Config;
});
export default config;
.vscode/instructions/shortcodes.instructions.md
New file
@@ -0,0 +1,17 @@
---
title: "Shortcodes"
applyTo: "layouts/_shortcodes/**/*.html"
description: This file describes the code style for shortcodes in the project.
---
* DO use [InnerDeindent](https://gohugo.io/functions/innerdeindent/) to format the content of shortcodes. This will remove any common leading whitespace from the content, making it easier to read and maintain. Markdown linting will warn/error on indented code blocks and force the user to use backticks instead.
* DO accept both named and positional parameters in the shortcode.
* DO use [IsNamedParams](https://gohugo.io/methods/shortcode/isnamedparams/) to check if the shortcode is being called with named parameters. This will allow you to handle both named and positional parameters in your shortcode.
* DO use [Page](https://gohugo.io/methods/shortcode/page/) and [Site](https://gohugo.io/methods/shortcode/site/) from the shortcode context to access page and site variables.
* DO NOT add any strings that are part of the output to the shortcode. These strings must be defined ino the i18n/en.toml file and accessed using the [`language.Translate`](https://gohugo.io/functions/lang/translate/) function.
* DO add documentation of all new or changed features in shortcodes in the documentation repository.
.vscode/prompts/test-hugo-versions.prompt.md
New file
@@ -0,0 +1,300 @@
---
description: Test an Ananke website against multiple local Hugo versions
---
# Test ananke websites with local hugo versions
Use these instructions when testing an Ananke-based website against multiple local Hugo binaries.
The goal is to verify that the website builds correctly across a requested Hugo version range, collect full logs per Hugo version, and compare output differences, warnings, and errors.
## Hugo executable location
Assume Hugo binaries are stored in:
`~/github.com/davidsneighbour/hugov/executables/`
The binary names follow this pattern:
```text
hugo-v0.162.1
hugo-v0.162.1-extended
```
Only use the **non-extended** Hugo binaries for these tests.
Do not use binaries ending in:
```text
-extended
```
## Version range interpretation
When the user says something like:
```text
test between 160 and 162
```
interpret it as:
```text
v0.160.0 <= version < v0.163.0
```
In other words:
* `160` means all available `v0.160.x` versions.
* `161` means all available `v0.161.x` versions.
* `162` means all available `v0.162.x` versions.
* Include every patch version found locally in that range.
* Do not invent missing versions.
* Do not download Hugo versions.
* Only test versions that exist as local non-extended binaries.
Examples:
```text
test between 160 and 162
```
should include binaries such as:
```text
hugo-v0.160.0
hugo-v0.160.1
hugo-v0.161.0
hugo-v0.162.0
hugo-v0.162.1
```
but only if they exist locally.
It must exclude:
```text
hugo-v0.160.0-extended
hugo-v0.162.1-extended
```
## Required test workflow
Run the test from the root of the Ananke website repository unless the user explicitly gives another path.
For each matching Hugo binary:
1. Resolve the absolute path of the Hugo binary.
2. Extract the semantic version from the filename.
3. Run the Hugo build command using that binary.
4. Capture stdout and stderr.
5. Store the full output in a log file.
6. Record the exit status.
7. Record warnings.
8. Record errors.
9. Compare the generated output and command output across all tested versions.
10. Summarise differences.
## Log directory
Store logs in:
```text
~/.logs/ananke-hugo-tests/
```
Create the directory if it does not exist.
Each test run should create a timestamped run directory:
```text
~/.logs/ananke-hugo-tests/YYYYMMDD-HHMMSS/
```
Inside that directory, write one log file per Hugo version.
Use filenames sorted naturally by version:
```text
hugo-v0.160.0.log
hugo-v0.160.1.log
hugo-v0.161.0.log
hugo-v0.162.1.log
```
Also create a summary file:
```text
summary.md
```
The summary file must include:
* tested repository path
* test timestamp
* requested version range
* resolved Hugo binaries
* command used per version
* exit status per version
* warning count per version
* error count per version
* output differences
* build output differences
* final judgement
## Hugo command
Use this default command unless the user requests another one:
```bash
hugo --gc --minify
```
Before each Hugo run, remove the generated output directory if it exists.
Default output directory:
```text
public/
```
This prevents stale output from one version affecting another version.
## Build output isolation
Each Hugo version must build into its own output directory so that generated files can be compared.
Use this pattern:
```text
.tmp/hugo-version-tests/v0.162.1/public/
```
Run Hugo with:
```bash
hugo --gc --minify --destination ".tmp/hugo-version-tests/v0.162.1/public"
```
Before each run, remove that version's output directory.
Do not remove unrelated folders.
## Comparison requirements
After all builds finish, compare:
1. Exit status
2. stdout and stderr
3. warnings
4. errors
5. generated file lists
6. generated file contents
The comparison must identify:
* versions that failed
* versions that passed
* warnings that appear only in specific versions
* errors that appear only in specific versions
* files generated by one version but missing in another
* files with changed contents
* relevant differences in generated HTML, CSS, JS, XML, JSON, and text files
Ignore irrelevant noise where appropriate, such as:
* timestamps generated by the build
* absolute temporary paths
* known cache paths
* ordering differences that do not change generated output
Do not hide real build differences.
## Warning and error detection
Scan logs case-insensitively for lines containing:
```text
warning
warn
error
failed
deprecated
panic
timeout
```
List matching lines grouped by Hugo version.
When warnings or errors repeat across all versions, list them once and mark them as shared.
When warnings or errors only happen in some versions, highlight the affected versions.
## Required final response format
When reporting results, use this structure:
```markdown
## Hugo version test summary
Repository: `...`
Requested range: `...`
Resolved Hugo versions:
* `v0.160.0` - passed
* `v0.160.1` - passed
* `v0.161.0` - failed
* `v0.162.1` - passed
## Issues
### Errors
* `v0.161.0`: ...
### Warnings
* Shared across all versions: ...
* `v0.162.1` only: ...
## Output differences
### File list differences
* `v0.160.0` generated `...`, but `v0.162.1` did not.
### File content differences
* `public/index.html` differs between `v0.160.0` and `v0.162.1`.
  * Difference: ...
## Logs
Logs were written to:
`~/.logs/ananke-hugo-tests/YYYYMMDD-HHMMSS/`
Summary file:
`~/.logs/ananke-hugo-tests/YYYYMMDD-HHMMSS/summary.md`
## Final judgement
...
```
## Behaviour rules
* Do not use Hugo extended binaries.
* Do not download missing Hugo versions.
* Do not assume a patch version exists.
* Do not stop after the first failing version.
* Continue testing all resolved versions.
* Always keep the full log output.
* Always compare results after all runs.
* Always list the tested Hugo binary paths.
* Always show when no matching Hugo versions were found.
* Always distinguish between command output differences and generated site output differences.
* Always use explicit version numbers in the final summary.
.vscode/settings.json
@@ -11,9 +11,7 @@
            "addWords": true
        }
    ],
    "cSpell.dictionaries": [
        "workspace"
    ],
  "cSpell.dictionaries": ["workspace"],
    "cSpell.enabledFileTypes": {
        "markdown": true,
        "plaintext": true,
@@ -25,7 +23,7 @@
    },
    "explorer.fileNesting.enabled": true,
    "explorer.fileNesting.patterns": {
        "package.json": "package-lock.json, netlify.toml, .lintstagedrc.js, .release-it.ts, .markdownlint*, .nvmrc, lychee.toml, tsconfig.json, .coderabbit.yaml",
    "package.json": "package-lock.json, netlify.toml, lint-staged.config.ts, .release-it.ts, biome.json, renovate.json5, .nvmrc, lychee.toml, tsconfig.json, .coderabbit.yaml",
        "theme.toml": "go.mod, go.sum",
        "README.md": "CHANGELOG.md, LICENSE.md, CONTRIBUTING.md, RELEASES.md, DESIGN.md",
        "*.ts": "$(capture).md, $(capture).test.ts, $(capture).spec.ts, $(capture).d.ts, $(capture).map, $(capture).js, $(capture).jsx, $(capture).tsx"
ananke.code-workspace
assets/ananke/css/_code.css
@@ -1,4 +1,5 @@
pre, .pre  {
pre,
.pre {
  overflow-x: auto;
  overflow-y: hidden;
}
@@ -47,7 +48,9 @@
  border-radius: 4px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease-in-out, background-color 0.15s ease-in-out;
  transition:
    opacity 0.15s ease-in-out,
    background-color 0.15s ease-in-out;
}
/* Reveal on hover and when focused for keyboard users. */
assets/ananke/css/_hugo-internal-templates.css
@@ -5,18 +5,18 @@
.pagination li {
  display: inline-block;
  margin-right: .375rem;
  font-size: .875rem;
  margin-right: 0.375rem;
  font-size: 0.875rem;
  margin-bottom: 2.5em;
}
[dir="rtl"] .pagination li {
  margin-left: .375rem;
  margin-left: 0.375rem;
  margin-right: 0;
}
.pagination li a {
  padding: .5rem .625rem;
  padding: 0.5rem 0.625rem;
  background-color: white;
  color: #333;
  border: 1px solid #ddd;
assets/ananke/css/_social-icons.css
@@ -1,7 +1,7 @@
.ananke-socials a{
  display: inline-block;
  vertical-align: middle;
  color: #BABABA;
  color: #bababa;
  fill: currentColor;
}
.ananke-socials a .icon svg{
assets/ananke/css/_styles.css
@@ -6,13 +6,12 @@
.lh-copy blockquote {
  display: block;
  font-size: .875em;
  font-size: 0.875em;
  margin-left: 2rem;
  margin-top: 2rem;
  margin-bottom: 2rem;
  border-left: 4px solid #ccc;
  padding-left: 1rem;
}
.nested-links a{
biome.json
New file
@@ -0,0 +1,11 @@
{
  "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
  "extends": ["./node_modules/@dnbhq/biome-config/config.json"],
  "files": {
    "includes": [
      "!!**/*.html",
      "!!assets/ananke/css/_tachyons.css",
      "!!assets/ananke/dist"
    ]
  }
}
lint-staged.config.ts
New file
@@ -0,0 +1,22 @@
import { createLintStagedConfig } from "@dnbhq/lintstaged-config";
import type { Configuration } from "lint-staged";
const config: Configuration = createLintStagedConfig({
  secrets: { enabled: false },
  markdown: {
    configPath:
      "./node_modules/@dnbhq/markdownlint-config/.markdownlint-cli2.jsonc",
  },
  yaml: {
    enabled: true,
    configPath: ".yamllint.yml",
  },
  overrides: {
    ".github/workflows/**/*.y(a?)ml": ["zizmor --no-exit-codes"],
    "package-lock.json": [
      "lockfile-lint --path package-lock.json --validate-https --allowed-hosts npm",
    ],
  },
});
export default config;
package-lock.json
@@ -11,20 +11,17 @@
            "devDependencies": {
                "@axe-core/playwright": "4.13.0",
                "@biomejs/biome": "2.5.14",
                "@github/markdownlint-github": "0.8.4",
        "@dnbhq/biome-config": "0.3.1",
        "@dnbhq/lintstaged-config": "0.2.1",
        "@dnbhq/markdownlint-config": "0.2.11",
        "@dnbhq/release-config": "1.1.3",
        "@dnbhq/tsconfig": "0.1.6",
                "@playwright/test": "1.63.0",
                "@release-it/conventional-changelog": "12.0.2",
                "@types/node": "26.6.3",
                "dotenv": "18.0.4",
                "lint-staged": "17.6.0",
                "lockfile-lint": "5.0.1",
                "markdownlint": "0.41.1",
                "markdownlint-cli2": "0.23.3",
                "markdownlint-rule-extended-ascii": "0.2.1",
                "markdownlint-rule-list-duplicates": "0.0.1",
                "markdownlint-rule-relative-links": "5.1.3",
                "markdownlint-rule-search-replace": "1.2.0",
                "markdownlint-rule-title-case-style": "0.4.3",
                "release-it": "21.1.0",
                "simple-git-hooks": "2.14.0",
                "typescript": "7.0.2",
@@ -281,20 +278,296 @@
                "node": ">=22"
            }
        },
        "node_modules/@github/markdownlint-github": {
            "version": "0.8.4",
            "resolved": "https://registry.npmjs.org/@github/markdownlint-github/-/markdownlint-github-0.8.4.tgz",
            "integrity": "sha512-dPBvvCPonvJkP+1AKZ7qu8kODmFkuo8zEhSWxbcjj4PZjMoDDbz7Z0d+GXG2So598B0zfv29Av26kB0SrrqSiw==",
    "node_modules/@dnbhq/biome-config": {
      "version": "0.3.1",
      "resolved": "https://registry.npmjs.org/@dnbhq/biome-config/-/biome-config-0.3.1.tgz",
      "integrity": "sha512-G8ZlvwEOUewSkTVIGOXUV/xtecpSHOK352ik5hps9YI9hA2vI1vMN3xxsLMWnmhcnlF98z2dc4LuQPSc96cLBQ==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=26"
      },
      "peerDependencies": {
        "@biomejs/biome": ">=2.5.0"
      }
    },
    "node_modules/@dnbhq/lintstaged-config": {
      "version": "0.2.1",
      "resolved": "https://registry.npmjs.org/@dnbhq/lintstaged-config/-/lintstaged-config-0.2.1.tgz",
      "integrity": "sha512-gvgSQsilzd41iqTfSxfDKY+SJEpPpmww+3rM0GNJNOOqM/rX5EISobivUc36TSujjx1GX9sAn5LYdbX5oeHiaA==",
      "dev": true,
      "license": "MIT",
      "bin": {
        "lintstaged-config": "dist/cli.js"
      },
      "engines": {
        "node": ">=22"
      },
      "peerDependencies": {
        "lint-staged": ">=15.0.0"
      }
    },
    "node_modules/@dnbhq/markdownlint-config": {
      "version": "0.2.11",
      "resolved": "https://registry.npmjs.org/@dnbhq/markdownlint-config/-/markdownlint-config-0.2.11.tgz",
      "integrity": "sha512-toc1enTCmp8+99kvs2danCsL8iO5mS02cIaGTA66HkdCIpJ/WESQkzamgubA1rz/J4V3hVbZsoRe9M8djfAzxg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@github/markdownlint-github": "0.8.3",
        "markdownlint": "0.41.1",
        "markdownlint-cli2": "0.23.1",
        "markdownlint-rule-extended-ascii": "0.2.1",
        "markdownlint-rule-relative-links": "5.1.1",
        "markdownlint-rule-search-replace": "1.2.0",
        "markdownlint-rule-title-case-style": "0.4.3"
      },
      "engines": {
        "node": ">=26"
      }
    },
    "node_modules/@dnbhq/markdownlint-config/node_modules/@github/markdownlint-github": {
      "version": "0.8.3",
      "resolved": "https://registry.npmjs.org/@github/markdownlint-github/-/markdownlint-github-0.8.3.tgz",
      "integrity": "sha512-8DqM9t0frFpQCFYMqH2iyic/zB7budSONWfxMjUG8k4JTIJu+L5PaOpp+/xzNHQtb26WYIcc0aTpPWzXRO9J2Q==",
            "dev": true,
            "license": "ISC",
            "dependencies": {
                "lodash-es": "^4.17.21",
                "markdown-it": "15.0.2"
        "markdown-it": "14.2.0"
            },
            "engines": {
                "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
            }
        },
    "node_modules/@dnbhq/markdownlint-config/node_modules/entities": {
      "version": "4.5.0",
      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
      "dev": true,
      "license": "BSD-2-Clause",
      "engines": {
        "node": ">=0.12"
      },
      "funding": {
        "url": "https://github.com/fb55/entities?sponsor=1"
      }
    },
    "node_modules/@dnbhq/markdownlint-config/node_modules/globby": {
      "version": "16.2.1",
      "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.1.tgz",
      "integrity": "sha512-JmsqJalahxxgW8V2ecSQ2G7UjPlI9cpKdrkG9KoNiXhd/YslXOTEB0cViENWUznuovIuNT+FkMbraDGjr4FCUg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@sindresorhus/merge-streams": "^4.0.0",
        "fast-glob": "^3.3.3",
        "ignore": "^7.0.5",
        "is-path-inside": "^4.0.0",
        "slash": "^5.1.0",
        "unicorn-magic": "^0.4.0"
      },
      "engines": {
        "node": ">=20"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/@dnbhq/markdownlint-config/node_modules/js-yaml": {
      "version": "5.2.1",
      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.2.1.tgz",
      "integrity": "sha512-zfLtNfQqxVqq3uaTqSkh4x4hZw3KHobGUA0fJUj4wawW8bsQLTVqpHdXSIzidh7o+4lEW36tANuAGdaFx6Zgnw==",
      "dev": true,
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/puzrin"
        },
        {
          "type": "github",
          "url": "https://github.com/sponsors/nodeca"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "argparse": "^2.0.1"
      },
      "bin": {
        "js-yaml": "bin/js-yaml.mjs"
      }
    },
    "node_modules/@dnbhq/markdownlint-config/node_modules/linkify-it": {
      "version": "5.0.2",
      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz",
      "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==",
      "dev": true,
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/puzrin"
        },
        {
          "type": "github",
          "url": "https://github.com/sponsors/markdown-it"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "uc.micro": "^2.0.0"
      }
    },
    "node_modules/@dnbhq/markdownlint-config/node_modules/markdown-it": {
      "version": "14.2.0",
      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz",
      "integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==",
      "dev": true,
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/puzrin"
        },
        {
          "type": "github",
          "url": "https://github.com/sponsors/markdown-it"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "argparse": "^2.0.1",
        "entities": "^4.4.0",
        "linkify-it": "^5.0.1",
        "mdurl": "^2.0.0",
        "punycode.js": "^2.3.1",
        "uc.micro": "^2.1.0"
      },
      "bin": {
        "markdown-it": "bin/markdown-it.mjs"
      }
    },
    "node_modules/@dnbhq/markdownlint-config/node_modules/markdownlint-cli2": {
      "version": "0.23.1",
      "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.23.1.tgz",
      "integrity": "sha512-20JPI5W+HpV1OA+pUM712wgvL4GzYNUvbmhLU8KlEYJ1kCDx4soZ4/Xqd+WkLrPTOKMAn8SfO3zYFrK8GLlwQg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "globby": "16.2.1",
        "js-yaml": "5.2.1",
        "jsonc-parser": "3.3.1",
        "jsonpointer": "5.0.1",
        "markdown-it": "14.3.0",
        "markdownlint": "0.41.1",
        "markdownlint-cli2-formatter-default": "0.0.6",
        "micromatch": "4.0.8",
        "smol-toml": "1.7.0"
      },
      "bin": {
        "markdownlint-cli2": "markdownlint-cli2-bin.mjs"
      },
      "engines": {
        "node": ">=22"
      },
      "funding": {
        "url": "https://github.com/sponsors/DavidAnson"
      }
    },
    "node_modules/@dnbhq/markdownlint-config/node_modules/markdownlint-cli2/node_modules/markdown-it": {
      "version": "14.3.0",
      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.0.tgz",
      "integrity": "sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==",
      "dev": true,
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/puzrin"
        },
        {
          "type": "github",
          "url": "https://github.com/sponsors/markdown-it"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "argparse": "^2.0.1",
        "entities": "^4.5.0",
        "linkify-it": "^5.0.2",
        "mdurl": "^2.0.0",
        "punycode.js": "^2.3.1",
        "uc.micro": "^2.1.0"
      },
      "bin": {
        "markdown-it": "bin/markdown-it.mjs"
      }
    },
    "node_modules/@dnbhq/markdownlint-config/node_modules/markdownlint-rule-relative-links": {
      "version": "5.1.1",
      "resolved": "https://registry.npmjs.org/markdownlint-rule-relative-links/-/markdownlint-rule-relative-links-5.1.1.tgz",
      "integrity": "sha512-XgpNzADiFLxbDE6vbGRoauRgbE34YXAesFzTuWSxMxsdJwmcKCNnlkzjZITcb3/sP0SHx3t57Vq9/Q/WK9sU4w==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "markdown-it": "14.2.0",
        "mime": "4.1.0"
      },
      "engines": {
        "node": ">=22.0.0"
      }
    },
    "node_modules/@dnbhq/markdownlint-config/node_modules/smol-toml": {
      "version": "1.7.0",
      "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.0.tgz",
      "integrity": "sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==",
      "dev": true,
      "license": "BSD-3-Clause",
      "engines": {
        "node": ">= 18"
      },
      "funding": {
        "url": "https://github.com/sponsors/cyyynthia"
      }
    },
    "node_modules/@dnbhq/markdownlint-config/node_modules/uc.micro": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
      "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/@dnbhq/release-config": {
      "version": "1.1.3",
      "resolved": "https://registry.npmjs.org/@dnbhq/release-config/-/release-config-1.1.3.tgz",
      "integrity": "sha512-AOj3a7haQAULAreCf9gF5E061UVQyErLCzlVWr9SzlxZr2NnOH2K50H9cD5yf1tj03kn9mIP8DXeyy4feN/wxA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": "^22.22.2 || ^24.15.0 || ^26.0.0",
        "npm": ">=11.0.0"
      },
      "peerDependencies": {
        "@release-it/conventional-changelog": "^11.0.0 || ^12.0.0",
        "release-it": "^20.0.0 || ^21.0.0"
      }
    },
    "node_modules/@dnbhq/tsconfig": {
      "version": "0.1.6",
      "resolved": "https://registry.npmjs.org/@dnbhq/tsconfig/-/tsconfig-0.1.6.tgz",
      "integrity": "sha512-cxMn8+hfnM9mYiOKx4hK6qDTCxm+HPK/y3EGmIdivrxg0YlH4JAGoeoTtKR0dxFnLCU6x6yMmuu/i+lb2c4GmA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=25"
      },
      "peerDependencies": {
        "@types/node": ">=24",
        "typescript": ">=5.8"
      },
      "peerDependenciesMeta": {
        "@types/node": {
          "optional": true
        }
      }
    },
        "node_modules/@inquirer/ansi": {
            "version": "2.0.8",
            "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.8.tgz",
@@ -2163,6 +2436,7 @@
            "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==",
            "dev": true,
            "license": "BSD-2-Clause",
      "peer": true,
            "engines": {
                "node": ">=20.19.0"
            },
@@ -2476,6 +2750,7 @@
            "integrity": "sha512-c8B/VNLmxRcmqqenRA9t+9IyOjf9+V6lTxPaUJLqOCONdQkWZ0ETYgX0qbtJqPsgCNusT9MZ5Jeidw8Eb9tn2g==",
            "dev": true,
            "license": "MIT",
      "peer": true,
            "dependencies": {
                "@sindresorhus/merge-streams": "^4.0.0",
                "fast-glob": "^3.3.3",
@@ -2922,6 +3197,7 @@
                }
            ],
            "license": "MIT",
      "peer": true,
            "dependencies": {
                "uc.micro": "^3.0.0"
            }
@@ -3075,49 +3351,58 @@
            }
        },
        "node_modules/markdown-it": {
            "version": "15.0.2",
            "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-15.0.2.tgz",
            "integrity": "sha512-q4IGxMv56jCqT4OCRCADBoDP3LO4MhmTXjFbphHPXs4g3j9Xg5RDnxqN8IF/3vIWEU+VCnUq+7JUg/cfy2E6Qw==",
      "version": "13.0.1",
      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
      "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
            "dev": true,
            "funding": [
                {
                    "type": "github",
                    "url": "https://github.com/sponsors/puzrin"
                },
                {
                    "type": "github",
                    "url": "https://github.com/sponsors/markdown-it"
                }
            ],
            "license": "MIT",
            "dependencies": {
                "argparse": "^3.0.0",
                "entities": "^8.0.0",
                "linkify-it": "^6.0.0",
                "mdurl": "^2.1.0",
                "punycode.js": "^2.3.1",
                "uc.micro": "^3.0.0"
        "argparse": "^2.0.1",
        "entities": "~3.0.1",
        "linkify-it": "^4.0.1",
        "mdurl": "^1.0.1",
        "uc.micro": "^1.0.5"
            },
            "bin": {
                "markdown-it": "bin/markdown-it.mjs"
        "markdown-it": "bin/markdown-it.js"
            }
        },
        "node_modules/markdown-it/node_modules/argparse": {
            "version": "3.0.2",
            "resolved": "https://registry.npmjs.org/argparse/-/argparse-3.0.2.tgz",
            "integrity": "sha512-mFdDM6WqWKraGLsVb+C9CahPnzTXOefAOLq3jYcca2YZ8bEWpr++Tzj+zSaKW9+X9L5uSxcm1AZ3Y6aZJ09OhQ==",
    "node_modules/markdown-it/node_modules/entities": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
      "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
            "dev": true,
            "funding": [
                {
                    "type": "github",
                    "url": "https://github.com/sponsors/puzrin"
      "license": "BSD-2-Clause",
      "engines": {
        "node": ">=0.12"
                },
                {
                    "type": "github",
                    "url": "https://github.com/sponsors/nodeca"
      "funding": {
        "url": "https://github.com/fb55/entities?sponsor=1"
                }
            ],
            "license": "PSF-2.0"
    },
    "node_modules/markdown-it/node_modules/linkify-it": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
      "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "uc.micro": "^1.0.1"
      }
    },
    "node_modules/markdown-it/node_modules/mdurl": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
      "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/markdown-it/node_modules/uc.micro": {
      "version": "1.0.6",
      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
      "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
      "dev": true,
      "license": "MIT"
        },
        "node_modules/markdownlint": {
            "version": "0.41.1",
@@ -3149,6 +3434,7 @@
            "integrity": "sha512-xAr5o/TGpC3v6lE6cKIW4b5eOFRrRX5u7Vtjae9ix3RALv8nNOd94XMkD/1OXXBtpMcJ4uQGbpSo3hv5UqS4uQ==",
            "dev": true,
            "license": "MIT",
      "peer": true,
            "dependencies": {
                "globby": "16.2.4",
                "js-yaml": "5.4.1",
@@ -3199,6 +3485,7 @@
                }
            ],
            "license": "MIT",
      "peer": true,
            "dependencies": {
                "argparse": "^2.0.1"
            },
@@ -3222,6 +3509,7 @@
                }
            ],
            "license": "MIT",
      "peer": true,
            "dependencies": {
                "argparse": "^3.0.0",
                "entities": "^8.0.0",
@@ -3249,7 +3537,8 @@
                    "url": "https://github.com/sponsors/nodeca"
                }
            ],
            "license": "PSF-2.0"
      "license": "PSF-2.0",
      "peer": true
        },
        "node_modules/markdownlint-micromark": {
            "version": "0.1.2",
@@ -3284,75 +3573,6 @@
                "node": ">=16"
            }
        },
        "node_modules/markdownlint-rule-list-duplicates": {
            "version": "0.0.1",
            "resolved": "https://registry.npmjs.org/markdownlint-rule-list-duplicates/-/markdownlint-rule-list-duplicates-0.0.1.tgz",
            "integrity": "sha512-0dNOduVGbipS0YuUIX9OcLzojBxl/q+bXV1wRdYll2vyOVYekPdtm2fSrAKTnimOxNkQax7Qu2flOxxl+tXWkQ==",
            "dev": true,
            "license": "MIT",
            "dependencies": {
                "string-strip-html": "^8.3.0"
            }
        },
        "node_modules/markdownlint-rule-relative-links": {
            "version": "5.1.3",
            "resolved": "https://registry.npmjs.org/markdownlint-rule-relative-links/-/markdownlint-rule-relative-links-5.1.3.tgz",
            "integrity": "sha512-1ZRV3OyApUoYm4YVdLNZIN6vUVLzacD74n+yKx9ZL4H5yTmiLP2nKTwQMfOla158gblVL0jbB7QLLh3nmKUqvA==",
            "dev": true,
            "license": "MIT",
            "dependencies": {
                "markdown-it": "15.0.1",
                "mime": "4.1.0"
            },
            "engines": {
                "node": ">=22.0.0"
            }
        },
        "node_modules/markdownlint-rule-relative-links/node_modules/argparse": {
            "version": "3.0.2",
            "resolved": "https://registry.npmjs.org/argparse/-/argparse-3.0.2.tgz",
            "integrity": "sha512-mFdDM6WqWKraGLsVb+C9CahPnzTXOefAOLq3jYcca2YZ8bEWpr++Tzj+zSaKW9+X9L5uSxcm1AZ3Y6aZJ09OhQ==",
            "dev": true,
            "funding": [
                {
                    "type": "github",
                    "url": "https://github.com/sponsors/puzrin"
                },
                {
                    "type": "github",
                    "url": "https://github.com/sponsors/nodeca"
                }
            ],
            "license": "PSF-2.0"
        },
        "node_modules/markdownlint-rule-relative-links/node_modules/markdown-it": {
            "version": "15.0.1",
            "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-15.0.1.tgz",
            "integrity": "sha512-9/7gE95FNPkfUWrjJIoHZza2iLmuJlPD0UNMxPi7bxUrbCR525YZY0r+zyfes0dZI5ZZ/uNIXUJca0pJvtw41g==",
            "dev": true,
            "funding": [
                {
                    "type": "github",
                    "url": "https://github.com/sponsors/puzrin"
                },
                {
                    "type": "github",
                    "url": "https://github.com/sponsors/markdown-it"
                }
            ],
            "license": "MIT",
            "dependencies": {
                "argparse": "^3.0.0",
                "entities": "^8.0.0",
                "linkify-it": "^6.0.0",
                "mdurl": "^2.1.0",
                "punycode.js": "^2.3.1",
                "uc.micro": "^3.0.0"
            },
            "bin": {
                "markdown-it": "bin/markdown-it.mjs"
            }
        },
        "node_modules/markdownlint-rule-search-replace": {
            "version": "1.2.0",
            "resolved": "https://registry.npmjs.org/markdownlint-rule-search-replace/-/markdownlint-rule-search-replace-1.2.0.tgz",
@@ -3377,6 +3597,30 @@
                "title-case": "^4.1.2"
            }
        },
    "node_modules/markdownlint-rule-title-case-style/node_modules/markdownlint": {
      "version": "0.31.1",
      "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.31.1.tgz",
      "integrity": "sha512-CKMR2hgcIBrYlIUccDCOvi966PZ0kJExDrUi1R+oF9PvqQmCrTqjOsgIvf2403OmJ+CWomuzDoylr6KbuMyvHA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "markdown-it": "13.0.1",
        "markdownlint-micromark": "0.1.7"
      },
      "engines": {
        "node": ">=16"
      }
    },
    "node_modules/markdownlint-rule-title-case-style/node_modules/markdownlint-micromark": {
      "version": "0.1.7",
      "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.7.tgz",
      "integrity": "sha512-BbRPTC72fl5vlSKv37v/xIENSRDYL/7X/XoFzZ740FGEbs9vZerLrIkFRY0rv7slQKxDczToYuMmqQFN61fi4Q==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=16"
      }
    },
        "node_modules/mdurl": {
            "version": "2.1.0",
            "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.1.0.tgz",
@@ -4728,6 +4972,7 @@
            "integrity": "sha512-kCZr2V3ch9i00x8zXRhjUNVcjG9ijES5dDudkXvUVCT5QlJNQWElSJdZqyPemffHoLNUYwOcou0Fy+ojN0uHSQ==",
            "dev": true,
            "license": "BSD-3-Clause",
      "peer": true,
            "engines": {
                "node": ">= 18"
            },
@@ -4816,16 +5061,6 @@
                "node": ">=0.6.19"
            }
        },
        "node_modules/string-strip-html": {
            "version": "8.5.0",
            "resolved": "https://registry.npmjs.org/string-strip-html/-/string-strip-html-8.5.0.tgz",
            "integrity": "sha512-5ICsK1B1j0A3AF1d45m0sqQCcmi1Q+t1QpF+b794LO5FTHV+ITkGR5C+UCDJQZgs5LMuRruqr6j48PxQVIurJQ==",
            "dev": true,
            "license": "MIT",
            "engines": {
                "node": ">=14"
            }
        },
        "node_modules/string-width": {
            "version": "8.2.1",
            "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz",
@@ -4973,7 +5208,8 @@
            "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-3.0.0.tgz",
            "integrity": "sha512-U3PppEkleoTnIfi8BozMx3yju3qc/L6SwqWo2Sw+54PX+PX0q9I+r1Um5HCmqD7n9VDX5/v3vQH/AjA6deDdtw==",
            "dev": true,
            "license": "MIT"
      "license": "MIT",
      "peer": true
        },
        "node_modules/undici": {
            "version": "7.29.0",
package.json
@@ -3,7 +3,6 @@
    "description": "Ananke: A theme for Hugo Sites",
    "version": "2.19.1",
    "license": "MIT",
    "repository": "gohugo-ananke/ananke",
    "author": "Bud Parr (https://github.com/budparr)",
    "maintainers": [
        {
@@ -27,31 +26,28 @@
    "devDependencies": {
        "@axe-core/playwright": "4.13.0",
        "@biomejs/biome": "2.5.14",
        "@github/markdownlint-github": "0.8.4",
    "@dnbhq/biome-config": "0.3.1",
    "@dnbhq/lintstaged-config": "0.2.1",
    "@dnbhq/markdownlint-config": "0.2.11",
    "@dnbhq/release-config": "1.1.3",
    "@dnbhq/tsconfig": "0.1.6",
        "@playwright/test": "1.63.0",
        "@release-it/conventional-changelog": "12.0.2",
        "@types/node": "26.6.3",
        "dotenv": "18.0.4",
        "lint-staged": "17.6.0",
        "lockfile-lint": "5.0.1",
        "markdownlint": "0.41.1",
        "markdownlint-cli2": "0.23.3",
        "markdownlint-rule-extended-ascii": "0.2.1",
        "markdownlint-rule-list-duplicates": "0.0.1",
        "markdownlint-rule-relative-links": "5.1.3",
        "markdownlint-rule-search-replace": "1.2.0",
        "markdownlint-rule-title-case-style": "0.4.3",
        "release-it": "21.1.0",
        "simple-git-hooks": "2.14.0",
        "typescript": "7.0.2",
        "yaml": "2.9.1"
    },
    "scripts": {
        "hook:commit": "lint-staged --config .lintstagedrc.js",
    "hook:commit": "lint-staged",
        "hook:push": "node -e \"process.exit(require('child_process').execSync('git branch --show-current').toString().trim() === 'main' ? 0 : 1)\" && node scripts/test-hugo-quickstart.ts || true",
        "lint:links": "lychee --config lychee.toml public",
        "lint:markdown": "markdownlint-cli2",
        "lint:markdown:fix": "markdownlint-cli2 --fix",
    "lint:markdown": "markdownlint-cli2 --config ./node_modules/@dnbhq/markdownlint-config/.markdownlint-cli2.jsonc \"**/*.{md,mdx}\" \"#CHANGELOG.md\" \"#tests/.playwright/**\" \"#tests/fixtures/site/public/**\"",
    "lint:markdown:fix": "markdownlint-cli2 --config ./node_modules/@dnbhq/markdownlint-config/.markdownlint-cli2.jsonc --fix \"**/*.{md,mdx}\" \"#CHANGELOG.md\" \"#tests/.playwright/**\" \"#tests/fixtures/site/public/**\"",
        "lint:typescript": "tsc -p tsconfig.json --noEmit",
        "prepare": "simple-git-hooks install",
        "release": "release-it --config .release-it.ts",
@@ -63,7 +59,13 @@
        "test:e2e:ui": "playwright test --ui",
        "test:quickstart": "node scripts/test-hugo-quickstart.ts",
        "test:quickstart:submodule": "node scripts/test-hugo-quickstart.ts --use-submodule",
        "update:docs": "git add docs/ && (git diff --cached --quiet || git commit -m \"chore(git): update documentation submodule\")"
    "update:docs": "git add docs/ && (git diff --cached --quiet || git commit -m \"chore(git): update documentation submodule\")",
    "release:dry": "release-it --dry-run --config .release-it.ts",
    "lint:code": "biome check",
    "lint:lockfile": "lockfile-lint --path package-lock.json --validate-https --allowed-hosts npm",
    "lint": "npm run lint:code && npm run lint:lockfile && npm run lint:markdown && npm run lint:typescript",
    "check": "npm run lint && npm test && npm run test:coverage-gate",
    "lint:code:fix": "biome check --write"
    },
    "cspell": {
        "version": "0.2",
@@ -79,12 +81,11 @@
        "pre-push": "npm run hook:push"
    },
    "type": "module",
    "overrides": {
        "markdownlint-rule-title-case-style": {
            "markdownlint": "$markdownlint"
        }
    },
    "allowScripts": {
        "simple-git-hooks@2.14.0": true
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/gohugo-ananke/ananke.git"
    }
}
playwright.config.ts
renovate.json5
New file
@@ -0,0 +1,7 @@
{
    "$schema": "https://docs.renovatebot.com/renovate-schema.json",
    "extends": ["github>dnbhq/renovate-config"],
    "assignees": ["davidsneighbour"],
    "baseBranches": ["development"],
    "labels": ["type:dependencies"],
}
scripts/synch-social-icons.ts
scripts/test-hugo-quickstart.ts
@@ -1341,12 +1341,7 @@
        console.log("\n[RUN] List page image cards and summary dates (issue #217)");
        await writeListCardFixtures(join(projectRoot, "content"));
        const cardsListPath = join(
            projectRoot,
            "public",
            "cards",
            "index.html",
        );
    const cardsListPath = join(projectRoot, "public", "cards", "index.html");
        // Default configuration: no image cards, but dates show by default.
        await writeTextFile(
@@ -1370,11 +1365,10 @@
            projectRoot,
        );
        reports.push(cardsDefaultBuildReport);
        assertListCardSummaries(
            await readTextFile(cardsListPath),
            "defaults",
            { images: false, dates: true },
        );
    assertListCardSummaries(await readTextFile(cardsListPath), "defaults", {
      images: false,
      dates: true,
    });
        // Opt in to image cards and disable summary dates: images appear and the
        // dates disappear, proving the two settings are independent.
tests/coverage-gate.mjs
tests/e2e/accessibility.spec.ts
tests/e2e/copy-button.spec.ts
tests/support/dev-server.mjs
tests/support/prepare-site.mjs
tsconfig.json
@@ -1,29 +1,11 @@
{
  "extends": "@dnbhq/tsconfig/cli",
    "compilerOptions": {
        "module": "nodenext",
        "target": "esnext",
        "types": [
            "node"
        ],
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
        "sourceMap": true,
        "declaration": true,
        "declarationMap": true,
        "noUncheckedIndexedAccess": true,
        "exactOptionalPropertyTypes": true,
        "strict": true,
        "jsx": "react-jsx",
        "verbatimModuleSyntax": true,
        "isolatedModules": true,
        "noUncheckedSideEffectImports": true,
        "moduleDetection": "force",
        "skipLibCheck": true,
        "noImplicitOverride": true,
        "noPropertyAccessFromIndexSignature": true,
        "useUnknownInCatchVariables": true,
        "noFallthroughCasesInSwitch": true,
    "jsx": "react-jsx"
    },
    "include": [
        "**/*.ts",
        "scripts/**/*"
    ]
  "include": ["**/*.ts", "scripts/**/*"]
}