{"_id":"@allons-y/dashly","name":"@allons-y/dashly","dist-tags":{"beta":"0.1.0-beta.0","latest":"0.1.0-beta.0"},"versions":{"0.1.0-beta.0":{"publishConfig":{"access":"public"},"name":"@allons-y/dashly","version":"0.1.0-beta.0","description":"A standard-library of filters, transforms, and shortcodes for Eleventy.","license":"MPL-2.0","author":{"name":"Cassondra Roberts","email":"castastrophe@users.noreply.github.com","url":"https://allons-y.studio"},"homepage":"https://github.com/allonsy-studio/dashly#readme","funding":[{"type":"github","url":"https://github.com/sponsors/castastrophe"},{"type":"buy-me-a-coffee","url":"https://www.buymeacoffee.com/castastrophe"}],"repository":{"type":"git","url":"git+https://github.com/allonsy-studio/dashly.git"},"bugs":{"url":"https://github.com/allonsy-studio/dashly/issues"},"type":"module","exports":{".":"./src/index.js","./plugin":"./src/plugin.js","./filters":"./src/filters/index.js","./filters/*":"./src/filters/*.js","./transforms":"./src/transforms/index.js","./transforms/*":"./src/transforms/*.js","./shortcodes":"./src/shortcodes/index.js","./shortcodes/*":"./src/shortcodes/*.js"},"scripts":{"changeset":"changeset","ci:test":"vitest run","coverage":"vitest run --coverage","format":"yarn lint --fix","lint":"eslint .","postinstall":"husky && envoy || true","postpack":"pinst --enable","precommit":"lint-staged","prepack":"pinst --disable","prepare":"husky","release":"changeset publish","test":"vitest run","test:watch":"vitest watch","version":"changeset version"},"peerDependencies":{"@11ty/eleventy":">=3.0.0","html-minifier-terser":">=7.0.0","markdown-it":">=14.0.0","postcss":">=8.0.0","posthtml":">=0.16.0","prettier":">=3.0.0"},"peerDependenciesMeta":{"html-minifier-terser":{"optional":true},"markdown-it":{"optional":true},"postcss":{"optional":true},"posthtml":{"optional":true},"prettier":{"optional":true}},"devDependencies":{"@11ty/eleventy":"^3.1.6","@allons-y/envoy":"^1.1.0","@changesets/changelog-github":"^0.7.0","@changesets/cli":"^2.31.0","@eslint/css":"^1.3.0","@eslint/js":"^10.0.1","@eslint/json":"^2.0.0","@eslint/markdown":"^8.0.2","@vitest/eslint-plugin":"^1.6.20","eslint":"^10.6.0","eslint-config-prettier":"^10.1.8","eslint-plugin-jsonc":"^3.2.0","eslint-plugin-license-header":"^0.9.0","globals":"^17.7.0","html-minifier-terser":"^7.2.0","husky":"^9.1.7","lint-staged":"^17.0.8","markdown-it":"^14.2.0","pinst":"^3.0.0","postcss":"^8.5.16","posthtml":"^0.16.7","prettier":"^3.9.3","vitest":"^4.1.9"},"keywords":["eleventy","11ty","eleventy-plugin","filters","transforms","shortcodes","utilities"],"engines":{"node":">=24"},"lint-staged":{"*":["eslint --fix --format stylish"],".github/renovate.json":"npx --yes --package renovate -- renovate-config-validator --strict"},"packageManager":"yarn@4.17.0","gitHead":"9d0f470199e89667b0ac0b6d60ff457314609328","_id":"@allons-y/dashly@0.1.0-beta.0","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-QPY1DZy/JvT2OdzlVLnjKOrE/PgfnfTjWkwJ75voLNjFSnf//xwZR3AT97jraCD+aFWdA5gMCx650BHMF4HkvQ==","shasum":"c2195cd8be1724c0bb0a8397c11fac40de372065","tarball":"https://registry.npmjs.org/@allons-y/dashly/-/dashly-0.1.0-beta.0.tgz","fileCount":24,"unpackedSize":82832,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDWG1vLjmwpA1ESLtDIOVR2p2fTU8wSZSk/mx5TbAfAUAIhAPNa6Hq96/yvKo3KFVqx+rjVzLWe0vhAsxL7s5JfF5Dq"}]},"_npmUser":{"name":"castastrophe","email":"castastrophe+npm@hey.com"},"directories":{},"maintainers":[{"name":"castastrophe","email":"castastrophe+npm@hey.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dashly_0.1.0-beta.0_1785279356033_0.5576552897366578"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-28T22:55:55.821Z","0.1.0-beta.0":"2026-07-28T22:55:56.183Z","modified":"2026-07-28T22:55:56.860Z"},"maintainers":[{"name":"castastrophe","email":"castastrophe+npm@hey.com"}],"description":"A standard-library of filters, transforms, and shortcodes for Eleventy.","homepage":"https://github.com/allonsy-studio/dashly#readme","keywords":["eleventy","11ty","eleventy-plugin","filters","transforms","shortcodes","utilities"],"repository":{"type":"git","url":"git+https://github.com/allonsy-studio/dashly.git"},"author":{"name":"Cassondra Roberts","email":"castastrophe@users.noreply.github.com","url":"https://allons-y.studio"},"bugs":{"url":"https://github.com/allonsy-studio/dashly/issues"},"license":"MPL-2.0","readme":"<!-- weaver:header:START -->\n<!-- auto-generated by Weaver — do not edit between these markers -->\n\n<p align=\"center\">\n<a href=\"https://allons-y.studio\">\n    <img id=\"user-content-logo\" src=\"https://raw.githubusercontent.com/allonsy-studio/.github/main/assets/png/oss-banner.png\" alt=\"Brought to you by Allons-y Studio\" width=\"1500\">\n</a>\n</p>\n\n<h1 align=\"center\" border=\"none\">dashly</h1>\n\n<p align=\"center\">\n  <img src=\"https://github.com/allonsy-studio/.github/blob/main/assets/tag-rule.gif\" alt=\"\" height=\"30\" />\n</p>\n\n<p align=\"center\"><b>A standard-library of filters, transforms, and shortcodes for 11ty. One install, one plugin line, done.</b></p>\n\n<p align=\"center\">\n  <a href=\"https://www.npmjs.com/package/@allons-y/dashly\">\n    <img src=\"https://img.shields.io/npm/v/@allons-y/dashly.svg\" alt=\"NPM version\" height=\"20\" />\n  </a>\n  <a href=\"https://www.npmjs.com/package/@allons-y/dashly\">\n    <img src=\"https://img.shields.io/npm/dw/@allons-y/dashly.svg\" alt=\"NPM downloads\" height=\"20\" />\n  </a>\n  <a href=\"https://github.com/allonsy-studio/dashly/actions/workflows/testing.yml\">\n    <img src=\"https://github.com/allonsy-studio/dashly/actions/workflows/testing.yml/badge.svg?branch=main\" alt=\"Tests\" height=\"20\" />\n  </a>\n  <a href=\"https://github.com/allonsy-studio/dashly/blob/main/LICENSE\">\n    <img src=\"https://img.shields.io/github/license/allonsy-studio/dashly.svg\" alt=\"License\" height=\"20\" />\n  </a>\n  <a href=\"https://allons-y.studio\">\n    <img src=\"https://github.com/allonsy-studio/.github/blob/main/assets/svg/badge.svg\" alt=\"Brought to you by Allons-y Studio\" height=\"20\" />\n  </a>\n</p>\n\n<!-- weaver:header:END -->\n\ndashly is the standard-library helpers every 11ty site eventually rewrites from scratch — date formatting, RSS sanitization, HTML minification, URL validation, reading-time and excerpt generation, locale-aware number/currency/percent formatting, and more — bundled into a single tree-shakeable package.\n\n## Install\n\n```sh\nnpm install --save-dev @allons-y/dashly\n```\n\nHeavy dependencies (`prettier`, `html-minifier-terser`, `posthtml`, `markdown-it`, `postcss`) are declared as **optional peers**. Install only the ones you use.\n\n## Quick start\n\n```js\n// eleventy.config.js\nimport dashly from \"@allons-y/dashly\";\n\nexport default function (config) {\n\tconfig.addPlugin(dashly, {\n\t\tdateLocale: \"en-GB\",\n\t\tbaseUrl: \"https://example.com\",\n\t});\n}\n```\n\nTemplates can immediately use:\n\n```njk\n{{ post.date | longDate }}        {# 15 January 2026 #}\n{{ post.date | shortDate }}       {# Jan 2026 #}\n{{ post.date | year }}            {# 2026 #}\n{{ name | firstWord }}            {# \"Allons-y\" → \"Allons-y\" #}\n{{ phone | digitsOnly }}          {# \"(555) 123-4567\" → \"5551234567\" #}\n{{ \"example.com\" | validateURL }} {# https://example.com #}\n{{ post.content | cleanForRSS }}  {# safe HTML for feeds #}\n{{ post.content | wordCount }}    {# 842 #}\n{{ post.content | readingTime }}  {# 4 #}\n{{ post.content | excerpt(40) }}  {# first 40 words, ellipsised #}\n<pre>{{ page | dump }}</pre>      {# pretty-printed JSON, circular-safe #}\n{{ page.url | absoluteUrl }}      {# https://example.com/posts/hello/ #}\n{{ post.date | timeAgo }}         {# \"2 days ago\" #}\n{{ product.price | currency }}    {# \"$1,299.00\" #}\n{{ survey.rate | percent }}       {# \"25%\" — input 0.25 #}\n&copy; {% year %} Acme Corp.\n```\n\n## A la carte\n\n```js\nimport { filters, transforms } from \"@allons-y/dashly\";\n\nconfig.addFilter(\"long\", filters.longDate);\nconfig.addFilter(\"rss\", filters.cleanForRSS);\nconfig.addTransform(\"prettier\", transforms.createPrettierTransform());\n```\n\nOr import from the narrowest subpath so unused dependencies never enter your bundle:\n\n```js\nimport { longDate } from \"@allons-y/dashly/filters/dates\";\nimport { validateURL } from \"@allons-y/dashly/filters/urls\";\n```\n\n## What's in the box\n\n### Filters\n\n| Name                                    | Purpose                                                                         | Peer dep             |\n| --------------------------------------- | ------------------------------------------------------------------------------- | -------------------- |\n| `toISOString`                           | ISO-8601 string for `<time>` and JSON-LD                                        | –                    |\n| `year`                                  | Four-digit year                                                                 | –                    |\n| `dateFormat`                            | Pass-through `Intl.DateTimeFormat`                                              | –                    |\n| `longDate`                              | `15 January 2026`                                                               | –                    |\n| `shortDate`                             | `Jan 2026`                                                                      | –                    |\n| `firstWord`, `lastWord`                 | Pull first/last word from a string                                              | –                    |\n| `trim`, `stripWhitespace`, `digitsOnly` | Common string sanitizers                                                        | –                    |\n| `keys`                                  | Safe `Object.keys` for templates                                                | –                    |\n| `validateURL`                           | Force `https://` on bare hostnames; pass `mailto:`/`tel:`/relative URLs through | –                    |\n| `cleanForRSS`                           | Strip scripts, embeds, permalinks, custom elements from HTML                    | `posthtml`           |\n| `renderMarkdown`                        | Render a markdown string (with optional `\\n\\n` paragraph splitting)             | `markdown-it`        |\n| `wordCount`                             | Count words in a string (HTML stripped)                                         | –                    |\n| `readingTime`                           | Estimate minutes to read (configurable `wpm`, default 200)                      | –                    |\n| `excerpt`                               | First/last N words or chars, ellipsised. Negative N → trailing slice            | –                    |\n| `dump` / `jsonify`                      | Pretty-printed JSON for in-template debugging, circular-safe                    | –                    |\n| `first`                                 | First element of an array, or first N when a count is given                     | –                    |\n| `last`                                  | Last element of an array, or last N when a count is given                       | –                    |\n| `reverse`                               | Reverse an array or string (non-mutating, code-point safe)                      | –                    |\n| `capitalize`                            | Uppercase first letter, lowercase rest                                          | –                    |\n| `title`                                 | Title-case each word                                                            | –                    |\n| `stripTags`                             | Remove every HTML tag; collapse whitespace                                      | –                    |\n| `nl2br`                                 | Replace newlines with `<br>` for plain-text → HTML                              | –                    |\n| `absoluteUrl`                           | Resolve a path against `baseUrl` for canonical/OG/JSON-LD tags                  | –                    |\n| `relativeDate` / `timeAgo`              | `Intl.RelativeTimeFormat` wrapper (\"2 days ago\")                                | –                    |\n| `number`                                | `Intl.NumberFormat` wrapper with locale-aware grouping                          | –                    |\n| `currency`                              | Localized currency formatting (default `USD`)                                   | –                    |\n| `percent`                               | Localized percent formatting (fraction-aware)                                   | –                    |\n| `groupBy`                               | Group items by key, dot-path, or selector function                              | –                    |\n| `sortBy`                                | Sort by key/dot-path/function, `'asc'` or `'desc'`                              | –                    |\n| `chunk`                                 | Split into N-sized arrays (gallery rows, paginated grids)                       | –                    |\n| `where`                                 | Filter by key equality, or truthiness when no value is given                    | –                    |\n| `pluck`                                 | Project an array of objects onto a single key/path                              | –                    |\n| `tags`                                  | Strip Eleventy system tags (`all`/`post`/…) from a tag list                     | –                    |\n\n### Transforms\n\n| Name         | Purpose                                                               | Peer dep               |\n| ------------ | --------------------------------------------------------------------- | ---------------------- |\n| `prettier`   | Format HTML/XML/SVG output                                            | `prettier`             |\n| `htmlmin`    | Minify HTML (production-gated by default)                             | `html-minifier-terser` |\n| `cleanAttrs` | Strip `eleventy:ignore=\"\"` markers left on `<img>` inside `<picture>` | –                      |\n\nThe `postcss` helper (`@allons-y/dashly/transforms/postcss`) is exported separately for use in `addBundle` or `addExtension('css', …)` setups.\n\n### Shortcodes\n\n| Name   | Purpose                                         | Peer dep |\n| ------ | ----------------------------------------------- | -------- |\n| `year` | Current four-digit year (for footer copyrights) | –        |\n\n## Plugin options\n\n```ts\ninterface DashlyOptions {\n\tdateLocale?: string; // default 'en-US'; also used by relativeDate / number / currency / percent\n\tbaseUrl?: string; // origin used by `absoluteUrl`, e.g. 'https://example.com'\n\treadingTimeWpm?: number; // default 200\n\ttagsExclude?: string[]; // tag names stripped by the `tags` filter; default ['all', 'post', 'posts']\n\tfilters?: false | { exclude?: string[] };\n\ttransforms?:\n\t\t| false\n\t\t| {\n\t\t\t\texclude?: string[];\n\t\t\t\tprettier?: { extensions?: string[]; prettier?: PrettierOptions };\n\t\t\t\thtmlmin?: { production?: boolean; minifier?: HtmlMinifierOptions };\n\t\t\t\tcleanAttrs?: { attrs?: string[] };\n\t\t  };\n\tshortcodes?: false | { exclude?: string[] };\n}\n```\n\nPass `false` for any category to skip it entirely. Pass `exclude` to omit specific names.\n\n## Design notes\n\n**No `truncate` filter.** Mechanical mid-sentence truncation (`{{ content | truncate(100) }}`) is a poor reading experience — it hides content with no signal about what was cut and often clips mid-word or mid-tag. Use [`excerpt`](#filters) instead, which trims on word boundaries and is intended as a summary affordance, not a clipping one. For trailing slices (last N words), pass a negative N: `{{ content | excerpt(-20) }}`.\n\n**Smart quotes.** No dedicated filter; enable [markdown-it's `typographer: true`](https://github.com/markdown-it/markdown-it#init-with-presets-and-options) on the renderer you pass to `renderMarkdown`, which handles `'` → `’`, `--` → `—`, etc. for free.\n\n**Nunjucks-parity universals.** Nunjucks and Liquid templates ship many of these filters natively (`first`, `last`, `reverse`, `capitalize`, etc.) — dashly registers them through `addFilter` so they're available in **every** Eleventy template engine, including JS templates and shortcodes, with consistent semantics across engines. `first` and `last` accept an optional count argument so `{{ posts | first(3) }}` covers the common \"limit to N\" case without a separate filter name.\n\n\n<!-- weaver:contribution:START -->\n<!-- auto-generated by Weaver — do not edit between these markers -->\n\n<h2>Contributing</h2>\n\nContributions are welcome and appreciated! Please open an [issue](https://github.com/allonsy-studio/dashly/issues/new) (before submitting a pull request) if you find a bug, have a feature request, or have a question. Be sure to follow the [contribution guidelines](.github/CONTRIBUTING.md) and [code of conduct](.github/CODE_OF_CONDUCT.md) but most importantly, be excellent to each other. 💖\n\n<!-- weaver:contribution:END -->\n\n<!-- weaver:license:START -->\n<!-- auto-generated by Weaver — do not edit between these markers -->\n\n<h2>License</h2>\n\nThis project is licensed under the MPL-2.0 License - see the [LICENSE](LICENSE) file for details. This means you can use this freely, modify as needed; changes to MPL-licensed files should be shared back under the same license.\n\n<!-- weaver:license:END -->\n\n<!-- weaver:funding:START -->\n<!-- auto-generated by Weaver — do not edit between these markers -->\n\n<h2>Funding ☕️</h2>\n\nIf you find this plugin useful and would like to buy me a coffee/beer as a small thank you, I would greatly appreciate it!\n\n<a href=\"https://www.buymeacoffee.com/castastrophe\">\n    <img src=\"https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png\" alt=\"Buy Me A Coffee\" height=\"40\"/>\n</a>\n\n<!-- weaver:funding:END -->\n\n","readmeFilename":"README.md","_rev":"1-d10d5bf76e4c51aaba51618f5dc79779"}