@webdiscus/pug-loader
Advanced tools
Comparing version 2.1.1 to 2.2.0
# Change log | ||
## 2.2.0 (2022-05-15) | ||
- feat: add embedded filters `:code`, `:highlight` | ||
- fix: added `&` and `"` chars in `:escape` filter | ||
## 2.1.1 (2022-05-11) | ||
@@ -4,0 +9,0 @@ |
{ | ||
"name": "@webdiscus/pug-loader", | ||
"version": "2.1.1", | ||
"version": "2.2.0", | ||
"description": "Pug loader resolves paths and webpack aliases in a pug template and compiles it to HTML or into a template function.", | ||
@@ -69,2 +69,3 @@ "keywords": [ | ||
"ansis": "^1.3.6", | ||
"parse5": "^7.0.0", | ||
"pug": ">=3.0.2", | ||
@@ -74,5 +75,5 @@ "webpack-merge": "^5.8.0" | ||
"devDependencies": { | ||
"@babel/core": "^7.17.10", | ||
"@babel/preset-env": "^7.17.10", | ||
"@types/jest": "^27.5.0", | ||
"@babel/core": "^7.17.12", | ||
"@babel/preset-env": "^7.17.12", | ||
"@types/jest": "^27.5.1", | ||
"css-loader": "^6.7.1", | ||
@@ -83,3 +84,4 @@ "html-loader": "^3.1.0", | ||
"prettier": "^2.6.2", | ||
"pug-plugin": "^2.3.0", | ||
"prismjs": "^1.28.0", | ||
"pug-plugin": "^2.3.1", | ||
"rimraf": "^3.0.2", | ||
@@ -86,0 +88,0 @@ "tsconfig-paths-webpack-plugin": "^3.5.2", |
163
README.md
@@ -43,13 +43,18 @@ <div align="center"> | ||
1. [Install and Quick start](#install-and-quick-start) | ||
1. [Options](#options) | ||
1. [Embedded filters](#embed-filters) | ||
1. [Usage method `compile`](#method-compile) | ||
1. [Usage method `render`](#method-render) | ||
1. [Usage method `html`](#method-html) | ||
1. [Passing data into pug template](#passing-data-into-template) | ||
1. [Usage embedded resources](#usage-embedded-resources) | ||
1. [Usage with Angular Component](#usage-with-angular-component) | ||
1. [Recipes](#recipes) | ||
1. [Example "Hello World!"](https://github.com/webdiscus/pug-loader/tree/master/examples/webpack-app-hello-pug/) | ||
1. [More examples](https://github.com/webdiscus/pug-loader/tree/master/test/cases) | ||
2. [Options](#options) | ||
3. [Embedded Pug filters](#embed-filters) | ||
- [:escape](#filter-escape) | ||
- [:code](#filter-code) | ||
- [:highlight](#filter-highlight) | ||
4. [Usage of pug-loader methods](#method-compile) | ||
- [compile](#method-compile) | ||
- [render](#method-render) | ||
- [html](#method-html) | ||
5. [Passing data into pug template](#passing-data-into-template) | ||
6. [Usage embedded resources](#usage-embedded-resources) | ||
7. [Usage with Angular Component](#usage-with-angular-component) | ||
8. [Recipes](#recipes) | ||
9. [Example Hello World!](https://github.com/webdiscus/pug-loader/tree/master/examples/hello-world-app/) | ||
9. [Example of using Pug filters](https://github.com/webdiscus/pug-loader/tree/master/examples/pug-filters) | ||
10. [More examples](https://github.com/webdiscus/pug-loader/tree/master/test/cases) | ||
@@ -66,5 +71,5 @@ <a id="features" name="features" href="#features"></a> | ||
- resolves required images in the attribute `srcset` of `img` tag | ||
- has embedded filters, e.g `:escape` | ||
- resolves required JavaScript modules or JSON in pug | ||
- ignore the prefixes `~` `@` for webpack `resolve.alias` | ||
- embedded Pug filters: `:escape` `:code` `:highlight` | ||
- passing custom data into pug template | ||
@@ -304,3 +309,3 @@ - watching of changes in all dependencies | ||
Enable embedded pug filters. | ||
To enable a filter add to pug-loader options following: | ||
To enable a filter, add the following to the pug-loader options: | ||
```js | ||
@@ -325,15 +330,12 @@ { | ||
> 💡 We have currently only one embedded filter, but other useful filters will occasionally be added. | ||
> | ||
> The goal of the embedded filters is use fast and lightweight filters without additional dependencies in package.json. | ||
> Here we want collect most useful small filters. | ||
> It is like [custom filters](https://pugjs.org/language/filters.html#custom-filters), but already exists in the [filter collection](https://github.com/webdiscus/pug-loader/tree/master/src/filters), that can be simply via an option enabled. | ||
> | ||
> In issues, you can suggest your own filter, and we can add it. | ||
> 💡 The goal of the embedded filters is use fast and lightweight filters without additional dependencies in package.json. | ||
> Here we want to collect most useful small filters. | ||
> It is like [custom filters](https://pugjs.org/langucage/filters.html#custom-filters), but already exists in the [filter collection](https://github.com/webdiscus/pug-loader/tree/master/src/filters), that can be simply via an option enabled.\ | ||
> The complete usage cases with more information you can see on the GitHub Page [pug filter examples](https://webdiscus.github.io/pug-loader/) and in the [sources](https://github.com/webdiscus/pug-loader/tree/master/examples/pug-filters) of these examples. | ||
### `escape` | ||
Pug filter: `:escape` Filter options: `none`\ | ||
The filter escapes HTML tags to display HTML code in the browser as plain text. | ||
This is useful when using syntax highlighting for code containing HTML tags. | ||
<a id="filter-escape" name="filter-escape" href="#filter-escape"></a> | ||
### `:escape` | ||
The `:escape` filter replaces reserved HTML characters with their corresponding HTML entities to display these characters as text. | ||
Filter options: `none`. | ||
@@ -344,6 +346,11 @@ Enable the filter: | ||
{ | ||
embedFilters: { | ||
escape: true, | ||
test: /\.pug$/, | ||
loader: '@webdiscus/pug-loader', | ||
options: { | ||
// enable embedded filters | ||
embedFilters: { | ||
escape: true, // enable the :escape filter | ||
}, | ||
}, | ||
} | ||
}, | ||
``` | ||
@@ -353,20 +360,16 @@ | ||
```pug | ||
```html | ||
pre: code.language-html | ||
:escape | ||
<!-- HTML --> | ||
<div> | ||
<p>Text</p> | ||
</div> | ||
<h1>Header</h1> | ||
<p>Text</p> | ||
``` | ||
Generates plain text: | ||
Generated HTML: | ||
``` | ||
```html | ||
<pre> | ||
<code class="language-html"> | ||
<!-- HTML --> | ||
<div> | ||
<p>Text</p> | ||
</div> | ||
<h1>Header</h1> | ||
<p>Text</p> | ||
</code> | ||
@@ -376,32 +379,74 @@ </pre> | ||
Display in browser: | ||
Inline syntax: | ||
```html | ||
p. | ||
The #[:escape <html>] element is the root element.<br> | ||
Inside the #[:escape <html>] element there is a #[:escape <body>] element. | ||
``` | ||
Generated HTML: | ||
```html | ||
<!-- HTML --> | ||
<div> | ||
<p>Text</p> | ||
</div> | ||
<p>The <html> element is the root element.<br> | ||
Inside the <html> element there is a <body> element.</p> | ||
``` | ||
Inline syntax: | ||
> For more examples and info, see [pug filter :escape](https://webdiscus.github.io/pug-loader/escape.html). | ||
<a id="filter-code" name="filter-code" href="#filter-code"></a> | ||
### `:code` | ||
The `:code` filter wraps a content with the `<code>` tag. | ||
Filter options: | ||
- `className {string}` The class name of the `code` tag. For example, the `prismjs` use the `language-*` as class name in `<code>` for styling this tag. | ||
Enable the filter: | ||
```js | ||
{ | ||
test: /\.pug$/, | ||
loader: '@webdiscus/pug-loader', | ||
options: { | ||
// enable embedded filters | ||
embedFilters: { | ||
// enable the :code filter | ||
code: { | ||
className: 'language-', // class name of `<code>` tag, needed for `prismjs` theme | ||
}, | ||
}, | ||
}, | ||
}, | ||
``` | ||
p | ||
:escape The <strong> element has the closing </strong> tag. | ||
p. | ||
The #[:escape <html>] element is the root element.<br> | ||
Inside the #[:escape <html>] element there is a #[:escape <body>] element. | ||
> For more examples and info, see [pug filter :code](https://webdiscus.github.io/pug-loader/code.html). | ||
<a id="filter-highlight" name="filter-highlight" href="#filter-highlight"></a> | ||
### `:highlight` | ||
The `:highlight` filter highlights code syntax. | ||
Filter options: | ||
- `verbose {boolean}` Enable output process info in console. | ||
- `use {string}]` The name of a highlighting npm module. The module must be installed. Currently, is supported the [prismjs](https://prismjs.com) only. | ||
Enable the filter: | ||
```js | ||
{ | ||
embedFilters: { | ||
highlight: { | ||
verbose: true, | ||
use: 'prismjs', | ||
}, | ||
}, | ||
} | ||
``` | ||
Generates plain text: | ||
Usage example: | ||
```pug | ||
pre.language-: code | ||
:highlight(html) | ||
<!-- Comment --> | ||
<h1>Header</h1> | ||
<p>Text</p> | ||
``` | ||
<p> | ||
The <strong> element has the closing </strong> tag. | ||
</p> | ||
<p> | ||
The <html> element is the root element. | ||
<br> | ||
Inside the <html> element there is a <body> element. | ||
</p> | ||
``` | ||
> For more examples and info, see [pug filter :highlight](https://webdiscus.github.io/pug-loader/highlight.html). | ||
@@ -408,0 +453,0 @@ <a id="method-compile" name="method-compile" href="#method-compile"></a> |
@@ -20,3 +20,3 @@ const ansis = require('ansis'); | ||
*/ | ||
const PugLoaderError = function(message, error = '') { | ||
const PugLoaderError = function (message, error = '') { | ||
if (error && error instanceof PugLoaderException) { | ||
@@ -43,5 +43,4 @@ if (error.toString() === lastError) { | ||
const message = | ||
`${ansisLoaderName} the file ${ansis.yellow( | ||
file, | ||
)} can't be resolved in the pug template:\n` + ansis.cyan(templateFile); | ||
`${ansisLoaderName} the file ${ansis.yellow(file)} can't be resolved in the pug template:\n` + | ||
ansis.cyan(templateFile); | ||
@@ -59,6 +58,6 @@ PugLoaderError(message, error); | ||
`${ansisLoaderName} the expression ${ansis.yellow( | ||
value, | ||
value | ||
)} can't be interpolated with the 'compile' method in the pug template: ${ansis.cyan(templateFile)}\n` + | ||
`${ansis.yellow( | ||
'Possible solution: ', | ||
'Possible solution: ' | ||
)} Try to use the loader option 'method' as 'render' or change your dynamic filename to static or use webpack alias instead of alias from tsconfig.`; | ||
@@ -82,3 +81,3 @@ | ||
`then pass it into pug ${ansis.magenta( | ||
`'template.pug?customData=' + JSON.stringify({options:{title:'My title'}})`, | ||
`'template.pug?customData=' + JSON.stringify({options:{title:'My title'}})` | ||
)}`; | ||
@@ -95,4 +94,4 @@ | ||
const filterNotFoundException = (filterName, availableFilters) => { | ||
const message = `${ansisLoaderName} The 'embedFilters' option contains unknown filter name: ${ansis.red( | ||
filterName)}.\n` + | ||
const message = | ||
`${ansisLoaderName} The 'embedFilters' option contains unknown filter: ${ansis.red(filterName)}.\n` + | ||
`Available embedded filters: ${ansis.green(availableFilters)}.`; | ||
@@ -104,2 +103,26 @@ | ||
/** | ||
* @param {string} filterName | ||
* @param {string} filterPath | ||
* @param {Error} error | ||
*/ | ||
const filterLoadException = (filterName, filterPath, error) => { | ||
const message = | ||
`${ansisLoaderName} Error by load the ${ansis.red(filterName)} filter.\n` + | ||
`Filter file: ${ansis.cyan(filterPath)}\n` + | ||
error; | ||
PugLoaderError(message); | ||
}; | ||
/** | ||
* @param {string} filterName | ||
* @param {Error} error | ||
*/ | ||
const filterInitException = (filterName, error) => { | ||
const message = `${ansisLoaderName} Error by initialisation the ${ansis.red(filterName)} filter.\n` + error; | ||
PugLoaderError(message); | ||
}; | ||
/** | ||
* @param {string} error | ||
@@ -117,4 +140,6 @@ * @returns {string} | ||
executeTemplateFunctionException, | ||
getPugCompileErrorMessage, | ||
filterNotFoundException, | ||
getPugCompileErrorMessage, | ||
filterLoadException, | ||
filterInitException, | ||
}; |
/** | ||
* The filter `:escape` escapes HTML tags in pug. | ||
* The `:escape` filter replaces reserved HTML characters with their corresponding HTML entities. | ||
* @see https://developer.mozilla.org/en-US/docs/Glossary/Entity | ||
* | ||
* Note: the filename w/o ext is the filter name. | ||
* Block syntax: | ||
* | ||
* Usage: | ||
* pre: code | ||
* :escape | ||
* <div> | ||
* <a href="home.html">Home</a> | ||
* </div> | ||
* | ||
* pre: code | ||
* :escape | ||
* <a href="home.html">Home</a> | ||
* Inline syntax: | ||
* | ||
* The #[:escape <div>] tag. | ||
*/ | ||
// Add the filter `escape` in the options of pug loader: | ||
// To enable the filter add to `@webdiscus/pug-loader` options the following: | ||
// { | ||
@@ -24,4 +29,18 @@ // test: /\.pug$/, | ||
module.exports = function escape(text, options) { | ||
return text.replace(/</g, '<').replace(/>/g, '>'); | ||
const reservedChars = /[&<>"]/g; | ||
const charReplacements = { | ||
'&': '&', | ||
'<': '<', | ||
'>': '>', | ||
'"': '"', | ||
}; | ||
const escape = { | ||
name: 'escape', | ||
apply(text, options) { | ||
return text.replace(reservedChars, (char) => charReplacements[char]); | ||
}, | ||
}; | ||
module.exports = escape; |
@@ -11,3 +11,8 @@ // add polyfill for node.js >= 12.0.0 && < 15.0.0 | ||
const loader = require('./loader'); | ||
const { filterNotFoundException, getPugCompileErrorMessage } = require('./exeptions'); | ||
const { | ||
filterNotFoundException, | ||
filterLoadException, | ||
filterInitException, | ||
getPugCompileErrorMessage, | ||
} = require('./exeptions'); | ||
@@ -71,2 +76,38 @@ // path of embedded pug-loader filters | ||
/** | ||
* Load embedded pug filters. | ||
* @param {{filterName: string, options: boolean|string|object}} filters | ||
*/ | ||
const loadFilters = (filters) => { | ||
for (const filterName in filters) { | ||
const options = filters[filterName]; | ||
if (options) { | ||
let filterPath = path.resolve(filtersDir, filterName + '.js'); | ||
let filter; | ||
try { | ||
filter = require(filterPath); | ||
} catch (error) { | ||
if (error.toString().indexOf('Cannot find module') >= 0) { | ||
const entries = fs.readdirSync(filtersDir, { withFileTypes: true }); | ||
const files = entries.filter((file) => !file.isDirectory()).map((file) => path.basename(file.name, '.js')); | ||
filterNotFoundException(filterName, files.join(', ')); | ||
} | ||
filterLoadException(filterName, filterPath, error); | ||
} | ||
try { | ||
// filter module may have the `init(options)` method | ||
if (filter.init != null) { | ||
filter.init(options); | ||
} | ||
// add filter to pug compiler | ||
pug.filters[filterName] = filter.apply.bind(filter); | ||
} catch (error) { | ||
filterInitException(filterName, error); | ||
} | ||
} | ||
} | ||
}; | ||
/** | ||
* @param {string} content The pug template. | ||
@@ -76,3 +117,3 @@ * @param {function(error: string|null, result: string?)?} callback The asynchronous callback function. | ||
*/ | ||
const compile = function(content, callback) { | ||
const compile = function (content, callback) { | ||
const loaderContext = this; | ||
@@ -85,22 +126,4 @@ const loaderOptions = loaderContext.getOptions() || {}; | ||
if (!loaderOptions.name) loaderOptions.name = 'template'; | ||
if (loaderOptions.embedFilters) loadFilters(loaderOptions.embedFilters); | ||
// embedded pug-loader filters | ||
if (loaderOptions.embedFilters) { | ||
for (const filterName in loaderOptions.embedFilters) { | ||
const filterOptions = loaderOptions.embedFilters[filterName]; | ||
// TODO: if filterOptions is a object then add it to loaderOptions.filterOptions by filterName | ||
if (filterOptions) { | ||
let filterPath = path.resolve(filtersDir, filterName + '.js'); | ||
try { | ||
pug.filters[filterName] = require(filterPath); | ||
} catch (error) { | ||
const entries = fs.readdirSync(filtersDir, { withFileTypes: true }); | ||
const files = entries.filter((file) => !file.isDirectory()).map((file) => path.basename(file.name, '.js')); | ||
filterNotFoundException(filterName, files.join(', ')); | ||
} | ||
} | ||
} | ||
} | ||
const compilerOptions = { | ||
@@ -168,3 +191,2 @@ // used to resolve import/extends and to improve errors | ||
compileResult = pug.compileClientWithDependenciesTracked(content, compilerOptions); | ||
} catch (error) { | ||
@@ -203,3 +225,3 @@ // watch files in which an error occurred | ||
const pluginData = plugins.find( | ||
(item) => item.constructor.name === 'HtmlWebpackPlugin' && item.options.template.indexOf(filename) >= 0, | ||
(item) => item.constructor.name === 'HtmlWebpackPlugin' && item.options.template.indexOf(filename) >= 0 | ||
); | ||
@@ -219,3 +241,3 @@ | ||
module.exports = function(content, map, meta) { | ||
module.exports = function (content, map, meta) { | ||
const callback = this.async(); | ||
@@ -222,0 +244,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
90583
13
1352
1002
6
13
12
+ Addedparse5@^7.0.0
+ Addedentities@4.5.0(transitive)
+ Addedparse5@7.2.1(transitive)