Skip to content

Commit 668a297

Browse files
committed
feat: config.tokenizer
Introduces a way to extend/customize the tokenizer and its provided methods (setup, tokenize). - Abstract prism tokenizer - Adds package export `syntax-highlight-element/tokenizer/prism` - Export `setupTokenHighlights` method - Flat merge config with defaultConfig
1 parent e7608f5 commit 668a297

File tree

8 files changed

+441
-360
lines changed

8 files changed

+441
-360
lines changed

index.html

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,17 @@
3232
<script>
3333
window.she = window.she || {};
3434
window.she.config = {
35-
languages: ['html', 'css', 'js', 'jsx', 'md'], // Default
35+
languages: ['html', 'css', 'js', 'jsx', 'md'],
3636
// Optional: language specific token type overwrites
3737
languageTokens: {
3838
css: ['important'],
3939
md: ['title', 'list'],
40-
}
40+
},
41+
// Optional: extend/customize tokenizer
42+
// tokenizer: {
43+
// async setup() {},
44+
// tokenize: () => [],
45+
// }
4146
}
4247
</script>
4348
</head>
@@ -87,15 +92,55 @@
8792
</syntax-highlight>
8893

8994
<script type="module">
90-
// Manually loading prism dependencies
91-
// import 'https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-core.min.js'
95+
// /**
96+
// * Option 1. autoload - default
97+
// */
98+
// import '/src/index.js'
99+
// import SyntaxHighlightElement from '/src/index.js'
100+
101+
/**
102+
* Option 2. Opt out of prism autoload by manually importing prism core
103+
*/
104+
import 'https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-core.min.js'
105+
import SyntaxHighlightElement from '/src/index.js?define=false'
106+
107+
/**
108+
* Option 2.a. Load lang deps manually (without dependency resolution)
109+
*/
110+
// // - CDN
92111
// import 'https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-markup.min.js'
93112
// import 'https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-css.min.js'
94113
// import 'https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-clike.min.js'
95114
// import 'https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-javascript.min.js'
115+
// import 'https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-jsx.min.js'
96116
// import 'https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-markdown.min.js'
117+
// // - npm
118+
// import 'prismjs/components/prism-markup'
119+
// import 'prismjs/components/prism-css'
120+
// import 'prismjs/components/prism-clike'
121+
// import 'prismjs/components/prism-javascript'
122+
// import 'prismjs/components/prism-jsx'
123+
// import 'prismjs/components/prism-markdown'
97124

98-
import '/src/index.js'
125+
/**
126+
* Option 2.b. resolve language dependencies and load from URL/CDN
127+
*/
128+
// - CDN
129+
import { loadPrismLanguage } from '/src/tokenizer/prism.js'
130+
await loadPrismLanguage({
131+
baseUrl: 'https://unpkg.com/prismjs@1.30.0',
132+
language: window.she.config.languages
133+
});
134+
// // - npm
135+
// import { resolveLanguageDependencies } from '/src/tokenizer/prism.js'
136+
// const langDeps = resolveLanguageDependencies(window.she.config.languages);
137+
// for await (const lang of langDeps) {
138+
// const importPath = `prismjs/components/prism-${lang}`
139+
// await import(importPath);
140+
// console.log({importPath})
141+
// }
142+
// // - Manually define SyntaxHighlightElement with ?define=false once all dependecies are loaded
143+
window.SyntaxHighlightElement = SyntaxHighlightElement.define();
99144
</script>
100145
<script>
101146
document.addEventListener('DOMContentLoaded', () => {

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@
1414
".": {
1515
"import": "./dist/syntax-highlight-element.js"
1616
},
17-
"./themes/*": "./dist/themes/*"
17+
"./themes/*": "./dist/themes/*",
18+
"./tokenizer/*": "./dist/tokenizer/*"
1819
},
1920
"files": [
2021
"dist"
2122
],
2223
"scripts": {
2324
"dev": "vite",
2425
"dev:docs": "vite --config vite.docs.config.js",
25-
"build": "vite build && vite build --config vite.themes.config.js",
26+
"build": "vite build && vite build --config vite.themes.config.js && vite build --config vite.tokenizer.config.js",
2627
"preview": "vite preview",
2728
"format": "biome check --write",
2829
"lint": "biome ci",

src/constants.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1+
import { tokenizer as defaultTokenizer } from './tokenizer/prism';
2+
13
export const NAMESPACE = 'she';
24

35
/**
46
* @typedef Config
57
* @type {object}
6-
* @property {string[]} languages - Prism languages.
8+
* @property {string[]} languages - Languages.
79
* @property {{ [key: string]: string[] }} languageTokens - Language specific token types.
10+
* @property {object} tokenizer - Tokenizer.
811
*/
912

1013
/** @type {Config} */
11-
export const CONFIG = window[NAMESPACE]?.config || {};
14+
export const CONFIG = Object.assign(
15+
{
16+
languages: ['markup', 'css', 'javascript'],
17+
languageTokens: {},
18+
tokenizer: Object.assign(defaultTokenizer, window[NAMESPACE]?.config?.tokenizer || {}),
19+
},
20+
window[NAMESPACE]?.config || {},
21+
);

src/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { NAMESPACE } from './constants';
22
import { SyntaxHighlightElement } from './syntax-highlight-element';
3+
import { setupTokenHighlights } from './utils';
34

4-
export { SyntaxHighlightElement };
5+
export { SyntaxHighlightElement, setupTokenHighlights };
56
export default SyntaxHighlightElement;
67

78
window[NAMESPACE] = window[NAMESPACE] || {};

src/syntax-highlight-element.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
import { CONFIG } from './constants';
2-
import { setupTokenHighlights, setupTokenizer, tokenize } from './utils';
3-
4-
const DEFAULT_TAG_NAME = 'syntax-highlight';
52

63
export class SyntaxHighlightElement extends HTMLElement {
7-
static async define(tagName = DEFAULT_TAG_NAME, registry = customElements) {
4+
static async define(tagName = 'syntax-highlight', registry = customElements) {
85
if (!CSS.highlights) {
96
console.info('The CSS Custom Highlight API is not supported in this browser.');
107
return;
118
}
129

1310
if (!registry.get(tagName)) {
14-
await setupTokenizer();
15-
setupTokenHighlights(CONFIG?.languageTokens || {});
11+
CONFIG.tokenizer?.setup && (await CONFIG.tokenizer.setup());
1612
registry.define(tagName, SyntaxHighlightElement);
1713
return SyntaxHighlightElement;
1814
}
@@ -58,7 +54,7 @@ export class SyntaxHighlightElement extends HTMLElement {
5854
*/
5955
paintTokenHighlights() {
6056
// Tokenize the text
61-
const tokens = tokenize(this.contentElement.innerText, this.language);
57+
const tokens = CONFIG.tokenizer?.tokenize(this.contentElement.innerText, this.language) || [];
6258
const languageTokenTypes = CONFIG.languageTokens?.[this.language] || [];
6359

6460
// Paint highlights

0 commit comments

Comments
 (0)