├── test ├── fixtures │ ├── main │ │ └── src │ │ │ ├── dir │ │ │ └── test.pug │ │ │ ├── file.notjade │ │ │ ├── locals.pug │ │ │ ├── metadata.pug │ │ │ ├── text.txt.pug │ │ │ ├── index.pug │ │ │ ├── legacy.jade │ │ │ └── pretty.pug │ └── filters │ │ └── src │ │ └── test.pug └── index.js ├── .github ├── linters │ ├── .lychee.toml │ ├── .grype.yaml │ ├── .commit-lint.yml │ ├── .checkov.yml │ ├── .yamllint.yml │ ├── .mega-linter.yml │ └── .markdown-lint.yml ├── test-matrix.json ├── FUNDING.yml ├── workflows │ ├── pull_request_target.yml │ └── push.yml └── dependabot.yml ├── colophon.yml ├── .gitignore ├── .taprc.yml ├── .pandoc.yml ├── .npmignore ├── .editorconfig ├── docs ├── README.template └── README.md ├── LICENSE ├── package.json ├── Makefile ├── docker-compose.yml ├── .release.json ├── .semantic.json ├── src └── index.js └── README.md /test/fixtures/main/src/dir/test.pug: -------------------------------------------------------------------------------- 1 | h1 Hello 2 | -------------------------------------------------------------------------------- /test/fixtures/main/src/file.notjade: -------------------------------------------------------------------------------- 1 | h1= foo 2 | -------------------------------------------------------------------------------- /test/fixtures/main/src/locals.pug: -------------------------------------------------------------------------------- 1 | h1= title 2 | -------------------------------------------------------------------------------- /test/fixtures/main/src/metadata.pug: -------------------------------------------------------------------------------- 1 | h1= foo 2 | -------------------------------------------------------------------------------- /test/fixtures/main/src/text.txt.pug: -------------------------------------------------------------------------------- 1 | != foo 2 | -------------------------------------------------------------------------------- /test/fixtures/filters/src/test.pug: -------------------------------------------------------------------------------- 1 | :foo 2 | bar 3 | -------------------------------------------------------------------------------- /test/fixtures/main/src/index.pug: -------------------------------------------------------------------------------- 1 | h1 Hello World 2 | -------------------------------------------------------------------------------- /test/fixtures/main/src/legacy.jade: -------------------------------------------------------------------------------- 1 | h1 Hello World 2 | -------------------------------------------------------------------------------- /test/fixtures/main/src/pretty.pug: -------------------------------------------------------------------------------- 1 | div 2 | h1 Hello 3 | -------------------------------------------------------------------------------- /.github/linters/.lychee.toml: -------------------------------------------------------------------------------- 1 | exclude_path = [".github"] 2 | -------------------------------------------------------------------------------- /.github/linters/.grype.yaml: -------------------------------------------------------------------------------- 1 | check-for-app-update: false 2 | exclude: 3 | - '**/package-lock.json' 4 | -------------------------------------------------------------------------------- /.github/test-matrix.json: -------------------------------------------------------------------------------- 1 | { 2 | "os": ["ubuntu-latest"], 3 | "node-version": [14, 16, 18] 4 | } 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | github: [ahmadnassri] 6 | -------------------------------------------------------------------------------- /colophon.yml: -------------------------------------------------------------------------------- 1 | version: 2.0 2 | 3 | id: node-metalsmith-pug 4 | 5 | about: 6 | title: Metalsmith Pug 7 | description: Metalsmith plugin to convert pug files 8 | repository: ahmadnassri/node-metalsmith-pug 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-node-lib # 3 | # ----------------------------------------------- # 4 | 5 | *.log 6 | node_modules 7 | **/dist 8 | -------------------------------------------------------------------------------- /.taprc.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-node-lib # 3 | # ----------------------------------------------- # 4 | 5 | ts: false 6 | jsx: false 7 | flow: false 8 | coverage: true 9 | browser: false 10 | color: true 11 | coverage-report: html 12 | -------------------------------------------------------------------------------- /.github/linters/.commit-lint.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | extends: 6 | - "@commitlint/config-conventional" 7 | 8 | rules: 9 | body-max-line-length: [2, "always", 200] 10 | -------------------------------------------------------------------------------- /.github/linters/.checkov.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | quiet: true 6 | skip-check: 7 | - CKV_DOCKER_2 8 | - CKV_DOCKER_8 9 | - CKV_GHA_3 10 | - BC_DKR_3 11 | - CKV_GIT_1 12 | - CKV_GIT_5 13 | - CKV_GIT_6 14 | - CKV_TF_1 15 | -------------------------------------------------------------------------------- /.pandoc.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | input-file: docs/README.md 6 | output-file: README.md 7 | metadata-file: colophon.yml 8 | template: docs/README.template 9 | 10 | from: gfm 11 | to: gfm 12 | 13 | wrap: preserve 14 | reference-links: true 15 | fail-if-warnings: false 16 | -------------------------------------------------------------------------------- /.github/workflows/pull_request_target.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | name: pull_request_target 6 | 7 | on: pull_request_target 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | main: 13 | uses: ahmadnassri/actions/.github/workflows/pull-request-target.yml@master 14 | secrets: inherit 15 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-node-lib # 3 | # ----------------------------------------------- # 4 | 5 | # copy of .gitignore (npm will only use .npmignore if it exists) 6 | *.log 7 | node_modules 8 | **/dist 9 | 10 | # additional ignore 11 | .editorconfig 12 | .github 13 | .pandoc.yml 14 | .release.json 15 | colophon.yml 16 | docker-compose.yml 17 | Makefile 18 | test 19 | -------------------------------------------------------------------------------- /.github/linters/.yamllint.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | extends: default 6 | 7 | rules: 8 | brackets: 9 | max-spaces-inside: 1 10 | document-start: 11 | present: false 12 | truthy: 13 | check-keys: false 14 | line-length: 15 | max: 500 16 | comments: 17 | min-spaces-from-content: 1 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | root = true 6 | 7 | [*] 8 | charset = utf-8 9 | end_of_line = lf 10 | indent_size = 2 11 | indent_style = space 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | 18 | [Makefile] 19 | indent_style = tab 20 | -------------------------------------------------------------------------------- /docs/README.template: -------------------------------------------------------------------------------- 1 | # $about.title$ 2 | 3 | $about.description$ 4 | 5 | [![license][license-img]][license-url] 6 | [![release][release-img]][release-url] 7 | 8 | $body$ 9 | 10 | --- 11 | 12 | > Author: [Ahmad Nassri](https://www.ahmadnassri.com/) & 13 | 14 | [license-url]: LICENSE 15 | [license-img]: https://badgen.net/github/license/$about.repository$ 16 | [release-url]: https://github.com/$about.repository$/releases 17 | [release-img]: https://badgen.net/github/release/$about.repository$ 18 | -------------------------------------------------------------------------------- /.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-node-lib # 3 | # ----------------------------------------------- # 4 | 5 | name: push 6 | 7 | on: 8 | - push 9 | - workflow_dispatch 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | main: 15 | uses: ahmadnassri/actions/.github/workflows/push-javascript.yml@master 16 | secrets: inherit 17 | permissions: 18 | contents: write 19 | statuses: write 20 | packages: write 21 | pull-requests: write 22 | -------------------------------------------------------------------------------- /.github/linters/.mega-linter.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | DISABLE: 6 | - COPYPASTE 7 | 8 | DISABLE_LINTERS: 9 | - REPOSITORY_TRIVY 10 | - SPELL_CSPELL 11 | - JSON_PRETTIER 12 | - YAML_PRETTIER 13 | - JAVASCRIPT_PRETTIER 14 | - HTML_DJLINT 15 | - REPOSITORY_KICS 16 | - REPOSITORY_TRUFFLEHOG 17 | - REPOSITORY_DEVSKIM # temporarily disabled 18 | - TERRAFORM_TERRASCAN # temporarily disabled 19 | 20 | LOG_LEVEL: INFO 21 | PRINT_ALPACA: false 22 | CONFIG_REPORTER: false 23 | SHOW_ELAPSED_TIME: true 24 | FLAVOR_SUGGESTIONS: false 25 | VALIDATE_ALL_CODEBASE: false 26 | IGNORE_GENERATED_FILES: true 27 | FILTER_REGEX_EXCLUDE: (dist/*|README.md|vendor/*|/schemas/*|test/fixtures/*) 28 | 29 | MARKDOWN_MARKDOWNLINT_CONFIG_FILE: .markdown-lint.yml 30 | REPOSITORY_CHECKOV_ARGUMENTS: [--skip-path, schemas, --skip-path, test/fixtures] 31 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-node-lib # 3 | # ----------------------------------------------- # 4 | 5 | version: 2 6 | updates: 7 | - package-ecosystem: npm 8 | open-pull-requests-limit: 10 9 | directory: / 10 | commit-message: 11 | prefix: build 12 | prefix-development: chore 13 | include: scope 14 | schedule: 15 | interval: daily 16 | time: "10:00" 17 | timezone: America/Toronto 18 | 19 | - package-ecosystem: gitsubmodule 20 | open-pull-requests-limit: 10 21 | directory: / 22 | commit-message: 23 | prefix: build 24 | prefix-development: chore 25 | include: scope 26 | schedule: 27 | interval: daily 28 | time: "10:00" 29 | timezone: America/Toronto 30 | 31 | - package-ecosystem: docker 32 | open-pull-requests-limit: 10 33 | directory: / 34 | commit-message: 35 | prefix: build 36 | prefix-development: chore 37 | include: scope 38 | schedule: 39 | interval: daily 40 | time: "10:00" 41 | timezone: America/Toronto 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ahmad Nassri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.0-semantically-released", 3 | "name": "metalsmith-pug", 4 | "description": "Metalsmith plugin to convert pug files", 5 | "author": "Ahmad Nassri (https://www.ahmadnassri.com)", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/ahmadnassri/node-metalsmith-pug.git" 9 | }, 10 | "bugs": { 11 | "url": "https://github.com/ahmadnassri/node-metalsmith-pug/issues" 12 | }, 13 | "funding": { 14 | "type": "individual", 15 | "url": "https://github.com/sponsors/ahmadnassri" 16 | }, 17 | "license": "MIT", 18 | "keywords": [ 19 | "pug", 20 | "jade", 21 | "metalsmith", 22 | "plugin" 23 | ], 24 | "engines": { 25 | "node": ">=14" 26 | }, 27 | "files": [ 28 | "src" 29 | ], 30 | "main": "src/index.js", 31 | "scripts": { 32 | "test": "tap test --no-coverage", 33 | "test:ci": "tap test --100", 34 | "test:watch": "tap test --watch", 35 | "test:report": "opener coverage/lcov-report/index.html" 36 | }, 37 | "devDependencies": { 38 | "metalsmith": "^2.5.1", 39 | "rimraf": "^3.0.2", 40 | "tap": "^16.3.2" 41 | }, 42 | "dependencies": { 43 | "pug": "^3.0.2" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make 2 | 3 | # ----------------------------------------------- # 4 | # Note: this file originates in template-node-lib # 5 | # ----------------------------------------------- # 6 | 7 | NPMRC := $(shell npm config get userconfig) 8 | 9 | pull: ## pull latest containers 10 | @docker compose pull 11 | 12 | readme: ## generate root README.md 13 | @docker compose run --rm readme 14 | 15 | lint: ## run super-linter 16 | @docker compose run --rm lint 17 | 18 | install: ## install all dependencies 19 | @docker compose run --rm app install 20 | 21 | test: ## run all npm tests 22 | @docker compose run --rm app test 23 | 24 | shell: ## start the container shell 25 | @docker compose run --rm --entrypoint /bin/sh app 26 | 27 | clean: ## delete containers, images, volumes, node_modules 28 | @docker compose run --rm --entrypoint "rm -rf node_modules" app 29 | @docker compose rm --stop --force --volumes 30 | @docker compose down --remove-orphans --volumes --rmi local 31 | 32 | # Utility methods 33 | ## Help: https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html 34 | 35 | help: ## display this help 36 | @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) 37 | 38 | .DEFAULT_GOAL := help 39 | .PHONY: help all clean test 40 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-node-lib # 3 | # ----------------------------------------------- # 4 | 5 | services: 6 | # ---- mega-linter ---- # 7 | lint: 8 | profiles: ["dev"] 9 | image: oxsecurity/megalinter-javascript:v7.3.0 10 | volumes: 11 | - ./:/tmp/lint 12 | environment: 13 | MEGALINTER_CONFIG: .github/linters/.mega-linter.yml 14 | REPORT_OUTPUT_FOLDER: none 15 | VALIDATE_ALL_CODEBASE: true 16 | 17 | # ---- readme generator ---- # 18 | readme: 19 | profiles: ["dev"] 20 | image: pandoc/minimal:2.19 21 | volumes: 22 | - ./:/data 23 | command: --defaults=.pandoc.yml 24 | 25 | app: 26 | profiles: ["app"] 27 | image: node:latest 28 | working_dir: /usr/src/lib 29 | entrypoint: npm 30 | tty: true 31 | volumes: 32 | - ./:/usr/src/lib 33 | environment: 34 | NODE_ENV: test 35 | NPM_CONFIG_UPDATE_NOTIFIER: false 36 | NPM_CONFIG_FUND: false 37 | NPM_CONFIG_AUDIT: false 38 | 39 | test-command: 40 | extends: app 41 | command: run test 42 | 43 | test: 44 | profiles: ["test"] 45 | extends: test-command 46 | depends_on: 47 | - node18 48 | - node20 49 | 50 | node18: 51 | profiles: ["test"] 52 | extends: test-command 53 | image: node:18-alpine 54 | 55 | node20: 56 | profiles: ["test"] 57 | extends: test-command 58 | image: node:20-alpine 59 | -------------------------------------------------------------------------------- /.release.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["@semantic-release/commit-analyzer", { 4 | "preset": "conventionalcommits", 5 | "releaseRules": [ 6 | { "breaking": true, "release": "major" }, 7 | { "revert": true, "release": "patch" }, 8 | { "type": "build", "release": "patch" }, 9 | { "type": "docs", "release": "patch" }, 10 | { "type": "feat", "release": "minor" }, 11 | { "type": "fix", "release": "patch" }, 12 | { "type": "perf", "release": "patch" }, 13 | { "type": "refactor", "release": "patch" } 14 | ] 15 | }], 16 | ["@semantic-release/release-notes-generator", { 17 | "preset": "conventionalcommits", 18 | "presetConfig": { 19 | "types": [ 20 | { "type": "chore", "section": "Chores", "hidden": true }, 21 | { "type": "build", "section": "Build", "hidden": false }, 22 | { "type": "ci", "section": "CI/CD", "hidden": false }, 23 | { "type": "docs", "section": "Docs", "hidden": false }, 24 | { "type": "feat", "section": "Features", "hidden": false }, 25 | { "type": "fix", "section": "Bug Fixes", "hidden": false }, 26 | { "type": "perf", "section": "Performance", "hidden": false }, 27 | { "type": "refactor", "section": "Refactor", "hidden": false }, 28 | { "type": "style", "section": "Code Style", "hidden": false }, 29 | { "type": "test", "section": "Tests", "hidden": false } 30 | ] 31 | } 32 | }], 33 | ["@semantic-release/github", { 34 | "successComment": false, 35 | "failComment": false 36 | }] 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /.semantic.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["@semantic-release/commit-analyzer", { 4 | "preset": "conventionalcommits", 5 | "releaseRules": [ 6 | { "breaking": true, "release": "major" }, 7 | { "revert": true, "release": "patch" }, 8 | { "type": "build", "release": "patch" }, 9 | { "type": "docs", "release": "patch" }, 10 | { "type": "feat", "release": "minor" }, 11 | { "type": "fix", "release": "patch" }, 12 | { "type": "perf", "release": "patch" }, 13 | { "type": "refactor", "release": "patch" } 14 | ] 15 | }], 16 | ["@semantic-release/release-notes-generator", { 17 | "preset": "conventionalcommits", 18 | "presetConfig": { 19 | "types": [ 20 | { "type": "chore", "section": "Chores", "hidden": true }, 21 | { "type": "build", "section": "Build", "hidden": false }, 22 | { "type": "ci", "section": "CI/CD", "hidden": false }, 23 | { "type": "docs", "section": "Docs", "hidden": false }, 24 | { "type": "feat", "section": "Features", "hidden": false }, 25 | { "type": "fix", "section": "Bug Fixes", "hidden": false }, 26 | { "type": "perf", "section": "Performance", "hidden": false }, 27 | { "type": "refactor", "section": "Refactor", "hidden": false }, 28 | { "type": "style", "section": "Code Style", "hidden": false }, 29 | { "type": "test", "section": "Tests", "hidden": false } 30 | ] 31 | } 32 | }], 33 | ["@semantic-release/github", { 34 | "successComment": false, 35 | "failComment": false 36 | }], 37 | "@semantic-release/npm" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const pug = require('pug') 2 | const path = require('path') 3 | 4 | module.exports = function ({ locals = {}, filters = {}, useMetadata = false } = {}) { 5 | const opts = arguments[0] || {} 6 | 7 | return (files, metalsmith, done) => { 8 | setImmediate(done) 9 | 10 | // extend with metalsmith global metadata 11 | if (useMetadata) { 12 | locals = Object.assign({}, locals, metalsmith.metadata()) 13 | } 14 | 15 | Object.keys(files).forEach((file) => { 16 | if (!/\.(pug|jade)/.test(path.extname(file))) { 17 | return 18 | } 19 | 20 | const data = files[file] 21 | const dir = path.dirname(file) 22 | let name = path.basename(file, path.extname(file)) 23 | 24 | // do we need to add an extension? 25 | if (path.extname(name) === '') { 26 | name = path.basename(file, path.extname(file)) + '.html' 27 | } 28 | 29 | if (dir !== '.') { 30 | name = `${dir}/${name}` 31 | } 32 | 33 | const filename = path.join(metalsmith.source(), file) 34 | 35 | // also use the file's own data 36 | if (useMetadata) { 37 | locals = Object.assign(locals, data) 38 | } 39 | 40 | // assign filters 41 | /* istanbul ignore else */ 42 | if (filters) { 43 | Object.keys(filters).forEach((filter) => (pug.filters[filter] = filters[filter])) 44 | } 45 | 46 | const options = Object.assign(opts, { 47 | filename, 48 | locals 49 | }) 50 | 51 | // render 52 | const str = pug.compile(data.contents.toString(), options)(locals) 53 | 54 | // convert to a buffer 55 | data.contents = Buffer.from(str) 56 | 57 | // remove from global files object 58 | delete files[file] 59 | 60 | // assign the newly created file 61 | files[name] = data 62 | }) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Install 3 | 4 | ```bash 5 | npm install metalsmith-pug 6 | ``` 7 | 8 | ## Usage 9 | 10 | I recommend using an optimized build matching your Node.js environment version, otherwise, the standard `require` would work just fine with any version of Node `>= v4.0` . 11 | 12 | ```js 13 | /* 14 | * Node 7 15 | */ 16 | const metalsmith-jade = require('metalsmith-jade/lib/node7') 17 | 18 | /* 19 | * Node 6 20 | */ 21 | const metalsmith-jade = require('metalsmith-jade/lib/node6') 22 | 23 | /* 24 | * Node 4 (Default) 25 | * Note: additional ES2015 polyfills may be required 26 | */ 27 | var metalsmith-jade = require('metalsmith-jade') 28 | ``` 29 | 30 | ## API 31 | 32 | Pass `options` to the pug plugin and pass it to Metalsmith with the `use` method: 33 | 34 | ```js 35 | import Metalsmith from 'metalsmith' 36 | import pug from 'metalsmith-pug' 37 | 38 | const options = { 39 | pretty: false, 40 | 41 | locals: { 42 | postName: 'good post name' 43 | }, 44 | 45 | filters: { 46 | foo: block => block.replace('foo', 'bar') 47 | } 48 | } 49 | 50 | new Metalsmith(__dirname) 51 | .use(pug(options)) 52 | ``` 53 | 54 | ## CLI 55 | 56 | You can also use the plugin with the Metalsmith CLI by adding a key to your `metalsmith.json` file: 57 | 58 | ```json 59 | { 60 | "plugins": { 61 | "metalsmith-pug": { 62 | "pretty": false 63 | } 64 | } 65 | } 66 | ``` 67 | 68 | All options are passed directly to pug. If `options` has a `locals` key, that will be passed along to pug. 69 | 70 | ## Options 71 | 72 | any of the `options` parameters for [`pug`](http://jade-lang.com/api/) with the additional plugin specific properties below: 73 | 74 | | Name | Type | Required | Default | Details | 75 | | ----------------- | --------- | -------- | ------- | ------------------------------------------------------- | 76 | | **`useMetadata`** | `Boolean` | ❌ | `false` | Expose Metalsmith's global metadata to the pug template | 77 | | **`locals`** | `Object` | ❌ | `{}` | Pass additional locals to the template | 78 | | **`filters`** | `Object` | ❌ | `{}` | register functions to be used as template filters | 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Metalsmith Pug 2 | 3 | Metalsmith plugin to convert pug files 4 | 5 | [![license][license-img]][license-url] 6 | [![release][release-img]][release-url] 7 | [![semantic][semantic-img]][semantic-url] 8 | 9 | ## Install 10 | 11 | ``` bash 12 | npm install metalsmith-pug 13 | ``` 14 | 15 | ## Usage 16 | 17 | I recommend using an optimized build matching your Node.js environment version, otherwise, the standard `require` would work just fine with any version of Node `>= v4.0` . 18 | 19 | ``` js 20 | /* 21 | * Node 7 22 | */ 23 | const metalsmith-jade = require('metalsmith-jade/lib/node7') 24 | 25 | /* 26 | * Node 6 27 | */ 28 | const metalsmith-jade = require('metalsmith-jade/lib/node6') 29 | 30 | /* 31 | * Node 4 (Default) 32 | * Note: additional ES2015 polyfills may be required 33 | */ 34 | var metalsmith-jade = require('metalsmith-jade') 35 | ``` 36 | 37 | ## API 38 | 39 | Pass `options` to the pug plugin and pass it to Metalsmith with the `use` method: 40 | 41 | ``` js 42 | import Metalsmith from 'metalsmith' 43 | import pug from 'metalsmith-pug' 44 | 45 | const options = { 46 | pretty: false, 47 | 48 | locals: { 49 | postName: 'good post name' 50 | }, 51 | 52 | filters: { 53 | foo: block => block.replace('foo', 'bar') 54 | } 55 | } 56 | 57 | new Metalsmith(__dirname) 58 | .use(pug(options)) 59 | ``` 60 | 61 | ## CLI 62 | 63 | You can also use the plugin with the Metalsmith CLI by adding a key to your `metalsmith.json` file: 64 | 65 | ``` json 66 | { 67 | "plugins": { 68 | "metalsmith-pug": { 69 | "pretty": false 70 | } 71 | } 72 | } 73 | ``` 74 | 75 | All options are passed directly to pug. If `options` has a `locals` key, that will be passed along to pug. 76 | 77 | ## Options 78 | 79 | any of the `options` parameters for [`pug`][] with the additional plugin specific properties below: 80 | 81 | | Name | Type | Required | Default | Details | 82 | |-------------------|-----------|----------|---------|---------------------------------------------------------| 83 | | **`useMetadata`** | `Boolean` | ❌ | `false` | Expose Metalsmith's global metadata to the pug template | 84 | | **`locals`** | `Object` | ❌ | `{}` | Pass additional locals to the template | 85 | | **`filters`** | `Object` | ❌ | `{}` | register functions to be used as template filters | 86 | 87 | [`pug`]: http://jade-lang.com/api/ 88 | 89 | ---- 90 | > Author: [Ahmad Nassri](https://www.ahmadnassri.com/) • 91 | > Twitter: [@AhmadNassri](https://twitter.com/AhmadNassri) 92 | 93 | [license-url]: LICENSE 94 | [license-img]: https://badgen.net/github/license/ahmadnassri/node-metalsmith-pug 95 | 96 | [release-url]: https://github.com/ahmadnassri/node-metalsmith-pug/releases 97 | [release-img]: https://badgen.net/github/release/ahmadnassri/node-metalsmith-pug 98 | 99 | [semantic-url]: https://github.com/ahmadnassri/node-metalsmith-pug/actions?query=workflow%3Arelease 100 | [semantic-img]: https://badgen.net/badge/📦/semantically%20released/blue 101 | -------------------------------------------------------------------------------- /.github/linters/.markdown-lint.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- # 2 | # Note: this file originates in template-template # 3 | # ----------------------------------------------- # 4 | 5 | # Heading levels should only increment by one level at a time 6 | MD001: false 7 | 8 | # Heading style 9 | MD003: 10 | style: atx 11 | 12 | # Unordered list style 13 | MD004: 14 | style: dash 15 | 16 | # Inconsistent indentation for list items at the same level 17 | MD005: true 18 | 19 | # Unordered list indentation 20 | MD007: 21 | indent: 2 22 | start_indented: false 23 | 24 | # Trailing spaces 25 | MD009: 26 | br_spaces: 2 27 | list_item_empty_lines: false 28 | strict: false 29 | 30 | # Hard tabs 31 | MD010: 32 | code_blocks: false 33 | 34 | # Reversed link syntax 35 | MD011: true 36 | 37 | # Multiple consecutive blank lines 38 | MD012: 39 | maximum: 1 40 | 41 | # Line length 42 | MD013: 43 | line_length: 360 44 | strict: true 45 | stern: true 46 | 47 | # Dollar signs used before commands without showing output 48 | MD014: false 49 | 50 | # No space after hash on atx style heading 51 | MD018: true 52 | 53 | # Multiple spaces after hash on atx style heading 54 | MD019: true 55 | 56 | # No space inside hashes on closed atx style heading 57 | MD020: true 58 | 59 | # Multiple spaces inside hashes on closed atx style heading 60 | MD021: true 61 | 62 | # Headings should be surrounded by blank lines 63 | MD022: 64 | lines_above: 1 65 | lines_below: 1 66 | 67 | # Headings must start at the beginning of the line 68 | MD023: true 69 | 70 | # Multiple headings with the same content 71 | MD024: 72 | allow_different_nesting: true 73 | 74 | # Multiple top level headings in the same document 75 | MD025: true 76 | 77 | # Trailing punctuation in heading 78 | MD026: 79 | punctuation: ".,;:!?。,;:!?" 80 | 81 | # Multiple spaces after blockquote symbol 82 | MD027: true 83 | 84 | # Blank line inside blockquote 85 | MD028: true 86 | 87 | # Ordered list item prefix 88 | MD029: 89 | style: one_or_ordered 90 | 91 | # Spaces after list markers 92 | MD030: 93 | ul_single: 1 94 | ol_single: 1 95 | ul_multi: 1 96 | ol_multi: 1 97 | 98 | # Fenced code blocks should be surrounded by blank lines 99 | MD031: 100 | list_items: true 101 | 102 | # Lists should be surrounded by blank lines 103 | MD032: true 104 | 105 | # inline HTML 106 | MD033: 107 | allowed_elements: [details, summary] 108 | 109 | # Bare URL used 110 | MD034: true 111 | 112 | # Horizontal rule style 113 | MD035: 114 | style: "----" 115 | 116 | # Emphasis used instead of a heading 117 | MD036: 118 | punctuation: ".,;:!?。,;:!?" 119 | 120 | # Spaces inside emphasis markers 121 | MD037: true 122 | 123 | # Spaces inside code span elements 124 | MD038: true 125 | 126 | # Spaces inside link text 127 | MD039: true 128 | 129 | # Fenced code blocks should have a language specified 130 | MD040: true 131 | 132 | # First line in file should be a top level heading 133 | MD041: false 134 | 135 | # No empty links 136 | MD042: true 137 | 138 | # Required heading structure 139 | MD043: false 140 | 141 | # Proper names should have the correct capitalization 142 | MD044: false 143 | 144 | # Images should have alternate text (alt text) 145 | MD045: false 146 | 147 | # Code block style 148 | MD046: 149 | style: fenced 150 | 151 | # Files should end with a single newline character 152 | MD047: true 153 | 154 | # Code fence style 155 | MD048: 156 | style: backtick 157 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | const { exists, readFile } = require('node:fs') 2 | const { join } = require('node:path') 3 | 4 | const Metalsmith = require('metalsmith') 5 | const rimraf = require('rimraf') 6 | const { test, afterEach } = require('tap') 7 | 8 | const pug = require('../src') 9 | 10 | const fixtures = join(__dirname, '/fixtures') 11 | 12 | afterEach(() => rimraf(fixtures + '/*/build', () => {})) 13 | 14 | test('should render html', (assert) => { 15 | assert.plan(2) 16 | 17 | const smith = new Metalsmith('test/fixtures/main') 18 | 19 | smith.use(pug()) 20 | 21 | smith.build((err) => { 22 | assert.equal(err, null) 23 | exists(join(fixtures, 'main/build/index.html'), (exists) => assert.ok(exists)) 24 | }) 25 | }) 26 | 27 | test('should support .jade files', (assert) => { 28 | assert.plan(2) 29 | 30 | const smith = new Metalsmith('test/fixtures/main') 31 | 32 | smith.use(pug()) 33 | 34 | smith.build((err) => { 35 | assert.equal(err, null) 36 | 37 | exists('test/fixtures/main/build/legacy.html', (exists) => assert.ok(exists)) 38 | }) 39 | }) 40 | 41 | test('should pass options to pug', (assert) => { 42 | assert.plan(3) 43 | 44 | const smith = new Metalsmith('test/fixtures/main') 45 | 46 | smith.use(pug({ pretty: true })) 47 | 48 | smith.build((err) => { 49 | assert.equal(err, null) 50 | 51 | readFile('test/fixtures/main/build/pretty.html', (err, data) => { 52 | assert.equal(err, null) 53 | assert.equal(data.toString(), '\n
\n

