@refrakt-md/highlight 0.3.0

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.
@@ -0,0 +1,20 @@
1
+ import type { LanguageRegistration } from 'shiki';
2
+ import type { RendererNode } from '@refrakt-md/types';
3
+ export interface HighlightOptions {
4
+ /** Languages to pre-load when using the default Shiki highlighter.
5
+ * Accepts bundled language names or custom LanguageRegistration objects. */
6
+ langs?: (string | LanguageRegistration)[];
7
+ /** Custom highlight function. Receives raw code + language, returns HTML string.
8
+ * Default: Shiki with css-variables theme. */
9
+ highlight?: (code: string, lang: string) => string;
10
+ }
11
+ /**
12
+ * Create a syntax highlight transform that walks the serialized tree,
13
+ * finds elements with `data-language` + text children, highlights them,
14
+ * and sets `data-codeblock: true` for raw HTML injection by the Renderer.
15
+ *
16
+ * Uses Shiki with a CSS variables theme by default. Pass a custom
17
+ * `highlight` function to use a different highlighter.
18
+ */
19
+ export declare function createHighlightTransform(options?: HighlightOptions): Promise<(tree: RendererNode) => RendererNode>;
20
+ //# sourceMappingURL=highlight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlight.d.ts","sourceRoot":"","sources":["../src/highlight.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAElD,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,mBAAmB,CAAC;AAKrE,MAAM,WAAW,gBAAgB;IAChC;iFAC6E;IAC7E,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,oBAAoB,CAAC,EAAE,CAAC;IAC1C;mDAC+C;IAC/C,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACnD;AAUD;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,GAAE,gBAAqB,GAC5B,OAAO,CAAC,CAAC,IAAI,EAAE,YAAY,KAAK,YAAY,CAAC,CAmB/C"}
@@ -0,0 +1,84 @@
1
+ import { createHighlighter, createCssVariablesTheme } from 'shiki';
2
+ import { isTag } from '@refrakt-md/transform';
3
+ import { markdocLanguage } from './langs/markdoc.js';
4
+ const cssVarsTheme = createCssVariablesTheme();
5
+ const DEFAULT_LANGS = [
6
+ 'javascript', 'typescript', 'html', 'css', 'json', 'shell',
7
+ 'python', 'ruby', 'go', 'rust', 'java', 'c', 'cpp',
8
+ 'markdown', 'yaml', 'toml', 'sql', 'graphql', 'svelte',
9
+ 'jsx', 'tsx', 'diff', 'xml',
10
+ markdocLanguage,
11
+ ];
12
+ /**
13
+ * Create a syntax highlight transform that walks the serialized tree,
14
+ * finds elements with `data-language` + text children, highlights them,
15
+ * and sets `data-codeblock: true` for raw HTML injection by the Renderer.
16
+ *
17
+ * Uses Shiki with a CSS variables theme by default. Pass a custom
18
+ * `highlight` function to use a different highlighter.
19
+ */
20
+ export async function createHighlightTransform(options = {}) {
21
+ const { langs = DEFAULT_LANGS, highlight: customHighlight } = options;
22
+ let highlightFn;
23
+ if (customHighlight) {
24
+ highlightFn = customHighlight;
25
+ }
26
+ else {
27
+ const highlighter = await createHighlighter({
28
+ themes: [cssVarsTheme],
29
+ langs,
30
+ });
31
+ highlightFn = (code, lang) => {
32
+ const html = highlighter.codeToHtml(code, { lang, theme: 'css-variables' });
33
+ return extractInnerHtml(html);
34
+ };
35
+ }
36
+ return (tree) => walk(tree, highlightFn);
37
+ }
38
+ /** Walk the serialized tree, highlighting elements with `data-language`. */
39
+ function walk(node, highlightFn) {
40
+ if (node === null || node === undefined)
41
+ return node;
42
+ if (typeof node === 'string' || typeof node === 'number')
43
+ return node;
44
+ if (!isTag(node))
45
+ return node;
46
+ const lang = node.attributes?.['data-language'];
47
+ if (lang && hasTextChildren(node)) {
48
+ return highlightNode(node, lang, highlightFn);
49
+ }
50
+ return {
51
+ ...node,
52
+ children: node.children.map(c => walk(c, highlightFn)),
53
+ };
54
+ }
55
+ function hasTextChildren(node) {
56
+ return node.children.some(c => typeof c === 'string');
57
+ }
58
+ function highlightNode(node, lang, highlightFn) {
59
+ const text = node.children
60
+ .filter((c) => typeof c === 'string')
61
+ .join('');
62
+ try {
63
+ const html = highlightFn(text, lang);
64
+ return {
65
+ ...node,
66
+ attributes: { ...node.attributes, 'data-codeblock': true },
67
+ children: [html],
68
+ };
69
+ }
70
+ catch {
71
+ // Unknown language or highlight failure — leave text unchanged
72
+ return node;
73
+ }
74
+ }
75
+ /** Strip Shiki's <pre><code> wrapper to get just the highlighted spans. */
76
+ function extractInnerHtml(html) {
77
+ const codeStart = html.indexOf('<code>');
78
+ const codeEnd = html.lastIndexOf('</code>');
79
+ if (codeStart !== -1 && codeEnd !== -1) {
80
+ return html.slice(codeStart + '<code>'.length, codeEnd);
81
+ }
82
+ return html;
83
+ }
84
+ //# sourceMappingURL=highlight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlight.js","sourceRoot":"","sources":["../src/highlight.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { createHighlightTransform } from './highlight.js';
2
+ export type { HighlightOptions } from './highlight.js';
3
+ export { markdocLanguage } from './langs/markdoc.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { createHighlightTransform } from './highlight.js';
2
+ export { markdocLanguage } from './langs/markdoc.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { LanguageRegistration } from 'shiki';
2
+ /**
3
+ * TextMate grammar for Markdoc syntax.
4
+ *
5
+ * Highlights `{% tag %}` blocks with rune names, attributes, string values,
6
+ * numbers, and booleans. Markdown is the base language.
7
+ *
8
+ * Reusable by the VS Code extension (Phase 9a).
9
+ */
10
+ export declare const markdocLanguage: LanguageRegistration;
11
+ //# sourceMappingURL=markdoc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdoc.d.ts","sourceRoot":"","sources":["../../src/langs/markdoc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAElD;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,oBAmD7B,CAAC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * TextMate grammar for Markdoc syntax.
3
+ *
4
+ * Highlights `{% tag %}` blocks with rune names, attributes, string values,
5
+ * numbers, and booleans. Markdown is the base language.
6
+ *
7
+ * Reusable by the VS Code extension (Phase 9a).
8
+ */
9
+ export const markdocLanguage = {
10
+ name: 'markdoc',
11
+ scopeName: 'text.html.markdoc',
12
+ displayName: 'Markdoc',
13
+ embeddedLangs: ['markdown'],
14
+ patterns: [
15
+ { include: '#markdoc-tag' },
16
+ { include: 'text.html.markdown' },
17
+ ],
18
+ repository: {
19
+ 'markdoc-tag': {
20
+ name: 'meta.tag.markdoc',
21
+ begin: '(\\{%)(\\s*\\/?\\s*[a-z][a-z0-9-]*)',
22
+ end: '(%\\})',
23
+ beginCaptures: {
24
+ 1: { name: 'punctuation.definition.tag.begin.markdoc' },
25
+ 2: { name: 'entity.name.tag.markdoc' },
26
+ },
27
+ endCaptures: {
28
+ 1: { name: 'punctuation.definition.tag.end.markdoc' },
29
+ },
30
+ patterns: [
31
+ { include: '#tag-attributes' },
32
+ ],
33
+ },
34
+ 'tag-attributes': {
35
+ patterns: [
36
+ { include: '#attribute-name' },
37
+ { include: '#attribute-value-string' },
38
+ { include: '#attribute-value-number' },
39
+ { include: '#attribute-value-boolean' },
40
+ ],
41
+ },
42
+ 'attribute-name': {
43
+ name: 'entity.other.attribute-name.markdoc',
44
+ match: '[a-zA-Z_][a-zA-Z0-9_-]*(?=\\s*=)',
45
+ },
46
+ 'attribute-value-string': {
47
+ name: 'string.quoted.double.markdoc',
48
+ begin: '"',
49
+ end: '"',
50
+ },
51
+ 'attribute-value-number': {
52
+ name: 'constant.numeric.markdoc',
53
+ match: '\\b\\d+\\b',
54
+ },
55
+ 'attribute-value-boolean': {
56
+ name: 'constant.language.markdoc',
57
+ match: '\\b(true|false)\\b',
58
+ },
59
+ },
60
+ };
61
+ //# sourceMappingURL=markdoc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdoc.js","sourceRoot":"","sources":["../../src/langs/markdoc.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,eAAe,GAAyB;IACpD,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,mBAAmB;IAC9B,WAAW,EAAE,SAAS;IACtB,aAAa,EAAE,CAAC,UAAU,CAAC;IAC3B,QAAQ,EAAE;QACT,EAAE,OAAO,EAAE,cAAc,EAAE;QAC3B,EAAE,OAAO,EAAE,oBAAoB,EAAE;KACjC;IACD,UAAU,EAAE;QACX,aAAa,EAAE;YACd,IAAI,EAAE,kBAAkB;YACxB,KAAK,EAAE,qCAAqC;YAC5C,GAAG,EAAE,QAAQ;YACb,aAAa,EAAE;gBACd,CAAC,EAAE,EAAE,IAAI,EAAE,0CAA0C,EAAE;gBACvD,CAAC,EAAE,EAAE,IAAI,EAAE,yBAAyB,EAAE;aACtC;YACD,WAAW,EAAE;gBACZ,CAAC,EAAE,EAAE,IAAI,EAAE,wCAAwC,EAAE;aACrD;YACD,QAAQ,EAAE;gBACT,EAAE,OAAO,EAAE,iBAAiB,EAAE;aAC9B;SACD;QACD,gBAAgB,EAAE;YACjB,QAAQ,EAAE;gBACT,EAAE,OAAO,EAAE,iBAAiB,EAAE;gBAC9B,EAAE,OAAO,EAAE,yBAAyB,EAAE;gBACtC,EAAE,OAAO,EAAE,yBAAyB,EAAE;gBACtC,EAAE,OAAO,EAAE,0BAA0B,EAAE;aACvC;SACD;QACD,gBAAgB,EAAE;YACjB,IAAI,EAAE,qCAAqC;YAC3C,KAAK,EAAE,kCAAkC;SACzC;QACD,wBAAwB,EAAE;YACzB,IAAI,EAAE,8BAA8B;YACpC,KAAK,EAAE,GAAG;YACV,GAAG,EAAE,GAAG;SACR;QACD,wBAAwB,EAAE;YACzB,IAAI,EAAE,0BAA0B;YAChC,KAAK,EAAE,YAAY;SACnB;QACD,yBAAyB,EAAE;YAC1B,IAAI,EAAE,2BAA2B;YACjC,KAAK,EAAE,oBAAoB;SAC3B;KACD;CACD,CAAC"}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@refrakt-md/highlight",
3
+ "description": "Syntax highlighting transform for refrakt.md — Shiki-based tree walker with pluggable highlighter",
4
+ "version": "0.3.0",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/refrakt-md/refrakt.git",
10
+ "directory": "packages/highlight"
11
+ },
12
+ "bugs": "https://github.com/refrakt-md/refrakt/issues",
13
+ "homepage": "https://github.com/refrakt-md/refrakt",
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "main": "dist/index.js",
18
+ "types": "dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsc"
30
+ },
31
+ "dependencies": {
32
+ "@refrakt-md/types": "0.3.0",
33
+ "@refrakt-md/transform": "0.3.0",
34
+ "shiki": "^3.0.0"
35
+ }
36
+ }