rehype-pre-language 1.1.6 → 1.1.8

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 ipikuka
3
+ Copyright (c) 2026 ipikuka
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,12 +1,11 @@
1
- ### [Become a sponsor](https://github.com/sponsors/ipikuka) 🚀
1
+ # rehype-pre-language
2
2
 
3
- If you find **`rehype-pre-language`** useful in your projects, consider supporting my work.
4
- Your sponsorship means a lot 💖
3
+ **A robust Next.js newsletter `Next.js Weekly` is sponsoring me** 💖
4
+ [![NextjsWeekly banner](./assets/next-js-weekly.png)](https://nextjsweekly.com/)
5
5
 
6
- Be the **first sponsor** and get featured here and on [my sponsor wall](https://github.com/sponsors/ipikuka).
7
- Thank you for supporting open source! 🙌
6
+ A warm thanks 🙌 to [@ErfanEbrahimnia](https://github.com/ErfanEbrahimnia), [@recepkyk](https://github.com/recepkyk), and [@LSeaburg](https://github.com/LSeaburg) for the [support](https://github.com/sponsors/ipikuka) 💖
8
7
 
9
- # rehype-pre-language
8
+ ---
10
9
 
11
10
  [![npm version][badge-npm-version]][url-npm-package]
12
11
  [![npm downloads][badge-npm-download]][url-npm-package]
@@ -135,6 +134,14 @@ Use of **`rehype-pre-language`** involves rehype (hast), but doesn't lead to cro
135
134
 
136
135
  I like to contribute the Unified / Remark / MDX ecosystem, so I recommend you to have a look my plugins.
137
136
 
137
+ ### Support My Work ([become a sponsor](https://github.com/sponsors/ipikuka) 🚀)
138
+
139
+ If you find **`rehype-pre-language`** or any of my projects is useful and helpful, please consider supporting my work. Your sponsorship means a lot to me and keeps these projects alive and updated! 💖
140
+
141
+ My sponsors are going to be featured at the very top of the page and proudly displayed on my [Sponsor Wall](https://github.com/sponsors/ipikuka).
142
+
143
+ Thank you for supporting open source! 🙌
144
+
138
145
  ### My Remark Plugins
139
146
 
140
147
  - [`remark-flexible-code-titles`](https://www.npmjs.com/package/remark-flexible-code-titles)
@@ -151,6 +158,8 @@ I like to contribute the Unified / Remark / MDX ecosystem, so I recommend you to
151
158
  – Remark plugin to expose the table of contents via `vfile.data` or via an option reference
152
159
  - [`remark-mdx-remove-esm`](https://www.npmjs.com/package/remark-mdx-remove-esm)
153
160
  – Remark plugin to remove import and/or export statements (mdxjsEsm)
161
+ - [`remark-mdx-remove-expressions`](https://www.npmjs.com/package/remark-mdx-remove-expressions)
162
+ – Remark plugin to remove MDX expressions within curlybraces {} in MDX content
154
163
 
155
164
  ### My Rehype Plugins
156
165
 
@@ -180,6 +189,15 @@ I like to contribute the Unified / Remark / MDX ecosystem, so I recommend you to
180
189
  - [`recma-mdx-interpolate`](https://www.npmjs.com/package/recma-mdx-interpolate)
181
190
  – Recma plugin to enable interpolation of identifiers wrapped in curly braces within the `alt`, `src`, `href`, and `title` attributes of markdown link and image syntax in MDX.
182
191
 
192
+ ### My Unist Utils and Unified Plugins
193
+
194
+ I also build low-level utilities and plugins for the Unified ecosystem that can be used across Remark, Rehype, Recma, and other unist-based abstract syntax trees (ASTs).
195
+
196
+ - [`unist-util-find-between`](https://www.npmjs.com/package/unist-util-find-between)
197
+ – Unist utility to find the nodes between two nodes.
198
+ - [`unified-log-tree`](https://www.npmjs.com/package/unified-log-tree)
199
+ – Unified plugin to log abstract syntax trees (ASTs) for debugging without mutating.
200
+
183
201
  ## License
184
202
 
185
203
  [MIT License](./LICENSE) © ipikuka
@@ -8,3 +8,4 @@ export type PreLanguageOption = string;
8
8
  */
9
9
  declare const plugin: Plugin<[PreLanguageOption?], Root>;
10
10
  export default plugin;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAGjC,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAUvC;;;;GAIG;AACH,QAAA,MAAM,MAAM,EAAE,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC,EAAE,IAAI,CA2D9C,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -51,11 +51,11 @@ const plugin = (option) => {
51
51
  parent.properties[property] = language;
52
52
  }
53
53
  else {
54
- parent.properties.className = [
55
- /* v8 ignore next */
56
- ...(isStringArray(parent.properties.className) ? parent.properties.className : []),
57
- language,
58
- ];
54
+ /* v8 ignore next -- @preserve */
55
+ if (!isStringArray(parent.properties.className)) {
56
+ parent.properties.className = [];
57
+ }
58
+ parent.properties.className.push(language);
59
59
  }
60
60
  });
61
61
  };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAI7D,gCAAgC;AAChC,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO;IACL,iCAAiC;IACjC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CACxE,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,MAAM,GAAuC,CAAC,MAAM,EAAE,EAAE;IAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IAE7F;;;;OAIG;IACH,SAAS,WAAW,CAAC,UAAoB;QACvC,MAAM,gBAAgB,GAAG,CAAC,OAAe,EAAW,EAAE,CACpD,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAEjE,MAAM,cAAc,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAEzD,IAAI,CAAC,cAAc;YAAE,OAAO;QAE5B,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QAErF,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,IAAU,EAAa,EAAE;QAC/B,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,IAAI,EAAE,KAAK,EAAE,MAAM;YAClD,IAAI,CAAC,MAAM,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;gBAC9D,OAAO;YACT,CAAC;YAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;gBAC1D,OAAO;YACT,CAAC;YAED,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAE7C,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC;gBAAE,OAAO;YAEvC,MAAM,QAAQ,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;YAEzC,IAAI,CAAC,QAAQ;gBAAE,OAAO;YAEtB,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;gBAC7B,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACN,iCAAiC;gBACjC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;oBAChD,MAAM,CAAC,UAAU,CAAC,SAAS,GAAG,EAAE,CAAC;gBACnC,CAAC;gBAED,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,MAAM,CAAC","sourcesContent":["import type { Plugin } from \"unified\";\nimport type { Root } from \"hast\";\nimport { type VisitorResult, visit } from \"unist-util-visit\";\n\nexport type PreLanguageOption = string;\n\n// check if it is a string array\nfunction isStringArray(value: unknown): value is string[] {\n return (\n // type-coverage:ignore-next-line\n Array.isArray(value) && value.every((item) => typeof item === \"string\")\n );\n}\n\n/**\n *\n * add code language to <pre> element as a property\n *\n */\nconst plugin: Plugin<[PreLanguageOption?], Root> = (option) => {\n const property = option ? (option.startsWith(\"on\") ? option.slice(2) : option) : \"className\";\n\n /**\n *\n * get the language from classNames\n *\n */\n function getLanguage(classNames: string[]): string | undefined {\n const isLanguageString = (element: string): boolean =>\n element.startsWith(\"language-\") || element.startsWith(\"lang-\");\n\n const languageString = classNames.find(isLanguageString);\n\n if (!languageString) return;\n\n const language = languageString.slice(languageString.indexOf(\"-\") + 1).toLowerCase();\n\n return language;\n }\n\n /**\n * Transform.\n *\n * @param {Root} tree\n * Tree.\n * @returns {undefined}\n * Nothing.\n */\n return (tree: Root): undefined => {\n visit(tree, \"element\", function (code, index, parent): VisitorResult {\n if (!parent || index === undefined || code.tagName !== \"code\") {\n return;\n }\n\n if (parent.type !== \"element\" || parent.tagName !== \"pre\") {\n return;\n }\n\n const classNames = code.properties.className;\n\n if (!isStringArray(classNames)) return;\n\n const language = getLanguage(classNames);\n\n if (!language) return;\n\n if (property !== \"className\") {\n parent.properties[property] = language;\n } else {\n /* v8 ignore next -- @preserve */\n if (!isStringArray(parent.properties.className)) {\n parent.properties.className = [];\n }\n\n parent.properties.className.push(language);\n }\n });\n };\n};\n\nexport default plugin;\n"]}
package/package.json CHANGED
@@ -1,26 +1,31 @@
1
1
  {
2
2
  "name": "rehype-pre-language",
3
- "version": "1.1.6",
3
+ "version": "1.1.8",
4
4
  "description": "Rehype plugin to add language information as a property to pre element",
5
5
  "type": "module",
6
- "exports": "./dist/esm/index.js",
7
- "main": "./dist/esm/index.js",
8
- "types": "./dist/esm/index.d.ts",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
9
15
  "scripts": {
10
- "build": "rimraf dist && tsc --build && type-coverage",
16
+ "build": "rimraf dist && tsc --build tsconfig.build.json && type-coverage",
11
17
  "format": "npm run prettier && npm run lint",
12
18
  "prettier": "prettier --write .",
13
19
  "lint": "eslint .",
14
- "test": "vitest --watch=false",
20
+ "test": "vitest run",
15
21
  "test:watch": "vitest",
16
- "test:file": "vitest test.spec.ts",
22
+ "test:file": "vitest test.plugin.spec.ts",
23
+ "test-coverage": "vitest run --coverage",
17
24
  "prepack": "npm run build",
18
- "prepublishOnly": "npm run test && npm run format && npm run test-coverage",
19
- "test-coverage": "vitest run --coverage"
25
+ "prepublishOnly": "npm run format && npm run test-coverage"
20
26
  },
21
27
  "files": [
22
28
  "dist/",
23
- "src/",
24
29
  "LICENSE",
25
30
  "README.md"
26
31
  ],
@@ -47,34 +52,35 @@
47
52
  "url": "https://github.com/ipikuka/rehype-pre-language/issues"
48
53
  },
49
54
  "devDependencies": {
50
- "@eslint/js": "^9.39.1",
55
+ "@eslint/js": "^10.0.1",
51
56
  "@types/dedent": "^0.7.2",
52
- "@types/node": "^24.10.0",
53
- "@vitest/coverage-v8": "^4.0.8",
54
- "@vitest/eslint-plugin": "^1.4.2",
55
- "dedent": "^1.7.0",
56
- "eslint": "^9.39.1",
57
+ "@types/node": "^24.12.4",
58
+ "@vitest/coverage-v8": "^4.1.7",
59
+ "@vitest/eslint-plugin": "^1.6.18",
60
+ "dedent": "^1.7.2",
61
+ "eslint": "^10.4.0",
57
62
  "eslint-config-prettier": "^10.1.8",
58
- "eslint-plugin-prettier": "^5.5.4",
59
- "prettier": "^3.6.2",
63
+ "eslint-plugin-prettier": "^5.5.5",
64
+ "globals": "^17.6.0",
65
+ "prettier": "^3.8.3",
60
66
  "rehype-highlight": "^7.0.2",
61
67
  "rehype-parse": "^9.0.1",
62
68
  "rehype-stringify": "^10.0.1",
63
- "remark-flexible-code-titles": "^1.3.2",
69
+ "remark-flexible-code-titles": "^1.3.4",
64
70
  "remark-gfm": "^4.0.1",
65
71
  "remark-parse": "^11.0.0",
66
72
  "remark-rehype": "^11.1.2",
67
- "rimraf": "^6.1.0",
73
+ "rimraf": "^6.1.3",
68
74
  "type-coverage": "^2.29.7",
69
75
  "typescript": "^5.9.3",
70
- "typescript-eslint": "^8.46.3",
76
+ "typescript-eslint": "^8.60.0",
71
77
  "unified": "^11.0.5",
72
78
  "vfile": "^6.0.3",
73
- "vitest": "^4.0.8"
79
+ "vitest": "^4.1.7"
74
80
  },
75
81
  "dependencies": {
76
82
  "@types/hast": "^3.0.4",
77
- "unist-util-visit": "^5.0.0"
83
+ "unist-util-visit": "^5.1.0"
78
84
  },
79
85
  "peerDependencies": {
80
86
  "unified": "^11"
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAI7D,gCAAgC;AAChC,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO;IACL,iCAAiC;IACjC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CACxE,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,MAAM,GAAuC,CAAC,MAAM,EAAE,EAAE;IAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IAE7F;;;;OAIG;IACH,SAAS,WAAW,CAAC,UAAoB;QACvC,MAAM,gBAAgB,GAAG,CAAC,OAAe,EAAW,EAAE,CACpD,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAEjE,MAAM,cAAc,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAEzD,IAAI,CAAC,cAAc;YAAE,OAAO;QAE5B,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QAErF,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,IAAU,EAAa,EAAE;QAC/B,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,IAAI,EAAE,KAAK,EAAE,MAAM;YAClD,IAAI,CAAC,MAAM,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;gBAC9D,OAAO;YACT,CAAC;YAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;gBAC1D,OAAO;YACT,CAAC;YAED,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAE7C,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC;gBAAE,OAAO;YAEvC,MAAM,QAAQ,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;YAEzC,IAAI,CAAC,QAAQ;gBAAE,OAAO;YAEtB,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;gBAC7B,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,UAAU,CAAC,SAAS,GAAG;oBAC5B,oBAAoB;oBACpB,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;oBAClF,QAAQ;iBACT,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -1 +0,0 @@
1
- {"root":["../../src/index.ts"],"version":"5.9.3"}
package/src/index.ts DELETED
@@ -1,80 +0,0 @@
1
- import type { Plugin } from "unified";
2
- import type { Root } from "hast";
3
- import { type VisitorResult, visit } from "unist-util-visit";
4
-
5
- export type PreLanguageOption = string;
6
-
7
- // check if it is a string array
8
- function isStringArray(value: unknown): value is string[] {
9
- return (
10
- // type-coverage:ignore-next-line
11
- Array.isArray(value) && value.every((item) => typeof item === "string")
12
- );
13
- }
14
-
15
- /**
16
- *
17
- * add code language to <pre> element as a property
18
- *
19
- */
20
- const plugin: Plugin<[PreLanguageOption?], Root> = (option) => {
21
- const property = option ? (option.startsWith("on") ? option.slice(2) : option) : "className";
22
-
23
- /**
24
- *
25
- * get the language from classNames
26
- *
27
- */
28
- function getLanguage(classNames: string[]): string | undefined {
29
- const isLanguageString = (element: string): boolean =>
30
- element.startsWith("language-") || element.startsWith("lang-");
31
-
32
- const languageString = classNames.find(isLanguageString);
33
-
34
- if (!languageString) return;
35
-
36
- const language = languageString.slice(languageString.indexOf("-") + 1).toLowerCase();
37
-
38
- return language;
39
- }
40
-
41
- /**
42
- * Transform.
43
- *
44
- * @param {Root} tree
45
- * Tree.
46
- * @returns {undefined}
47
- * Nothing.
48
- */
49
- return (tree: Root): undefined => {
50
- visit(tree, "element", function (code, index, parent): VisitorResult {
51
- if (!parent || index === undefined || code.tagName !== "code") {
52
- return;
53
- }
54
-
55
- if (parent.type !== "element" || parent.tagName !== "pre") {
56
- return;
57
- }
58
-
59
- const classNames = code.properties.className;
60
-
61
- if (!isStringArray(classNames)) return;
62
-
63
- const language = getLanguage(classNames);
64
-
65
- if (!language) return;
66
-
67
- if (property !== "className") {
68
- parent.properties[property] = language;
69
- } else {
70
- parent.properties.className = [
71
- /* v8 ignore next */
72
- ...(isStringArray(parent.properties.className) ? parent.properties.className : []),
73
- language,
74
- ];
75
- }
76
- });
77
- };
78
- };
79
-
80
- export default plugin;