@vortexlabs/kirari-rehype 1.0.0 → 1.0.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @vortexlabs/kirari-rehype
2
2
 
3
+ ## 1.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 52ad674: Stop line wrappers from adding an empty last line after a code block's trailing newline. Markdown code blocks always end with a newline, so every block rendered with `lines` or fence line metadata such as `{2,4-6}` showed an extra empty line, and an extra number when line numbers come from CSS. The newline still follows the last wrapper, so the source text is unchanged, and blank lines before it keep their wrappers.
8
+
9
+ ## 1.0.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 3ee99c0: Update the package homepage and documentation links to https://kirari.sh.
14
+
3
15
  ## 1.0.0
4
16
 
5
17
  ### Major Changes
package/README.md CHANGED
@@ -8,6 +8,8 @@ Run it while building your content to send highlighted HTML and CSS to the
8
8
  browser, with no client-side highlighter. The integration is separate from the
9
9
  core package and does not change its bundle.
10
10
 
11
+ [Documentation](https://kirari.sh/docs/) · [Playground](https://kirari.sh/playground/)
12
+
11
13
  ## Install
12
14
 
13
15
  ```sh
@@ -15,7 +17,6 @@ npm install @vortexlabs/kirari @vortexlabs/kirari-rehype
15
17
  ```
16
18
 
17
19
  The plugin uses your application's Kirari through a peer dependency.
18
- Inside this workspace, use `workspace:*` for both packages instead.
19
20
 
20
21
  ## Markdown to HTML
21
22
 
@@ -74,7 +75,7 @@ and children.
74
75
  ## Register only what you need
75
76
 
76
77
  No languages are registered by default. Import each definition and pass it in
77
- `languages`. Labels resolve through [Kirari's language registry](../../docs/language-integration.md),
78
+ `languages`. Labels resolve through [Kirari's language registry](https://github.com/vortexkit/kirari/blob/main/docs/language-integration.md),
78
79
  so `js` selects registered JavaScript and `ts` selects registered TypeScript.
79
80
  There is no language detection or automatic grammar loading. JSX and TSX need
80
81
  their own definitions.
@@ -122,6 +123,7 @@ The `lineClassName` callback can append your own classes:
122
123
 
123
124
  ```ts
124
125
  import type { Options } from '@vortexlabs/kirari-rehype'
126
+ import { javascript } from '@vortexlabs/kirari/languages/javascript'
125
127
 
126
128
  const options = {
127
129
  languages: [javascript],
@@ -130,8 +132,8 @@ const options = {
130
132
  } satisfies Options
131
133
  ```
132
134
 
133
- Line endings remain outside the wrappers. Empty and trailing lines are
134
- preserved. Callback offsets are UTF-16 code units into the code block's source;
135
+ Line endings remain outside the wrappers. Empty lines are preserved; the
136
+ fence's trailing newline does not add an extra line. Callback offsets are UTF-16 code units into the code block's source;
135
137
  `start` is inclusive and `end` is exclusive and excludes the line ending.
136
138
  Token class callbacks receive each original token once, even when a token spans
137
139
  multiple lines.
@@ -171,4 +173,4 @@ remain trusted application code.
171
173
 
172
174
  ## License
173
175
 
174
- [MIT](LICENSE) © 2026 [Ugi](https://ugi.dev)
176
+ [MIT](https://github.com/vortexkit/kirari/blob/main/packages/rehype/LICENSE) © 2026 [Ugi](https://ugi.dev)
package/dist/index.js CHANGED
@@ -106,10 +106,30 @@ const tokenNodes = (source, tokens, options, ranges) => {
106
106
  break;
107
107
  nodes.push({ type: 'text', value: match[0] });
108
108
  start = end + match[0].length;
109
+ if (start === source.length)
110
+ break;
109
111
  number++;
110
112
  } while (true);
111
113
  return nodes;
112
114
  };
115
+ const optsOut = (classNames) => {
116
+ return classNames.some(name => name === 'no-highlight' || name === 'nohighlight');
117
+ };
118
+ /** Replaces the text of a `<code>` with highlighted nodes; returns whether it did. */
119
+ const highlightCode = (code, registry, options) => {
120
+ if (code.type !== 'element' || code.tagName !== 'code' || code.children.some(node => node.type !== 'text'))
121
+ return false;
122
+ const codeClasses = classes(code.properties.className);
123
+ if (optsOut(codeClasses))
124
+ return false;
125
+ const language = codeClasses.filter(name => name.startsWith('language-')).map(name => registry.resolve(name.slice(9))).find(Boolean);
126
+ if (!language)
127
+ return false;
128
+ const source = code.children.map(node => node.type === 'text' ? node.value : '').join('');
129
+ const meta = code.data && 'meta' in code.data ? code.data.meta : undefined;
130
+ code.children = tokenNodes(source, tokenize(source, language), options, lineRanges(meta));
131
+ return true;
132
+ };
113
133
  const rehypeKirari = (options = {}) => {
114
134
  const registry = createRegistry(options.languages ?? []);
115
135
  return tree => {
@@ -119,22 +139,11 @@ const rehypeKirari = (options = {}) => {
119
139
  for (const child of parent.children) {
120
140
  if (child.type === 'element' && child.tagName === 'pre') {
121
141
  const preClasses = classes(child.properties.className);
122
- if (!preClasses.some(name => name === 'no-highlight' || name === 'nohighlight')) {
123
- for (const code of child.children) {
124
- if (code.type !== 'element' || code.tagName !== 'code' || code.children.some(node => node.type !== 'text'))
125
- continue;
126
- const codeClasses = classes(code.properties.className);
127
- if (codeClasses.some(name => name === 'no-highlight' || name === 'nohighlight'))
128
- continue;
129
- const language = codeClasses.filter(name => name.startsWith('language-')).map(name => registry.resolve(name.slice(9))).find(Boolean);
130
- if (!language)
131
- continue;
132
- const source = code.children.map(node => node.type === 'text' ? node.value : '').join('');
133
- const meta = code.data && 'meta' in code.data ? code.data.meta : undefined;
134
- const children = tokenNodes(source, tokenize(source, language), options, lineRanges(meta));
135
- code.children = children;
142
+ if (optsOut(preClasses))
143
+ continue;
144
+ for (const code of child.children) {
145
+ if (highlightCode(code, registry, options))
136
146
  child.properties.className = [...new Set([...preClasses, 'kirari'])];
137
- }
138
147
  }
139
148
  continue;
140
149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vortexlabs/kirari-rehype",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Kirari syntax highlighting for Rehype and MDX.",
5
5
  "keywords": [
6
6
  "rehype",
@@ -10,7 +10,7 @@
10
10
  ],
11
11
  "author": "Ugi (https://ugi.dev)",
12
12
  "license": "MIT",
13
- "homepage": "https://kirari.vortex.design",
13
+ "homepage": "https://kirari.sh",
14
14
  "repository": {
15
15
  "type": "git",
16
16
  "url": "git+https://github.com/vortexkit/kirari.git",
@@ -47,7 +47,7 @@
47
47
  "@mdx-js/mdx": "^3.1.1",
48
48
  "@types/react": "^19.3.0",
49
49
  "@types/react-dom": "^19.3.0",
50
- "@vortexlabs/kirari": "1.0.0",
50
+ "@vortexlabs/kirari": "1.0.5",
51
51
  "react": "^19.3.1",
52
52
  "react-dom": "^19.3.1",
53
53
  "rehype-sanitize": "^6.0.0",