Hello

\n
') 54 | }) 55 | }) 56 | }) 57 | 58 | test('should render files within directories', (assert) => { 59 | assert.plan(2) 60 | 61 | const smith = new Metalsmith('test/fixtures/main') 62 | 63 | smith.use(pug()) 64 | 65 | smith.build((err) => { 66 | assert.equal(err, null) 67 | 68 | exists('test/fixtures/main/build/dir/test.html', (exists) => assert.ok(exists)) 69 | }) 70 | }) 71 | 72 | test('should render html with locals', (assert) => { 73 | assert.plan(3) 74 | 75 | const smith = new Metalsmith('test/fixtures/main') 76 | const locals = { 77 | title: 'Foo' 78 | } 79 | 80 | smith.use(pug({ locals })) 81 | 82 | smith.build((err) => { 83 | assert.equal(err, null) 84 | 85 | readFile('test/fixtures/main/build/locals.html', (err, data) => { 86 | assert.equal(err, null) 87 | assert.equal(data.toString(), '

Foo

') 88 | }) 89 | }) 90 | }) 91 | 92 | test('should use Metalsmith.metadata()', (assert) => { 93 | assert.plan(3) 94 | 95 | const smith = new Metalsmith('test/fixtures/main') 96 | 97 | smith.metadata({ foo: 'bar' }) 98 | smith.use(pug({ useMetadata: true })) 99 | 100 | smith.build((err) => { 101 | assert.equal(err, null) 102 | 103 | readFile('test/fixtures/main/build/metadata.html', (err, data) => { 104 | assert.equal(err, null) 105 | assert.equal(data.toString(), '

