@nocturnium/svelte-ide 1.0.0-rc.1

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.
Files changed (330) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +251 -0
  3. package/dist/components/agents/AgentActivityPanel.svelte +565 -0
  4. package/dist/components/agents/AgentActivityPanel.svelte.d.ts +24 -0
  5. package/dist/components/agents/AgentAvatar.svelte +417 -0
  6. package/dist/components/agents/AgentAvatar.svelte.d.ts +23 -0
  7. package/dist/components/agents/AgentCursor.svelte +224 -0
  8. package/dist/components/agents/AgentCursor.svelte.d.ts +35 -0
  9. package/dist/components/agents/AgentPresenceBar.svelte +261 -0
  10. package/dist/components/agents/AgentPresenceBar.svelte.d.ts +20 -0
  11. package/dist/components/agents/index.d.ts +4 -0
  12. package/dist/components/agents/index.js +5 -0
  13. package/dist/components/ai/AIConversationList.svelte +524 -0
  14. package/dist/components/ai/AIConversationList.svelte.d.ts +17 -0
  15. package/dist/components/ai/AIEditPreview.svelte +132 -0
  16. package/dist/components/ai/AIEditPreview.svelte.d.ts +8 -0
  17. package/dist/components/ai/AIInlineEdit.svelte +155 -0
  18. package/dist/components/ai/AIInlineEdit.svelte.d.ts +10 -0
  19. package/dist/components/ai/AIMessage.svelte +239 -0
  20. package/dist/components/ai/AIMessage.svelte.d.ts +13 -0
  21. package/dist/components/ai/AIMessageActions.svelte +176 -0
  22. package/dist/components/ai/AIMessageActions.svelte.d.ts +12 -0
  23. package/dist/components/ai/AIMessageContent.svelte +355 -0
  24. package/dist/components/ai/AIMessageContent.svelte.d.ts +7 -0
  25. package/dist/components/ai/AIPanel.svelte +561 -0
  26. package/dist/components/ai/AIPanel.svelte.d.ts +7 -0
  27. package/dist/components/ai/AISuggestionWidget.svelte +132 -0
  28. package/dist/components/ai/AISuggestionWidget.svelte.d.ts +10 -0
  29. package/dist/components/ai/AIToolCallDisplay.svelte +317 -0
  30. package/dist/components/ai/AIToolCallDisplay.svelte.d.ts +12 -0
  31. package/dist/components/ai/index.d.ts +9 -0
  32. package/dist/components/ai/index.js +10 -0
  33. package/dist/components/core/Avatar.svelte +110 -0
  34. package/dist/components/core/Avatar.svelte.d.ts +12 -0
  35. package/dist/components/core/Badge.svelte +98 -0
  36. package/dist/components/core/Badge.svelte.d.ts +11 -0
  37. package/dist/components/core/Button.svelte +175 -0
  38. package/dist/components/core/Button.svelte.d.ts +18 -0
  39. package/dist/components/core/ConnectionStatus.svelte +294 -0
  40. package/dist/components/core/ConnectionStatus.svelte.d.ts +20 -0
  41. package/dist/components/core/ContextMenu.svelte +176 -0
  42. package/dist/components/core/ContextMenu.svelte.d.ts +19 -0
  43. package/dist/components/core/ErrorBoundary.svelte +277 -0
  44. package/dist/components/core/ErrorBoundary.svelte.d.ts +23 -0
  45. package/dist/components/core/Icon.svelte +107 -0
  46. package/dist/components/core/Icon.svelte.d.ts +8 -0
  47. package/dist/components/core/Input.svelte +138 -0
  48. package/dist/components/core/Input.svelte.d.ts +20 -0
  49. package/dist/components/core/Kbd.svelte +34 -0
  50. package/dist/components/core/Kbd.svelte.d.ts +7 -0
  51. package/dist/components/core/ResizeHandle.svelte +200 -0
  52. package/dist/components/core/ResizeHandle.svelte.d.ts +23 -0
  53. package/dist/components/core/Spinner.svelte +35 -0
  54. package/dist/components/core/Spinner.svelte.d.ts +7 -0
  55. package/dist/components/core/Textarea.svelte +112 -0
  56. package/dist/components/core/Textarea.svelte.d.ts +18 -0
  57. package/dist/components/core/Tooltip.svelte +103 -0
  58. package/dist/components/core/Tooltip.svelte.d.ts +11 -0
  59. package/dist/components/core/index.d.ts +13 -0
  60. package/dist/components/core/index.js +14 -0
  61. package/dist/components/editor/AIFocusLayer.svelte +430 -0
  62. package/dist/components/editor/AIFocusLayer.svelte.d.ts +32 -0
  63. package/dist/components/editor/Breadcrumbs.svelte +435 -0
  64. package/dist/components/editor/Breadcrumbs.svelte.d.ts +33 -0
  65. package/dist/components/editor/BreakpointLayer.svelte +642 -0
  66. package/dist/components/editor/BreakpointLayer.svelte.d.ts +20 -0
  67. package/dist/components/editor/CognitiveLoadMeter.svelte +324 -0
  68. package/dist/components/editor/CognitiveLoadMeter.svelte.d.ts +18 -0
  69. package/dist/components/editor/CollaborativeEditor.svelte +218 -0
  70. package/dist/components/editor/CollaborativeEditor.svelte.d.ts +32 -0
  71. package/dist/components/editor/CommandPalette.svelte +434 -0
  72. package/dist/components/editor/CommandPalette.svelte.d.ts +11 -0
  73. package/dist/components/editor/ComplexityLayer.svelte +293 -0
  74. package/dist/components/editor/ComplexityLayer.svelte.d.ts +23 -0
  75. package/dist/components/editor/ConflictZoneLayer.svelte +441 -0
  76. package/dist/components/editor/ConflictZoneLayer.svelte.d.ts +25 -0
  77. package/dist/components/editor/ContextLens.svelte +262 -0
  78. package/dist/components/editor/ContextLens.svelte.d.ts +27 -0
  79. package/dist/components/editor/CustomEditor.svelte +1242 -0
  80. package/dist/components/editor/CustomEditor.svelte.d.ts +37 -0
  81. package/dist/components/editor/DebugConsole.svelte +646 -0
  82. package/dist/components/editor/DebugConsole.svelte.d.ts +41 -0
  83. package/dist/components/editor/EchoCursorLayer.svelte +363 -0
  84. package/dist/components/editor/EchoCursorLayer.svelte.d.ts +24 -0
  85. package/dist/components/editor/Editor.svelte +61 -0
  86. package/dist/components/editor/Editor.svelte.d.ts +22 -0
  87. package/dist/components/editor/EditorGutter.svelte +119 -0
  88. package/dist/components/editor/EditorGutter.svelte.d.ts +19 -0
  89. package/dist/components/editor/EditorLines.svelte +182 -0
  90. package/dist/components/editor/EditorLines.svelte.d.ts +43 -0
  91. package/dist/components/editor/EditorPane.svelte +134 -0
  92. package/dist/components/editor/EditorPane.svelte.d.ts +9 -0
  93. package/dist/components/editor/EditorSelections.svelte +186 -0
  94. package/dist/components/editor/EditorSelections.svelte.d.ts +25 -0
  95. package/dist/components/editor/EditorTabs.svelte +170 -0
  96. package/dist/components/editor/EditorTabs.svelte.d.ts +12 -0
  97. package/dist/components/editor/FileExplorer.svelte +811 -0
  98. package/dist/components/editor/FileExplorer.svelte.d.ts +67 -0
  99. package/dist/components/editor/FileIcon.svelte +110 -0
  100. package/dist/components/editor/FileIcon.svelte.d.ts +10 -0
  101. package/dist/components/editor/FindReplace.svelte +448 -0
  102. package/dist/components/editor/FindReplace.svelte.d.ts +40 -0
  103. package/dist/components/editor/GhostBracketLayer.svelte +391 -0
  104. package/dist/components/editor/GhostBracketLayer.svelte.d.ts +24 -0
  105. package/dist/components/editor/GitBlameLayer.svelte +436 -0
  106. package/dist/components/editor/GitBlameLayer.svelte.d.ts +18 -0
  107. package/dist/components/editor/InlineDiagnosticsLayer.svelte +540 -0
  108. package/dist/components/editor/InlineDiagnosticsLayer.svelte.d.ts +35 -0
  109. package/dist/components/editor/InlineDiffLayer.svelte +337 -0
  110. package/dist/components/editor/InlineDiffLayer.svelte.d.ts +31 -0
  111. package/dist/components/editor/MinimalEditor.svelte +75 -0
  112. package/dist/components/editor/MinimalEditor.svelte.d.ts +6 -0
  113. package/dist/components/editor/MinimalEditor2.svelte +84 -0
  114. package/dist/components/editor/MinimalEditor2.svelte.d.ts +6 -0
  115. package/dist/components/editor/Minimap.svelte +327 -0
  116. package/dist/components/editor/Minimap.svelte.d.ts +34 -0
  117. package/dist/components/editor/PluginPreviewSandbox.svelte +793 -0
  118. package/dist/components/editor/PluginPreviewSandbox.svelte.d.ts +49 -0
  119. package/dist/components/editor/ProblemsPanel.svelte +628 -0
  120. package/dist/components/editor/ProblemsPanel.svelte.d.ts +25 -0
  121. package/dist/components/editor/QuickActionsMenu.svelte +403 -0
  122. package/dist/components/editor/QuickActionsMenu.svelte.d.ts +18 -0
  123. package/dist/components/editor/SnippetPalette.svelte +530 -0
  124. package/dist/components/editor/SnippetPalette.svelte.d.ts +16 -0
  125. package/dist/components/editor/StructureMap.svelte +431 -0
  126. package/dist/components/editor/StructureMap.svelte.d.ts +37 -0
  127. package/dist/components/editor/SymbolOutline.svelte +722 -0
  128. package/dist/components/editor/SymbolOutline.svelte.d.ts +44 -0
  129. package/dist/components/editor/TimelineScrubber.svelte +470 -0
  130. package/dist/components/editor/TimelineScrubber.svelte.d.ts +40 -0
  131. package/dist/components/editor/TokenRenderer.svelte +69 -0
  132. package/dist/components/editor/TokenRenderer.svelte.d.ts +15 -0
  133. package/dist/components/editor/constants.d.ts +32 -0
  134. package/dist/components/editor/constants.js +36 -0
  135. package/dist/components/editor/core/ai-awareness.d.ts +176 -0
  136. package/dist/components/editor/core/ai-awareness.js +210 -0
  137. package/dist/components/editor/core/bracket-healer.d.ts +189 -0
  138. package/dist/components/editor/core/bracket-healer.js +406 -0
  139. package/dist/components/editor/core/breakpoints.d.ts +203 -0
  140. package/dist/components/editor/core/breakpoints.js +414 -0
  141. package/dist/components/editor/core/commands.d.ts +108 -0
  142. package/dist/components/editor/core/commands.js +246 -0
  143. package/dist/components/editor/core/complexity-analyzer.d.ts +123 -0
  144. package/dist/components/editor/core/complexity-analyzer.js +376 -0
  145. package/dist/components/editor/core/conflict-predictor.d.ts +135 -0
  146. package/dist/components/editor/core/conflict-predictor.js +316 -0
  147. package/dist/components/editor/core/crdt-binding.d.ts +118 -0
  148. package/dist/components/editor/core/crdt-binding.js +286 -0
  149. package/dist/components/editor/core/diagnostics.d.ts +210 -0
  150. package/dist/components/editor/core/diagnostics.js +335 -0
  151. package/dist/components/editor/core/echo-cursor.d.ts +201 -0
  152. package/dist/components/editor/core/echo-cursor.js +267 -0
  153. package/dist/components/editor/core/folding.d.ts +124 -0
  154. package/dist/components/editor/core/folding.js +672 -0
  155. package/dist/components/editor/core/ghost-pair.d.ts +122 -0
  156. package/dist/components/editor/core/ghost-pair.js +221 -0
  157. package/dist/components/editor/core/git-blame.d.ts +170 -0
  158. package/dist/components/editor/core/git-blame.js +324 -0
  159. package/dist/components/editor/core/index.d.ts +26 -0
  160. package/dist/components/editor/core/index.js +24 -0
  161. package/dist/components/editor/core/keybindings.d.ts +79 -0
  162. package/dist/components/editor/core/keybindings.js +357 -0
  163. package/dist/components/editor/core/multi-cursor.d.ts +196 -0
  164. package/dist/components/editor/core/multi-cursor.js +521 -0
  165. package/dist/components/editor/core/navigation.d.ts +107 -0
  166. package/dist/components/editor/core/navigation.js +408 -0
  167. package/dist/components/editor/core/quick-actions.d.ts +189 -0
  168. package/dist/components/editor/core/quick-actions.js +427 -0
  169. package/dist/components/editor/core/search.d.ts +88 -0
  170. package/dist/components/editor/core/search.js +192 -0
  171. package/dist/components/editor/core/semantic-analyzer.d.ts +77 -0
  172. package/dist/components/editor/core/semantic-analyzer.js +424 -0
  173. package/dist/components/editor/core/snippet-manager.d.ts +202 -0
  174. package/dist/components/editor/core/snippet-manager.js +565 -0
  175. package/dist/components/editor/core/state.d.ts +367 -0
  176. package/dist/components/editor/core/state.js +900 -0
  177. package/dist/components/editor/core/timeline.d.ts +204 -0
  178. package/dist/components/editor/core/timeline.js +349 -0
  179. package/dist/components/editor/editor-find.d.ts +56 -0
  180. package/dist/components/editor/editor-find.js +148 -0
  181. package/dist/components/editor/editor-input.d.ts +77 -0
  182. package/dist/components/editor/editor-input.js +445 -0
  183. package/dist/components/editor/editor-multicursor.d.ts +21 -0
  184. package/dist/components/editor/editor-multicursor.js +196 -0
  185. package/dist/components/editor/editor-scroll.d.ts +14 -0
  186. package/dist/components/editor/editor-scroll.js +34 -0
  187. package/dist/components/editor/index.d.ts +15 -0
  188. package/dist/components/editor/index.js +21 -0
  189. package/dist/components/editor/languages.d.ts +62 -0
  190. package/dist/components/editor/languages.js +285 -0
  191. package/dist/components/editor/theme.d.ts +88 -0
  192. package/dist/components/editor/theme.js +139 -0
  193. package/dist/components/editor/tokenizer/base.d.ts +40 -0
  194. package/dist/components/editor/tokenizer/base.js +203 -0
  195. package/dist/components/editor/tokenizer/index.d.ts +56 -0
  196. package/dist/components/editor/tokenizer/index.js +215 -0
  197. package/dist/components/editor/tokenizer/languages/css.d.ts +17 -0
  198. package/dist/components/editor/tokenizer/languages/css.js +194 -0
  199. package/dist/components/editor/tokenizer/languages/go.d.ts +17 -0
  200. package/dist/components/editor/tokenizer/languages/go.js +220 -0
  201. package/dist/components/editor/tokenizer/languages/html.d.ts +24 -0
  202. package/dist/components/editor/tokenizer/languages/html.js +145 -0
  203. package/dist/components/editor/tokenizer/languages/javascript.d.ts +56 -0
  204. package/dist/components/editor/tokenizer/languages/javascript.js +452 -0
  205. package/dist/components/editor/tokenizer/languages/json.d.ts +12 -0
  206. package/dist/components/editor/tokenizer/languages/json.js +91 -0
  207. package/dist/components/editor/tokenizer/languages/markdown.d.ts +16 -0
  208. package/dist/components/editor/tokenizer/languages/markdown.js +156 -0
  209. package/dist/components/editor/tokenizer/languages/python.d.ts +20 -0
  210. package/dist/components/editor/tokenizer/languages/python.js +227 -0
  211. package/dist/components/editor/tokenizer/languages/svelte.d.ts +40 -0
  212. package/dist/components/editor/tokenizer/languages/svelte.js +326 -0
  213. package/dist/components/editor/tokenizer/types.d.ts +86 -0
  214. package/dist/components/editor/tokenizer/types.js +4 -0
  215. package/dist/components/layout/IDELayout.svelte +274 -0
  216. package/dist/components/layout/IDELayout.svelte.d.ts +29 -0
  217. package/dist/components/layout/StatusBar.svelte +511 -0
  218. package/dist/components/layout/StatusBar.svelte.d.ts +47 -0
  219. package/dist/components/layout/index.d.ts +2 -0
  220. package/dist/components/layout/index.js +3 -0
  221. package/dist/components/lsp/AutocompleteWidget.svelte +364 -0
  222. package/dist/components/lsp/AutocompleteWidget.svelte.d.ts +33 -0
  223. package/dist/components/lsp/DiagnosticMarker.svelte +166 -0
  224. package/dist/components/lsp/DiagnosticMarker.svelte.d.ts +19 -0
  225. package/dist/components/lsp/DiagnosticsPanel.svelte +388 -0
  226. package/dist/components/lsp/DiagnosticsPanel.svelte.d.ts +21 -0
  227. package/dist/components/lsp/HoverTooltip.svelte +274 -0
  228. package/dist/components/lsp/HoverTooltip.svelte.d.ts +24 -0
  229. package/dist/components/lsp/LSPEditor.svelte +486 -0
  230. package/dist/components/lsp/LSPEditor.svelte.d.ts +39 -0
  231. package/dist/components/lsp/SignatureHelpWidget.svelte +216 -0
  232. package/dist/components/lsp/SignatureHelpWidget.svelte.d.ts +22 -0
  233. package/dist/components/lsp/index.d.ts +6 -0
  234. package/dist/components/lsp/index.js +7 -0
  235. package/dist/components/plugins/PluginCard.svelte +153 -0
  236. package/dist/components/plugins/PluginCard.svelte.d.ts +19 -0
  237. package/dist/components/plugins/PluginPanel.svelte +280 -0
  238. package/dist/components/plugins/PluginPanel.svelte.d.ts +8 -0
  239. package/dist/components/plugins/PluginProposalForm.svelte +250 -0
  240. package/dist/components/plugins/PluginProposalForm.svelte.d.ts +6 -0
  241. package/dist/components/plugins/PluginStatusBadge.svelte +14 -0
  242. package/dist/components/plugins/PluginStatusBadge.svelte.d.ts +8 -0
  243. package/dist/components/plugins/index.d.ts +4 -0
  244. package/dist/components/plugins/index.js +5 -0
  245. package/dist/components/vfs/LockConflictDialog.svelte +705 -0
  246. package/dist/components/vfs/LockConflictDialog.svelte.d.ts +21 -0
  247. package/dist/components/vfs/LockIndicator.svelte +194 -0
  248. package/dist/components/vfs/LockIndicator.svelte.d.ts +29 -0
  249. package/dist/components/vfs/LockOverlay.svelte +344 -0
  250. package/dist/components/vfs/LockOverlay.svelte.d.ts +17 -0
  251. package/dist/components/vfs/VersionConflictDialog.svelte +549 -0
  252. package/dist/components/vfs/VersionConflictDialog.svelte.d.ts +24 -0
  253. package/dist/components/vfs/index.d.ts +4 -0
  254. package/dist/components/vfs/index.js +5 -0
  255. package/dist/crdt/awareness.d.ts +42 -0
  256. package/dist/crdt/awareness.js +109 -0
  257. package/dist/crdt/document.d.ts +101 -0
  258. package/dist/crdt/document.js +187 -0
  259. package/dist/crdt/index.d.ts +9 -0
  260. package/dist/crdt/index.js +8 -0
  261. package/dist/crdt/provider.d.ts +85 -0
  262. package/dist/crdt/provider.js +150 -0
  263. package/dist/crdt/types.d.ts +61 -0
  264. package/dist/crdt/types.js +4 -0
  265. package/dist/crdt/undo.d.ts +34 -0
  266. package/dist/crdt/undo.js +70 -0
  267. package/dist/index.d.ts +277 -0
  268. package/dist/index.js +280 -0
  269. package/dist/plugins/index.d.ts +103 -0
  270. package/dist/plugins/index.js +153 -0
  271. package/dist/services/error-handling.d.ts +95 -0
  272. package/dist/services/error-handling.js +413 -0
  273. package/dist/services/ide-integration.d.ts +83 -0
  274. package/dist/services/ide-integration.js +367 -0
  275. package/dist/services/lsp-client.d.ts +69 -0
  276. package/dist/services/lsp-client.js +667 -0
  277. package/dist/services/mock-ai.d.ts +37 -0
  278. package/dist/services/mock-ai.js +318 -0
  279. package/dist/services/optimistic.d.ts +141 -0
  280. package/dist/services/optimistic.js +367 -0
  281. package/dist/services/vfs-client.d.ts +81 -0
  282. package/dist/services/vfs-client.js +348 -0
  283. package/dist/stores/agents.svelte.d.ts +85 -0
  284. package/dist/stores/agents.svelte.js +459 -0
  285. package/dist/stores/ai-persistence.svelte.d.ts +76 -0
  286. package/dist/stores/ai-persistence.svelte.js +334 -0
  287. package/dist/stores/ai.svelte.d.ts +140 -0
  288. package/dist/stores/ai.svelte.js +383 -0
  289. package/dist/stores/collaboration.svelte.d.ts +164 -0
  290. package/dist/stores/collaboration.svelte.js +334 -0
  291. package/dist/stores/editor.svelte.d.ts +131 -0
  292. package/dist/stores/editor.svelte.js +250 -0
  293. package/dist/stores/index.d.ts +10 -0
  294. package/dist/stores/index.js +29 -0
  295. package/dist/stores/layout.svelte.d.ts +171 -0
  296. package/dist/stores/layout.svelte.js +351 -0
  297. package/dist/stores/plugin.svelte.d.ts +121 -0
  298. package/dist/stores/plugin.svelte.js +410 -0
  299. package/dist/stores/vfs.svelte.d.ts +123 -0
  300. package/dist/stores/vfs.svelte.js +680 -0
  301. package/dist/styles/theme.css +623 -0
  302. package/dist/types/agents.d.ts +127 -0
  303. package/dist/types/agents.js +5 -0
  304. package/dist/types/ai.d.ts +137 -0
  305. package/dist/types/ai.js +4 -0
  306. package/dist/types/crdt.d.ts +222 -0
  307. package/dist/types/crdt.js +5 -0
  308. package/dist/types/editor.d.ts +52 -0
  309. package/dist/types/editor.js +18 -0
  310. package/dist/types/events.d.ts +133 -0
  311. package/dist/types/events.js +4 -0
  312. package/dist/types/filesystem.d.ts +77 -0
  313. package/dist/types/filesystem.js +4 -0
  314. package/dist/types/index.d.ts +9 -0
  315. package/dist/types/index.js +12 -0
  316. package/dist/types/lsp.d.ts +691 -0
  317. package/dist/types/lsp.js +108 -0
  318. package/dist/types/plugin.d.ts +239 -0
  319. package/dist/types/plugin.js +5 -0
  320. package/dist/types/vfs.d.ts +191 -0
  321. package/dist/types/vfs.js +18 -0
  322. package/dist/utils/format.d.ts +55 -0
  323. package/dist/utils/format.js +152 -0
  324. package/dist/utils/index.d.ts +3 -0
  325. package/dist/utils/index.js +4 -0
  326. package/dist/utils/keybindings.d.ts +33 -0
  327. package/dist/utils/keybindings.js +171 -0
  328. package/dist/utils/language.d.ts +27 -0
  329. package/dist/utils/language.js +222 -0
  330. package/package.json +178 -0
