@pfmcodes/caret 0.1.1 → 0.1.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/README.md +22 -22
- package/commonjs/editor.js +272 -0
- package/commonjs/index.js +10 -0
- package/commonjs/languages.js +97 -0
- package/commonjs/theme.js +18 -0
- package/esm/editor.js +69 -19
- package/esm/languages.js +54 -3
- package/package.json +2 -2
- package/types/editor.d.ts +156 -16
- package/types/language-utils.d.ts +428 -0
- package/types/languages.d.ts +128 -13
- package/types/types.d.ts +347 -0
package/esm/languages.js
CHANGED
|
@@ -18,7 +18,9 @@ import bash from "../highlight.js/es/languages/bash.js";
|
|
|
18
18
|
import plaintext from "../highlight.js/es/languages/plaintext.js";
|
|
19
19
|
import hljs from "../highlight.js/es/core.js";
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
let registeredLanguages = [];
|
|
22
|
+
|
|
23
|
+
function init() {
|
|
22
24
|
// Register all languages
|
|
23
25
|
hljs.registerLanguage("javascript", javascript);
|
|
24
26
|
hljs.registerLanguage("xml", xml);
|
|
@@ -40,7 +42,56 @@ export function init() {
|
|
|
40
42
|
hljs.registerLanguage("bash", bash);
|
|
41
43
|
hljs.registerLanguage("shell", bash);
|
|
42
44
|
hljs.registerLanguage("sh", bash);
|
|
43
|
-
hljs.registerLanguage("plaintext", plaintext)
|
|
45
|
+
hljs.registerLanguage("plaintext", plaintext);
|
|
46
|
+
registeredLanguages = [
|
|
47
|
+
"javascript",
|
|
48
|
+
"js",
|
|
49
|
+
"xml",
|
|
50
|
+
"html",
|
|
51
|
+
"svg",
|
|
52
|
+
"python",
|
|
53
|
+
"java",
|
|
54
|
+
"csharp",
|
|
55
|
+
"cpp",
|
|
56
|
+
"ruby",
|
|
57
|
+
"php",
|
|
58
|
+
"go",
|
|
59
|
+
"c",
|
|
60
|
+
"rust",
|
|
61
|
+
"kotlin",
|
|
62
|
+
"swift",
|
|
63
|
+
"typescript",
|
|
64
|
+
"json",
|
|
65
|
+
"bash",
|
|
66
|
+
"shell",
|
|
67
|
+
"sh",
|
|
68
|
+
"plaintext"
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function registerLanguage(name, definition) {
|
|
73
|
+
hljs.registerLanguage(name, definition);
|
|
74
|
+
if (!registeredLanguages.includes(name)) {
|
|
75
|
+
registeredLanguages.push(name);
|
|
76
|
+
}
|
|
44
77
|
}
|
|
45
78
|
|
|
46
|
-
|
|
79
|
+
const languages = {
|
|
80
|
+
init,
|
|
81
|
+
registeredLanguages,
|
|
82
|
+
registerLanguage,
|
|
83
|
+
hljs
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export default languages;
|
|
87
|
+
|
|
88
|
+
/*
|
|
89
|
+
|
|
90
|
+
registeredLannguage: added for the editor.js can check if the langauge provided already is regsitered or not
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
init: just registers some languages and updates the registeredLangauges variable
|
|
94
|
+
|
|
95
|
+
registerLanguage: just registers a language
|
|
96
|
+
|
|
97
|
+
*/
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pfmcodes/caret",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "The official code editor engine for lexius",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.cjs",
|
|
7
|
-
"types": "./types/
|
|
7
|
+
"types": "./types/types.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
10
|
"import": "./esm/index.js",
|
package/types/editor.d.ts
CHANGED
|
@@ -1,27 +1,167 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Caret Editor - TypeScript Type Definitions
|
|
3
|
+
* A lightweight code editor with syntax highlighting and custom caret rendering
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Configuration options for creating a Caret editor instance
|
|
8
|
+
*/
|
|
9
|
+
export interface CaretEditorConfig {
|
|
10
|
+
/**
|
|
11
|
+
* Initial code content to display in the editor
|
|
12
|
+
* @default ""
|
|
13
|
+
*/
|
|
3
14
|
value?: string;
|
|
4
15
|
|
|
5
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Programming language for syntax highlighting
|
|
18
|
+
* Must be a language supported by Highlight.js
|
|
19
|
+
* @example "javascript", "python", "html", "css"
|
|
20
|
+
*/
|
|
6
21
|
language: string;
|
|
7
22
|
|
|
8
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Highlight.js theme name for syntax highlighting
|
|
25
|
+
* Can be any theme available in the highlight.js/styles directory
|
|
26
|
+
* @example "hybrid", "monokai", "github", "atom-one-dark"
|
|
27
|
+
* @default "hybrid"
|
|
28
|
+
*/
|
|
9
29
|
theme?: string;
|
|
10
30
|
}
|
|
11
31
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Font metrics information returned by getFontMetrics
|
|
34
|
+
*/
|
|
35
|
+
export interface FontMetrics {
|
|
36
|
+
/**
|
|
37
|
+
* Height of the ascender (portion of characters above baseline)
|
|
38
|
+
*/
|
|
39
|
+
ascent: number;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Height of the descender (portion of characters below baseline)
|
|
43
|
+
*/
|
|
44
|
+
descent: number;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Total height of the font (ascent + descent)
|
|
48
|
+
*/
|
|
49
|
+
height: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Caret editor instance returned by createEditor
|
|
54
|
+
*/
|
|
55
|
+
export interface CaretEditorInstance {
|
|
56
|
+
/**
|
|
57
|
+
* Get the current value/content of the editor
|
|
58
|
+
* @returns The current code content as a string
|
|
59
|
+
*/
|
|
60
|
+
getValue(): string;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Set the value/content of the editor
|
|
64
|
+
* @param value - The new code content to set
|
|
65
|
+
*/
|
|
66
|
+
setValue(value: string): void;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Focus the editor textarea
|
|
70
|
+
*/
|
|
71
|
+
focus(): void;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Change the programming language for syntax highlighting
|
|
75
|
+
* @param language - The new language identifier (e.g., "javascript", "python")
|
|
76
|
+
*/
|
|
77
|
+
setLanguage(language: string): void;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Destroy the editor instance and remove all event listeners
|
|
81
|
+
* Cleans up the DOM and prepares for garbage collection
|
|
82
|
+
*/
|
|
83
|
+
destroy(): void;
|
|
16
84
|
}
|
|
17
85
|
|
|
18
86
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* @param editor DOM element that will contain the editor
|
|
22
|
-
* @param data Initial editor configuration
|
|
87
|
+
* Language manager for registering and initializing Highlight.js languages
|
|
23
88
|
*/
|
|
24
|
-
export
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
89
|
+
export interface LanguageManager {
|
|
90
|
+
/**
|
|
91
|
+
* Initialize the language manager
|
|
92
|
+
*/
|
|
93
|
+
init(): void;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Register a new language for syntax highlighting
|
|
97
|
+
* @param language - The language identifier to register
|
|
98
|
+
*/
|
|
99
|
+
registerLanguage(language: string): void;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* List of currently registered languages
|
|
103
|
+
*/
|
|
104
|
+
registeredLanguages: string[];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Main editor object containing the createEditor function
|
|
109
|
+
*/
|
|
110
|
+
export interface CaretEditor {
|
|
111
|
+
/**
|
|
112
|
+
* Create a new Caret editor instance
|
|
113
|
+
*
|
|
114
|
+
* @param container - The HTMLElement that will contain the editor
|
|
115
|
+
* @param config - Configuration options for the editor
|
|
116
|
+
* @returns A CaretEditorInstance with methods to control the editor
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* import editor from 'caret';
|
|
121
|
+
*
|
|
122
|
+
* const editorContainer = document.getElementById('editor');
|
|
123
|
+
* const instance = await editor.createEditor(editorContainer, {
|
|
124
|
+
* value: 'console.log("Hello, World!");',
|
|
125
|
+
* language: 'javascript',
|
|
126
|
+
* theme: 'monokai'
|
|
127
|
+
* });
|
|
128
|
+
*
|
|
129
|
+
* // Get current value
|
|
130
|
+
* const code = instance.getValue();
|
|
131
|
+
*
|
|
132
|
+
* // Update the content
|
|
133
|
+
* instance.setValue('const x = 42;');
|
|
134
|
+
*
|
|
135
|
+
* // Change language
|
|
136
|
+
* instance.setLanguage('typescript');
|
|
137
|
+
*
|
|
138
|
+
* // Clean up when done
|
|
139
|
+
* instance.destroy();
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
createEditor(
|
|
143
|
+
container: HTMLElement,
|
|
144
|
+
config: CaretEditorConfig
|
|
145
|
+
): Promise<CaretEditorInstance>;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Default export - the main Caret editor object
|
|
150
|
+
*/
|
|
151
|
+
declare const editor: CaretEditor;
|
|
152
|
+
|
|
153
|
+
export default editor;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Module augmentation for importing Highlight.js
|
|
157
|
+
*/
|
|
158
|
+
declare module "../highlight.js/es/core.js" {
|
|
159
|
+
import type { HLJSApi } from "highlight.js";
|
|
160
|
+
const hljs: HLJSApi;
|
|
161
|
+
export default hljs;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
declare module "./languages.js" {
|
|
165
|
+
const languages: LanguageManager;
|
|
166
|
+
export default languages;
|
|
167
|
+
}
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caret Editor - Language Utilities
|
|
3
|
+
* Helper types and utilities for working with language registration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { LanguageFn } from 'highlight.js';
|
|
7
|
+
import type { PreRegisteredLanguage, LanguagesModule } from './languages';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Language information object
|
|
11
|
+
*/
|
|
12
|
+
export interface LanguageInfo {
|
|
13
|
+
/**
|
|
14
|
+
* Primary language identifier
|
|
15
|
+
*/
|
|
16
|
+
name: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Display name for the language
|
|
20
|
+
*/
|
|
21
|
+
displayName: string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* File extensions associated with this language
|
|
25
|
+
*/
|
|
26
|
+
extensions: string[];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Common aliases for the language
|
|
30
|
+
*/
|
|
31
|
+
aliases: string[];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Whether this language is pre-registered
|
|
35
|
+
*/
|
|
36
|
+
isPreRegistered: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Map of language information for all pre-registered languages
|
|
41
|
+
*/
|
|
42
|
+
export const LANGUAGE_INFO: Record<PreRegisteredLanguage, LanguageInfo> = {
|
|
43
|
+
javascript: {
|
|
44
|
+
name: 'javascript',
|
|
45
|
+
displayName: 'JavaScript',
|
|
46
|
+
extensions: ['.js', '.mjs', '.cjs'],
|
|
47
|
+
aliases: ['js'],
|
|
48
|
+
isPreRegistered: true
|
|
49
|
+
},
|
|
50
|
+
js: {
|
|
51
|
+
name: 'javascript',
|
|
52
|
+
displayName: 'JavaScript',
|
|
53
|
+
extensions: ['.js', '.mjs', '.cjs'],
|
|
54
|
+
aliases: ['javascript'],
|
|
55
|
+
isPreRegistered: true
|
|
56
|
+
},
|
|
57
|
+
typescript: {
|
|
58
|
+
name: 'typescript',
|
|
59
|
+
displayName: 'TypeScript',
|
|
60
|
+
extensions: ['.ts', '.tsx'],
|
|
61
|
+
aliases: ['ts'],
|
|
62
|
+
isPreRegistered: true
|
|
63
|
+
},
|
|
64
|
+
python: {
|
|
65
|
+
name: 'python',
|
|
66
|
+
displayName: 'Python',
|
|
67
|
+
extensions: ['.py', '.pyw'],
|
|
68
|
+
aliases: ['py'],
|
|
69
|
+
isPreRegistered: true
|
|
70
|
+
},
|
|
71
|
+
java: {
|
|
72
|
+
name: 'java',
|
|
73
|
+
displayName: 'Java',
|
|
74
|
+
extensions: ['.java'],
|
|
75
|
+
aliases: [],
|
|
76
|
+
isPreRegistered: true
|
|
77
|
+
},
|
|
78
|
+
csharp: {
|
|
79
|
+
name: 'csharp',
|
|
80
|
+
displayName: 'C#',
|
|
81
|
+
extensions: ['.cs'],
|
|
82
|
+
aliases: ['cs', 'c#'],
|
|
83
|
+
isPreRegistered: true
|
|
84
|
+
},
|
|
85
|
+
cpp: {
|
|
86
|
+
name: 'cpp',
|
|
87
|
+
displayName: 'C++',
|
|
88
|
+
extensions: ['.cpp', '.cc', '.cxx', '.hpp', '.h'],
|
|
89
|
+
aliases: ['c++'],
|
|
90
|
+
isPreRegistered: true
|
|
91
|
+
},
|
|
92
|
+
c: {
|
|
93
|
+
name: 'c',
|
|
94
|
+
displayName: 'C',
|
|
95
|
+
extensions: ['.c', '.h'],
|
|
96
|
+
aliases: [],
|
|
97
|
+
isPreRegistered: true
|
|
98
|
+
},
|
|
99
|
+
ruby: {
|
|
100
|
+
name: 'ruby',
|
|
101
|
+
displayName: 'Ruby',
|
|
102
|
+
extensions: ['.rb'],
|
|
103
|
+
aliases: ['rb'],
|
|
104
|
+
isPreRegistered: true
|
|
105
|
+
},
|
|
106
|
+
php: {
|
|
107
|
+
name: 'php',
|
|
108
|
+
displayName: 'PHP',
|
|
109
|
+
extensions: ['.php'],
|
|
110
|
+
aliases: [],
|
|
111
|
+
isPreRegistered: true
|
|
112
|
+
},
|
|
113
|
+
go: {
|
|
114
|
+
name: 'go',
|
|
115
|
+
displayName: 'Go',
|
|
116
|
+
extensions: ['.go'],
|
|
117
|
+
aliases: ['golang'],
|
|
118
|
+
isPreRegistered: true
|
|
119
|
+
},
|
|
120
|
+
rust: {
|
|
121
|
+
name: 'rust',
|
|
122
|
+
displayName: 'Rust',
|
|
123
|
+
extensions: ['.rs'],
|
|
124
|
+
aliases: ['rs'],
|
|
125
|
+
isPreRegistered: true
|
|
126
|
+
},
|
|
127
|
+
kotlin: {
|
|
128
|
+
name: 'kotlin',
|
|
129
|
+
displayName: 'Kotlin',
|
|
130
|
+
extensions: ['.kt', '.kts'],
|
|
131
|
+
aliases: ['kt'],
|
|
132
|
+
isPreRegistered: true
|
|
133
|
+
},
|
|
134
|
+
swift: {
|
|
135
|
+
name: 'swift',
|
|
136
|
+
displayName: 'Swift',
|
|
137
|
+
extensions: ['.swift'],
|
|
138
|
+
aliases: [],
|
|
139
|
+
isPreRegistered: true
|
|
140
|
+
},
|
|
141
|
+
xml: {
|
|
142
|
+
name: 'xml',
|
|
143
|
+
displayName: 'XML',
|
|
144
|
+
extensions: ['.xml'],
|
|
145
|
+
aliases: [],
|
|
146
|
+
isPreRegistered: true
|
|
147
|
+
},
|
|
148
|
+
html: {
|
|
149
|
+
name: 'html',
|
|
150
|
+
displayName: 'HTML',
|
|
151
|
+
extensions: ['.html', '.htm'],
|
|
152
|
+
aliases: [],
|
|
153
|
+
isPreRegistered: true
|
|
154
|
+
},
|
|
155
|
+
svg: {
|
|
156
|
+
name: 'svg',
|
|
157
|
+
displayName: 'SVG',
|
|
158
|
+
extensions: ['.svg'],
|
|
159
|
+
aliases: [],
|
|
160
|
+
isPreRegistered: true
|
|
161
|
+
},
|
|
162
|
+
css: {
|
|
163
|
+
name: 'css',
|
|
164
|
+
displayName: 'CSS',
|
|
165
|
+
extensions: ['.css'],
|
|
166
|
+
aliases: [],
|
|
167
|
+
isPreRegistered: true
|
|
168
|
+
},
|
|
169
|
+
json: {
|
|
170
|
+
name: 'json',
|
|
171
|
+
displayName: 'JSON',
|
|
172
|
+
extensions: ['.json'],
|
|
173
|
+
aliases: [],
|
|
174
|
+
isPreRegistered: true
|
|
175
|
+
},
|
|
176
|
+
bash: {
|
|
177
|
+
name: 'bash',
|
|
178
|
+
displayName: 'Bash',
|
|
179
|
+
extensions: ['.sh', '.bash'],
|
|
180
|
+
aliases: ['shell', 'sh'],
|
|
181
|
+
isPreRegistered: true
|
|
182
|
+
},
|
|
183
|
+
shell: {
|
|
184
|
+
name: 'shell',
|
|
185
|
+
displayName: 'Shell',
|
|
186
|
+
extensions: ['.sh'],
|
|
187
|
+
aliases: ['bash', 'sh'],
|
|
188
|
+
isPreRegistered: true
|
|
189
|
+
},
|
|
190
|
+
sh: {
|
|
191
|
+
name: 'sh',
|
|
192
|
+
displayName: 'Shell',
|
|
193
|
+
extensions: ['.sh'],
|
|
194
|
+
aliases: ['bash', 'shell'],
|
|
195
|
+
isPreRegistered: true
|
|
196
|
+
},
|
|
197
|
+
plaintext: {
|
|
198
|
+
name: 'plaintext',
|
|
199
|
+
displayName: 'Plain Text',
|
|
200
|
+
extensions: ['.txt'],
|
|
201
|
+
aliases: ['text', 'plain'],
|
|
202
|
+
isPreRegistered: true
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Type guard to check if a language is pre-registered
|
|
208
|
+
*/
|
|
209
|
+
export function isPreRegisteredLanguage(language: string): language is PreRegisteredLanguage {
|
|
210
|
+
const preRegistered: PreRegisteredLanguage[] = [
|
|
211
|
+
'javascript', 'js', 'xml', 'html', 'svg', 'css',
|
|
212
|
+
'python', 'java', 'csharp', 'cpp', 'ruby', 'php',
|
|
213
|
+
'go', 'c', 'rust', 'kotlin', 'swift', 'typescript',
|
|
214
|
+
'json', 'bash', 'shell', 'sh', 'plaintext'
|
|
215
|
+
];
|
|
216
|
+
return preRegistered.includes(language as PreRegisteredLanguage);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Check if a language is currently registered
|
|
221
|
+
*/
|
|
222
|
+
export function isLanguageRegistered(
|
|
223
|
+
languages: LanguagesModule,
|
|
224
|
+
language: string
|
|
225
|
+
): boolean {
|
|
226
|
+
return languages.registeredLanguages.includes(language);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Get language information by name or alias
|
|
231
|
+
*/
|
|
232
|
+
export function getLanguageInfo(language: string): LanguageInfo | null {
|
|
233
|
+
// Check if it's a direct match
|
|
234
|
+
if (isPreRegisteredLanguage(language)) {
|
|
235
|
+
return LANGUAGE_INFO[language];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Check if it's an alias
|
|
239
|
+
for (const [key, info] of Object.entries(LANGUAGE_INFO)) {
|
|
240
|
+
if (info.aliases.includes(language)) {
|
|
241
|
+
return info;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get language by file extension
|
|
250
|
+
*/
|
|
251
|
+
export function getLanguageByExtension(extension: string): string | null {
|
|
252
|
+
const normalizedExt = extension.startsWith('.') ? extension : `.${extension}`;
|
|
253
|
+
|
|
254
|
+
for (const [key, info] of Object.entries(LANGUAGE_INFO)) {
|
|
255
|
+
if (info.extensions.includes(normalizedExt)) {
|
|
256
|
+
return info.name;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Get all available language names (primary names only)
|
|
265
|
+
*/
|
|
266
|
+
export function getAllLanguageNames(): string[] {
|
|
267
|
+
const uniqueNames = new Set<string>();
|
|
268
|
+
|
|
269
|
+
for (const info of Object.values(LANGUAGE_INFO)) {
|
|
270
|
+
uniqueNames.add(info.name);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return Array.from(uniqueNames);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Language registration helper class
|
|
278
|
+
*/
|
|
279
|
+
export class LanguageRegistry {
|
|
280
|
+
private languages: LanguagesModule;
|
|
281
|
+
|
|
282
|
+
constructor(languagesModule: LanguagesModule) {
|
|
283
|
+
this.languages = languagesModule;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Register a language if it's not already registered
|
|
288
|
+
*/
|
|
289
|
+
registerIfNeeded(name: string, definition: LanguageFn): boolean {
|
|
290
|
+
if (this.isRegistered(name)) {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
this.languages.registerLanguage(name, definition);
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Check if a language is registered
|
|
300
|
+
*/
|
|
301
|
+
isRegistered(name: string): boolean {
|
|
302
|
+
return isLanguageRegistered(this.languages, name);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Get all registered languages
|
|
307
|
+
*/
|
|
308
|
+
getRegistered(): string[] {
|
|
309
|
+
return [...this.languages.registeredLanguages];
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Get language info
|
|
314
|
+
*/
|
|
315
|
+
getInfo(name: string): LanguageInfo | null {
|
|
316
|
+
return getLanguageInfo(name);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Register multiple languages at once
|
|
321
|
+
*/
|
|
322
|
+
registerBulk(definitions: Record<string, LanguageFn>): void {
|
|
323
|
+
for (const [name, definition] of Object.entries(definitions)) {
|
|
324
|
+
this.registerIfNeeded(name, definition);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Options for lazy language loading
|
|
331
|
+
*/
|
|
332
|
+
export interface LazyLanguageOptions {
|
|
333
|
+
/**
|
|
334
|
+
* Base path for language modules
|
|
335
|
+
* @default "../highlight.js/es/languages/"
|
|
336
|
+
*/
|
|
337
|
+
basePath?: string;
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Whether to cache loaded languages
|
|
341
|
+
* @default true
|
|
342
|
+
*/
|
|
343
|
+
cache?: boolean;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Lazy language loader for dynamic imports
|
|
348
|
+
*/
|
|
349
|
+
export class LazyLanguageLoader {
|
|
350
|
+
private languages: LanguagesModule;
|
|
351
|
+
private basePath: string;
|
|
352
|
+
private cache: boolean;
|
|
353
|
+
private loadedLanguages: Set<string> = new Set();
|
|
354
|
+
|
|
355
|
+
constructor(
|
|
356
|
+
languagesModule: LanguagesModule,
|
|
357
|
+
options: LazyLanguageOptions = {}
|
|
358
|
+
) {
|
|
359
|
+
this.languages = languagesModule;
|
|
360
|
+
this.basePath = options.basePath || '../highlight.js/es/languages/';
|
|
361
|
+
this.cache = options.cache !== false;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Load a language dynamically
|
|
366
|
+
*/
|
|
367
|
+
async loadLanguage(name: string): Promise<void> {
|
|
368
|
+
// Check if already loaded (if caching is enabled)
|
|
369
|
+
if (this.cache && this.loadedLanguages.has(name)) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Check if pre-registered
|
|
374
|
+
if (isLanguageRegistered(this.languages, name)) {
|
|
375
|
+
this.loadedLanguages.add(name);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
try {
|
|
380
|
+
const module = await import(
|
|
381
|
+
`${this.basePath}${name}.js`
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
const definition = module.default;
|
|
385
|
+
this.languages.registerLanguage(name, definition);
|
|
386
|
+
|
|
387
|
+
if (this.cache) {
|
|
388
|
+
this.loadedLanguages.add(name);
|
|
389
|
+
}
|
|
390
|
+
} catch (error) {
|
|
391
|
+
throw new Error(
|
|
392
|
+
`Failed to load language "${name}": ${(error as Error).message}`
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Load multiple languages
|
|
399
|
+
*/
|
|
400
|
+
async loadLanguages(names: string[]): Promise<void> {
|
|
401
|
+
await Promise.all(names.map(name => this.loadLanguage(name)));
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Check if a language has been loaded
|
|
406
|
+
*/
|
|
407
|
+
isLoaded(name: string): boolean {
|
|
408
|
+
return this.loadedLanguages.has(name);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Clear the cache
|
|
413
|
+
*/
|
|
414
|
+
clearCache(): void {
|
|
415
|
+
this.loadedLanguages.clear();
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Export utility functions
|
|
421
|
+
*/
|
|
422
|
+
export const LanguageUtils = {
|
|
423
|
+
isPreRegisteredLanguage,
|
|
424
|
+
isLanguageRegistered,
|
|
425
|
+
getLanguageInfo,
|
|
426
|
+
getLanguageByExtension,
|
|
427
|
+
getAllLanguageNames
|
|
428
|
+
};
|