bar

') 106 | }) 107 | }) 108 | }) 109 | 110 | test('should use extension prefix as extension', (assert) => { 111 | assert.plan(4) 112 | 113 | const smith = new Metalsmith('test/fixtures/main') 114 | const locals = { 115 | foo: 'bar' 116 | } 117 | 118 | smith.use(pug({ locals })) 119 | 120 | smith.build((err) => { 121 | assert.equal(err, null) 122 | 123 | exists('test/fixtures/main/build/text.txt', (exists) => { 124 | assert.ok(exists) 125 | 126 | readFile('test/fixtures/main/build/text.txt', (err, data) => { 127 | assert.equal(err, null) 128 | assert.equal(data.toString(), 'bar') 129 | }) 130 | }) 131 | }) 132 | }) 133 | 134 | test('should not run on none .pug files', (assert) => { 135 | assert.plan(2) 136 | 137 | const smith = new Metalsmith('test/fixtures/main') 138 | 139 | smith.use(pug()) 140 | 141 | smith.build((err) => { 142 | assert.equal(err, null) 143 | 144 | exists('test/fixtures/main/file.html', (exists) => assert.notOk(exists)) 145 | }) 146 | }) 147 | 148 | test('should register pug filters', (assert) => { 149 | assert.plan(3) 150 | 151 | const smith = new Metalsmith('test/fixtures/filters') 152 | 153 | smith.use(pug({ 154 | filters: { foo: block => block } 155 | })) 156 | 157 | smith.build((err) => { 158 | assert.equal(err, null) 159 | 160 | readFile('test/fixtures/filters/build/test.html', (err, data) => { 161 | assert.equal(err, null) 162 | assert.equal(data.toString(), 'bar') 163 | }) 164 | }) 165 | }) 166 | --------------------------------------------------------------------------------