metalsmith-prism 5.0.4 → 5.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,6 +7,7 @@ A Metalsmith plugin that **adds Prism specific HTML markup** to code sections fo
7
7
  [![license: MIT][license-badge]][license-url]
8
8
  [![coverage][coverage-badge]][coverage-url]
9
9
  [![ESM/CommonJS][modules-badge]][npm-url]
10
+ [![Known Vulnerabilities](https://snyk.io/test/npm/metalsmith-prism/badge.svg)](https://snyk.io/test/npm/metalsmith-prism)
10
11
 
11
12
  ## Dual Module Support (ESM and CommonJS)
12
13
 
@@ -170,26 +171,108 @@ Metalsmith(__dirname).use(
170
171
  );
171
172
  ```
172
173
 
173
- ## Debug
174
+ ## Examples
174
175
 
175
- To enable debug logs, set the `DEBUG` environment variable to `metalsmith-prism`:
176
+ ### Basic Usage
176
177
 
177
- Linux/Mac:
178
+ Transform a simple code block with JavaScript:
178
179
 
179
- ```bash
180
- DEBUG=metalsmith-prism npm test
180
+ **Input HTML:**
181
+
182
+ ```html
183
+ <pre><code class="language-javascript">
184
+ const greeting = 'Hello, World!';
185
+ console.log(greeting);
186
+ </code></pre>
181
187
  ```
182
188
 
183
- Windows:
189
+ **Output HTML (with syntax highlighting):**
184
190
 
185
- ```bash
186
- set "DEBUG=metalsmith-prism" && npm test
191
+ ```html
192
+ <pre class="language-javascript"><code class="language-javascript">
193
+ <span class="token keyword">const</span> greeting <span class="token operator">=</span> <span class="token string">'Hello, World!'</span><span class="token punctuation">;</span>
194
+ console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>greeting<span class="token punctuation">)</span><span class="token punctuation">;</span>
195
+ </code></pre>
196
+ ```
197
+
198
+ ### With Line Numbers
199
+
200
+ Enable line numbers for longer code examples:
201
+
202
+ ```javascript
203
+ metalsmith(__dirname)
204
+ .use(
205
+ prism({
206
+ lineNumbers: true
207
+ })
208
+ )
209
+ .build();
210
+ ```
211
+
212
+ This adds the `line-numbers` class and line number markup to your code blocks.
213
+
214
+ ### Working with Markdown
215
+
216
+ When using with @metalsmith/markdown, code blocks in markdown files are automatically processed:
217
+
218
+ **Markdown file:**
219
+
220
+ ````markdown
221
+ ```python
222
+ def fibonacci(n):
223
+ if n <= 1:
224
+ return n
225
+ return fibonacci(n-1) + fibonacci(n-2)
187
226
  ```
227
+ ````
228
+
229
+ **Build configuration:**
188
230
 
189
- Or use the test:debug script:
231
+ ```javascript
232
+ metalsmith(__dirname)
233
+ .use(markdown())
234
+ .use(
235
+ prism({
236
+ preLoad: ['python'] // Ensure Python support is loaded
237
+ })
238
+ )
239
+ .build();
240
+ ```
241
+
242
+ ### Preloading Languages
243
+
244
+ For better performance with known languages, preload them:
245
+
246
+ ```javascript
247
+ metalsmith(__dirname)
248
+ .use(
249
+ prism({
250
+ preLoad: ['python', 'ruby', 'go', 'rust']
251
+ })
252
+ )
253
+ .build();
254
+ ```
255
+
256
+ ### Handling Special Characters
257
+
258
+ For code with HTML entities, use the decode option:
259
+
260
+ ```javascript
261
+ metalsmith(__dirname)
262
+ .use(
263
+ prism({
264
+ decode: true // Properly handle &lt;, &gt;, &amp; etc.
265
+ })
266
+ )
267
+ .build();
268
+ ```
269
+
270
+ ## Debug
271
+
272
+ To enable debug logs, set the DEBUG environment variable to metalsmith-prism\*:
190
273
 
191
274
  ```bash
192
- npm run test:debug
275
+ metalsmith.env('DEBUG', 'metalsmith-prism*');
193
276
  ```
194
277
 
195
278
  ## CLI Usage
@@ -220,16 +303,12 @@ This project maintains high statement and line coverage for the source code. Cov
220
303
 
221
304
  Code released under [the MIT license](https://github.com/wernerglinka/metalsmith-prism/blob/main/LICENSE).
222
305
 
223
- [coverage-badge]: https://img.shields.io/badge/coverage-94%25-brightgreen
224
- [coverage-url]: #test-coverage
225
- [modules-badge]: https://img.shields.io/badge/modules-ESM%2FCJS-blue
226
- [npm-url]: https://npmjs.org/package/metalsmith-prism
227
- [npm-badge]: https://img.shields.io/npm/v/metalsmith-prism.svg
228
- [npm-url]: https://www.npmjs.com/package/metalsmith-prism
229
306
  [metalsmith-badge]: https://img.shields.io/badge/metalsmith-plugin-green.svg?longCache=true
230
307
  [metalsmith-url]: https://metalsmith.io
308
+ [npm-badge]: https://img.shields.io/npm/v/metalsmith-prism.svg
309
+ [npm-url]: https://www.npmjs.com/package/metalsmith-prism
231
310
  [license-badge]: https://img.shields.io/github/license/wernerglinka/metalsmith-prism
232
311
  [license-url]: LICENSE
233
- [coverage-badge]: https://img.shields.io/badge/test%20coverage-98%25-brightgreen
312
+ [coverage-badge]: https://img.shields.io/badge/test%20coverage-94%25-brightgreen
234
313
  [coverage-url]: #test-coverage
235
314
  [modules-badge]: https://img.shields.io/badge/modules-ESM%2FCJS-blue
package/lib/index.cjs CHANGED
@@ -5,16 +5,12 @@ var path = require('path');
5
5
  var Prism = require('prismjs');
6
6
  var loadLanguages = require('prismjs/components/index.js');
7
7
  var he = require('he');
8
- var debugLib = require('debug');
9
8
 
10
9
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
10
 
12
11
  var Prism__default = /*#__PURE__*/_interopDefaultLegacy(Prism);
13
12
  var loadLanguages__default = /*#__PURE__*/_interopDefaultLegacy(loadLanguages);
14
13
  var he__default = /*#__PURE__*/_interopDefaultLegacy(he);
15
- var debugLib__default = /*#__PURE__*/_interopDefaultLegacy(debugLib);
16
-
17
- const debug = debugLib__default["default"]('metalsmith-prism');
18
14
 
19
15
  // Import languages from Prism's default export
20
16
  const {
@@ -73,72 +69,76 @@ const metalsmithPrism = (options = {}) => {
73
69
  // Track loaded languages to avoid duplicate loading
74
70
  const loadedLanguages = new Set();
75
71
 
76
- // Always load PHP by default
77
- debug('Loading PHP by default');
78
- try {
79
- loadLanguages__default["default"](['php']);
80
- loadedLanguages.add('php');
81
- } catch (e) {
82
- debug('Failed to load PHP:', e);
83
- }
84
- if (opts.preLoad && opts.preLoad.length) {
85
- debug('Preloading languages:', opts.preLoad);
86
- opts.preLoad.forEach(language => {
87
- if (!loadedLanguages.has(language)) {
88
- try {
89
- loadLanguages__default["default"]([language]);
90
- loadedLanguages.add(language);
91
- debug(`Successfully preloaded language: ${language}`);
92
- } catch (e) {
93
- console.warn(`Failed to preload prism syntax: ${language}!`, e);
94
- debug(`Error preloading language ${language}:`, e);
95
- }
96
- } else {
97
- debug(`Language ${language} already loaded, skipping`);
98
- }
99
- });
100
- }
101
-
102
- /**
103
- * Require optional language package
104
- * @param {string} language
105
- * @param {Set} loadedLanguages
106
- */
107
- const requireLanguage = (language, loadedLanguages) => {
108
- if (loadedLanguages.has(language) || languages[language]) {
109
- debug(`Language ${language} already available, skipping load`);
110
- return;
111
- }
112
- debug(`Loading language on-demand: ${language}`);
113
- try {
114
- loadLanguages__default["default"]([language]);
115
- loadedLanguages.add(language);
116
- debug(`Successfully loaded language: ${language}`);
117
- } catch (e) {
118
- console.warn(`Failed to load prism syntax: ${language}!`, e);
119
- debug(`Error loading language ${language}:`, e);
120
- }
121
- };
122
-
123
72
  // Set up line numbers functionality
124
73
  const NEW_LINE_EXP = /\n(?!$)/g;
125
74
  let lineNumbersWrapper;
126
-
127
- // Only set up the hook if line numbers are requested
128
- if (opts.lineNumbers) {
129
- debug('Setting up line numbers hook');
130
- Prism__default["default"].hooks.add('after-tokenize', env => {
131
- const match = env.code.match(NEW_LINE_EXP);
132
- const linesNum = match ? match.length + 1 : 1;
133
- debug(`Counted ${linesNum} lines for line numbers`);
134
- const lines = new Array(linesNum + 1).join('<span></span>');
135
- lineNumbersWrapper = `<span aria-hidden="true" class="line-numbers-rows">${lines}</span>`;
136
- });
137
- }
138
75
  return (files, metalsmith, done) => {
76
+ // Get debug instance from metalsmith
77
+ const debug = metalsmith.debug('metalsmith-prism');
139
78
  debug('Starting metalsmith-prism plugin');
140
79
  debug('Options:', opts);
141
80
 
81
+ // Always load PHP by default
82
+ debug('Loading PHP by default');
83
+ try {
84
+ loadLanguages__default["default"](['php']);
85
+ loadedLanguages.add('php');
86
+ } catch (e) {
87
+ debug('Failed to load PHP:', e);
88
+ }
89
+
90
+ // Preload languages if specified
91
+ if (opts.preLoad && opts.preLoad.length) {
92
+ debug('Preloading languages:', opts.preLoad);
93
+ opts.preLoad.forEach(language => {
94
+ if (!loadedLanguages.has(language)) {
95
+ try {
96
+ loadLanguages__default["default"]([language]);
97
+ loadedLanguages.add(language);
98
+ debug(`Successfully preloaded language: ${language}`);
99
+ } catch (e) {
100
+ console.warn(`Failed to preload prism syntax: ${language}!`, e);
101
+ debug(`Error preloading language ${language}:`, e);
102
+ }
103
+ } else {
104
+ debug(`Language ${language} already loaded, skipping`);
105
+ }
106
+ });
107
+ }
108
+
109
+ /**
110
+ * Require optional language package
111
+ * @param {string} language
112
+ * @param {Set} loadedLanguages
113
+ */
114
+ const requireLanguage = (language, loadedLanguages) => {
115
+ if (loadedLanguages.has(language) || languages[language]) {
116
+ debug(`Language ${language} already available, skipping load`);
117
+ return;
118
+ }
119
+ debug(`Loading language on-demand: ${language}`);
120
+ try {
121
+ loadLanguages__default["default"]([language]);
122
+ loadedLanguages.add(language);
123
+ debug(`Successfully loaded language: ${language}`);
124
+ } catch (e) {
125
+ console.warn(`Failed to load prism syntax: ${language}!`, e);
126
+ debug(`Error loading language ${language}:`, e);
127
+ }
128
+ };
129
+
130
+ // Only set up the hook if line numbers are requested
131
+ if (opts.lineNumbers) {
132
+ debug('Setting up line numbers hook');
133
+ Prism__default["default"].hooks.add('after-tokenize', env => {
134
+ const match = env.code.match(NEW_LINE_EXP);
135
+ const linesNum = match ? match.length + 1 : 1;
136
+ debug(`Counted ${linesNum} lines for line numbers`);
137
+ const lines = new Array(linesNum + 1).join('<span></span>');
138
+ lineNumbersWrapper = `<span aria-hidden="true" class="line-numbers-rows">${lines}</span>`;
139
+ });
140
+ }
141
+
142
142
  // Call done asynchronously to avoid blocking
143
143
  setImmediate(done);
144
144
  try {
@@ -198,7 +198,7 @@ const metalsmithPrism = (options = {}) => {
198
198
  });
199
199
  debug('Completed metalsmith-prism plugin');
200
200
  } catch (error) {
201
- debug('Error in metalsmith-prism plugin:', error);
201
+ debug.error('Error in metalsmith-prism plugin:', error);
202
202
  // We can't call done(error) here because done has already been called
203
203
  console.error('Error processing files:', error);
204
204
  }
package/lib/index.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/index.js"],"sourcesContent":["import { load } from 'cheerio';\nimport { extname } from 'path';\nimport Prism from 'prismjs';\nimport loadLanguages from 'prismjs/components/index.js';\nimport he from 'he';\nimport debugLib from 'debug';\n\nconst debug = debugLib( 'metalsmith-prism' );\n\n// Import languages from Prism's default export\nconst { languages } = Prism;\n\n/**\n * Check if a file is HTML based on its extension\n * @param {string} filePath - Path to the file\n * @returns {boolean} - True if the file has an HTML extension\n */\nconst isHTMLFile = ( filePath ) => {\n const extension = extname( filePath ).toLowerCase();\n return [ '.html', '.htm' ].includes( extension );\n};\n\n/**\n * @typedef Options\n * @property {boolean} [decode=false] - Whether to decode HTML entities\n * @property {boolean} [lineNumbers=false] - Whether to add line numbers\n * @property {string[]} [preLoad=[]] - Languages to preload\n */\n\n/**\n * Metalsmith plugin to highlight code syntax with PrismJS\n *\n * This plugin finds all code blocks in HTML files that have language-* classes\n * and applies Prism.js syntax highlighting to them. It can also add line numbers\n * and handle HTML entity decoding.\n *\n * @param {Options} [options] - Configuration options\n * @param {boolean} [options.decode=false] - Whether to decode HTML entities in code blocks\n * @param {boolean} [options.lineNumbers=false] - Whether to add line numbers to code blocks\n * @param {string[]} [options.preLoad=[]] - Languages to preload before processing\n * @returns {import('metalsmith').Plugin} - A metalsmith plugin function\n * @example\n * // Basic usage\n * metalsmith.use(prism());\n *\n * // With options\n * metalsmith.use(prism({\n * decode: true,\n * lineNumbers: true,\n * preLoad: ['java', 'scala']\n * }));\n */\nconst metalsmithPrism = ( options = {} ) => {\n // Create a new options object with defaults\n const opts = {\n decode: false,\n lineNumbers: false,\n preLoad: [],\n ...options\n };\n\n // Track loaded languages to avoid duplicate loading\n const loadedLanguages = new Set();\n\n // Always load PHP by default\n debug( 'Loading PHP by default' );\n try {\n loadLanguages( [ 'php' ] );\n loadedLanguages.add( 'php' );\n } catch ( e ) {\n debug( 'Failed to load PHP:', e );\n }\n\n if ( opts.preLoad && opts.preLoad.length ) {\n debug( 'Preloading languages:', opts.preLoad );\n opts.preLoad.forEach( ( language ) => {\n if ( !loadedLanguages.has( language ) ) {\n try {\n loadLanguages( [ language ] );\n loadedLanguages.add( language );\n debug( `Successfully preloaded language: ${ language }` );\n } catch ( e ) {\n console.warn( `Failed to preload prism syntax: ${ language }!`, e );\n debug( `Error preloading language ${ language }:`, e );\n }\n } else {\n debug( `Language ${ language } already loaded, skipping` );\n }\n } );\n }\n\n /**\n * Require optional language package\n * @param {string} language\n * @param {Set} loadedLanguages\n */\n const requireLanguage = ( language, loadedLanguages ) => {\n if ( loadedLanguages.has( language ) || languages[ language ] ) {\n debug( `Language ${ language } already available, skipping load` );\n return;\n }\n\n debug( `Loading language on-demand: ${ language }` );\n try {\n loadLanguages( [ language ] );\n loadedLanguages.add( language );\n debug( `Successfully loaded language: ${ language }` );\n } catch ( e ) {\n console.warn( `Failed to load prism syntax: ${ language }!`, e );\n debug( `Error loading language ${ language }:`, e );\n }\n };\n\n // Set up line numbers functionality\n const NEW_LINE_EXP = /\\n(?!$)/g;\n let lineNumbersWrapper;\n\n // Only set up the hook if line numbers are requested\n if ( opts.lineNumbers ) {\n debug( 'Setting up line numbers hook' );\n Prism.hooks.add( 'after-tokenize', ( env ) => {\n const match = env.code.match( NEW_LINE_EXP );\n const linesNum = match ? match.length + 1 : 1;\n debug( `Counted ${ linesNum } lines for line numbers` );\n const lines = new Array( linesNum + 1 ).join( '<span></span>' );\n lineNumbersWrapper = `<span aria-hidden=\"true\" class=\"line-numbers-rows\">${ lines }</span>`;\n } );\n }\n\n return ( files, metalsmith, done ) => {\n debug( 'Starting metalsmith-prism plugin' );\n debug( 'Options:', opts );\n\n // Call done asynchronously to avoid blocking\n setImmediate( done );\n\n try {\n Object.keys( files ).forEach( ( file ) => {\n if ( !isHTMLFile( file ) ) {\n return;\n }\n\n debug( `Processing HTML file: ${ file }` );\n const contents = files[ file ].contents.toString();\n const $ = load( contents, { decodeEntities: false } );\n let highlighted = false;\n const code = $( 'code' );\n\n if ( !code.length ) {\n debug( `No code blocks found in ${ file }` );\n return;\n }\n\n debug( `Found ${ code.length } code blocks in ${ file }` );\n\n code.each( function() {\n const $this = $( this );\n\n const className = $this.attr( 'class' ) || '';\n const targets = className.split( 'language-' );\n let addLineNumbers = false;\n\n if ( targets.length > 1 ) {\n const $pre = $this.parent( 'pre' );\n\n if ( $pre ) {\n // Copy className to <pre> container\n $pre.addClass( className );\n\n if ( opts.lineNumbers ) {\n $pre.addClass( 'line-numbers' );\n addLineNumbers = true;\n debug( 'Adding line numbers' );\n }\n }\n\n highlighted = true;\n let language = targets[ 1 ];\n debug( `Detected language: ${ language }` );\n requireLanguage( language, loadedLanguages );\n\n if ( !languages[ language ] ) {\n debug( `Language ${ language } not available, falling back to markup` );\n language = 'markup';\n }\n\n const html = language === 'markup' && !opts.decode ? $this.html() : he.decode( $this.html() );\n debug( `HTML decoding ${ opts.decode ? 'applied' : 'not applied' } for language ${ language }` );\n\n debug( `Highlighting code with language: ${ language }` );\n const highlightedCode = Prism.highlight( html, languages[ language ] );\n $this.html( addLineNumbers ? highlightedCode + lineNumbersWrapper : highlightedCode );\n }\n } );\n\n if ( highlighted ) {\n debug( `Updating contents of ${ file } with highlighted code` );\n files[ file ].contents = Buffer.from( $.html() );\n } else {\n debug( `No code was highlighted in ${ file }` );\n }\n } );\n\n debug( 'Completed metalsmith-prism plugin' );\n } catch ( error ) {\n debug( 'Error in metalsmith-prism plugin:', error );\n // We can't call done(error) here because done has already been called\n console.error( 'Error processing files:', error );\n }\n };\n};\n\n// ESM export\nexport default metalsmithPrism;\n"],"names":["debug","debugLib","languages","Prism","isHTMLFile","filePath","extension","extname","toLowerCase","includes","metalsmithPrism","options","opts","decode","lineNumbers","preLoad","loadedLanguages","Set","loadLanguages","add","e","length","forEach","language","has","console","warn","requireLanguage","NEW_LINE_EXP","lineNumbersWrapper","hooks","env","match","code","linesNum","lines","Array","join","files","metalsmith","done","setImmediate","Object","keys","file","contents","toString","$","load","decodeEntities","highlighted","each","$this","className","attr","targets","split","addLineNumbers","$pre","parent","addClass","html","he","highlightedCode","highlight","Buffer","from","error"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/index.js"],"sourcesContent":["import { load } from 'cheerio';\nimport { extname } from 'path';\nimport Prism from 'prismjs';\nimport loadLanguages from 'prismjs/components/index.js';\nimport he from 'he';\n\n// Import languages from Prism's default export\nconst { languages } = Prism;\n\n/**\n * Check if a file is HTML based on its extension\n * @param {string} filePath - Path to the file\n * @returns {boolean} - True if the file has an HTML extension\n */\nconst isHTMLFile = (filePath) => {\n const extension = extname(filePath).toLowerCase();\n return ['.html', '.htm'].includes(extension);\n};\n\n/**\n * @typedef Options\n * @property {boolean} [decode=false] - Whether to decode HTML entities\n * @property {boolean} [lineNumbers=false] - Whether to add line numbers\n * @property {string[]} [preLoad=[]] - Languages to preload\n */\n\n/**\n * Metalsmith plugin to highlight code syntax with PrismJS\n *\n * This plugin finds all code blocks in HTML files that have language-* classes\n * and applies Prism.js syntax highlighting to them. It can also add line numbers\n * and handle HTML entity decoding.\n *\n * @param {Options} [options] - Configuration options\n * @param {boolean} [options.decode=false] - Whether to decode HTML entities in code blocks\n * @param {boolean} [options.lineNumbers=false] - Whether to add line numbers to code blocks\n * @param {string[]} [options.preLoad=[]] - Languages to preload before processing\n * @returns {import('metalsmith').Plugin} - A metalsmith plugin function\n * @example\n * // Basic usage\n * metalsmith.use(prism());\n *\n * // With options\n * metalsmith.use(prism({\n * decode: true,\n * lineNumbers: true,\n * preLoad: ['java', 'scala']\n * }));\n */\nconst metalsmithPrism = (options = {}) => {\n // Create a new options object with defaults\n const opts = {\n decode: false,\n lineNumbers: false,\n preLoad: [],\n ...options\n };\n\n // Track loaded languages to avoid duplicate loading\n const loadedLanguages = new Set();\n\n // Set up line numbers functionality\n const NEW_LINE_EXP = /\\n(?!$)/g;\n let lineNumbersWrapper;\n\n return (files, metalsmith, done) => {\n // Get debug instance from metalsmith\n const debug = metalsmith.debug('metalsmith-prism');\n \n debug('Starting metalsmith-prism plugin');\n debug('Options:', opts);\n\n // Always load PHP by default\n debug('Loading PHP by default');\n try {\n loadLanguages(['php']);\n loadedLanguages.add('php');\n } catch (e) {\n debug('Failed to load PHP:', e);\n }\n\n // Preload languages if specified\n if (opts.preLoad && opts.preLoad.length) {\n debug('Preloading languages:', opts.preLoad);\n opts.preLoad.forEach((language) => {\n if (!loadedLanguages.has(language)) {\n try {\n loadLanguages([language]);\n loadedLanguages.add(language);\n debug(`Successfully preloaded language: ${language}`);\n } catch (e) {\n console.warn(`Failed to preload prism syntax: ${language}!`, e);\n debug(`Error preloading language ${language}:`, e);\n }\n } else {\n debug(`Language ${language} already loaded, skipping`);\n }\n });\n }\n\n /**\n * Require optional language package\n * @param {string} language\n * @param {Set} loadedLanguages\n */\n const requireLanguage = (language, loadedLanguages) => {\n if (loadedLanguages.has(language) || languages[language]) {\n debug(`Language ${language} already available, skipping load`);\n return;\n }\n\n debug(`Loading language on-demand: ${language}`);\n try {\n loadLanguages([language]);\n loadedLanguages.add(language);\n debug(`Successfully loaded language: ${language}`);\n } catch (e) {\n console.warn(`Failed to load prism syntax: ${language}!`, e);\n debug(`Error loading language ${language}:`, e);\n }\n };\n\n // Only set up the hook if line numbers are requested\n if (opts.lineNumbers) {\n debug('Setting up line numbers hook');\n Prism.hooks.add('after-tokenize', (env) => {\n const match = env.code.match(NEW_LINE_EXP);\n const linesNum = match ? match.length + 1 : 1;\n debug(`Counted ${linesNum} lines for line numbers`);\n const lines = new Array(linesNum + 1).join('<span></span>');\n lineNumbersWrapper = `<span aria-hidden=\"true\" class=\"line-numbers-rows\">${lines}</span>`;\n });\n }\n\n // Call done asynchronously to avoid blocking\n setImmediate(done);\n\n try {\n Object.keys(files).forEach((file) => {\n if (!isHTMLFile(file)) {\n return;\n }\n\n debug(`Processing HTML file: ${file}`);\n const contents = files[file].contents.toString();\n const $ = load(contents, { decodeEntities: false });\n let highlighted = false;\n const code = $('code');\n\n if (!code.length) {\n debug(`No code blocks found in ${file}`);\n return;\n }\n\n debug(`Found ${code.length} code blocks in ${file}`);\n\n code.each(function () {\n const $this = $(this);\n\n const className = $this.attr('class') || '';\n const targets = className.split('language-');\n let addLineNumbers = false;\n\n if (targets.length > 1) {\n const $pre = $this.parent('pre');\n\n if ($pre) {\n // Copy className to <pre> container\n $pre.addClass(className);\n\n if (opts.lineNumbers) {\n $pre.addClass('line-numbers');\n addLineNumbers = true;\n debug('Adding line numbers');\n }\n }\n\n highlighted = true;\n let language = targets[1];\n debug(`Detected language: ${language}`);\n requireLanguage(language, loadedLanguages);\n\n if (!languages[language]) {\n debug(`Language ${language} not available, falling back to markup`);\n language = 'markup';\n }\n\n const html = language === 'markup' && !opts.decode ? $this.html() : he.decode($this.html());\n debug(`HTML decoding ${opts.decode ? 'applied' : 'not applied'} for language ${language}`);\n\n debug(`Highlighting code with language: ${language}`);\n const highlightedCode = Prism.highlight(html, languages[language]);\n $this.html(addLineNumbers ? highlightedCode + lineNumbersWrapper : highlightedCode);\n }\n });\n\n if (highlighted) {\n debug(`Updating contents of ${file} with highlighted code`);\n files[file].contents = Buffer.from($.html());\n } else {\n debug(`No code was highlighted in ${file}`);\n }\n });\n\n debug('Completed metalsmith-prism plugin');\n } catch (error) {\n debug.error('Error in metalsmith-prism plugin:', error);\n // We can't call done(error) here because done has already been called\n console.error('Error processing files:', error);\n }\n };\n};\n\n// ESM export\nexport default metalsmithPrism;\n"],"names":["languages","Prism","isHTMLFile","filePath","extension","extname","toLowerCase","includes","metalsmithPrism","options","opts","decode","lineNumbers","preLoad","loadedLanguages","Set","NEW_LINE_EXP","lineNumbersWrapper","files","metalsmith","done","debug","loadLanguages","add","e","length","forEach","language","has","console","warn","requireLanguage","hooks","env","match","code","linesNum","lines","Array","join","setImmediate","Object","keys","file","contents","toString","$","load","decodeEntities","highlighted","each","$this","className","attr","targets","split","addLineNumbers","$pre","parent","addClass","html","he","highlightedCode","highlight","Buffer","from","error"],"mappings":"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"}
package/lib/index.js CHANGED
@@ -3,9 +3,6 @@ import { extname } from 'path';
3
3
  import Prism from 'prismjs';
4
4
  import loadLanguages from 'prismjs/components/index.js';
5
5
  import he from 'he';
6
- import debugLib from 'debug';
7
-
8
- const debug = debugLib('metalsmith-prism');
9
6
 
10
7
  // Import languages from Prism's default export
11
8
  const {
@@ -64,72 +61,76 @@ const metalsmithPrism = (options = {}) => {
64
61
  // Track loaded languages to avoid duplicate loading
65
62
  const loadedLanguages = new Set();
66
63
 
67
- // Always load PHP by default
68
- debug('Loading PHP by default');
69
- try {
70
- loadLanguages(['php']);
71
- loadedLanguages.add('php');
72
- } catch (e) {
73
- debug('Failed to load PHP:', e);
74
- }
75
- if (opts.preLoad && opts.preLoad.length) {
76
- debug('Preloading languages:', opts.preLoad);
77
- opts.preLoad.forEach(language => {
78
- if (!loadedLanguages.has(language)) {
79
- try {
80
- loadLanguages([language]);
81
- loadedLanguages.add(language);
82
- debug(`Successfully preloaded language: ${language}`);
83
- } catch (e) {
84
- console.warn(`Failed to preload prism syntax: ${language}!`, e);
85
- debug(`Error preloading language ${language}:`, e);
86
- }
87
- } else {
88
- debug(`Language ${language} already loaded, skipping`);
89
- }
90
- });
91
- }
92
-
93
- /**
94
- * Require optional language package
95
- * @param {string} language
96
- * @param {Set} loadedLanguages
97
- */
98
- const requireLanguage = (language, loadedLanguages) => {
99
- if (loadedLanguages.has(language) || languages[language]) {
100
- debug(`Language ${language} already available, skipping load`);
101
- return;
102
- }
103
- debug(`Loading language on-demand: ${language}`);
104
- try {
105
- loadLanguages([language]);
106
- loadedLanguages.add(language);
107
- debug(`Successfully loaded language: ${language}`);
108
- } catch (e) {
109
- console.warn(`Failed to load prism syntax: ${language}!`, e);
110
- debug(`Error loading language ${language}:`, e);
111
- }
112
- };
113
-
114
64
  // Set up line numbers functionality
115
65
  const NEW_LINE_EXP = /\n(?!$)/g;
116
66
  let lineNumbersWrapper;
117
-
118
- // Only set up the hook if line numbers are requested
119
- if (opts.lineNumbers) {
120
- debug('Setting up line numbers hook');
121
- Prism.hooks.add('after-tokenize', env => {
122
- const match = env.code.match(NEW_LINE_EXP);
123
- const linesNum = match ? match.length + 1 : 1;
124
- debug(`Counted ${linesNum} lines for line numbers`);
125
- const lines = new Array(linesNum + 1).join('<span></span>');
126
- lineNumbersWrapper = `<span aria-hidden="true" class="line-numbers-rows">${lines}</span>`;
127
- });
128
- }
129
67
  return (files, metalsmith, done) => {
68
+ // Get debug instance from metalsmith
69
+ const debug = metalsmith.debug('metalsmith-prism');
130
70
  debug('Starting metalsmith-prism plugin');
131
71
  debug('Options:', opts);
132
72
 
73
+ // Always load PHP by default
74
+ debug('Loading PHP by default');
75
+ try {
76
+ loadLanguages(['php']);
77
+ loadedLanguages.add('php');
78
+ } catch (e) {
79
+ debug('Failed to load PHP:', e);
80
+ }
81
+
82
+ // Preload languages if specified
83
+ if (opts.preLoad && opts.preLoad.length) {
84
+ debug('Preloading languages:', opts.preLoad);
85
+ opts.preLoad.forEach(language => {
86
+ if (!loadedLanguages.has(language)) {
87
+ try {
88
+ loadLanguages([language]);
89
+ loadedLanguages.add(language);
90
+ debug(`Successfully preloaded language: ${language}`);
91
+ } catch (e) {
92
+ console.warn(`Failed to preload prism syntax: ${language}!`, e);
93
+ debug(`Error preloading language ${language}:`, e);
94
+ }
95
+ } else {
96
+ debug(`Language ${language} already loaded, skipping`);
97
+ }
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Require optional language package
103
+ * @param {string} language
104
+ * @param {Set} loadedLanguages
105
+ */
106
+ const requireLanguage = (language, loadedLanguages) => {
107
+ if (loadedLanguages.has(language) || languages[language]) {
108
+ debug(`Language ${language} already available, skipping load`);
109
+ return;
110
+ }
111
+ debug(`Loading language on-demand: ${language}`);
112
+ try {
113
+ loadLanguages([language]);
114
+ loadedLanguages.add(language);
115
+ debug(`Successfully loaded language: ${language}`);
116
+ } catch (e) {
117
+ console.warn(`Failed to load prism syntax: ${language}!`, e);
118
+ debug(`Error loading language ${language}:`, e);
119
+ }
120
+ };
121
+
122
+ // Only set up the hook if line numbers are requested
123
+ if (opts.lineNumbers) {
124
+ debug('Setting up line numbers hook');
125
+ Prism.hooks.add('after-tokenize', env => {
126
+ const match = env.code.match(NEW_LINE_EXP);
127
+ const linesNum = match ? match.length + 1 : 1;
128
+ debug(`Counted ${linesNum} lines for line numbers`);
129
+ const lines = new Array(linesNum + 1).join('<span></span>');
130
+ lineNumbersWrapper = `<span aria-hidden="true" class="line-numbers-rows">${lines}</span>`;
131
+ });
132
+ }
133
+
133
134
  // Call done asynchronously to avoid blocking
134
135
  setImmediate(done);
135
136
  try {
@@ -189,7 +190,7 @@ const metalsmithPrism = (options = {}) => {
189
190
  });
190
191
  debug('Completed metalsmith-prism plugin');
191
192
  } catch (error) {
192
- debug('Error in metalsmith-prism plugin:', error);
193
+ debug.error('Error in metalsmith-prism plugin:', error);
193
194
  // We can't call done(error) here because done has already been called
194
195
  console.error('Error processing files:', error);
195
196
  }
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.js"],"sourcesContent":["import { load } from 'cheerio';\nimport { extname } from 'path';\nimport Prism from 'prismjs';\nimport loadLanguages from 'prismjs/components/index.js';\nimport he from 'he';\nimport debugLib from 'debug';\n\nconst debug = debugLib( 'metalsmith-prism' );\n\n// Import languages from Prism's default export\nconst { languages } = Prism;\n\n/**\n * Check if a file is HTML based on its extension\n * @param {string} filePath - Path to the file\n * @returns {boolean} - True if the file has an HTML extension\n */\nconst isHTMLFile = ( filePath ) => {\n const extension = extname( filePath ).toLowerCase();\n return [ '.html', '.htm' ].includes( extension );\n};\n\n/**\n * @typedef Options\n * @property {boolean} [decode=false] - Whether to decode HTML entities\n * @property {boolean} [lineNumbers=false] - Whether to add line numbers\n * @property {string[]} [preLoad=[]] - Languages to preload\n */\n\n/**\n * Metalsmith plugin to highlight code syntax with PrismJS\n *\n * This plugin finds all code blocks in HTML files that have language-* classes\n * and applies Prism.js syntax highlighting to them. It can also add line numbers\n * and handle HTML entity decoding.\n *\n * @param {Options} [options] - Configuration options\n * @param {boolean} [options.decode=false] - Whether to decode HTML entities in code blocks\n * @param {boolean} [options.lineNumbers=false] - Whether to add line numbers to code blocks\n * @param {string[]} [options.preLoad=[]] - Languages to preload before processing\n * @returns {import('metalsmith').Plugin} - A metalsmith plugin function\n * @example\n * // Basic usage\n * metalsmith.use(prism());\n *\n * // With options\n * metalsmith.use(prism({\n * decode: true,\n * lineNumbers: true,\n * preLoad: ['java', 'scala']\n * }));\n */\nconst metalsmithPrism = ( options = {} ) => {\n // Create a new options object with defaults\n const opts = {\n decode: false,\n lineNumbers: false,\n preLoad: [],\n ...options\n };\n\n // Track loaded languages to avoid duplicate loading\n const loadedLanguages = new Set();\n\n // Always load PHP by default\n debug( 'Loading PHP by default' );\n try {\n loadLanguages( [ 'php' ] );\n loadedLanguages.add( 'php' );\n } catch ( e ) {\n debug( 'Failed to load PHP:', e );\n }\n\n if ( opts.preLoad && opts.preLoad.length ) {\n debug( 'Preloading languages:', opts.preLoad );\n opts.preLoad.forEach( ( language ) => {\n if ( !loadedLanguages.has( language ) ) {\n try {\n loadLanguages( [ language ] );\n loadedLanguages.add( language );\n debug( `Successfully preloaded language: ${ language }` );\n } catch ( e ) {\n console.warn( `Failed to preload prism syntax: ${ language }!`, e );\n debug( `Error preloading language ${ language }:`, e );\n }\n } else {\n debug( `Language ${ language } already loaded, skipping` );\n }\n } );\n }\n\n /**\n * Require optional language package\n * @param {string} language\n * @param {Set} loadedLanguages\n */\n const requireLanguage = ( language, loadedLanguages ) => {\n if ( loadedLanguages.has( language ) || languages[ language ] ) {\n debug( `Language ${ language } already available, skipping load` );\n return;\n }\n\n debug( `Loading language on-demand: ${ language }` );\n try {\n loadLanguages( [ language ] );\n loadedLanguages.add( language );\n debug( `Successfully loaded language: ${ language }` );\n } catch ( e ) {\n console.warn( `Failed to load prism syntax: ${ language }!`, e );\n debug( `Error loading language ${ language }:`, e );\n }\n };\n\n // Set up line numbers functionality\n const NEW_LINE_EXP = /\\n(?!$)/g;\n let lineNumbersWrapper;\n\n // Only set up the hook if line numbers are requested\n if ( opts.lineNumbers ) {\n debug( 'Setting up line numbers hook' );\n Prism.hooks.add( 'after-tokenize', ( env ) => {\n const match = env.code.match( NEW_LINE_EXP );\n const linesNum = match ? match.length + 1 : 1;\n debug( `Counted ${ linesNum } lines for line numbers` );\n const lines = new Array( linesNum + 1 ).join( '<span></span>' );\n lineNumbersWrapper = `<span aria-hidden=\"true\" class=\"line-numbers-rows\">${ lines }</span>`;\n } );\n }\n\n return ( files, metalsmith, done ) => {\n debug( 'Starting metalsmith-prism plugin' );\n debug( 'Options:', opts );\n\n // Call done asynchronously to avoid blocking\n setImmediate( done );\n\n try {\n Object.keys( files ).forEach( ( file ) => {\n if ( !isHTMLFile( file ) ) {\n return;\n }\n\n debug( `Processing HTML file: ${ file }` );\n const contents = files[ file ].contents.toString();\n const $ = load( contents, { decodeEntities: false } );\n let highlighted = false;\n const code = $( 'code' );\n\n if ( !code.length ) {\n debug( `No code blocks found in ${ file }` );\n return;\n }\n\n debug( `Found ${ code.length } code blocks in ${ file }` );\n\n code.each( function() {\n const $this = $( this );\n\n const className = $this.attr( 'class' ) || '';\n const targets = className.split( 'language-' );\n let addLineNumbers = false;\n\n if ( targets.length > 1 ) {\n const $pre = $this.parent( 'pre' );\n\n if ( $pre ) {\n // Copy className to <pre> container\n $pre.addClass( className );\n\n if ( opts.lineNumbers ) {\n $pre.addClass( 'line-numbers' );\n addLineNumbers = true;\n debug( 'Adding line numbers' );\n }\n }\n\n highlighted = true;\n let language = targets[ 1 ];\n debug( `Detected language: ${ language }` );\n requireLanguage( language, loadedLanguages );\n\n if ( !languages[ language ] ) {\n debug( `Language ${ language } not available, falling back to markup` );\n language = 'markup';\n }\n\n const html = language === 'markup' && !opts.decode ? $this.html() : he.decode( $this.html() );\n debug( `HTML decoding ${ opts.decode ? 'applied' : 'not applied' } for language ${ language }` );\n\n debug( `Highlighting code with language: ${ language }` );\n const highlightedCode = Prism.highlight( html, languages[ language ] );\n $this.html( addLineNumbers ? highlightedCode + lineNumbersWrapper : highlightedCode );\n }\n } );\n\n if ( highlighted ) {\n debug( `Updating contents of ${ file } with highlighted code` );\n files[ file ].contents = Buffer.from( $.html() );\n } else {\n debug( `No code was highlighted in ${ file }` );\n }\n } );\n\n debug( 'Completed metalsmith-prism plugin' );\n } catch ( error ) {\n debug( 'Error in metalsmith-prism plugin:', error );\n // We can't call done(error) here because done has already been called\n console.error( 'Error processing files:', error );\n }\n };\n};\n\n// ESM export\nexport default metalsmithPrism;\n"],"names":["debug","debugLib","languages","Prism","isHTMLFile","filePath","extension","extname","toLowerCase","includes","metalsmithPrism","options","opts","decode","lineNumbers","preLoad","loadedLanguages","Set","loadLanguages","add","e","length","forEach","language","has","console","warn","requireLanguage","NEW_LINE_EXP","lineNumbersWrapper","hooks","env","match","code","linesNum","lines","Array","join","files","metalsmith","done","setImmediate","Object","keys","file","contents","toString","$","load","decodeEntities","highlighted","each","$this","className","attr","targets","split","addLineNumbers","$pre","parent","addClass","html","he","highlightedCode","highlight","Buffer","from","error"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.js"],"sourcesContent":["import { load } from 'cheerio';\nimport { extname } from 'path';\nimport Prism from 'prismjs';\nimport loadLanguages from 'prismjs/components/index.js';\nimport he from 'he';\n\n// Import languages from Prism's default export\nconst { languages } = Prism;\n\n/**\n * Check if a file is HTML based on its extension\n * @param {string} filePath - Path to the file\n * @returns {boolean} - True if the file has an HTML extension\n */\nconst isHTMLFile = (filePath) => {\n const extension = extname(filePath).toLowerCase();\n return ['.html', '.htm'].includes(extension);\n};\n\n/**\n * @typedef Options\n * @property {boolean} [decode=false] - Whether to decode HTML entities\n * @property {boolean} [lineNumbers=false] - Whether to add line numbers\n * @property {string[]} [preLoad=[]] - Languages to preload\n */\n\n/**\n * Metalsmith plugin to highlight code syntax with PrismJS\n *\n * This plugin finds all code blocks in HTML files that have language-* classes\n * and applies Prism.js syntax highlighting to them. It can also add line numbers\n * and handle HTML entity decoding.\n *\n * @param {Options} [options] - Configuration options\n * @param {boolean} [options.decode=false] - Whether to decode HTML entities in code blocks\n * @param {boolean} [options.lineNumbers=false] - Whether to add line numbers to code blocks\n * @param {string[]} [options.preLoad=[]] - Languages to preload before processing\n * @returns {import('metalsmith').Plugin} - A metalsmith plugin function\n * @example\n * // Basic usage\n * metalsmith.use(prism());\n *\n * // With options\n * metalsmith.use(prism({\n * decode: true,\n * lineNumbers: true,\n * preLoad: ['java', 'scala']\n * }));\n */\nconst metalsmithPrism = (options = {}) => {\n // Create a new options object with defaults\n const opts = {\n decode: false,\n lineNumbers: false,\n preLoad: [],\n ...options\n };\n\n // Track loaded languages to avoid duplicate loading\n const loadedLanguages = new Set();\n\n // Set up line numbers functionality\n const NEW_LINE_EXP = /\\n(?!$)/g;\n let lineNumbersWrapper;\n\n return (files, metalsmith, done) => {\n // Get debug instance from metalsmith\n const debug = metalsmith.debug('metalsmith-prism');\n \n debug('Starting metalsmith-prism plugin');\n debug('Options:', opts);\n\n // Always load PHP by default\n debug('Loading PHP by default');\n try {\n loadLanguages(['php']);\n loadedLanguages.add('php');\n } catch (e) {\n debug('Failed to load PHP:', e);\n }\n\n // Preload languages if specified\n if (opts.preLoad && opts.preLoad.length) {\n debug('Preloading languages:', opts.preLoad);\n opts.preLoad.forEach((language) => {\n if (!loadedLanguages.has(language)) {\n try {\n loadLanguages([language]);\n loadedLanguages.add(language);\n debug(`Successfully preloaded language: ${language}`);\n } catch (e) {\n console.warn(`Failed to preload prism syntax: ${language}!`, e);\n debug(`Error preloading language ${language}:`, e);\n }\n } else {\n debug(`Language ${language} already loaded, skipping`);\n }\n });\n }\n\n /**\n * Require optional language package\n * @param {string} language\n * @param {Set} loadedLanguages\n */\n const requireLanguage = (language, loadedLanguages) => {\n if (loadedLanguages.has(language) || languages[language]) {\n debug(`Language ${language} already available, skipping load`);\n return;\n }\n\n debug(`Loading language on-demand: ${language}`);\n try {\n loadLanguages([language]);\n loadedLanguages.add(language);\n debug(`Successfully loaded language: ${language}`);\n } catch (e) {\n console.warn(`Failed to load prism syntax: ${language}!`, e);\n debug(`Error loading language ${language}:`, e);\n }\n };\n\n // Only set up the hook if line numbers are requested\n if (opts.lineNumbers) {\n debug('Setting up line numbers hook');\n Prism.hooks.add('after-tokenize', (env) => {\n const match = env.code.match(NEW_LINE_EXP);\n const linesNum = match ? match.length + 1 : 1;\n debug(`Counted ${linesNum} lines for line numbers`);\n const lines = new Array(linesNum + 1).join('<span></span>');\n lineNumbersWrapper = `<span aria-hidden=\"true\" class=\"line-numbers-rows\">${lines}</span>`;\n });\n }\n\n // Call done asynchronously to avoid blocking\n setImmediate(done);\n\n try {\n Object.keys(files).forEach((file) => {\n if (!isHTMLFile(file)) {\n return;\n }\n\n debug(`Processing HTML file: ${file}`);\n const contents = files[file].contents.toString();\n const $ = load(contents, { decodeEntities: false });\n let highlighted = false;\n const code = $('code');\n\n if (!code.length) {\n debug(`No code blocks found in ${file}`);\n return;\n }\n\n debug(`Found ${code.length} code blocks in ${file}`);\n\n code.each(function () {\n const $this = $(this);\n\n const className = $this.attr('class') || '';\n const targets = className.split('language-');\n let addLineNumbers = false;\n\n if (targets.length > 1) {\n const $pre = $this.parent('pre');\n\n if ($pre) {\n // Copy className to <pre> container\n $pre.addClass(className);\n\n if (opts.lineNumbers) {\n $pre.addClass('line-numbers');\n addLineNumbers = true;\n debug('Adding line numbers');\n }\n }\n\n highlighted = true;\n let language = targets[1];\n debug(`Detected language: ${language}`);\n requireLanguage(language, loadedLanguages);\n\n if (!languages[language]) {\n debug(`Language ${language} not available, falling back to markup`);\n language = 'markup';\n }\n\n const html = language === 'markup' && !opts.decode ? $this.html() : he.decode($this.html());\n debug(`HTML decoding ${opts.decode ? 'applied' : 'not applied'} for language ${language}`);\n\n debug(`Highlighting code with language: ${language}`);\n const highlightedCode = Prism.highlight(html, languages[language]);\n $this.html(addLineNumbers ? highlightedCode + lineNumbersWrapper : highlightedCode);\n }\n });\n\n if (highlighted) {\n debug(`Updating contents of ${file} with highlighted code`);\n files[file].contents = Buffer.from($.html());\n } else {\n debug(`No code was highlighted in ${file}`);\n }\n });\n\n debug('Completed metalsmith-prism plugin');\n } catch (error) {\n debug.error('Error in metalsmith-prism plugin:', error);\n // We can't call done(error) here because done has already been called\n console.error('Error processing files:', error);\n }\n };\n};\n\n// ESM export\nexport default metalsmithPrism;\n"],"names":["languages","Prism","isHTMLFile","filePath","extension","extname","toLowerCase","includes","metalsmithPrism","options","opts","decode","lineNumbers","preLoad","loadedLanguages","Set","NEW_LINE_EXP","lineNumbersWrapper","files","metalsmith","done","debug","loadLanguages","add","e","length","forEach","language","has","console","warn","requireLanguage","hooks","env","match","code","linesNum","lines","Array","join","setImmediate","Object","keys","file","contents","toString","$","load","decodeEntities","highlighted","each","$this","className","attr","targets","split","addLineNumbers","$pre","parent","addClass","html","he","highlightedCode","highlight","Buffer","from","error"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metalsmith-prism",
3
- "version": "5.0.4",
3
+ "version": "5.0.5",
4
4
  "description": "Syntax highlighting for Metalsmith HTML templates using Prism.js",
5
5
  "type": "module",
6
6
  "main": "./lib/index.cjs",
@@ -16,21 +16,21 @@
16
16
  "scripts": {
17
17
  "build": "microbundle --entry src/index.js --output lib/index.js --target node -f esm,cjs --strict --generateTypes=false",
18
18
  "changelog": "auto-changelog -u --commit-limit false --ignore-commit-pattern '^((dev|chore|ci):|Release)'",
19
- "coverage": "npm test && c8 report --reporter=text-lcov > ./coverage.info",
20
- "format": "prettier --write \"**/*.{yml,md,json}\"",
19
+ "coverage": "c8 --include=src/**/*.js --reporter=lcov --reporter=text-summary mocha 'test/index.js' 'test/cjs.test.cjs' 'test/comprehensive.mjs' 'test/additional.mjs' -t 15000",
20
+ "format": "prettier --write \"**/*.{yml,md,js,json}\"",
21
21
  "format:check": "prettier --list-different \"**/*.{yml,md,js,json}\"",
22
22
  "lint": "eslint --fix .",
23
23
  "lint:check": "eslint --fix-dry-run .",
24
- "format-and-lint": "npm run format && npm run lint",
25
24
  "prepublishOnly": "npm run build",
26
- "update-coverage": "node scripts/update-coverage-badge.js",
27
- "prerelease": "npm run update-coverage && git add README.md && git commit -m \"Update coverage badge in README\" || true",
28
- "release": "npm run build && GITHUB_TOKEN=$(grep GITHUB_TOKEN .env | cut -d '=' -f2) ./node_modules/.bin/release-it . ",
29
- "release:check": "npm run lint:check && npm run build && GITHUB_TOKEN=$(grep GITHUB_TOKEN .env | cut -d '=' -f2) ./node_modules/.bin/release-it . --dry-run",
25
+ "release:patch": "./scripts/release.sh patch --ci",
26
+ "release:minor": "./scripts/release.sh minor --ci",
27
+ "release:major": "./scripts/release.sh major --ci",
28
+ "release:check": "npm run lint:check && npm run build && release-it --dry-run",
30
29
  "test": "c8 --include=src/**/*.js mocha 'test/index.js' 'test/cjs.test.cjs' 'test/comprehensive.mjs' 'test/additional.mjs' -t 15000",
30
+ "test:coverage": "c8 npm test",
31
+ "test:unit": "mocha 'test/unit/**/*.js' -t 5000",
31
32
  "test:esm": "c8 --include=src/**/*.js mocha 'test/index.js' 'test/comprehensive.mjs' 'test/additional.mjs' -t 15000",
32
33
  "test:cjs": "c8 --include=src/**/*.js mocha test/cjs.test.cjs -t 15000",
33
- "test:e2e": "serve -l 3000 test/fixtures",
34
34
  "depcheck": "depcheck"
35
35
  },
36
36
  "repository": {
@@ -39,14 +39,15 @@
39
39
  },
40
40
  "keywords": [
41
41
  "metalsmith",
42
+ "metalsmith-plugin",
42
43
  "prismjs",
43
44
  "syntax",
44
45
  "highlighting"
45
46
  ],
46
47
  "files": [
47
- "src",
48
48
  "lib",
49
- "README.md"
49
+ "README.md",
50
+ "LICENSE"
50
51
  ],
51
52
  "author": "Werner Glinka <werner@glinka.co>",
52
53
  "license": "MIT",
@@ -55,24 +56,28 @@
55
56
  },
56
57
  "homepage": "https://github.com/wernerglinka/metalsmith-prism",
57
58
  "dependencies": {
58
- "cheerio": "^1.0.0",
59
- "debug": "^4.4.0",
60
- "dotenv": "^16.5.0",
59
+ "cheerio": "1.1.2",
61
60
  "he": "^1.2.0",
62
- "metalsmith": "^2.6.3",
61
+ "metalsmith": "^2.5.0",
63
62
  "prismjs": "^1.30.0"
64
63
  },
65
64
  "devDependencies": {
66
65
  "auto-changelog": "^2.5.0",
67
66
  "c8": "^10.1.3",
68
- "chai": "^5.2.0",
69
- "eslint": "^9.25.1",
70
- "eslint-config-prettier": "^10.1.2",
71
- "eslint-plugin-prettier": "^5.2.6",
72
- "globals": "^16.0.0",
67
+ "chai": "5.2.1",
68
+ "eslint": "9.32.0",
69
+ "eslint-config-prettier": "10.1.8",
70
+ "eslint-plugin-prettier": "5.5.3",
71
+ "globals": "16.3.0",
73
72
  "microbundle": "^0.15.1",
74
- "mocha": "^11.1.0",
75
- "prettier": "^3.5.3",
76
- "release-it": "^19.0.1"
73
+ "mocha": "11.7.1",
74
+ "prettier": "3.6.2",
75
+ "release-it": "19.0.4"
76
+ },
77
+ "peerDependencies": {
78
+ "metalsmith": "^2.5.0"
79
+ },
80
+ "publishConfig": {
81
+ "access": "public"
77
82
  }
78
83
  }
@@ -1,186 +0,0 @@
1
- import { load } from 'cheerio';
2
- import { extname } from 'path';
3
- import Prism from 'prismjs';
4
- import loadLanguages from 'prismjs/components/index.js';
5
- import he from 'he';
6
- import debugLib from 'debug';
7
-
8
- const debug = debugLib('metalsmith-prism');
9
-
10
- // Import languages from Prism's default export
11
- const {
12
- languages
13
- } = Prism;
14
-
15
- /**
16
- * Check if a file is HTML based on its extension
17
- * @param {string} filePath - Path to the file
18
- * @returns {boolean} - True if the file has an HTML extension
19
- */
20
- const isHTMLFile = filePath => {
21
- const extension = extname(filePath).toLowerCase();
22
- return extension === '.html' || extension === '.htm';
23
- };
24
-
25
- /**
26
- * @typedef Options
27
- * @property {boolean} [decode=false] - Whether to decode HTML entities
28
- * @property {boolean} [lineNumbers=false] - Whether to add line numbers
29
- * @property {string[]} [preLoad=[]] - Languages to preload
30
- */
31
-
32
- /**
33
- * Metalsmith plugin to highlight code syntax with PrismJS
34
- *
35
- * This plugin finds all code blocks in HTML files that have language-* classes
36
- * and applies Prism.js syntax highlighting to them. It can also add line numbers
37
- * and handle HTML entity decoding.
38
- *
39
- * @param {Options} [options] - Configuration options
40
- * @param {boolean} [options.decode=false] - Whether to decode HTML entities in code blocks
41
- * @param {boolean} [options.lineNumbers=false] - Whether to add line numbers to code blocks
42
- * @param {string[]} [options.preLoad=[]] - Languages to preload before processing
43
- * @returns {import('metalsmith').Plugin} - A metalsmith plugin function
44
- * @example
45
- * // Basic usage
46
- * metalsmith.use(prism());
47
- *
48
- * // With options
49
- * metalsmith.use(prism({
50
- * decode: true,
51
- * lineNumbers: true,
52
- * preLoad: ['java', 'scala']
53
- * }));
54
- */
55
- function metalsmithPrism(options = {}) {
56
- // Track loaded languages to avoid duplicate loading
57
- const loadedLanguages = new Set();
58
-
59
- // Always load PHP by default
60
- debug('Loading PHP by default');
61
- try {
62
- loadLanguages(['php']);
63
- loadedLanguages.add('php');
64
- } catch (e) {
65
- debug('Failed to load PHP:', e);
66
- }
67
- if (options.preLoad) {
68
- debug('Preloading languages:', options.preLoad);
69
- options.preLoad.forEach(language => {
70
- if (!loadedLanguages.has(language)) {
71
- try {
72
- loadLanguages([language]);
73
- loadedLanguages.add(language);
74
- debug(`Successfully preloaded language: ${language}`);
75
- } catch (e) {
76
- console.warn(`Failed to preload prism syntax: ${language}!`, e);
77
- debug(`Error preloading language ${language}:`, e);
78
- }
79
- } else {
80
- debug(`Language ${language} already loaded, skipping`);
81
- }
82
- });
83
- }
84
-
85
- /**
86
- * Require optional language package
87
- * @param {string} language
88
- */
89
- function requireLanguage(language) {
90
- if (!loadedLanguages.has(language) && !languages[language]) {
91
- debug(`Loading language on-demand: ${language}`);
92
- try {
93
- loadLanguages([language]);
94
- loadedLanguages.add(language);
95
- debug(`Successfully loaded language: ${language}`);
96
- } catch (e) {
97
- console.warn(`Failed to load prism syntax: ${language}!`, e);
98
- debug(`Error loading language ${language}:`, e);
99
- }
100
- }
101
- }
102
-
103
- // Set up line numbers functionality
104
- const NEW_LINE_EXP = /\n(?!$)/g;
105
- let lineNumbersWrapper;
106
-
107
- // Only set up the hook if line numbers are requested
108
- if (options.lineNumbers) {
109
- debug('Setting up line numbers hook');
110
- Prism.hooks.add('after-tokenize', env => {
111
- const match = env.code.match(NEW_LINE_EXP);
112
- const linesNum = match ? match.length + 1 : 1;
113
- debug(`Counted ${linesNum} lines for line numbers`);
114
- const lines = new Array(linesNum + 1).join('<span></span>');
115
- lineNumbersWrapper = `<span aria-hidden="true" class="line-numbers-rows">${lines}</span>`;
116
- });
117
- }
118
- return function (files, metalsmith, done) {
119
- debug('Starting metalsmith-prism plugin');
120
- debug('Options:', options);
121
- setImmediate(done);
122
- Object.keys(files).forEach(file => {
123
- if (!isHTMLFile(file)) {
124
- return;
125
- }
126
- debug(`Processing HTML file: ${file}`);
127
- const contents = files[file].contents.toString();
128
- const $ = load(contents, {
129
- decodeEntities: false
130
- });
131
- let highlighted = false;
132
- const code = $('code');
133
- if (!code.length) {
134
- debug(`No code blocks found in ${file}`);
135
- return;
136
- }
137
- debug(`Found ${code.length} code blocks in ${file}`);
138
- code.each(function () {
139
- const $this = $(this);
140
- const className = $this.attr('class') || '';
141
- const targets = className.split('language-');
142
- let addLineNumbers = false;
143
- if (targets.length > 1) {
144
- const $pre = $this.parent('pre');
145
- if ($pre) {
146
- // Copy className to <pre> container
147
- $pre.addClass(className);
148
- if (options.lineNumbers) {
149
- $pre.addClass('line-numbers');
150
- addLineNumbers = true;
151
- debug('Adding line numbers');
152
- }
153
- }
154
- highlighted = true;
155
- let language = targets[1];
156
- debug(`Detected language: ${language}`);
157
- requireLanguage(language);
158
- if (!languages[language]) {
159
- debug(`Language ${language} not available, falling back to markup`);
160
- language = 'markup';
161
- }
162
- const html = language === 'markup' && !options.decode ? $this.html() : he.decode($this.html());
163
- debug(`HTML decoding ${options.decode ? 'applied' : 'not applied'} for language ${language}`);
164
- debug(`Highlighting code with language: ${language}`);
165
- const highlightedCode = Prism.highlight(html, languages[language]);
166
- $this.html(addLineNumbers ? highlightedCode + lineNumbersWrapper : highlightedCode);
167
- }
168
- });
169
- if (highlighted) {
170
- debug(`Updating contents of ${file} with highlighted code`);
171
- files[file].contents = Buffer.from($.html());
172
- } else {
173
- debug(`No code was highlighted in ${file}`);
174
- }
175
- });
176
- debug('Completed metalsmith-prism plugin');
177
- };
178
- }
179
-
180
- // CommonJS export compatibility
181
- if (typeof module !== 'undefined') {
182
- module.exports = metalsmithPrism;
183
- }
184
-
185
- export { metalsmithPrism as default };
186
- //# sourceMappingURL=index.modern.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.modern.js","sources":["../src/index.js"],"sourcesContent":["import { load } from 'cheerio';\nimport { extname } from 'path';\nimport Prism from 'prismjs';\nimport loadLanguages from 'prismjs/components/index.js';\nimport he from 'he';\nimport debugLib from 'debug';\n\nconst debug = debugLib('metalsmith-prism');\n\n// Import languages from Prism's default export\nconst { languages } = Prism;\n\n/**\n * Check if a file is HTML based on its extension\n * @param {string} filePath - Path to the file\n * @returns {boolean} - True if the file has an HTML extension\n */\nconst isHTMLFile = (filePath) => {\n const extension = extname(filePath).toLowerCase();\n return extension === '.html' || extension === '.htm';\n};\n\n/**\n * @typedef Options\n * @property {boolean} [decode=false] - Whether to decode HTML entities\n * @property {boolean} [lineNumbers=false] - Whether to add line numbers\n * @property {string[]} [preLoad=[]] - Languages to preload\n */\n\n/**\n * Metalsmith plugin to highlight code syntax with PrismJS\n *\n * This plugin finds all code blocks in HTML files that have language-* classes\n * and applies Prism.js syntax highlighting to them. It can also add line numbers\n * and handle HTML entity decoding.\n *\n * @param {Options} [options] - Configuration options\n * @param {boolean} [options.decode=false] - Whether to decode HTML entities in code blocks\n * @param {boolean} [options.lineNumbers=false] - Whether to add line numbers to code blocks\n * @param {string[]} [options.preLoad=[]] - Languages to preload before processing\n * @returns {import('metalsmith').Plugin} - A metalsmith plugin function\n * @example\n * // Basic usage\n * metalsmith.use(prism());\n *\n * // With options\n * metalsmith.use(prism({\n * decode: true,\n * lineNumbers: true,\n * preLoad: ['java', 'scala']\n * }));\n */\nfunction metalsmithPrism(options = {}) {\n // Track loaded languages to avoid duplicate loading\n const loadedLanguages = new Set();\n\n // Always load PHP by default\n debug('Loading PHP by default');\n try {\n loadLanguages(['php']);\n loadedLanguages.add('php');\n } catch (e) {\n debug('Failed to load PHP:', e);\n }\n\n if (options.preLoad) {\n debug('Preloading languages:', options.preLoad);\n options.preLoad.forEach((language) => {\n if (!loadedLanguages.has(language)) {\n try {\n loadLanguages([language]);\n loadedLanguages.add(language);\n debug(`Successfully preloaded language: ${language}`);\n } catch (e) {\n console.warn(`Failed to preload prism syntax: ${language}!`, e);\n debug(`Error preloading language ${language}:`, e);\n }\n } else {\n debug(`Language ${language} already loaded, skipping`);\n }\n });\n }\n\n /**\n * Require optional language package\n * @param {string} language\n */\n function requireLanguage(language) {\n if (!loadedLanguages.has(language) && !languages[language]) {\n debug(`Loading language on-demand: ${language}`);\n try {\n loadLanguages([language]);\n loadedLanguages.add(language);\n debug(`Successfully loaded language: ${language}`);\n } catch (e) {\n console.warn(`Failed to load prism syntax: ${language}!`, e);\n debug(`Error loading language ${language}:`, e);\n }\n }\n }\n\n // Set up line numbers functionality\n const NEW_LINE_EXP = /\\n(?!$)/g;\n let lineNumbersWrapper;\n\n // Only set up the hook if line numbers are requested\n if (options.lineNumbers) {\n debug('Setting up line numbers hook');\n Prism.hooks.add('after-tokenize', (env) => {\n const match = env.code.match(NEW_LINE_EXP);\n const linesNum = match ? match.length + 1 : 1;\n debug(`Counted ${linesNum} lines for line numbers`);\n const lines = new Array(linesNum + 1).join('<span></span>');\n lineNumbersWrapper = `<span aria-hidden=\"true\" class=\"line-numbers-rows\">${lines}</span>`;\n });\n }\n\n return function (files, metalsmith, done) {\n debug('Starting metalsmith-prism plugin');\n debug('Options:', options);\n\n setImmediate(done);\n\n Object.keys(files).forEach((file) => {\n if (!isHTMLFile(file)) {\n return;\n }\n\n debug(`Processing HTML file: ${file}`);\n const contents = files[file].contents.toString();\n const $ = load(contents, { decodeEntities: false });\n let highlighted = false;\n const code = $('code');\n\n if (!code.length) {\n debug(`No code blocks found in ${file}`);\n return;\n }\n\n debug(`Found ${code.length} code blocks in ${file}`);\n\n code.each(function () {\n const $this = $(this);\n\n const className = $this.attr('class') || '';\n const targets = className.split('language-');\n let addLineNumbers = false;\n\n if (targets.length > 1) {\n const $pre = $this.parent('pre');\n\n if ($pre) {\n // Copy className to <pre> container\n $pre.addClass(className);\n\n if (options.lineNumbers) {\n $pre.addClass('line-numbers');\n addLineNumbers = true;\n debug('Adding line numbers');\n }\n }\n\n highlighted = true;\n let language = targets[1];\n debug(`Detected language: ${language}`);\n requireLanguage(language);\n\n if (!languages[language]) {\n debug(`Language ${language} not available, falling back to markup`);\n language = 'markup';\n }\n\n const html = language === 'markup' && !options.decode ? $this.html() : he.decode($this.html());\n debug(`HTML decoding ${options.decode ? 'applied' : 'not applied'} for language ${language}`);\n\n debug(`Highlighting code with language: ${language}`);\n const highlightedCode = Prism.highlight(html, languages[language]);\n $this.html(addLineNumbers ? highlightedCode + lineNumbersWrapper : highlightedCode);\n }\n });\n\n if (highlighted) {\n debug(`Updating contents of ${file} with highlighted code`);\n files[file].contents = Buffer.from($.html());\n } else {\n debug(`No code was highlighted in ${file}`);\n }\n });\n\n debug('Completed metalsmith-prism plugin');\n };\n}\n\n// ESM export\nexport { metalsmithPrism as default };\n\n// CommonJS export compatibility\nif (typeof module !== 'undefined') {\n module.exports = metalsmithPrism;\n}\n"],"names":["debug","debugLib","languages","Prism","isHTMLFile","filePath","extension","extname","toLowerCase","metalsmithPrism","options","loadedLanguages","Set","loadLanguages","add","e","preLoad","forEach","language","has","console","warn","requireLanguage","NEW_LINE_EXP","lineNumbersWrapper","lineNumbers","hooks","env","match","code","linesNum","length","lines","Array","join","files","metalsmith","done","setImmediate","Object","keys","file","contents","toString","$","load","decodeEntities","highlighted","each","$this","className","attr","targets","split","addLineNumbers","$pre","parent","addClass","html","decode","he","highlightedCode","highlight","Buffer","from","module","exports"],"mappings":";;;;;;;AAOA,MAAMA,KAAK,GAAGC,QAAQ,CAAC,kBAAkB,CAAC,CAAA;;AAE1C;AACA,MAAM;AAAEC,EAAAA,SAAAA;AAAU,CAAC,GAAGC,KAAK,CAAA;;AAE3B;AACA;AACA;AACA;AACA;AACA,MAAMC,UAAU,GAAIC,QAAQ,IAAK;EAC/B,MAAMC,SAAS,GAAGC,OAAO,CAACF,QAAQ,CAAC,CAACG,WAAW,EAAE,CAAA;AACjD,EAAA,OAAOF,SAAS,KAAK,OAAO,IAAIA,SAAS,KAAK,MAAM,CAAA;AACtD,CAAC,CAAA;;AAED;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASG,eAAeA,CAACC,OAAO,GAAG,EAAE,EAAE;AACrC;AACA,EAAA,MAAMC,eAAe,GAAG,IAAIC,GAAG,EAAE,CAAA;;AAEjC;EACAZ,KAAK,CAAC,wBAAwB,CAAC,CAAA;EAC/B,IAAI;AACFa,IAAAA,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;AACtBF,IAAAA,eAAe,CAACG,GAAG,CAAC,KAAK,CAAC,CAAA;GAC3B,CAAC,OAAOC,CAAC,EAAE;AACVf,IAAAA,KAAK,CAAC,qBAAqB,EAAEe,CAAC,CAAC,CAAA;AACjC,GAAA;EAEA,IAAIL,OAAO,CAACM,OAAO,EAAE;AACnBhB,IAAAA,KAAK,CAAC,uBAAuB,EAAEU,OAAO,CAACM,OAAO,CAAC,CAAA;AAC/CN,IAAAA,OAAO,CAACM,OAAO,CAACC,OAAO,CAAEC,QAAQ,IAAK;AACpC,MAAA,IAAI,CAACP,eAAe,CAACQ,GAAG,CAACD,QAAQ,CAAC,EAAE;QAClC,IAAI;AACFL,UAAAA,aAAa,CAAC,CAACK,QAAQ,CAAC,CAAC,CAAA;AACzBP,UAAAA,eAAe,CAACG,GAAG,CAACI,QAAQ,CAAC,CAAA;AAC7BlB,UAAAA,KAAK,CAAC,CAAA,iCAAA,EAAoCkB,QAAQ,CAAA,CAAE,CAAC,CAAA;SACtD,CAAC,OAAOH,CAAC,EAAE;UACVK,OAAO,CAACC,IAAI,CAAC,CAAA,gCAAA,EAAmCH,QAAQ,CAAG,CAAA,CAAA,EAAEH,CAAC,CAAC,CAAA;AAC/Df,UAAAA,KAAK,CAAC,CAA6BkB,0BAAAA,EAAAA,QAAQ,CAAG,CAAA,CAAA,EAAEH,CAAC,CAAC,CAAA;AACpD,SAAA;AACF,OAAC,MAAM;AACLf,QAAAA,KAAK,CAAC,CAAA,SAAA,EAAYkB,QAAQ,CAAA,yBAAA,CAA2B,CAAC,CAAA;AACxD,OAAA;AACF,KAAC,CAAC,CAAA;AACJ,GAAA;;AAEA;AACF;AACA;AACA;EACE,SAASI,eAAeA,CAACJ,QAAQ,EAAE;AACjC,IAAA,IAAI,CAACP,eAAe,CAACQ,GAAG,CAACD,QAAQ,CAAC,IAAI,CAAChB,SAAS,CAACgB,QAAQ,CAAC,EAAE;AAC1DlB,MAAAA,KAAK,CAAC,CAAA,4BAAA,EAA+BkB,QAAQ,CAAA,CAAE,CAAC,CAAA;MAChD,IAAI;AACFL,QAAAA,aAAa,CAAC,CAACK,QAAQ,CAAC,CAAC,CAAA;AACzBP,QAAAA,eAAe,CAACG,GAAG,CAACI,QAAQ,CAAC,CAAA;AAC7BlB,QAAAA,KAAK,CAAC,CAAA,8BAAA,EAAiCkB,QAAQ,CAAA,CAAE,CAAC,CAAA;OACnD,CAAC,OAAOH,CAAC,EAAE;QACVK,OAAO,CAACC,IAAI,CAAC,CAAA,6BAAA,EAAgCH,QAAQ,CAAG,CAAA,CAAA,EAAEH,CAAC,CAAC,CAAA;AAC5Df,QAAAA,KAAK,CAAC,CAA0BkB,uBAAAA,EAAAA,QAAQ,CAAG,CAAA,CAAA,EAAEH,CAAC,CAAC,CAAA;AACjD,OAAA;AACF,KAAA;AACF,GAAA;;AAEA;EACA,MAAMQ,YAAY,GAAG,UAAU,CAAA;AAC/B,EAAA,IAAIC,kBAAkB,CAAA;;AAEtB;EACA,IAAId,OAAO,CAACe,WAAW,EAAE;IACvBzB,KAAK,CAAC,8BAA8B,CAAC,CAAA;IACrCG,KAAK,CAACuB,KAAK,CAACZ,GAAG,CAAC,gBAAgB,EAAGa,GAAG,IAAK;MACzC,MAAMC,KAAK,GAAGD,GAAG,CAACE,IAAI,CAACD,KAAK,CAACL,YAAY,CAAC,CAAA;MAC1C,MAAMO,QAAQ,GAAGF,KAAK,GAAGA,KAAK,CAACG,MAAM,GAAG,CAAC,GAAG,CAAC,CAAA;AAC7C/B,MAAAA,KAAK,CAAC,CAAA,QAAA,EAAW8B,QAAQ,CAAA,uBAAA,CAAyB,CAAC,CAAA;AACnD,MAAA,MAAME,KAAK,GAAG,IAAIC,KAAK,CAACH,QAAQ,GAAG,CAAC,CAAC,CAACI,IAAI,CAAC,eAAe,CAAC,CAAA;MAC3DV,kBAAkB,GAAG,CAAsDQ,mDAAAA,EAAAA,KAAK,CAAS,OAAA,CAAA,CAAA;AAC3F,KAAC,CAAC,CAAA;AACJ,GAAA;AAEA,EAAA,OAAO,UAAUG,KAAK,EAAEC,UAAU,EAAEC,IAAI,EAAE;IACxCrC,KAAK,CAAC,kCAAkC,CAAC,CAAA;AACzCA,IAAAA,KAAK,CAAC,UAAU,EAAEU,OAAO,CAAC,CAAA;IAE1B4B,YAAY,CAACD,IAAI,CAAC,CAAA;IAElBE,MAAM,CAACC,IAAI,CAACL,KAAK,CAAC,CAAClB,OAAO,CAAEwB,IAAI,IAAK;AACnC,MAAA,IAAI,CAACrC,UAAU,CAACqC,IAAI,CAAC,EAAE;AACrB,QAAA,OAAA;AACF,OAAA;AAEAzC,MAAAA,KAAK,CAAC,CAAA,sBAAA,EAAyByC,IAAI,CAAA,CAAE,CAAC,CAAA;MACtC,MAAMC,QAAQ,GAAGP,KAAK,CAACM,IAAI,CAAC,CAACC,QAAQ,CAACC,QAAQ,EAAE,CAAA;AAChD,MAAA,MAAMC,CAAC,GAAGC,IAAI,CAACH,QAAQ,EAAE;AAAEI,QAAAA,cAAc,EAAE,KAAA;AAAM,OAAC,CAAC,CAAA;MACnD,IAAIC,WAAW,GAAG,KAAK,CAAA;AACvB,MAAA,MAAMlB,IAAI,GAAGe,CAAC,CAAC,MAAM,CAAC,CAAA;AAEtB,MAAA,IAAI,CAACf,IAAI,CAACE,MAAM,EAAE;AAChB/B,QAAAA,KAAK,CAAC,CAAA,wBAAA,EAA2ByC,IAAI,CAAA,CAAE,CAAC,CAAA;AACxC,QAAA,OAAA;AACF,OAAA;MAEAzC,KAAK,CAAC,SAAS6B,IAAI,CAACE,MAAM,CAAmBU,gBAAAA,EAAAA,IAAI,EAAE,CAAC,CAAA;MAEpDZ,IAAI,CAACmB,IAAI,CAAC,YAAY;AACpB,QAAA,MAAMC,KAAK,GAAGL,CAAC,CAAC,IAAI,CAAC,CAAA;QAErB,MAAMM,SAAS,GAAGD,KAAK,CAACE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;AAC3C,QAAA,MAAMC,OAAO,GAAGF,SAAS,CAACG,KAAK,CAAC,WAAW,CAAC,CAAA;QAC5C,IAAIC,cAAc,GAAG,KAAK,CAAA;AAE1B,QAAA,IAAIF,OAAO,CAACrB,MAAM,GAAG,CAAC,EAAE;AACtB,UAAA,MAAMwB,IAAI,GAAGN,KAAK,CAACO,MAAM,CAAC,KAAK,CAAC,CAAA;AAEhC,UAAA,IAAID,IAAI,EAAE;AACR;AACAA,YAAAA,IAAI,CAACE,QAAQ,CAACP,SAAS,CAAC,CAAA;YAExB,IAAIxC,OAAO,CAACe,WAAW,EAAE;AACvB8B,cAAAA,IAAI,CAACE,QAAQ,CAAC,cAAc,CAAC,CAAA;AAC7BH,cAAAA,cAAc,GAAG,IAAI,CAAA;cACrBtD,KAAK,CAAC,qBAAqB,CAAC,CAAA;AAC9B,aAAA;AACF,WAAA;AAEA+C,UAAAA,WAAW,GAAG,IAAI,CAAA;AAClB,UAAA,IAAI7B,QAAQ,GAAGkC,OAAO,CAAC,CAAC,CAAC,CAAA;AACzBpD,UAAAA,KAAK,CAAC,CAAA,mBAAA,EAAsBkB,QAAQ,CAAA,CAAE,CAAC,CAAA;UACvCI,eAAe,CAACJ,QAAQ,CAAC,CAAA;AAEzB,UAAA,IAAI,CAAChB,SAAS,CAACgB,QAAQ,CAAC,EAAE;AACxBlB,YAAAA,KAAK,CAAC,CAAA,SAAA,EAAYkB,QAAQ,CAAA,sCAAA,CAAwC,CAAC,CAAA;AACnEA,YAAAA,QAAQ,GAAG,QAAQ,CAAA;AACrB,WAAA;UAEA,MAAMwC,IAAI,GAAGxC,QAAQ,KAAK,QAAQ,IAAI,CAACR,OAAO,CAACiD,MAAM,GAAGV,KAAK,CAACS,IAAI,EAAE,GAAGE,EAAE,CAACD,MAAM,CAACV,KAAK,CAACS,IAAI,EAAE,CAAC,CAAA;AAC9F1D,UAAAA,KAAK,CAAC,CAAA,cAAA,EAAiBU,OAAO,CAACiD,MAAM,GAAG,SAAS,GAAG,aAAa,CAAA,cAAA,EAAiBzC,QAAQ,CAAA,CAAE,CAAC,CAAA;AAE7FlB,UAAAA,KAAK,CAAC,CAAA,iCAAA,EAAoCkB,QAAQ,CAAA,CAAE,CAAC,CAAA;AACrD,UAAA,MAAM2C,eAAe,GAAG1D,KAAK,CAAC2D,SAAS,CAACJ,IAAI,EAAExD,SAAS,CAACgB,QAAQ,CAAC,CAAC,CAAA;UAClE+B,KAAK,CAACS,IAAI,CAACJ,cAAc,GAAGO,eAAe,GAAGrC,kBAAkB,GAAGqC,eAAe,CAAC,CAAA;AACrF,SAAA;AACF,OAAC,CAAC,CAAA;AAEF,MAAA,IAAId,WAAW,EAAE;AACf/C,QAAAA,KAAK,CAAC,CAAA,qBAAA,EAAwByC,IAAI,CAAA,sBAAA,CAAwB,CAAC,CAAA;AAC3DN,QAAAA,KAAK,CAACM,IAAI,CAAC,CAACC,QAAQ,GAAGqB,MAAM,CAACC,IAAI,CAACpB,CAAC,CAACc,IAAI,EAAE,CAAC,CAAA;AAC9C,OAAC,MAAM;AACL1D,QAAAA,KAAK,CAAC,CAAA,2BAAA,EAA8ByC,IAAI,CAAA,CAAE,CAAC,CAAA;AAC7C,OAAA;AACF,KAAC,CAAC,CAAA;IAEFzC,KAAK,CAAC,mCAAmC,CAAC,CAAA;GAC3C,CAAA;AACH,CAAA;;AAKA;AACA,IAAI,OAAOiE,MAAM,KAAK,WAAW,EAAE;EACjCA,MAAM,CAACC,OAAO,GAAGzD,eAAe,CAAA;AAClC;;;;"}
package/src/index.js DELETED
@@ -1,214 +0,0 @@
1
- import { load } from 'cheerio';
2
- import { extname } from 'path';
3
- import Prism from 'prismjs';
4
- import loadLanguages from 'prismjs/components/index.js';
5
- import he from 'he';
6
- import debugLib from 'debug';
7
-
8
- const debug = debugLib( 'metalsmith-prism' );
9
-
10
- // Import languages from Prism's default export
11
- const { languages } = Prism;
12
-
13
- /**
14
- * Check if a file is HTML based on its extension
15
- * @param {string} filePath - Path to the file
16
- * @returns {boolean} - True if the file has an HTML extension
17
- */
18
- const isHTMLFile = ( filePath ) => {
19
- const extension = extname( filePath ).toLowerCase();
20
- return [ '.html', '.htm' ].includes( extension );
21
- };
22
-
23
- /**
24
- * @typedef Options
25
- * @property {boolean} [decode=false] - Whether to decode HTML entities
26
- * @property {boolean} [lineNumbers=false] - Whether to add line numbers
27
- * @property {string[]} [preLoad=[]] - Languages to preload
28
- */
29
-
30
- /**
31
- * Metalsmith plugin to highlight code syntax with PrismJS
32
- *
33
- * This plugin finds all code blocks in HTML files that have language-* classes
34
- * and applies Prism.js syntax highlighting to them. It can also add line numbers
35
- * and handle HTML entity decoding.
36
- *
37
- * @param {Options} [options] - Configuration options
38
- * @param {boolean} [options.decode=false] - Whether to decode HTML entities in code blocks
39
- * @param {boolean} [options.lineNumbers=false] - Whether to add line numbers to code blocks
40
- * @param {string[]} [options.preLoad=[]] - Languages to preload before processing
41
- * @returns {import('metalsmith').Plugin} - A metalsmith plugin function
42
- * @example
43
- * // Basic usage
44
- * metalsmith.use(prism());
45
- *
46
- * // With options
47
- * metalsmith.use(prism({
48
- * decode: true,
49
- * lineNumbers: true,
50
- * preLoad: ['java', 'scala']
51
- * }));
52
- */
53
- const metalsmithPrism = ( options = {} ) => {
54
- // Create a new options object with defaults
55
- const opts = {
56
- decode: false,
57
- lineNumbers: false,
58
- preLoad: [],
59
- ...options
60
- };
61
-
62
- // Track loaded languages to avoid duplicate loading
63
- const loadedLanguages = new Set();
64
-
65
- // Always load PHP by default
66
- debug( 'Loading PHP by default' );
67
- try {
68
- loadLanguages( [ 'php' ] );
69
- loadedLanguages.add( 'php' );
70
- } catch ( e ) {
71
- debug( 'Failed to load PHP:', e );
72
- }
73
-
74
- if ( opts.preLoad && opts.preLoad.length ) {
75
- debug( 'Preloading languages:', opts.preLoad );
76
- opts.preLoad.forEach( ( language ) => {
77
- if ( !loadedLanguages.has( language ) ) {
78
- try {
79
- loadLanguages( [ language ] );
80
- loadedLanguages.add( language );
81
- debug( `Successfully preloaded language: ${ language }` );
82
- } catch ( e ) {
83
- console.warn( `Failed to preload prism syntax: ${ language }!`, e );
84
- debug( `Error preloading language ${ language }:`, e );
85
- }
86
- } else {
87
- debug( `Language ${ language } already loaded, skipping` );
88
- }
89
- } );
90
- }
91
-
92
- /**
93
- * Require optional language package
94
- * @param {string} language
95
- * @param {Set} loadedLanguages
96
- */
97
- const requireLanguage = ( language, loadedLanguages ) => {
98
- if ( loadedLanguages.has( language ) || languages[ language ] ) {
99
- debug( `Language ${ language } already available, skipping load` );
100
- return;
101
- }
102
-
103
- debug( `Loading language on-demand: ${ language }` );
104
- try {
105
- loadLanguages( [ language ] );
106
- loadedLanguages.add( language );
107
- debug( `Successfully loaded language: ${ language }` );
108
- } catch ( e ) {
109
- console.warn( `Failed to load prism syntax: ${ language }!`, e );
110
- debug( `Error loading language ${ language }:`, e );
111
- }
112
- };
113
-
114
- // Set up line numbers functionality
115
- const NEW_LINE_EXP = /\n(?!$)/g;
116
- let lineNumbersWrapper;
117
-
118
- // Only set up the hook if line numbers are requested
119
- if ( opts.lineNumbers ) {
120
- debug( 'Setting up line numbers hook' );
121
- Prism.hooks.add( 'after-tokenize', ( env ) => {
122
- const match = env.code.match( NEW_LINE_EXP );
123
- const linesNum = match ? match.length + 1 : 1;
124
- debug( `Counted ${ linesNum } lines for line numbers` );
125
- const lines = new Array( linesNum + 1 ).join( '<span></span>' );
126
- lineNumbersWrapper = `<span aria-hidden="true" class="line-numbers-rows">${ lines }</span>`;
127
- } );
128
- }
129
-
130
- return ( files, metalsmith, done ) => {
131
- debug( 'Starting metalsmith-prism plugin' );
132
- debug( 'Options:', opts );
133
-
134
- // Call done asynchronously to avoid blocking
135
- setImmediate( done );
136
-
137
- try {
138
- Object.keys( files ).forEach( ( file ) => {
139
- if ( !isHTMLFile( file ) ) {
140
- return;
141
- }
142
-
143
- debug( `Processing HTML file: ${ file }` );
144
- const contents = files[ file ].contents.toString();
145
- const $ = load( contents, { decodeEntities: false } );
146
- let highlighted = false;
147
- const code = $( 'code' );
148
-
149
- if ( !code.length ) {
150
- debug( `No code blocks found in ${ file }` );
151
- return;
152
- }
153
-
154
- debug( `Found ${ code.length } code blocks in ${ file }` );
155
-
156
- code.each( function() {
157
- const $this = $( this );
158
-
159
- const className = $this.attr( 'class' ) || '';
160
- const targets = className.split( 'language-' );
161
- let addLineNumbers = false;
162
-
163
- if ( targets.length > 1 ) {
164
- const $pre = $this.parent( 'pre' );
165
-
166
- if ( $pre ) {
167
- // Copy className to <pre> container
168
- $pre.addClass( className );
169
-
170
- if ( opts.lineNumbers ) {
171
- $pre.addClass( 'line-numbers' );
172
- addLineNumbers = true;
173
- debug( 'Adding line numbers' );
174
- }
175
- }
176
-
177
- highlighted = true;
178
- let language = targets[ 1 ];
179
- debug( `Detected language: ${ language }` );
180
- requireLanguage( language, loadedLanguages );
181
-
182
- if ( !languages[ language ] ) {
183
- debug( `Language ${ language } not available, falling back to markup` );
184
- language = 'markup';
185
- }
186
-
187
- const html = language === 'markup' && !opts.decode ? $this.html() : he.decode( $this.html() );
188
- debug( `HTML decoding ${ opts.decode ? 'applied' : 'not applied' } for language ${ language }` );
189
-
190
- debug( `Highlighting code with language: ${ language }` );
191
- const highlightedCode = Prism.highlight( html, languages[ language ] );
192
- $this.html( addLineNumbers ? highlightedCode + lineNumbersWrapper : highlightedCode );
193
- }
194
- } );
195
-
196
- if ( highlighted ) {
197
- debug( `Updating contents of ${ file } with highlighted code` );
198
- files[ file ].contents = Buffer.from( $.html() );
199
- } else {
200
- debug( `No code was highlighted in ${ file }` );
201
- }
202
- } );
203
-
204
- debug( 'Completed metalsmith-prism plugin' );
205
- } catch ( error ) {
206
- debug( 'Error in metalsmith-prism plugin:', error );
207
- // We can't call done(error) here because done has already been called
208
- console.error( 'Error processing files:', error );
209
- }
210
- };
211
- };
212
-
213
- // ESM export
214
- export default metalsmithPrism;