@podlite/highlight 0.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.podlite +9 -0
- package/LICENSE +22 -0
- package/README.md +39 -0
- package/esm/HighlightedCode.d.ts +26 -0
- package/esm/HighlightedCode.js +106 -0
- package/esm/HighlightedCode.js.map +1 -0
- package/esm/index.d.ts +4 -0
- package/esm/index.js +3 -0
- package/esm/index.js.map +1 -0
- package/esm/shiki.d.ts +36 -0
- package/esm/shiki.js +157 -0
- package/esm/shiki.js.map +1 -0
- package/lib/HighlightedCode.d.ts +26 -0
- package/lib/HighlightedCode.js +143 -0
- package/lib/HighlightedCode.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +16 -0
- package/lib/index.js.map +1 -0
- package/lib/shiki.d.ts +36 -0
- package/lib/shiki.js +198 -0
- package/lib/shiki.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @podlite/highlight
|
|
2
|
+
|
|
3
|
+
=head1 Upcoming
|
|
4
|
+
|
|
5
|
+
=head1 0.0.2
|
|
6
|
+
|
|
7
|
+
=item a caller that does not say how to wrap a code block gets the wrapping that shows a caption. The other wrapping drops it, and a caption written on a block was disappearing for callers that said nothing
|
|
8
|
+
|
|
9
|
+
=item the package carries the syntax highlighting that the renderer and the editor used to hold a copy of each, so both share one highlighter and one grammar cache. shiki is a peer declared optional: type checking passes without it and a chunk that fails to load leaves plain text, though the name still has to resolve when you bundle. A block with no lang attribute loads no grammar at all
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright © 2021-2026 Aliaksandr Zahatski
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @podlite/highlight
|
|
2
|
+
|
|
3
|
+
Syntax highlighting for Podlite code blocks. The renderer (`@podlite/to-jsx`) and
|
|
4
|
+
the editor (`@podlite/editor-react`) both take it from here, so a document looks
|
|
5
|
+
the same in a preview as it does in an editor.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @podlite/highlight shiki
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`shiki` is a peer, declared optional so it is never pulled in unnoticed. What
|
|
14
|
+
that does and does not buy you:
|
|
15
|
+
|
|
16
|
+
- **Types.** This package describes the parts of shiki it uses, so type checking
|
|
17
|
+
passes with shiki absent.
|
|
18
|
+
- **Bundling.** The loader names `shiki` in a plain dynamic import, which lets a
|
|
19
|
+
bundler split it into its own chunk. That same plain name has to resolve at
|
|
20
|
+
build time, so install shiki if you bundle this package.
|
|
21
|
+
- **Runtime.** If the chunk fails to load, the component renders the code as
|
|
22
|
+
plain `<pre><code>` instead of throwing.
|
|
23
|
+
|
|
24
|
+
A block with no `:lang` never loads a grammar at all.
|
|
25
|
+
|
|
26
|
+
## Use
|
|
27
|
+
|
|
28
|
+
```jsx
|
|
29
|
+
import { HighlightedCode } from '@podlite/highlight'
|
|
30
|
+
|
|
31
|
+
<HighlightedCode node={node} ctx={ctx} keyProp={key} wrap="block">
|
|
32
|
+
{children}
|
|
33
|
+
</HighlightedCode>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
A block with no `:lang` attribute is not highlighted: nothing declares what the
|
|
37
|
+
code is, so no grammar is loaded for it.
|
|
38
|
+
|
|
39
|
+
Grammars load one at a time, when a block asks for one.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type Decoration = {
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
tagName: string;
|
|
6
|
+
properties?: {
|
|
7
|
+
class?: string;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export declare const extractPlainAndDecorations: (nodes: unknown) => {
|
|
11
|
+
plain: string;
|
|
12
|
+
decorations: Decoration[];
|
|
13
|
+
};
|
|
14
|
+
export type HighlightedCodeProps = {
|
|
15
|
+
node: {
|
|
16
|
+
content?: unknown;
|
|
17
|
+
config?: unknown;
|
|
18
|
+
};
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
keyProp: string | number;
|
|
21
|
+
ctx: unknown;
|
|
22
|
+
id?: string;
|
|
23
|
+
wrap?: 'pre-code' | 'block';
|
|
24
|
+
};
|
|
25
|
+
declare const HighlightedCode: React.FC<HighlightedCodeProps>;
|
|
26
|
+
export default HighlightedCode;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { makeAttrs } from '@podlite/schema';
|
|
3
|
+
import { codeToThemedHtml } from './shiki';
|
|
4
|
+
const fcodeToTag = {
|
|
5
|
+
B: 'strong',
|
|
6
|
+
I: 'em',
|
|
7
|
+
C: 'code',
|
|
8
|
+
U: 'u',
|
|
9
|
+
K: 'kbd',
|
|
10
|
+
};
|
|
11
|
+
export const extractPlainAndDecorations = (nodes) => {
|
|
12
|
+
const decorations = [];
|
|
13
|
+
let plain = '';
|
|
14
|
+
const walk = (input) => {
|
|
15
|
+
if (input == null)
|
|
16
|
+
return;
|
|
17
|
+
if (typeof input === 'string') {
|
|
18
|
+
plain += input;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(input)) {
|
|
22
|
+
for (const child of input)
|
|
23
|
+
walk(child);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const node = input;
|
|
27
|
+
if (node.type === 'text' && typeof node.value === 'string') {
|
|
28
|
+
plain += node.value;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (node.type === 'verbatim' && typeof node.value === 'string') {
|
|
32
|
+
plain += node.value;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (node.type === 'fcode' && typeof node.name === 'string') {
|
|
36
|
+
const tagName = fcodeToTag[node.name] || 'span';
|
|
37
|
+
const start = plain.length;
|
|
38
|
+
walk(node.content);
|
|
39
|
+
const end = plain.length;
|
|
40
|
+
if (end > start) {
|
|
41
|
+
decorations.push({
|
|
42
|
+
start,
|
|
43
|
+
end,
|
|
44
|
+
tagName,
|
|
45
|
+
properties: { class: `fc-${node.name}` },
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (node.content !== undefined) {
|
|
51
|
+
walk(node.content);
|
|
52
|
+
}
|
|
53
|
+
else if (typeof node.text === 'string') {
|
|
54
|
+
plain += node.text;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
walk(nodes);
|
|
58
|
+
return { plain, decorations };
|
|
59
|
+
};
|
|
60
|
+
// Block wrapping is the default because it is the one that shows a caption:
|
|
61
|
+
// a caller that says nothing gets the caption rather than silently losing it.
|
|
62
|
+
const HighlightedCode = React.memo(({ node, children, keyProp, ctx, id, wrap = 'block' }) => {
|
|
63
|
+
const conf = makeAttrs(node, ctx);
|
|
64
|
+
const caption = conf.exists('caption') ? conf.getFirstValue('caption') : null;
|
|
65
|
+
const lang = conf.getFirstValue('lang');
|
|
66
|
+
const [html, setHtml] = useState(null);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (!lang)
|
|
69
|
+
return;
|
|
70
|
+
let cancelled = false;
|
|
71
|
+
const highlight = async () => {
|
|
72
|
+
try {
|
|
73
|
+
const isDark = typeof document !== 'undefined' && document.body && document.body.className.toLowerCase().includes('dark');
|
|
74
|
+
const { plain, decorations } = extractPlainAndDecorations(node.content);
|
|
75
|
+
const result = await codeToThemedHtml({
|
|
76
|
+
code: plain,
|
|
77
|
+
language: lang,
|
|
78
|
+
theme: isDark ? 'dark' : 'light',
|
|
79
|
+
decorations,
|
|
80
|
+
});
|
|
81
|
+
if (!cancelled)
|
|
82
|
+
setHtml(result);
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
console.error('[podlite] shiki highlight error:', e);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
highlight();
|
|
89
|
+
return () => {
|
|
90
|
+
cancelled = true;
|
|
91
|
+
};
|
|
92
|
+
}, [lang, node.content]);
|
|
93
|
+
// The id goes on whichever element the branch puts outermost, so a link to
|
|
94
|
+
// the block keeps working once highlighting replaces the plain output.
|
|
95
|
+
const codeBody = html ? (React.createElement("code", { key: keyProp, id: id, className: "shiki", dangerouslySetInnerHTML: { __html: html } })) : (React.createElement("pre", { key: `${keyProp}-pre`, id: id },
|
|
96
|
+
React.createElement("code", { key: keyProp }, children)));
|
|
97
|
+
if (wrap === 'block') {
|
|
98
|
+
return (React.createElement("div", { className: "code-block", key: `${keyProp}-code-div` },
|
|
99
|
+
codeBody,
|
|
100
|
+
caption ? (React.createElement("div", { key: `${keyProp}-caption`, className: "caption" }, caption)) : null));
|
|
101
|
+
}
|
|
102
|
+
return codeBody;
|
|
103
|
+
});
|
|
104
|
+
HighlightedCode.displayName = 'HighlightedCode';
|
|
105
|
+
export default HighlightedCode;
|
|
106
|
+
//# sourceMappingURL=HighlightedCode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HighlightedCode.js","sourceRoot":"","sources":["../src/HighlightedCode.tsx"],"names":[],"mappings":"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"}
|
package/esm/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as HighlightedCode, extractPlainAndDecorations } from './HighlightedCode';
|
|
2
|
+
export type { HighlightedCodeProps } from './HighlightedCode';
|
|
3
|
+
export { codeToHtml, codeToThemedHtml, getHighlighter, isLanguageLoaded, normalizeLanguage } from './shiki';
|
|
4
|
+
export type { BundledLanguage, BundledTheme, DecorationItem, ExtendedLanguage, Highlighter } from './shiki';
|
package/esm/index.js
ADDED
package/esm/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AAE1F,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA"}
|
package/esm/shiki.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type BundledLanguage = string;
|
|
2
|
+
export type BundledTheme = string;
|
|
3
|
+
export type DecorationItem = {
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
tagName?: string;
|
|
7
|
+
properties?: Record<string, string>;
|
|
8
|
+
};
|
|
9
|
+
type CodeToHtmlOptions = {
|
|
10
|
+
lang: string;
|
|
11
|
+
theme?: BundledTheme;
|
|
12
|
+
themes?: {
|
|
13
|
+
light: BundledTheme;
|
|
14
|
+
dark: BundledTheme;
|
|
15
|
+
};
|
|
16
|
+
decorations?: DecorationItem[];
|
|
17
|
+
};
|
|
18
|
+
export type Highlighter = {
|
|
19
|
+
codeToHtml: (code: string, options: CodeToHtmlOptions) => string;
|
|
20
|
+
loadLanguage: (lang: BundledLanguage) => Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
export type ExtendedLanguage = BundledLanguage | 'txt';
|
|
23
|
+
export declare function normalizeLanguage(language?: string): Promise<ExtendedLanguage>;
|
|
24
|
+
export declare function getHighlighter(language?: string): Promise<Highlighter>;
|
|
25
|
+
export declare function codeToHtml({ code, language }: {
|
|
26
|
+
code: string;
|
|
27
|
+
language: string;
|
|
28
|
+
}): Promise<string>;
|
|
29
|
+
export declare function codeToThemedHtml({ code, language, theme, decorations, }: {
|
|
30
|
+
code: string;
|
|
31
|
+
language: string;
|
|
32
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
33
|
+
decorations?: DecorationItem[];
|
|
34
|
+
}): Promise<string>;
|
|
35
|
+
export declare const isLanguageLoaded: (language: ExtendedLanguage) => boolean;
|
|
36
|
+
export {};
|
package/esm/shiki.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
const isShikiModule = (m) => typeof m === 'object' && m !== null && 'createHighlighter' in m && 'bundledLanguages' in m;
|
|
2
|
+
// A rejected import and an unusable module are the same event to the caller:
|
|
3
|
+
// highlighting is unavailable, and the caller falls back to plain output.
|
|
4
|
+
const loadShiki = async () => {
|
|
5
|
+
const module = await import('shiki');
|
|
6
|
+
if (!isShikiModule(module))
|
|
7
|
+
throw new Error('shiki is not available');
|
|
8
|
+
return module;
|
|
9
|
+
};
|
|
10
|
+
const CONFIG = {
|
|
11
|
+
themes: {
|
|
12
|
+
light: 'one-light',
|
|
13
|
+
dark: 'github-dark',
|
|
14
|
+
},
|
|
15
|
+
// Only the fallback grammar is preloaded; everything else arrives through
|
|
16
|
+
// loadLanguage when a block asks for it.
|
|
17
|
+
initialLanguages: ['txt'],
|
|
18
|
+
};
|
|
19
|
+
// Language aliases mapping
|
|
20
|
+
const languageAliases = {
|
|
21
|
+
text: 'txt',
|
|
22
|
+
plaintext: 'txt',
|
|
23
|
+
plain: 'txt',
|
|
24
|
+
sh: 'shell',
|
|
25
|
+
bash: 'shell',
|
|
26
|
+
zsh: 'shell',
|
|
27
|
+
shellscript: 'shell',
|
|
28
|
+
'shell-script': 'shell',
|
|
29
|
+
console: 'shell',
|
|
30
|
+
terminal: 'shell',
|
|
31
|
+
js: 'javascript',
|
|
32
|
+
node: 'javascript',
|
|
33
|
+
nodejs: 'javascript',
|
|
34
|
+
ts: 'typescript',
|
|
35
|
+
py: 'python',
|
|
36
|
+
python3: 'python',
|
|
37
|
+
py3: 'python',
|
|
38
|
+
rb: 'ruby',
|
|
39
|
+
md: 'markdown',
|
|
40
|
+
cpp: 'c++',
|
|
41
|
+
cc: 'c++',
|
|
42
|
+
cs: 'c#',
|
|
43
|
+
csharp: 'c#',
|
|
44
|
+
htm: 'html',
|
|
45
|
+
yml: 'yaml',
|
|
46
|
+
dockerfile: 'docker',
|
|
47
|
+
styles: 'css',
|
|
48
|
+
style: 'css',
|
|
49
|
+
jsonc: 'json',
|
|
50
|
+
json5: 'json',
|
|
51
|
+
xaml: 'xml',
|
|
52
|
+
xhtml: 'xml',
|
|
53
|
+
svg: 'xml',
|
|
54
|
+
mysql: 'sql',
|
|
55
|
+
postgresql: 'sql',
|
|
56
|
+
postgres: 'sql',
|
|
57
|
+
pgsql: 'sql',
|
|
58
|
+
plsql: 'sql',
|
|
59
|
+
oracle: 'sql',
|
|
60
|
+
};
|
|
61
|
+
// One highlighter for the process: both the renderer and the editor reach it
|
|
62
|
+
// through this module, so a grammar is fetched once however many views ask.
|
|
63
|
+
const state = {
|
|
64
|
+
instance: null,
|
|
65
|
+
initPromise: null,
|
|
66
|
+
loadedLanguages: new Set(['txt']),
|
|
67
|
+
pendingLoads: new Map(),
|
|
68
|
+
warnedLanguages: new Set(),
|
|
69
|
+
};
|
|
70
|
+
// Normalize language to valid Shiki language
|
|
71
|
+
export async function normalizeLanguage(language) {
|
|
72
|
+
if (!language)
|
|
73
|
+
return 'txt';
|
|
74
|
+
const normalized = language.toLowerCase();
|
|
75
|
+
const { bundledLanguages } = await loadShiki();
|
|
76
|
+
if (normalized in bundledLanguages) {
|
|
77
|
+
return normalized;
|
|
78
|
+
}
|
|
79
|
+
if (normalized in languageAliases) {
|
|
80
|
+
return languageAliases[normalized];
|
|
81
|
+
}
|
|
82
|
+
if (!state.warnedLanguages.has(language)) {
|
|
83
|
+
console.warn(`[podlite] shiki unrecognized language '${language}', defaulting to [txt]`);
|
|
84
|
+
state.warnedLanguages.add(language);
|
|
85
|
+
}
|
|
86
|
+
return 'txt';
|
|
87
|
+
}
|
|
88
|
+
// Get or create highlighter instance
|
|
89
|
+
async function getHighlighterInstance() {
|
|
90
|
+
if (!state.initPromise) {
|
|
91
|
+
state.initPromise = (async () => {
|
|
92
|
+
const { createHighlighter } = await loadShiki();
|
|
93
|
+
const instance = await createHighlighter({
|
|
94
|
+
themes: Object.values(CONFIG.themes),
|
|
95
|
+
langs: CONFIG.initialLanguages,
|
|
96
|
+
});
|
|
97
|
+
state.instance = instance;
|
|
98
|
+
CONFIG.initialLanguages.forEach(lang => state.loadedLanguages.add(lang));
|
|
99
|
+
return instance;
|
|
100
|
+
})();
|
|
101
|
+
}
|
|
102
|
+
return state.initPromise;
|
|
103
|
+
}
|
|
104
|
+
// Load a language if not already loaded
|
|
105
|
+
async function ensureLanguageLoaded(instance, lang) {
|
|
106
|
+
if (state.loadedLanguages.has(lang))
|
|
107
|
+
return;
|
|
108
|
+
let pending = state.pendingLoads.get(lang);
|
|
109
|
+
if (!pending) {
|
|
110
|
+
pending = instance
|
|
111
|
+
.loadLanguage(lang)
|
|
112
|
+
.then(() => {
|
|
113
|
+
state.loadedLanguages.add(lang);
|
|
114
|
+
})
|
|
115
|
+
.finally(() => state.pendingLoads.delete(lang));
|
|
116
|
+
state.pendingLoads.set(lang, pending);
|
|
117
|
+
}
|
|
118
|
+
await pending;
|
|
119
|
+
}
|
|
120
|
+
// Main API: get highlighter with language loaded
|
|
121
|
+
export async function getHighlighter(language) {
|
|
122
|
+
const lang = await normalizeLanguage(language);
|
|
123
|
+
const instance = await getHighlighterInstance();
|
|
124
|
+
await ensureLanguageLoaded(instance, lang);
|
|
125
|
+
return instance;
|
|
126
|
+
}
|
|
127
|
+
// Convenience: convert code to HTML with dual themes (CSS-based switching)
|
|
128
|
+
export async function codeToHtml({ code, language }) {
|
|
129
|
+
const lang = await normalizeLanguage(language);
|
|
130
|
+
const highlighter = await getHighlighter(language);
|
|
131
|
+
return highlighter.codeToHtml(code, {
|
|
132
|
+
lang,
|
|
133
|
+
themes: CONFIG.themes,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Convert code to HTML with explicit theme selection (for runtime theme detection)
|
|
137
|
+
export async function codeToThemedHtml({ code, language, theme, decorations, }) {
|
|
138
|
+
const lang = await normalizeLanguage(language);
|
|
139
|
+
const highlighter = await getHighlighter(language);
|
|
140
|
+
if (theme === 'light' || theme === 'dark') {
|
|
141
|
+
return highlighter.codeToHtml(code, {
|
|
142
|
+
lang,
|
|
143
|
+
theme: CONFIG.themes[theme],
|
|
144
|
+
decorations,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return highlighter.codeToHtml(code, {
|
|
148
|
+
lang,
|
|
149
|
+
themes: CONFIG.themes,
|
|
150
|
+
decorations,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// Check if a language is loaded (sync — only meaningful after a prior async normalize)
|
|
154
|
+
export const isLanguageLoaded = (language) => {
|
|
155
|
+
return state.loadedLanguages.has(language);
|
|
156
|
+
};
|
|
157
|
+
//# sourceMappingURL=shiki.js.map
|
package/esm/shiki.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shiki.js","sourceRoot":"","sources":["../src/shiki.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type Decoration = {
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
tagName: string;
|
|
6
|
+
properties?: {
|
|
7
|
+
class?: string;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export declare const extractPlainAndDecorations: (nodes: unknown) => {
|
|
11
|
+
plain: string;
|
|
12
|
+
decorations: Decoration[];
|
|
13
|
+
};
|
|
14
|
+
export type HighlightedCodeProps = {
|
|
15
|
+
node: {
|
|
16
|
+
content?: unknown;
|
|
17
|
+
config?: unknown;
|
|
18
|
+
};
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
keyProp: string | number;
|
|
21
|
+
ctx: unknown;
|
|
22
|
+
id?: string;
|
|
23
|
+
wrap?: 'pre-code' | 'block';
|
|
24
|
+
};
|
|
25
|
+
declare const HighlightedCode: React.FC<HighlightedCodeProps>;
|
|
26
|
+
export default HighlightedCode;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.extractPlainAndDecorations = void 0;
|
|
37
|
+
const react_1 = __importStar(require("react"));
|
|
38
|
+
const schema_1 = require("@podlite/schema");
|
|
39
|
+
const shiki_1 = require("./shiki");
|
|
40
|
+
const fcodeToTag = {
|
|
41
|
+
B: 'strong',
|
|
42
|
+
I: 'em',
|
|
43
|
+
C: 'code',
|
|
44
|
+
U: 'u',
|
|
45
|
+
K: 'kbd',
|
|
46
|
+
};
|
|
47
|
+
const extractPlainAndDecorations = (nodes) => {
|
|
48
|
+
const decorations = [];
|
|
49
|
+
let plain = '';
|
|
50
|
+
const walk = (input) => {
|
|
51
|
+
if (input == null)
|
|
52
|
+
return;
|
|
53
|
+
if (typeof input === 'string') {
|
|
54
|
+
plain += input;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(input)) {
|
|
58
|
+
for (const child of input)
|
|
59
|
+
walk(child);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const node = input;
|
|
63
|
+
if (node.type === 'text' && typeof node.value === 'string') {
|
|
64
|
+
plain += node.value;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (node.type === 'verbatim' && typeof node.value === 'string') {
|
|
68
|
+
plain += node.value;
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (node.type === 'fcode' && typeof node.name === 'string') {
|
|
72
|
+
const tagName = fcodeToTag[node.name] || 'span';
|
|
73
|
+
const start = plain.length;
|
|
74
|
+
walk(node.content);
|
|
75
|
+
const end = plain.length;
|
|
76
|
+
if (end > start) {
|
|
77
|
+
decorations.push({
|
|
78
|
+
start,
|
|
79
|
+
end,
|
|
80
|
+
tagName,
|
|
81
|
+
properties: { class: `fc-${node.name}` },
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (node.content !== undefined) {
|
|
87
|
+
walk(node.content);
|
|
88
|
+
}
|
|
89
|
+
else if (typeof node.text === 'string') {
|
|
90
|
+
plain += node.text;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
walk(nodes);
|
|
94
|
+
return { plain, decorations };
|
|
95
|
+
};
|
|
96
|
+
exports.extractPlainAndDecorations = extractPlainAndDecorations;
|
|
97
|
+
// Block wrapping is the default because it is the one that shows a caption:
|
|
98
|
+
// a caller that says nothing gets the caption rather than silently losing it.
|
|
99
|
+
const HighlightedCode = react_1.default.memo(({ node, children, keyProp, ctx, id, wrap = 'block' }) => {
|
|
100
|
+
const conf = (0, schema_1.makeAttrs)(node, ctx);
|
|
101
|
+
const caption = conf.exists('caption') ? conf.getFirstValue('caption') : null;
|
|
102
|
+
const lang = conf.getFirstValue('lang');
|
|
103
|
+
const [html, setHtml] = (0, react_1.useState)(null);
|
|
104
|
+
(0, react_1.useEffect)(() => {
|
|
105
|
+
if (!lang)
|
|
106
|
+
return;
|
|
107
|
+
let cancelled = false;
|
|
108
|
+
const highlight = async () => {
|
|
109
|
+
try {
|
|
110
|
+
const isDark = typeof document !== 'undefined' && document.body && document.body.className.toLowerCase().includes('dark');
|
|
111
|
+
const { plain, decorations } = (0, exports.extractPlainAndDecorations)(node.content);
|
|
112
|
+
const result = await (0, shiki_1.codeToThemedHtml)({
|
|
113
|
+
code: plain,
|
|
114
|
+
language: lang,
|
|
115
|
+
theme: isDark ? 'dark' : 'light',
|
|
116
|
+
decorations,
|
|
117
|
+
});
|
|
118
|
+
if (!cancelled)
|
|
119
|
+
setHtml(result);
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
console.error('[podlite] shiki highlight error:', e);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
highlight();
|
|
126
|
+
return () => {
|
|
127
|
+
cancelled = true;
|
|
128
|
+
};
|
|
129
|
+
}, [lang, node.content]);
|
|
130
|
+
// The id goes on whichever element the branch puts outermost, so a link to
|
|
131
|
+
// the block keeps working once highlighting replaces the plain output.
|
|
132
|
+
const codeBody = html ? (react_1.default.createElement("code", { key: keyProp, id: id, className: "shiki", dangerouslySetInnerHTML: { __html: html } })) : (react_1.default.createElement("pre", { key: `${keyProp}-pre`, id: id },
|
|
133
|
+
react_1.default.createElement("code", { key: keyProp }, children)));
|
|
134
|
+
if (wrap === 'block') {
|
|
135
|
+
return (react_1.default.createElement("div", { className: "code-block", key: `${keyProp}-code-div` },
|
|
136
|
+
codeBody,
|
|
137
|
+
caption ? (react_1.default.createElement("div", { key: `${keyProp}-caption`, className: "caption" }, caption)) : null));
|
|
138
|
+
}
|
|
139
|
+
return codeBody;
|
|
140
|
+
});
|
|
141
|
+
HighlightedCode.displayName = 'HighlightedCode';
|
|
142
|
+
exports.default = HighlightedCode;
|
|
143
|
+
//# sourceMappingURL=HighlightedCode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HighlightedCode.js","sourceRoot":"","sources":["../src/HighlightedCode.tsx"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as HighlightedCode, extractPlainAndDecorations } from './HighlightedCode';
|
|
2
|
+
export type { HighlightedCodeProps } from './HighlightedCode';
|
|
3
|
+
export { codeToHtml, codeToThemedHtml, getHighlighter, isLanguageLoaded, normalizeLanguage } from './shiki';
|
|
4
|
+
export type { BundledLanguage, BundledTheme, DecorationItem, ExtendedLanguage, Highlighter } from './shiki';
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.normalizeLanguage = exports.isLanguageLoaded = exports.getHighlighter = exports.codeToThemedHtml = exports.codeToHtml = exports.extractPlainAndDecorations = exports.HighlightedCode = void 0;
|
|
7
|
+
var HighlightedCode_1 = require("./HighlightedCode");
|
|
8
|
+
Object.defineProperty(exports, "HighlightedCode", { enumerable: true, get: function () { return __importDefault(HighlightedCode_1).default; } });
|
|
9
|
+
Object.defineProperty(exports, "extractPlainAndDecorations", { enumerable: true, get: function () { return HighlightedCode_1.extractPlainAndDecorations; } });
|
|
10
|
+
var shiki_1 = require("./shiki");
|
|
11
|
+
Object.defineProperty(exports, "codeToHtml", { enumerable: true, get: function () { return shiki_1.codeToHtml; } });
|
|
12
|
+
Object.defineProperty(exports, "codeToThemedHtml", { enumerable: true, get: function () { return shiki_1.codeToThemedHtml; } });
|
|
13
|
+
Object.defineProperty(exports, "getHighlighter", { enumerable: true, get: function () { return shiki_1.getHighlighter; } });
|
|
14
|
+
Object.defineProperty(exports, "isLanguageLoaded", { enumerable: true, get: function () { return shiki_1.isLanguageLoaded; } });
|
|
15
|
+
Object.defineProperty(exports, "normalizeLanguage", { enumerable: true, get: function () { return shiki_1.normalizeLanguage; } });
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,qDAA0F;AAAjF,mIAAA,OAAO,OAAmB;AAAE,6HAAA,0BAA0B,OAAA;AAE/D,iCAA2G;AAAlG,mGAAA,UAAU,OAAA;AAAE,yGAAA,gBAAgB,OAAA;AAAE,uGAAA,cAAc,OAAA;AAAE,yGAAA,gBAAgB,OAAA;AAAE,0GAAA,iBAAiB,OAAA"}
|
package/lib/shiki.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type BundledLanguage = string;
|
|
2
|
+
export type BundledTheme = string;
|
|
3
|
+
export type DecorationItem = {
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
tagName?: string;
|
|
7
|
+
properties?: Record<string, string>;
|
|
8
|
+
};
|
|
9
|
+
type CodeToHtmlOptions = {
|
|
10
|
+
lang: string;
|
|
11
|
+
theme?: BundledTheme;
|
|
12
|
+
themes?: {
|
|
13
|
+
light: BundledTheme;
|
|
14
|
+
dark: BundledTheme;
|
|
15
|
+
};
|
|
16
|
+
decorations?: DecorationItem[];
|
|
17
|
+
};
|
|
18
|
+
export type Highlighter = {
|
|
19
|
+
codeToHtml: (code: string, options: CodeToHtmlOptions) => string;
|
|
20
|
+
loadLanguage: (lang: BundledLanguage) => Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
export type ExtendedLanguage = BundledLanguage | 'txt';
|
|
23
|
+
export declare function normalizeLanguage(language?: string): Promise<ExtendedLanguage>;
|
|
24
|
+
export declare function getHighlighter(language?: string): Promise<Highlighter>;
|
|
25
|
+
export declare function codeToHtml({ code, language }: {
|
|
26
|
+
code: string;
|
|
27
|
+
language: string;
|
|
28
|
+
}): Promise<string>;
|
|
29
|
+
export declare function codeToThemedHtml({ code, language, theme, decorations, }: {
|
|
30
|
+
code: string;
|
|
31
|
+
language: string;
|
|
32
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
33
|
+
decorations?: DecorationItem[];
|
|
34
|
+
}): Promise<string>;
|
|
35
|
+
export declare const isLanguageLoaded: (language: ExtendedLanguage) => boolean;
|
|
36
|
+
export {};
|
package/lib/shiki.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.isLanguageLoaded = void 0;
|
|
37
|
+
exports.normalizeLanguage = normalizeLanguage;
|
|
38
|
+
exports.getHighlighter = getHighlighter;
|
|
39
|
+
exports.codeToHtml = codeToHtml;
|
|
40
|
+
exports.codeToThemedHtml = codeToThemedHtml;
|
|
41
|
+
const isShikiModule = (m) => typeof m === 'object' && m !== null && 'createHighlighter' in m && 'bundledLanguages' in m;
|
|
42
|
+
// A rejected import and an unusable module are the same event to the caller:
|
|
43
|
+
// highlighting is unavailable, and the caller falls back to plain output.
|
|
44
|
+
const loadShiki = async () => {
|
|
45
|
+
const module = await Promise.resolve().then(() => __importStar(require('shiki')));
|
|
46
|
+
if (!isShikiModule(module))
|
|
47
|
+
throw new Error('shiki is not available');
|
|
48
|
+
return module;
|
|
49
|
+
};
|
|
50
|
+
const CONFIG = {
|
|
51
|
+
themes: {
|
|
52
|
+
light: 'one-light',
|
|
53
|
+
dark: 'github-dark',
|
|
54
|
+
},
|
|
55
|
+
// Only the fallback grammar is preloaded; everything else arrives through
|
|
56
|
+
// loadLanguage when a block asks for it.
|
|
57
|
+
initialLanguages: ['txt'],
|
|
58
|
+
};
|
|
59
|
+
// Language aliases mapping
|
|
60
|
+
const languageAliases = {
|
|
61
|
+
text: 'txt',
|
|
62
|
+
plaintext: 'txt',
|
|
63
|
+
plain: 'txt',
|
|
64
|
+
sh: 'shell',
|
|
65
|
+
bash: 'shell',
|
|
66
|
+
zsh: 'shell',
|
|
67
|
+
shellscript: 'shell',
|
|
68
|
+
'shell-script': 'shell',
|
|
69
|
+
console: 'shell',
|
|
70
|
+
terminal: 'shell',
|
|
71
|
+
js: 'javascript',
|
|
72
|
+
node: 'javascript',
|
|
73
|
+
nodejs: 'javascript',
|
|
74
|
+
ts: 'typescript',
|
|
75
|
+
py: 'python',
|
|
76
|
+
python3: 'python',
|
|
77
|
+
py3: 'python',
|
|
78
|
+
rb: 'ruby',
|
|
79
|
+
md: 'markdown',
|
|
80
|
+
cpp: 'c++',
|
|
81
|
+
cc: 'c++',
|
|
82
|
+
cs: 'c#',
|
|
83
|
+
csharp: 'c#',
|
|
84
|
+
htm: 'html',
|
|
85
|
+
yml: 'yaml',
|
|
86
|
+
dockerfile: 'docker',
|
|
87
|
+
styles: 'css',
|
|
88
|
+
style: 'css',
|
|
89
|
+
jsonc: 'json',
|
|
90
|
+
json5: 'json',
|
|
91
|
+
xaml: 'xml',
|
|
92
|
+
xhtml: 'xml',
|
|
93
|
+
svg: 'xml',
|
|
94
|
+
mysql: 'sql',
|
|
95
|
+
postgresql: 'sql',
|
|
96
|
+
postgres: 'sql',
|
|
97
|
+
pgsql: 'sql',
|
|
98
|
+
plsql: 'sql',
|
|
99
|
+
oracle: 'sql',
|
|
100
|
+
};
|
|
101
|
+
// One highlighter for the process: both the renderer and the editor reach it
|
|
102
|
+
// through this module, so a grammar is fetched once however many views ask.
|
|
103
|
+
const state = {
|
|
104
|
+
instance: null,
|
|
105
|
+
initPromise: null,
|
|
106
|
+
loadedLanguages: new Set(['txt']),
|
|
107
|
+
pendingLoads: new Map(),
|
|
108
|
+
warnedLanguages: new Set(),
|
|
109
|
+
};
|
|
110
|
+
// Normalize language to valid Shiki language
|
|
111
|
+
async function normalizeLanguage(language) {
|
|
112
|
+
if (!language)
|
|
113
|
+
return 'txt';
|
|
114
|
+
const normalized = language.toLowerCase();
|
|
115
|
+
const { bundledLanguages } = await loadShiki();
|
|
116
|
+
if (normalized in bundledLanguages) {
|
|
117
|
+
return normalized;
|
|
118
|
+
}
|
|
119
|
+
if (normalized in languageAliases) {
|
|
120
|
+
return languageAliases[normalized];
|
|
121
|
+
}
|
|
122
|
+
if (!state.warnedLanguages.has(language)) {
|
|
123
|
+
console.warn(`[podlite] shiki unrecognized language '${language}', defaulting to [txt]`);
|
|
124
|
+
state.warnedLanguages.add(language);
|
|
125
|
+
}
|
|
126
|
+
return 'txt';
|
|
127
|
+
}
|
|
128
|
+
// Get or create highlighter instance
|
|
129
|
+
async function getHighlighterInstance() {
|
|
130
|
+
if (!state.initPromise) {
|
|
131
|
+
state.initPromise = (async () => {
|
|
132
|
+
const { createHighlighter } = await loadShiki();
|
|
133
|
+
const instance = await createHighlighter({
|
|
134
|
+
themes: Object.values(CONFIG.themes),
|
|
135
|
+
langs: CONFIG.initialLanguages,
|
|
136
|
+
});
|
|
137
|
+
state.instance = instance;
|
|
138
|
+
CONFIG.initialLanguages.forEach(lang => state.loadedLanguages.add(lang));
|
|
139
|
+
return instance;
|
|
140
|
+
})();
|
|
141
|
+
}
|
|
142
|
+
return state.initPromise;
|
|
143
|
+
}
|
|
144
|
+
// Load a language if not already loaded
|
|
145
|
+
async function ensureLanguageLoaded(instance, lang) {
|
|
146
|
+
if (state.loadedLanguages.has(lang))
|
|
147
|
+
return;
|
|
148
|
+
let pending = state.pendingLoads.get(lang);
|
|
149
|
+
if (!pending) {
|
|
150
|
+
pending = instance
|
|
151
|
+
.loadLanguage(lang)
|
|
152
|
+
.then(() => {
|
|
153
|
+
state.loadedLanguages.add(lang);
|
|
154
|
+
})
|
|
155
|
+
.finally(() => state.pendingLoads.delete(lang));
|
|
156
|
+
state.pendingLoads.set(lang, pending);
|
|
157
|
+
}
|
|
158
|
+
await pending;
|
|
159
|
+
}
|
|
160
|
+
// Main API: get highlighter with language loaded
|
|
161
|
+
async function getHighlighter(language) {
|
|
162
|
+
const lang = await normalizeLanguage(language);
|
|
163
|
+
const instance = await getHighlighterInstance();
|
|
164
|
+
await ensureLanguageLoaded(instance, lang);
|
|
165
|
+
return instance;
|
|
166
|
+
}
|
|
167
|
+
// Convenience: convert code to HTML with dual themes (CSS-based switching)
|
|
168
|
+
async function codeToHtml({ code, language }) {
|
|
169
|
+
const lang = await normalizeLanguage(language);
|
|
170
|
+
const highlighter = await getHighlighter(language);
|
|
171
|
+
return highlighter.codeToHtml(code, {
|
|
172
|
+
lang,
|
|
173
|
+
themes: CONFIG.themes,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
// Convert code to HTML with explicit theme selection (for runtime theme detection)
|
|
177
|
+
async function codeToThemedHtml({ code, language, theme, decorations, }) {
|
|
178
|
+
const lang = await normalizeLanguage(language);
|
|
179
|
+
const highlighter = await getHighlighter(language);
|
|
180
|
+
if (theme === 'light' || theme === 'dark') {
|
|
181
|
+
return highlighter.codeToHtml(code, {
|
|
182
|
+
lang,
|
|
183
|
+
theme: CONFIG.themes[theme],
|
|
184
|
+
decorations,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return highlighter.codeToHtml(code, {
|
|
188
|
+
lang,
|
|
189
|
+
themes: CONFIG.themes,
|
|
190
|
+
decorations,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
// Check if a language is loaded (sync — only meaningful after a prior async normalize)
|
|
194
|
+
const isLanguageLoaded = (language) => {
|
|
195
|
+
return state.loadedLanguages.has(language);
|
|
196
|
+
};
|
|
197
|
+
exports.isLanguageLoaded = isLanguageLoaded;
|
|
198
|
+
//# sourceMappingURL=shiki.js.map
|
package/lib/shiki.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shiki.js","sourceRoot":"","sources":["../src/shiki.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@podlite/highlight",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Syntax highlighting for Podlite code blocks, shared by the renderer and the editor",
|
|
5
|
+
"main": "./lib/index.js",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"homepage": "https://podlite.org",
|
|
8
|
+
"bugs": {
|
|
9
|
+
"url": "https://github.com/podlite/podlite/issues"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/podlite/podlite.git",
|
|
14
|
+
"directory": "packages/podlite-highlight"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"funding": {
|
|
18
|
+
"type": "opencollective",
|
|
19
|
+
"url": "https://opencollective.com/podlite"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "yarn g:build",
|
|
23
|
+
"test": "yarn g:jest --passWithNoTests"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@podlite/schema": "0.0.68"
|
|
27
|
+
},
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./lib/index.d.ts",
|
|
31
|
+
"import": "./esm/index.js",
|
|
32
|
+
"require": "./lib/index.js",
|
|
33
|
+
"default": "./lib/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./index": {
|
|
36
|
+
"import": "./esm/index.js",
|
|
37
|
+
"require": "./lib/index.js"
|
|
38
|
+
},
|
|
39
|
+
"./package.json": "./package.json",
|
|
40
|
+
"./lib/*": {
|
|
41
|
+
"types": "./lib/*.d.ts",
|
|
42
|
+
"default": "./lib/*.js"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"lib",
|
|
47
|
+
"esm",
|
|
48
|
+
"README.md",
|
|
49
|
+
"CHANGELOG.podlite",
|
|
50
|
+
"LICENSE"
|
|
51
|
+
],
|
|
52
|
+
"keywords": [
|
|
53
|
+
"podlite",
|
|
54
|
+
"syntax-highlighting",
|
|
55
|
+
"shiki",
|
|
56
|
+
"react",
|
|
57
|
+
"react-component",
|
|
58
|
+
"code",
|
|
59
|
+
"markup-language"
|
|
60
|
+
],
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"@podlite/schema": "*",
|
|
66
|
+
"react": "^16.0.0 || ^17.0.0 || ^18",
|
|
67
|
+
"react-dom": "^16.0.0 || ^17.0.0 || ^18",
|
|
68
|
+
"shiki": "^3.0.0"
|
|
69
|
+
},
|
|
70
|
+
"peerDependenciesMeta": {
|
|
71
|
+
"shiki": {
|
|
72
|
+
"optional": true
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"module": "./esm/index.js",
|
|
76
|
+
"types": "./lib/index.d.ts",
|
|
77
|
+
"devDependencies": {
|
|
78
|
+
"shiki": "^3.21.0"
|
|
79
|
+
}
|
|
80
|
+
}
|