@@ -0,0 +1,145 @@
1
+ /**
2
+ * HTML/XML tokenizer
3
+ */
4
+ import { createToken } from '../base';
5
+ export class HTMLTokenizer {
6
+ language;
7
+ isXML;
8
+ constructor(options = {}) {
9
+ this.isXML = options.xml ?? false;
10
+ this.language = this.isXML ? 'xml' : 'html';
11
+ }
12
+ getInitialState() {
13
+ return {};
14
+ }
15
+ tokenizeLine(line, lineNumber, prevState) {
16
+ const tokens = [];
17
+ let pos = 0;
18
+ const state = { ...prevState };
19
+ // Handle multi-line comment continuation
20
+ if (state.inBlockComment) {
21
+ const endIdx = line.indexOf('-->');
22
+ if (endIdx !== -1) {
23
+ tokens.push(createToken('comment.block', line.slice(0, endIdx + 3), 0));
24
+ pos = endIdx + 3;
25
+ state.inBlockComment = false;
26
+ }
27
+ else {
28
+ tokens.push(createToken('comment.block', line, 0));
29
+ return { lineNumber, tokens, text: line, state };
30
+ }
31
+ }
32
+ while (pos < line.length) {
33
+ const remaining = line.slice(pos);
34
+ const token = this.getNextToken(remaining, pos, state, line);
35
+ if (token) {
36
+ tokens.push(token);
37
+ pos = token.end;
38
+ }
39
+ else {
40
+ tokens.push(createToken('text', remaining[0], pos));
41
+ pos += 1;
42
+ }
43
+ }
44
+ if (tokens.length === 0) {
45
+ tokens.push(createToken('text', '', 0));
46
+ }
47
+ return { lineNumber, tokens, text: line, state };
48
+ }
49
+ getNextToken(text, pos, state, fullLine) {
50
+ // Whitespace
51
+ const wsMatch = text.match(/^[ \t]+/);
52
+ if (wsMatch) {
53
+ return createToken('text', wsMatch[0], pos);
54
+ }
55
+ // Comments
56
+ if (text.startsWith('<!--')) {
57
+ const endIdx = text.indexOf('-->', 4);
58
+ if (endIdx !== -1) {
59
+ return createToken('comment.block', text.slice(0, endIdx + 3), pos);
60
+ }
61
+ else {
62
+ state.inBlockComment = true;
63
+ return createToken('comment.block', text, pos);
64
+ }
65
+ }
66
+ // DOCTYPE
67
+ if (text.match(/^<!DOCTYPE/i)) {
68
+ const endIdx = text.indexOf('>');
69
+ if (endIdx !== -1) {
70
+ return createToken('keyword', text.slice(0, endIdx + 1), pos);
71
+ }
72
+ }
73
+ // CDATA (XML)
74
+ if (this.isXML && text.startsWith('<![CDATA[')) {
75
+ const endIdx = text.indexOf(']]>');
76
+ if (endIdx !== -1) {
77
+ return createToken('string', text.slice(0, endIdx + 3), pos);
78
+ }
79
+ return createToken('string', text, pos);
80
+ }
81
+ // Processing instructions (XML)
82
+ if (this.isXML && text.startsWith('<?')) {
83
+ const endIdx = text.indexOf('?>');
84
+ if (endIdx !== -1) {
85
+ return createToken('keyword', text.slice(0, endIdx + 2), pos);
86
+ }
87
+ }
88
+ // Closing tag
89
+ const closingTagMatch = text.match(/^<\/([a-zA-Z][a-zA-Z0-9:-]*)>/);
90
+ if (closingTagMatch) {
91
+ const tagName = closingTagMatch[1].toLowerCase();
92
+ if (tagName === 'script')
93
+ state.inScript = false;
94
+ if (tagName === 'style')
95
+ state.inStyle = false;
96
+ return createToken('tag', closingTagMatch[0], pos);
97
+ }
98
+ // Opening tag
99
+ const openingTagMatch = text.match(/^<([a-zA-Z][a-zA-Z0-9:-]*)(?:\s|\/?>|$)/);
100
+ if (openingTagMatch) {
101
+ return this.tokenizeTag(text, pos, state);
102
+ }
103
+ // Entity references
104
+ const entityMatch = text.match(/^&(?:#[0-9]+|#x[0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]*);/);
105
+ if (entityMatch) {
106
+ return createToken('constant.builtin', entityMatch[0], pos);
107
+ }
108
+ // Text content
109
+ const textMatch = text.match(/^[^<&]+/);
110
+ if (textMatch) {
111
+ return createToken('text', textMatch[0], pos);
112
+ }
113
+ return createToken('text', text[0], pos);
114
+ }
115
+ tokenizeTag(text, pos, state) {
116
+ // Match entire tag with attributes
117
+ const selfClosingMatch = text.match(/^<([a-zA-Z][a-zA-Z0-9:-]*)([^>]*?)\/>/);
118
+ const openingMatch = text.match(/^<([a-zA-Z][a-zA-Z0-9:-]*)([^>]*)>/);
119
+ if (selfClosingMatch) {
120
+ return createToken('tag', selfClosingMatch[0], pos);
121
+ }
122
+ if (openingMatch) {
123
+ const tagName = openingMatch[1].toLowerCase();
124
+ if (tagName === 'script')
125
+ state.inScript = true;
126
+ if (tagName === 'style')
127
+ state.inStyle = true;
128
+ return createToken('tag', openingMatch[0], pos);
129
+ }
130
+ // Partial tag - just match the tag name part
131
+ const partialMatch = text.match(/^<([a-zA-Z][a-zA-Z0-9:-]*)/);
132
+ if (partialMatch) {
133
+ state.inTag = true;
134
+ state.tagName = partialMatch[1];
135
+ return createToken('tag.name', partialMatch[0], pos);
136
+ }
137
+ return createToken('tag.punctuation', '<', pos);
138
+ }
139
+ }
140
+ export function createHTMLTokenizer() {
141
+ return new HTMLTokenizer();
142
+ }
143
+ export function createXMLTokenizer() {
144
+ return new HTMLTokenizer({ xml: true });
145
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * JavaScript/TypeScript tokenizer
3
+ */
4
+ import type { TokenizedLine, TokenizerState } from '../types';
5
+ interface JSTokenizerState extends TokenizerState {
6
+ templateDepth?: number;
7
+ jsxDepth?: number;
8
+ /** Track if regex is valid in current context (for division vs regex ambiguity) */
9
+ expectExpression?: boolean;
10
+ /**
11
+ * Last significant token text, used for regex/division disambiguation.
12
+ * Stored per-line in the threaded state (not on the tokenizer instance) so a
13
+ * single cached tokenizer instance can be safely shared across multiple
14
+ * EditorStates / split views without corrupting each other's context.
15
+ */
16
+ lastToken?: string;
17
+ }
18
+ export declare class JavaScriptTokenizer {
19
+ language: string;
20
+ private isTypeScript;
21
+ private isJSX;
22
+ constructor(options?: {
23
+ typescript?: boolean;
24
+ jsx?: boolean;
25
+ });
26
+ getInitialState(): JSTokenizerState;
27
+ tokenizeLine(line: string, lineNumber: number, prevState?: JSTokenizerState): TokenizedLine;
28
+ private getNextToken;
29
+ private classifyIdentifier;
30
+ /**
31
+ * Check if a regex literal can start in the current context
32
+ * This disambiguates between `/` as division vs regex start.
33
+ * Reads the last significant token from the threaded per-line state.
34
+ */
35
+ private canStartRegex;
36
+ /**
37
+ * Update the last token for context tracking.
38
+ * Stores onto the threaded per-line state so that a shared tokenizer
39
+ * instance does not leak context across documents.
40
+ */
41
+ private updateLastToken;
42
+ /**
43
+ * Try to match a regex literal using iterative parsing (avoids regex DoS)
44
+ * Returns the matched regex string or null if not a valid regex
45
+ */
46
+ private tryMatchRegex;
47
+ private tokenizeString;
48
+ private tokenizeTemplateLiteral;
49
+ private tokenizeTemplateLiteralContinuation;
50
+ private tokenizeJSXTag;
51
+ }
52
+ export declare function createJavaScriptTokenizer(): JavaScriptTokenizer;
53
+ export declare function createTypeScriptTokenizer(): JavaScriptTokenizer;
54
+ export declare function createJSXTokenizer(): JavaScriptTokenizer;
55
+ export declare function createTSXTokenizer(): JavaScriptTokenizer;
56
+ export {};
@@ -0,0 +1,452 @@
1
+ /**
2
+ * JavaScript/TypeScript tokenizer
3
+ */
4
+ import { createToken } from '../base';
5
+ // JavaScript/TypeScript keywords
6
+ const keywords = new Set([
7
+ 'await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger',
8
+ 'default', 'delete', 'do', 'else', 'enum', 'export', 'extends', 'finally',
9
+ 'for', 'function', 'if', 'import', 'in', 'instanceof', 'let', 'new', 'of',
10
+ 'return', 'static', 'super', 'switch', 'this', 'throw', 'try', 'typeof',
11
+ 'var', 'void', 'while', 'with', 'yield', 'async', 'from', 'as', 'get', 'set'
12
+ ]);
13
+ // TypeScript-specific keywords
14
+ const tsKeywords = new Set([
15
+ 'abstract', 'any', 'as', 'asserts', 'bigint', 'boolean', 'declare', 'infer',
16
+ 'interface', 'is', 'keyof', 'module', 'namespace', 'never', 'null', 'number',
17
+ 'object', 'override', 'private', 'protected', 'public', 'readonly', 'require',
18
+ 'string', 'symbol', 'type', 'undefined', 'unique', 'unknown', 'void'
19
+ ]);
20
+ // Control flow keywords
21
+ const controlKeywords = new Set([
22
+ 'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'default', 'break',
23
+ 'continue', 'return', 'throw', 'try', 'catch', 'finally', 'await', 'yield'
24
+ ]);
25
+ // Built-in constants
26
+ const builtins = new Set(['true', 'false', 'null', 'undefined', 'NaN', 'Infinity']);
27
+ // Built-in type names
28
+ const builtinTypes = new Set([
29
+ 'Array', 'Object', 'String', 'Number', 'Boolean', 'Function', 'Symbol',
30
+ 'Promise', 'Map', 'Set', 'WeakMap', 'WeakSet', 'Date', 'RegExp', 'Error',
31
+ 'TypeError', 'ReferenceError', 'SyntaxError', 'JSON', 'Math', 'console',
32
+ 'window', 'document', 'globalThis', 'Buffer', 'process'
33
+ ]);
34
+ /**
35
+ * Tokens after which a regex literal can appear (expression start context)
36
+ */
37
+ const REGEX_VALID_AFTER = new Set([
38
+ // Keywords that expect expressions
39
+ 'return', 'throw', 'case', 'in', 'of', 'typeof', 'instanceof', 'void',
40
+ 'delete', 'new', 'await', 'yield', 'default', 'extends', 'else', 'do',
41
+ // Operators
42
+ '=', '==', '===', '!=', '!==', '<', '>', '<=', '>=',
43
+ '+', '-', '*', '/', '%', '**', '&', '|', '^', '~', '!',
44
+ '&&', '||', '??', '?', ':', ',', ';',
45
+ '+=', '-=', '*=', '/=', '%=', '**=', '&=', '|=', '^=',
46
+ '&&=', '||=', '??=', '<<', '>>', '>>>', '<<=', '>>=', '>>>=',
47
+ // Opening brackets
48
+ '(', '[', '{',
49
+ // Arrow
50
+ '=>'
51
+ ]);
52
+ /**
53
+ * Tokens after which division operator appears (expression end context)
54
+ */
55
+ const DIVISION_VALID_AFTER = new Set([
56
+ // These token types indicate an expression just ended
57
+ ')', ']', '}', // Closing brackets
58
+ '++', '--', // Postfix operators
59
+ ]);
60
+ export class JavaScriptTokenizer {
61
+ language;
62
+ isTypeScript;
63
+ isJSX;
64
+ constructor(options = {}) {
65
+ this.isTypeScript = options.typescript ?? false;
66
+ this.isJSX = options.jsx ?? false;
67
+ this.language = this.isTypeScript
68
+ ? (this.isJSX ? 'tsx' : 'typescript')
69
+ : (this.isJSX ? 'jsx' : 'javascript');
70
+ }
71
+ getInitialState() {
72
+ return {
73
+ templateDepth: 0,
74
+ jsxDepth: 0
75
+ };
76
+ }
77
+ tokenizeLine(line, lineNumber, prevState) {
78
+ const tokens = [];
79
+ let pos = 0;
80
+ const state = {
81
+ ...this.getInitialState(),
82
+ ...prevState
83
+ };
84
+ // Reset context tracking at start of line if no continuation state
85
+ if (!state.inBlockComment && !state.inTemplateLiteral) {
86
+ // At line start, assume expression context (regex is valid)
87
+ state.lastToken = '';
88
+ }
89
+ // Handle block comment continuation
90
+ if (state.inBlockComment) {
91
+ const endIdx = line.indexOf('*/');
92
+ if (endIdx !== -1) {
93
+ tokens.push(createToken('comment.block', line.slice(0, endIdx + 2), 0));
94
+ pos = endIdx + 2;
95
+ state.inBlockComment = false;
96
+ }
97
+ else {
98
+ tokens.push(createToken('comment.block', line, 0));
99
+ return { lineNumber, tokens, text: line, state };
100
+ }
101
+ }
102
+ // Handle template literal continuation
103
+ if (state.inTemplateLiteral && (state.templateDepth ?? 0) > 0) {
104
+ const result = this.tokenizeTemplateLiteralContinuation(line, pos, state);
105
+ tokens.push(...result.tokens);
106
+ pos = result.pos;
107
+ if (pos >= line.length) {
108
+ return { lineNumber, tokens, text: line, state };
109
+ }
110
+ }
111
+ while (pos < line.length) {
112
+ const remaining = line.slice(pos);
113
+ const token = this.getNextToken(remaining, pos, state);
114
+ if (token) {
115
+ tokens.push(token);
116
+ this.updateLastToken(token, state);
117
+ pos = token.end;
118
+ }
119
+ else {
120
+ // No match - shouldn't happen but handle gracefully
121
+ const fallbackToken = createToken('text', remaining[0], pos);
122
+ tokens.push(fallbackToken);
123
+ this.updateLastToken(fallbackToken, state);
124
+ pos += 1;
125
+ }
126
+ }
127
+ if (tokens.length === 0) {
128
+ tokens.push(createToken('text', '', 0));
129
+ }
130
+ return { lineNumber, tokens, text: line, state };
131
+ }
132
+ getNextToken(text, pos, state) {
133
+ // Skip whitespace
134
+ const wsMatch = text.match(/^[ \t]+/);
135
+ if (wsMatch) {
136
+ return createToken('text', wsMatch[0], pos);
137
+ }
138
+ // Line comments
139
+ if (text.startsWith('//')) {
140
+ return createToken('comment.line', text, pos);
141
+ }
142
+ // Block comments
143
+ if (text.startsWith('/*')) {
144
+ const endIdx = text.indexOf('*/', 2);
145
+ if (endIdx !== -1) {
146
+ return createToken('comment.block', text.slice(0, endIdx + 2), pos);
147
+ }
148
+ else {
149
+ state.inBlockComment = true;
150
+ return createToken('comment.block', text, pos);
151
+ }
152
+ }
153
+ // Template literals
154
+ if (text.startsWith('`')) {
155
+ return this.tokenizeTemplateLiteral(text, pos, state);
156
+ }
157
+ // Regular strings
158
+ if (text.startsWith('"') || text.startsWith("'")) {
159
+ return this.tokenizeString(text, pos, text[0]);
160
+ }
161
+ // Regular expressions vs division - use context to disambiguate
162
+ if (text.startsWith('/') && !text.startsWith('//') && !text.startsWith('/*')) {
163
+ // Check if we're in a context where regex is valid
164
+ const canBeRegex = this.canStartRegex(state);
165
+ if (canBeRegex) {
166
+ const regexLiteral = this.tryMatchRegex(text);
167
+ if (regexLiteral) {
168
+ return createToken('string.regex', regexLiteral, pos);
169
+ }
170
+ }
171
+ // Otherwise, fall through to operator handling (will be tokenized as '/')
172
+ }
173
+ // Numbers
174
+ const numMatch = text.match(/^(?:0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?n?)/);
175
+ if (numMatch) {
176
+ const numText = numMatch[0];
177
+ let type = 'number';
178
+ if (numText.startsWith('0x') || numText.startsWith('0X')) {
179
+ type = 'number.hex';
180
+ }
181
+ else if (numText.startsWith('0b') || numText.startsWith('0B')) {
182
+ type = 'number.binary';
183
+ }
184
+ else if (numText.includes('.') || numText.includes('e') || numText.includes('E')) {
185
+ type = 'number.float';
186
+ }
187
+ else {
188
+ type = 'number.integer';
189
+ }
190
+ return createToken(type, numText, pos);
191
+ }
192
+ // Identifiers and keywords
193
+ const identMatch = text.match(/^[a-zA-Z_$][a-zA-Z0-9_$]*/);
194
+ if (identMatch) {
195
+ const word = identMatch[0];
196
+ return createToken(this.classifyIdentifier(word, text, identMatch[0].length), word, pos);
197
+ }
198
+ // JSX tags (basic)
199
+ if (this.isJSX && text.startsWith('<')) {
200
+ return this.tokenizeJSXTag(text, pos, state);
201
+ }
202
+ // Operators
203
+ const opMatch = text.match(/^(?:>>>|===|!==|<<=|>>=|=>|&&|\|\||[+\-*/%&|^!<>=]=?|[?:.~]|\?\?|\?\.)/);
204
+ if (opMatch) {
205
+ return createToken('operator', opMatch[0], pos);
206
+ }
207
+ // Punctuation
208
+ const punctMatch = text.match(/^[{}[\](),;]/);
209
+ if (punctMatch) {
210
+ const char = punctMatch[0];
211
+ let type = 'punctuation';
212
+ if (char === '{' || char === '}')
213
+ type = 'punctuation.brace';
214
+ else if (char === '[' || char === ']')
215
+ type = 'punctuation.bracket';
216
+ else if (char === '(' || char === ')')
217
+ type = 'punctuation.paren';
218
+ else if (char === ',' || char === ';')
219
+ type = 'punctuation.separator';
220
+ return createToken(type, char, pos);
221
+ }
222
+ // Dot accessor
223
+ if (text.startsWith('.')) {
224
+ return createToken('punctuation.accessor', '.', pos);
225
+ }
226
+ // Default: single character
227
+ return createToken('text', text[0], pos);
228
+ }
229
+ classifyIdentifier(word, context, wordLength) {
230
+ // Check for built-in constants
231
+ if (builtins.has(word)) {
232
+ if (word === 'true' || word === 'false')
233
+ return 'constant.boolean';
234
+ if (word === 'null' || word === 'undefined')
235
+ return 'constant.null';
236
+ return 'constant.builtin';
237
+ }
238
+ // Check for keywords
239
+ if (keywords.has(word)) {
240
+ if (controlKeywords.has(word))
241
+ return 'keyword.control';
242
+ if (word === 'function' || word === 'class' || word === 'const' || word === 'let' || word === 'var') {
243
+ return 'keyword.definition';
244
+ }
245
+ if (word === 'import' || word === 'export' || word === 'from' || word === 'as') {
246
+ return 'keyword.module';
247
+ }
248
+ return 'keyword';
249
+ }
250
+ // TypeScript keywords
251
+ if (this.isTypeScript && tsKeywords.has(word)) {
252
+ if (word === 'interface' || word === 'type' || word === 'namespace' || word === 'module') {
253
+ return 'keyword.definition';
254
+ }
255
+ // Type keywords like 'string', 'number', 'boolean' etc
256
+ if (['string', 'number', 'boolean', 'any', 'unknown', 'never', 'void', 'null', 'undefined', 'object', 'symbol', 'bigint'].includes(word)) {
257
+ return 'type.builtin';
258
+ }
259
+ return 'keyword.storage';
260
+ }
261
+ // Check if followed by ( - likely a function call
262
+ const afterWord = context.slice(wordLength).trim();
263
+ if (afterWord.startsWith('(')) {
264
+ return 'function.call';
265
+ }
266
+ // Check if it's a type (PascalCase)
267
+ if (/^[A-Z][a-zA-Z0-9]*$/.test(word)) {
268
+ if (builtinTypes.has(word))
269
+ return 'type.builtin';
270
+ return 'type.class';
271
+ }
272
+ // Check context for function definition
273
+ const beforeContext = context.slice(0, 0); // We don't have before context here
274
+ // Would need more context to detect 'function foo' pattern
275
+ return 'variable';
276
+ }
277
+ /**
278
+ * Check if a regex literal can start in the current context
279
+ * This disambiguates between `/` as division vs regex start.
280
+ * Reads the last significant token from the threaded per-line state.
281
+ */
282
+ canStartRegex(state) {
283
+ const lastToken = state.lastToken;
284
+ // At start of expression or line, regex is valid
285
+ if (!lastToken)
286
+ return true;
287
+ // After certain operators and keywords, regex is valid
288
+ if (REGEX_VALID_AFTER.has(lastToken))
289
+ return true;
290
+ // After identifiers, numbers, or closing brackets, it's division
291
+ if (DIVISION_VALID_AFTER.has(lastToken))
292
+ return false;
293
+ // If last token was an identifier or number, it's likely division
294
+ // (e.g., `x / 2` or `5 / 2`)
295
+ if (/^[a-zA-Z_$]/.test(lastToken) || /^\d/.test(lastToken)) {
296
+ return false;
297
+ }
298
+ // Default to allowing regex in ambiguous cases
299
+ return true;
300
+ }
301
+ /**
302
+ * Update the last token for context tracking.
303
+ * Stores onto the threaded per-line state so that a shared tokenizer
304
+ * instance does not leak context across documents.
305
+ */
306
+ updateLastToken(token, state) {
307
+ // Track significant tokens for regex/division disambiguation
308
+ const text = token.text.trim();
309
+ if (text && token.type !== 'comment' && !token.type.startsWith('comment.')) {
310
+ state.lastToken = text;
311
+ }
312
+ }
313
+ /**
314
+ * Try to match a regex literal using iterative parsing (avoids regex DoS)
315
+ * Returns the matched regex string or null if not a valid regex
316
+ */
317
+ tryMatchRegex(text) {
318
+ if (text.length < 2 || text[0] !== '/')
319
+ return null;
320
+ let i = 1;
321
+ let inCharClass = false;
322
+ // Match regex body
323
+ while (i < text.length) {
324
+ const char = text[i];
325
+ // End of line means not a valid regex literal
326
+ if (char === '\n')
327
+ return null;
328
+ // Handle escape sequences
329
+ if (char === '\\' && i + 1 < text.length) {
330
+ i += 2;
331
+ continue;
332
+ }
333
+ // Track character class [...] to ignore / inside
334
+ if (char === '[' && !inCharClass) {
335
+ inCharClass = true;
336
+ i++;
337
+ continue;
338
+ }
339
+ if (char === ']' && inCharClass) {
340
+ inCharClass = false;
341
+ i++;
342
+ continue;
343
+ }
344
+ // End of regex body (not inside character class)
345
+ if (char === '/' && !inCharClass) {
346
+ i++; // Include the closing /
347
+ // Match flags
348
+ while (i < text.length && /[gimsuvy]/.test(text[i])) {
349
+ i++;
350
+ }
351
+ return text.slice(0, i);
352
+ }
353
+ i++;
354
+ }
355
+ return null; // Unclosed regex
356
+ }
357
+ tokenizeString(text, pos, delimiter) {
358
+ let i = 1;
359
+ while (i < text.length) {
360
+ if (text[i] === '\\' && i + 1 < text.length) {
361
+ i += 2; // Skip escape sequence
362
+ continue;
363
+ }
364
+ if (text[i] === delimiter) {
365
+ return createToken('string', text.slice(0, i + 1), pos);
366
+ }
367
+ if (text[i] === '\n') {
368
+ // Unterminated string
369
+ return createToken('string', text.slice(0, i), pos);
370
+ }
371
+ i++;
372
+ }
373
+ // Unterminated string at end of line
374
+ return createToken('string', text, pos);
375
+ }
376
+ tokenizeTemplateLiteral(text, pos, state) {
377
+ let i = 1;
378
+ let result = '`';
379
+ while (i < text.length) {
380
+ if (text[i] === '\\' && i + 1 < text.length) {
381
+ result += text.slice(i, i + 2);
382
+ i += 2;
383
+ continue;
384
+ }
385
+ if (text[i] === '`') {
386
+ result += '`';
387
+ return createToken('string.template', result, pos);
388
+ }
389
+ if (text[i] === '$' && text[i + 1] === '{') {
390
+ // Template expression - for simplicity, tokenize up to this point
391
+ if (result.length > 1) {
392
+ // Return string part first
393
+ state.inTemplateLiteral = true;
394
+ state.templateDepth = (state.templateDepth ?? 0) + 1;
395
+ return createToken('string.template', result, pos);
396
+ }
397
+ }
398
+ result += text[i];
399
+ i++;
400
+ }
401
+ // Multi-line template literal
402
+ state.inTemplateLiteral = true;
403
+ return createToken('string.template', result, pos);
404
+ }
405
+ tokenizeTemplateLiteralContinuation(line, startPos, state) {
406
+ const tokens = [];
407
+ let pos = startPos;
408
+ let result = '';
409
+ while (pos < line.length) {
410
+ if (line[pos] === '\\' && pos + 1 < line.length) {
411
+ result += line.slice(pos, pos + 2);
412
+ pos += 2;
413
+ continue;
414
+ }
415
+ if (line[pos] === '`') {
416
+ result += '`';
417
+ tokens.push(createToken('string.template', result, startPos));
418
+ state.inTemplateLiteral = false;
419
+ state.templateDepth = Math.max(0, (state.templateDepth ?? 1) - 1);
420
+ return { tokens, pos: pos + 1 };
421
+ }
422
+ result += line[pos];
423
+ pos++;
424
+ }
425
+ if (result) {
426
+ tokens.push(createToken('string.template', result, startPos));
427
+ }
428
+ return { tokens, pos };
429
+ }
430
+ tokenizeJSXTag(text, pos, state) {
431
+ // Simple JSX tag detection
432
+ const match = text.match(/^<\/?[a-zA-Z][a-zA-Z0-9.]*(?:\s+[^>]*)?\/?>/);
433
+ if (match) {
434
+ return createToken('tag', match[0], pos);
435
+ }
436
+ // Just the opening <
437
+ return createToken('tag.punctuation', '<', pos);
438
+ }
439
+ }
440
+ // Factory functions for convenience
441
+ export function createJavaScriptTokenizer() {
442
+ return new JavaScriptTokenizer();
443
+ }
444
+ export function createTypeScriptTokenizer() {
445
+ return new JavaScriptTokenizer({ typescript: true });
446
+ }
447
+ export function createJSXTokenizer() {
448
+ return new JavaScriptTokenizer({ jsx: true });
449
+ }
450
+ export function createTSXTokenizer() {
451
+ return new JavaScriptTokenizer({ typescript: true, jsx: true });
452
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * JSON tokenizer
3
+ */
4
+ import type { TokenizedLine, TokenizerState } from '../types';
5
+ export declare class JSONTokenizer {
6
+ language: string;
7
+ getInitialState(): TokenizerState;
8
+ tokenizeLine(line: string, lineNumber: number, prevState?: TokenizerState): TokenizedLine;
9
+ private getNextToken;
10
+ private findStringEnd;
11
+ }
12
+ export declare function createJSONTokenizer(): JSONTokenizer;