@kispace-io/core 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/dist/api/base-classes.d.ts +7 -0
  2. package/dist/api/base-classes.d.ts.map +1 -0
  3. package/dist/api/constants.d.ts +2 -0
  4. package/dist/api/constants.d.ts.map +1 -0
  5. package/dist/api/index.d.ts +6 -0
  6. package/dist/api/index.d.ts.map +1 -0
  7. package/dist/api/index.js +80 -0
  8. package/dist/api/index.js.map +1 -0
  9. package/dist/api/services.d.ts +27 -0
  10. package/dist/api/services.d.ts.map +1 -0
  11. package/dist/api/types.d.ts +11 -0
  12. package/dist/api/types.d.ts.map +1 -0
  13. package/dist/commands/files.d.ts +2 -0
  14. package/dist/commands/files.d.ts.map +1 -0
  15. package/dist/commands/global.d.ts +1 -0
  16. package/dist/commands/global.d.ts.map +1 -0
  17. package/dist/commands/index.d.ts +1 -0
  18. package/dist/commands/index.d.ts.map +1 -0
  19. package/dist/commands/version-info.d.ts +2 -0
  20. package/dist/commands/version-info.d.ts.map +1 -0
  21. package/dist/components/index.d.ts +1 -0
  22. package/dist/components/index.d.ts.map +1 -0
  23. package/dist/components/k-app-selector.d.ts +17 -0
  24. package/dist/components/k-app-selector.d.ts.map +1 -0
  25. package/dist/components/k-app-switcher.d.ts +13 -0
  26. package/dist/components/k-app-switcher.d.ts.map +1 -0
  27. package/dist/components/k-command.d.ts +31 -0
  28. package/dist/components/k-command.d.ts.map +1 -0
  29. package/dist/components/k-extensions.d.ts +32 -0
  30. package/dist/components/k-extensions.d.ts.map +1 -0
  31. package/dist/components/k-fastviews.d.ts +34 -0
  32. package/dist/components/k-fastviews.d.ts.map +1 -0
  33. package/dist/components/k-filebrowser.d.ts +40 -0
  34. package/dist/components/k-filebrowser.d.ts.map +1 -0
  35. package/dist/components/k-language-selector.d.ts +12 -0
  36. package/dist/components/k-language-selector.d.ts.map +1 -0
  37. package/dist/components/k-log-terminal.d.ts +36 -0
  38. package/dist/components/k-log-terminal.d.ts.map +1 -0
  39. package/dist/components/k-part-name.d.ts +12 -0
  40. package/dist/components/k-part-name.d.ts.map +1 -0
  41. package/dist/components/k-tasks.d.ts +13 -0
  42. package/dist/components/k-tasks.d.ts.map +1 -0
  43. package/dist/components/k-workspace-name.d.ts +14 -0
  44. package/dist/components/k-workspace-name.d.ts.map +1 -0
  45. package/dist/contributions/default-ui-contributions.d.ts +2 -0
  46. package/dist/contributions/default-ui-contributions.d.ts.map +1 -0
  47. package/dist/contributions/index.d.ts +1 -0
  48. package/dist/contributions/index.d.ts.map +1 -0
  49. package/dist/contributions/marketplace-catalog-contributions.d.ts +2 -0
  50. package/dist/contributions/marketplace-catalog-contributions.d.ts.map +1 -0
  51. package/dist/core/app-host-config.d.ts +7 -0
  52. package/dist/core/app-host-config.d.ts.map +1 -0
  53. package/dist/core/apploader.d.ts +214 -0
  54. package/dist/core/apploader.d.ts.map +1 -0
  55. package/dist/core/appstate.d.ts +12 -0
  56. package/dist/core/appstate.d.ts.map +1 -0
  57. package/dist/core/commandregistry.d.ts +79 -0
  58. package/dist/core/commandregistry.d.ts.map +1 -0
  59. package/dist/core/config.d.ts +15 -0
  60. package/dist/core/config.d.ts.map +1 -0
  61. package/dist/core/constants.d.ts +21 -0
  62. package/dist/core/constants.d.ts.map +1 -0
  63. package/dist/core/contributionregistry.d.ts +49 -0
  64. package/dist/core/contributionregistry.d.ts.map +1 -0
  65. package/dist/core/di.d.ts +18 -0
  66. package/dist/core/di.d.ts.map +1 -0
  67. package/dist/core/dialogservice.d.ts +33 -0
  68. package/dist/core/dialogservice.d.ts.map +1 -0
  69. package/dist/core/editorregistry.d.ts +73 -0
  70. package/dist/core/editorregistry.d.ts.map +1 -0
  71. package/dist/core/esmsh-service.d.ts +40 -0
  72. package/dist/core/esmsh-service.d.ts.map +1 -0
  73. package/dist/core/events.d.ts +7 -0
  74. package/dist/core/events.d.ts.map +1 -0
  75. package/dist/core/events.js +63 -0
  76. package/dist/core/events.js.map +1 -0
  77. package/dist/core/extensionregistry.d.ts +98 -0
  78. package/dist/core/extensionregistry.d.ts.map +1 -0
  79. package/dist/core/filesys.d.ts +139 -0
  80. package/dist/core/filesys.d.ts.map +1 -0
  81. package/dist/core/i18n.d.ts +50 -0
  82. package/dist/core/i18n.d.ts.map +1 -0
  83. package/dist/core/index.d.ts +1 -0
  84. package/dist/core/index.d.ts.map +1 -0
  85. package/dist/core/k-utils.d.ts +2 -0
  86. package/dist/core/k-utils.d.ts.map +1 -0
  87. package/dist/core/keybindings.d.ts +67 -0
  88. package/dist/core/keybindings.d.ts.map +1 -0
  89. package/dist/core/logger.d.ts +44 -0
  90. package/dist/core/logger.d.ts.map +1 -0
  91. package/dist/core/marketplaceregistry.d.ts +25 -0
  92. package/dist/core/marketplaceregistry.d.ts.map +1 -0
  93. package/dist/core/packageinfoservice.d.ts +16 -0
  94. package/dist/core/packageinfoservice.d.ts.map +1 -0
  95. package/dist/core/persistenceservice.d.ts +6 -0
  96. package/dist/core/persistenceservice.d.ts.map +1 -0
  97. package/dist/core/settingsservice.d.ts +19 -0
  98. package/dist/core/settingsservice.d.ts.map +1 -0
  99. package/dist/core/signals.d.ts +3 -0
  100. package/dist/core/signals.d.ts.map +1 -0
  101. package/dist/core/taskservice.d.ts +20 -0
  102. package/dist/core/taskservice.d.ts.map +1 -0
  103. package/dist/core/toast.d.ts +4 -0
  104. package/dist/core/toast.d.ts.map +1 -0
  105. package/dist/core/tree-utils.d.ts +16 -0
  106. package/dist/core/tree-utils.d.ts.map +1 -0
  107. package/dist/dialogs/confirm-dialog.d.ts +14 -0
  108. package/dist/dialogs/confirm-dialog.d.ts.map +1 -0
  109. package/dist/dialogs/index.d.ts +5 -0
  110. package/dist/dialogs/index.d.ts.map +1 -0
  111. package/dist/dialogs/info-dialog.d.ts +13 -0
  112. package/dist/dialogs/info-dialog.d.ts.map +1 -0
  113. package/dist/dialogs/navigable-info-dialog.d.ts +33 -0
  114. package/dist/dialogs/navigable-info-dialog.d.ts.map +1 -0
  115. package/dist/dialogs/prompt-dialog.d.ts +21 -0
  116. package/dist/dialogs/prompt-dialog.d.ts.map +1 -0
  117. package/dist/externals/lit.d.ts +20 -0
  118. package/dist/externals/lit.d.ts.map +1 -0
  119. package/dist/externals/lit.js +15 -0
  120. package/dist/externals/lit.js.map +1 -0
  121. package/dist/externals/third-party.d.ts +7 -0
  122. package/dist/externals/third-party.d.ts.map +1 -0
  123. package/dist/externals/third-party.js +2 -0
  124. package/dist/externals/third-party.js.map +1 -0
  125. package/dist/externals/webawesome.d.ts +1 -0
  126. package/dist/externals/webawesome.d.ts.map +1 -0
  127. package/dist/externals/webawesome.js +52 -0
  128. package/dist/externals/webawesome.js.map +1 -0
  129. package/dist/i18n/extensions.json.d.ts +42 -0
  130. package/dist/i18n/fastviews.json.d.ts +13 -0
  131. package/dist/i18n/filebrowser.json.d.ts +35 -0
  132. package/dist/i18n/index.d.ts +2 -0
  133. package/dist/i18n/index.d.ts.map +1 -0
  134. package/dist/i18n/logterminal.json.d.ts +45 -0
  135. package/dist/i18n/partname.json.d.ts +15 -0
  136. package/dist/i18n/tasks.json.d.ts +15 -0
  137. package/dist/i18n/workspace.json.d.ts +15 -0
  138. package/dist/index.d.ts +2 -0
  139. package/dist/index.d.ts.map +1 -0
  140. package/dist/index.js +80 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/k-icon-BZC7dQV0.js +492 -0
  143. package/dist/k-icon-BZC7dQV0.js.map +1 -0
  144. package/dist/k-nocontent-Bh_yToGh.js +48 -0
  145. package/dist/k-nocontent-Bh_yToGh.js.map +1 -0
  146. package/dist/k-resizable-grid-Ch3iWZaL.js +3157 -0
  147. package/dist/k-resizable-grid-Ch3iWZaL.js.map +1 -0
  148. package/dist/k-standard-layout-CQ1VZoxa.js +5011 -0
  149. package/dist/k-standard-layout-CQ1VZoxa.js.map +1 -0
  150. package/dist/layouts/k-standard-layout.d.ts +16 -0
  151. package/dist/layouts/k-standard-layout.d.ts.map +1 -0
  152. package/dist/parts/index.d.ts +1 -0
  153. package/dist/parts/index.d.ts.map +1 -0
  154. package/dist/parts/index.js +53 -0
  155. package/dist/parts/index.js.map +1 -0
  156. package/dist/parts/k-app.d.ts +11 -0
  157. package/dist/parts/k-app.d.ts.map +1 -0
  158. package/dist/parts/k-container.d.ts +4 -0
  159. package/dist/parts/k-container.d.ts.map +1 -0
  160. package/dist/parts/k-contextmenu.d.ts +38 -0
  161. package/dist/parts/k-contextmenu.d.ts.map +1 -0
  162. package/dist/parts/k-dialog-content.d.ts +9 -0
  163. package/dist/parts/k-dialog-content.d.ts.map +1 -0
  164. package/dist/parts/k-element.d.ts +36 -0
  165. package/dist/parts/k-element.d.ts.map +1 -0
  166. package/dist/parts/k-part.d.ts +96 -0
  167. package/dist/parts/k-part.d.ts.map +1 -0
  168. package/dist/parts/k-resizable-grid.d.ts +31 -0
  169. package/dist/parts/k-resizable-grid.d.ts.map +1 -0
  170. package/dist/parts/k-tabs.d.ts +74 -0
  171. package/dist/parts/k-tabs.d.ts.map +1 -0
  172. package/dist/parts/k-toolbar.d.ts +21 -0
  173. package/dist/parts/k-toolbar.d.ts.map +1 -0
  174. package/dist/widgets/index.d.ts +1 -0
  175. package/dist/widgets/index.d.ts.map +1 -0
  176. package/dist/widgets/index.js +3 -0
  177. package/dist/widgets/index.js.map +1 -0
  178. package/dist/widgets/k-icon.d.ts +10 -0
  179. package/dist/widgets/k-icon.d.ts.map +1 -0
  180. package/dist/widgets/k-nocontent.d.ts +13 -0
  181. package/dist/widgets/k-nocontent.d.ts.map +1 -0
  182. package/dist/widgets/k-widget.d.ts +25 -0
  183. package/dist/widgets/k-widget.d.ts.map +1 -0
  184. package/package.json +81 -0
  185. package/src/api/base-classes.ts +10 -0
  186. package/src/api/constants.ts +3 -0
  187. package/src/api/index.ts +31 -0
  188. package/src/api/services.ts +52 -0
  189. package/src/api/types.ts +46 -0
  190. package/src/commands/files.ts +829 -0
  191. package/src/commands/global.ts +225 -0
  192. package/src/commands/index.ts +4 -0
  193. package/src/commands/version-info.ts +214 -0
  194. package/src/components/index.ts +10 -0
  195. package/src/components/k-app-selector.ts +233 -0
  196. package/src/components/k-app-switcher.ts +126 -0
  197. package/src/components/k-command.ts +236 -0
  198. package/src/components/k-extensions.ts +615 -0
  199. package/src/components/k-fastviews.ts +314 -0
  200. package/src/components/k-filebrowser.ts +442 -0
  201. package/src/components/k-language-selector.ts +166 -0
  202. package/src/components/k-log-terminal.ts +337 -0
  203. package/src/components/k-part-name.ts +54 -0
  204. package/src/components/k-tasks.ts +267 -0
  205. package/src/components/k-workspace-name.ts +56 -0
  206. package/src/contributions/default-ui-contributions.ts +51 -0
  207. package/src/contributions/index.ts +3 -0
  208. package/src/contributions/marketplace-catalog-contributions.ts +6 -0
  209. package/src/core/app-host-config.ts +23 -0
  210. package/src/core/apploader.ts +630 -0
  211. package/src/core/appstate.ts +15 -0
  212. package/src/core/commandregistry.ts +210 -0
  213. package/src/core/config.ts +29 -0
  214. package/src/core/constants.ts +27 -0
  215. package/src/core/contributionregistry.ts +77 -0
  216. package/src/core/di.ts +54 -0
  217. package/src/core/dialogservice.ts +266 -0
  218. package/src/core/editorregistry.ts +303 -0
  219. package/src/core/esmsh-service.ts +404 -0
  220. package/src/core/events.ts +68 -0
  221. package/src/core/extensionregistry.ts +399 -0
  222. package/src/core/filesys.ts +618 -0
  223. package/src/core/i18n.ts +221 -0
  224. package/src/core/index.ts +51 -0
  225. package/src/core/k-utils.ts +11 -0
  226. package/src/core/keybindings.ts +274 -0
  227. package/src/core/logger.ts +187 -0
  228. package/src/core/marketplaceregistry.ts +197 -0
  229. package/src/core/packageinfoservice.ts +56 -0
  230. package/src/core/persistenceservice.ts +15 -0
  231. package/src/core/settingsservice.ts +70 -0
  232. package/src/core/signals.ts +18 -0
  233. package/src/core/taskservice.ts +72 -0
  234. package/src/core/toast.ts +11 -0
  235. package/src/core/tree-utils.ts +24 -0
  236. package/src/dialogs/confirm-dialog.ts +72 -0
  237. package/src/dialogs/index.ts +4 -0
  238. package/src/dialogs/info-dialog.ts +67 -0
  239. package/src/dialogs/navigable-info-dialog.ts +256 -0
  240. package/src/dialogs/prompt-dialog.ts +123 -0
  241. package/src/externals/lit.ts +26 -0
  242. package/src/externals/third-party.ts +9 -0
  243. package/src/externals/webawesome.ts +54 -0
  244. package/src/i18n/extensions.json +39 -0
  245. package/src/i18n/fastviews.json +10 -0
  246. package/src/i18n/filebrowser.json +33 -0
  247. package/src/i18n/index.ts +25 -0
  248. package/src/i18n/logterminal.json +42 -0
  249. package/src/i18n/partname.json +12 -0
  250. package/src/i18n/tasks.json +12 -0
  251. package/src/i18n/workspace.json +12 -0
  252. package/src/icons/icons.txt +3 -0
  253. package/src/icons/js.svg +6 -0
  254. package/src/icons/jupyter.svg +18 -0
  255. package/src/icons/python.svg +15 -0
  256. package/src/index.ts +3 -0
  257. package/src/layouts/k-standard-layout.ts +174 -0
  258. package/src/parts/index.ts +6 -0
  259. package/src/parts/k-app.ts +29 -0
  260. package/src/parts/k-container.ts +4 -0
  261. package/src/parts/k-contextmenu.ts +245 -0
  262. package/src/parts/k-dialog-content.ts +31 -0
  263. package/src/parts/k-element.ts +100 -0
  264. package/src/parts/k-part.ts +158 -0
  265. package/src/parts/k-resizable-grid.ts +366 -0
  266. package/src/parts/k-tabs.ts +574 -0
  267. package/src/parts/k-toolbar.ts +158 -0
  268. package/src/vite-env.d.ts +2 -0
  269. package/src/widgets/index.ts +2 -0
  270. package/src/widgets/k-icon.ts +39 -0
  271. package/src/widgets/k-nocontent.ts +40 -0
  272. package/src/widgets/k-widget.ts +90 -0
@@ -0,0 +1,303 @@
1
+ import {EDITOR_AREA_MAIN} from "./constants";
2
+ import {KPart} from "../parts/k-part";
3
+ import {activePartSignal, activeEditorSignal, partDirtySignal} from "./appstate";
4
+ import {watchSignal} from "./signals";
5
+ import {subscribe} from "./events";
6
+ import {TOPIC_WORKSPACE_CONNECTED} from "./filesys";
7
+ import {KTabs} from "../parts/k-tabs";
8
+ import {TabContribution, IconContribution, contributionRegistry, TOPIC_CONTRIBUTEIONS_CHANGED} from "./contributionregistry";
9
+ import {rootContext} from "./di";
10
+
11
+ export const EVENT_SHOW_EDITOR = "editors/showEditor";
12
+
13
+ export interface EditorInput {
14
+ key: string;
15
+ editorId: string;
16
+ title: string;
17
+ icon?: string;
18
+ data: any;
19
+ noOverflow?: boolean;
20
+ widgetFactory: (container: any, tab: HTMLElement) => any;
21
+ state: { [key: string]: any };
22
+ }
23
+
24
+ export interface EditorInputHandler {
25
+ canHandle: (input: any) => boolean;
26
+ handle: (input: any) => Promise<EditorInput>;
27
+ lazyInit?: () => Promise<void> | void;
28
+ ranking?: number; // Higher ranking = higher priority (default: 0)
29
+ }
30
+
31
+ interface RegisteredEditorInputHandler {
32
+ definition: EditorInputHandler;
33
+ initialized: boolean;
34
+ lazyInitPromise?: Promise<void>;
35
+ }
36
+
37
+ /**
38
+ * Interface for editors that can provide content, selection, and snippets.
39
+ * Implement this interface to make editor content accessible via commands.
40
+ */
41
+ export interface EditorContentProvider {
42
+ /**
43
+ * Gets the complete contents of the editor.
44
+ * @returns The full content as a string, or null if not available.
45
+ */
46
+ getContent(): string | null;
47
+
48
+ /**
49
+ * Gets the currently selected text in the editor.
50
+ * @returns The selected text, or null if no selection exists.
51
+ */
52
+ getSelection(): string | null;
53
+
54
+ /**
55
+ * Gets a code snippet with n lines before and after the cursor position.
56
+ * @param lines Number of lines before and after the cursor (default: 5).
57
+ * @returns An object containing the snippet, cursor line number, or null if not available.
58
+ */
59
+ getSnippet(lines?: number): { snippet: string; cursorLine: number } | null;
60
+
61
+ /**
62
+ * Gets the programming language of the editor content.
63
+ * @returns The language identifier (e.g., 'python', 'javascript'), or null if not available.
64
+ */
65
+ getLanguage(): string | null;
66
+
67
+ /**
68
+ * Gets the workspace path of the file being edited.
69
+ * @returns The file path relative to the workspace, or null if not available.
70
+ */
71
+ getFilePath(): string | null;
72
+ }
73
+
74
+ class EditorRegistry {
75
+ private editorInputHandlers: RegisteredEditorInputHandler[] = [];
76
+ private listenersAttached = false;
77
+ private cachedIconContributions: IconContribution[] | null = null;
78
+ private signalCleanup?: () => void;
79
+
80
+ constructor() {
81
+ subscribe(TOPIC_WORKSPACE_CONNECTED, () => {
82
+ // TODO close all editors
83
+ });
84
+
85
+ subscribe(TOPIC_CONTRIBUTEIONS_CHANGED, (event: any) => {
86
+ if (event.target === 'system.icons') {
87
+ this.cachedIconContributions = null;
88
+ }
89
+ });
90
+ }
91
+
92
+ private getSortedIconContributions(): IconContribution[] {
93
+ if (this.cachedIconContributions !== null) {
94
+ return this.cachedIconContributions;
95
+ }
96
+
97
+ const contributions = contributionRegistry.getContributions('system.icons') as IconContribution[];
98
+
99
+ // Sort by priority (higher priority first), then by label for tie-breaking
100
+ this.cachedIconContributions = [...contributions].sort((a, b) => {
101
+ const priorityA = a.priority ?? 0;
102
+ const priorityB = b.priority ?? 0;
103
+ if (priorityB !== priorityA) {
104
+ // Higher priority comes first (descending order)
105
+ return priorityB - priorityA;
106
+ }
107
+ return a.label.localeCompare(b.label);
108
+ });
109
+
110
+ return this.cachedIconContributions;
111
+ }
112
+
113
+ private setupEventListeners(editorArea: KTabs) {
114
+ if (this.listenersAttached) {
115
+ return;
116
+ }
117
+ this.listenersAttached = true;
118
+
119
+ const handler = (event: CustomEvent) => {
120
+ const tabPanel = event.detail
121
+ if (tabPanel) {
122
+ const parts = Array.from(tabPanel.querySelectorAll(`*`)).filter((element): element is KPart => element instanceof KPart)
123
+ parts.forEach((part) => {
124
+ activePartSignal.set(part)
125
+ // Only update activeEditorSignal if this is an editor part
126
+ if ((part as KPart).isEditor) {
127
+ activeEditorSignal.set(part)
128
+ }
129
+ })
130
+ }
131
+ }
132
+ // @ts-ignore
133
+ editorArea.addEventListener("tab-shown", handler)
134
+
135
+ const closed = (event: CustomEvent) => {
136
+ const tabPanel: HTMLElement = event.detail
137
+ const parts = Array.from(tabPanel.querySelectorAll(`*`)).filter((element): element is KPart => element instanceof KPart)
138
+ parts.forEach((part) => {
139
+ // part.close() will be automatically called by disconnected callback of part
140
+ if (activePartSignal.get() == part) {
141
+ activePartSignal.set(null as unknown as KPart)
142
+ }
143
+ if (activeEditorSignal.get() == part) {
144
+ activeEditorSignal.set(null as unknown as KPart)
145
+ }
146
+ })
147
+ }
148
+ // @ts-ignore
149
+ editorArea.addEventListener("tab-closed", closed)
150
+
151
+ const dirtyHandler = (targetPart: KPart) => {
152
+ const tabPanel = targetPart.closest("wa-tab-panel") as HTMLElement
153
+ const name = tabPanel.getAttribute("name") as string
154
+ editorArea.markDirty(name, targetPart.isDirty())
155
+ }
156
+ this.signalCleanup = watchSignal(partDirtySignal, dirtyHandler)
157
+ }
158
+
159
+ registerEditorInputHandler(editorInputHandler: EditorInputHandler) {
160
+ this.editorInputHandlers.push({
161
+ definition: editorInputHandler,
162
+ initialized: false
163
+ });
164
+ // Sort by ranking (higher ranking first), default ranking is 0
165
+ this.editorInputHandlers.sort((a, b) => {
166
+ const rankA = a.definition.ranking ?? 0;
167
+ const rankB = b.definition.ranking ?? 0;
168
+ return rankB - rankA;
169
+ });
170
+ }
171
+
172
+ private async ensureHandlerInitialized(entry: RegisteredEditorInputHandler): Promise<void> {
173
+ const handler = entry.definition;
174
+ if (!handler.lazyInit || entry.initialized) {
175
+ return;
176
+ }
177
+
178
+ if (!entry.lazyInitPromise) {
179
+ entry.lazyInitPromise = Promise.resolve(handler.lazyInit()).then(() => {
180
+ entry.initialized = true;
181
+ entry.lazyInitPromise = undefined;
182
+ }).catch(error => {
183
+ entry.lazyInitPromise = undefined;
184
+ throw error;
185
+ });
186
+ }
187
+
188
+ await entry.lazyInitPromise;
189
+ }
190
+
191
+ async handleInput(input: any) {
192
+ // Handlers are already sorted by ranking, so iterate in order
193
+ for (let i = 0; i < this.editorInputHandlers.length; i++) {
194
+ const entry = this.editorInputHandlers[i];
195
+ const editorInputHandler = entry.definition;
196
+ if (editorInputHandler.canHandle(input)) {
197
+ await this.ensureHandlerInitialized(entry);
198
+ return await editorInputHandler.handle(input);
199
+ }
200
+ }
201
+ }
202
+
203
+ getEditorArea(): KTabs | null {
204
+ return document.querySelector(`k-tabs#${EDITOR_AREA_MAIN}`) as KTabs | null
205
+ }
206
+
207
+ async loadEditor(editorInput: EditorInput | any) {
208
+ if (!editorInput) {
209
+ return
210
+ }
211
+
212
+ if (!("widgetFactory" in editorInput)) {
213
+ editorInput = await this.handleInput(editorInput)
214
+ }
215
+
216
+ if (!editorInput || !("widgetFactory" in editorInput)) {
217
+ return
218
+ }
219
+
220
+ const editorArea = this.getEditorArea();
221
+
222
+ if (!editorArea) {
223
+ console.error("Editor area not found. The split pane system may not be initialized yet.");
224
+ return;
225
+ }
226
+
227
+ this.setupEventListeners(editorArea);
228
+
229
+ if (editorArea.has(editorInput.key)) {
230
+ editorArea.activate(editorInput.key)
231
+ return
232
+ }
233
+
234
+ editorArea.open({
235
+ name: editorInput.key,
236
+ editorId: editorInput.editorId,
237
+ label: editorInput.title,
238
+ icon: editorInput.icon,
239
+ closable: true,
240
+ noOverflow: editorInput.noOverflow,
241
+ component: editorInput.widgetFactory
242
+ } as TabContribution)
243
+ }
244
+
245
+ getFileIcon(fileNameOrType: string): string {
246
+ const extension = fileNameOrType.includes('.')
247
+ ? fileNameOrType.split('.').pop()?.toLowerCase() || ''
248
+ : fileNameOrType.toLowerCase();
249
+
250
+ const sortedContributions = this.getSortedIconContributions();
251
+
252
+ if (sortedContributions.length === 0) {
253
+ return 'file';
254
+ }
255
+
256
+ for (const contribution of sortedContributions) {
257
+ if (contribution.mappings && contribution.mappings[extension]) {
258
+ return contribution.mappings[extension];
259
+ }
260
+ }
261
+
262
+ return 'file';
263
+ }
264
+ }
265
+
266
+ export const editorRegistry = new EditorRegistry();
267
+ rootContext.put("editorRegistry", editorRegistry);
268
+
269
+ contributionRegistry.registerContribution<IconContribution>('system.icons', {
270
+ label: 'Default File Icons',
271
+ mappings: {
272
+ 'pdf': 'file-pdf',
273
+ 'md': 'book',
274
+ 'txt': 'file-lines',
275
+ 'ts': 'code',
276
+ 'tsx': 'code',
277
+ 'js': 'code',
278
+ 'jsx': 'code',
279
+ 'json': 'file-code',
280
+ 'geojson': 'file-code',
281
+ 'py': 'python',
282
+ 'html': 'code',
283
+ 'htm': 'code',
284
+ 'css': 'code',
285
+ 'scss': 'code',
286
+ 'sass': 'code',
287
+ 'xml': 'file-code',
288
+ 'yaml': 'file-code',
289
+ 'yml': 'file-code',
290
+ 'sql': 'database',
291
+ 'kml': 'file-code',
292
+ 'gpx': 'file-code',
293
+ 'jpg': 'image',
294
+ 'jpeg': 'image',
295
+ 'png': 'image',
296
+ 'gif': 'image',
297
+ 'svg': 'image',
298
+ 'webp': 'image',
299
+ 'bmp': 'image',
300
+ 'ico': 'image',
301
+ },
302
+ priority: 0
303
+ });
@@ -0,0 +1,404 @@
1
+ import { rootContext } from "./di";
2
+ import { i18nService } from "./i18n";
3
+ import { createLogger } from "./logger";
4
+
5
+ const logger = createLogger('EsmShService');
6
+
7
+ export interface EsmShSource {
8
+ type: 'npm' | 'github' | 'jsr' | 'pr';
9
+ package?: string;
10
+ owner?: string;
11
+ repo?: string;
12
+ version?: string;
13
+ path?: string;
14
+ commit?: string;
15
+ }
16
+
17
+ export interface EsmShOptions {
18
+ deps?: Record<string, string>;
19
+ target?: string;
20
+ dev?: boolean;
21
+ bundle?: boolean;
22
+ external?: string[];
23
+ externalAll?: boolean;
24
+ }
25
+
26
+ class EsmShService {
27
+ private static readonly ESM_SH_BASE = 'https://esm.sh';
28
+ private static readonly GITHUB_PREFIX = 'gh/';
29
+ private static readonly JSR_PREFIX = 'jsr/';
30
+ private static readonly PR_PREFIX = 'pr/';
31
+
32
+ isEsmShUrl(url: string): boolean {
33
+ try {
34
+ const urlObj = new URL(url);
35
+ return urlObj.hostname === 'esm.sh' || urlObj.hostname === 'raw.esm.sh';
36
+ } catch {
37
+ return false;
38
+ }
39
+ }
40
+
41
+ isSourceIdentifier(source: string): boolean {
42
+ if (this.isEsmShUrl(source)) {
43
+ return false;
44
+ }
45
+
46
+ if (this.isHttpUrl(source)) {
47
+ return false;
48
+ }
49
+
50
+ return this.parseSource(source) !== null;
51
+ }
52
+
53
+ private isHttpUrl(url: string): boolean {
54
+ try {
55
+ const parsed = new URL(url);
56
+ return parsed.protocol === 'http:' || parsed.protocol === 'https:';
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+
62
+ parseSource(source: string): EsmShSource | null {
63
+ if (!source || typeof source !== 'string') {
64
+ return null;
65
+ }
66
+
67
+ source = source.trim();
68
+
69
+ if (this.isHttpUrl(source)) {
70
+ return null;
71
+ }
72
+
73
+ if (source.startsWith(EsmShService.GITHUB_PREFIX)) {
74
+ return this.parseGitHubSource(source);
75
+ }
76
+
77
+ if (source.startsWith(EsmShService.JSR_PREFIX)) {
78
+ return this.parseJsrSource(source);
79
+ }
80
+
81
+ if (source.startsWith(EsmShService.PR_PREFIX)) {
82
+ return this.parsePrSource(source);
83
+ }
84
+
85
+ return this.parseNpmSource(source);
86
+ }
87
+
88
+ private parseGitHubSource(source: string): EsmShSource | null {
89
+ const withoutPrefix = source.substring(EsmShService.GITHUB_PREFIX.length);
90
+ const parts = withoutPrefix.split('/');
91
+
92
+ if (parts.length < 2) {
93
+ return null;
94
+ }
95
+
96
+ const owner = parts[0];
97
+ const repoWithRef = parts[1];
98
+
99
+ let repo: string;
100
+ let version: string | undefined;
101
+ let path: string | undefined;
102
+
103
+ const refMatch = repoWithRef.match(/^(.+?)(@(.+))?$/);
104
+ if (!refMatch) {
105
+ return null;
106
+ }
107
+
108
+ repo = refMatch[1];
109
+ version = refMatch[3];
110
+
111
+ if (parts.length > 2) {
112
+ path = parts.slice(2).join('/');
113
+ }
114
+
115
+ return {
116
+ type: 'github',
117
+ owner,
118
+ repo,
119
+ version,
120
+ path
121
+ };
122
+ }
123
+
124
+ private parseJsrSource(source: string): EsmShSource | null {
125
+ const withoutPrefix = source.substring(EsmShService.JSR_PREFIX.length);
126
+
127
+ if (!withoutPrefix.startsWith('@')) {
128
+ return null;
129
+ }
130
+
131
+ const parts = withoutPrefix.split('/');
132
+ if (parts.length < 2) {
133
+ return null;
134
+ }
135
+
136
+ const scope = parts[0];
137
+ const packageWithVersion = parts[1];
138
+
139
+ let packageName: string;
140
+ let version: string | undefined;
141
+ let path: string | undefined;
142
+
143
+ const versionMatch = packageWithVersion.match(/^(.+?)(@(.+))?$/);
144
+ if (!versionMatch) {
145
+ return null;
146
+ }
147
+
148
+ packageName = `${scope}/${versionMatch[1]}`;
149
+ version = versionMatch[3];
150
+
151
+ if (parts.length > 2) {
152
+ path = parts.slice(2).join('/');
153
+ }
154
+
155
+ return {
156
+ type: 'jsr',
157
+ package: packageName,
158
+ version,
159
+ path
160
+ };
161
+ }
162
+
163
+ private parsePrSource(source: string): EsmShSource | null {
164
+ const withoutPrefix = source.substring(EsmShService.PR_PREFIX.length);
165
+ const parts = withoutPrefix.split('/');
166
+
167
+ if (parts.length < 2) {
168
+ return null;
169
+ }
170
+
171
+ const owner = parts[0];
172
+ const repoWithCommit = parts[1];
173
+
174
+ let repo: string;
175
+ let commit: string | undefined;
176
+
177
+ const commitMatch = repoWithCommit.match(/^(.+?)@(.+)$/);
178
+ if (commitMatch) {
179
+ repo = commitMatch[1];
180
+ commit = commitMatch[2];
181
+ } else {
182
+ repo = repoWithCommit;
183
+ }
184
+
185
+ return {
186
+ type: 'pr',
187
+ owner,
188
+ repo,
189
+ commit
190
+ };
191
+ }
192
+
193
+ private parseNpmSource(source: string): EsmShSource | null {
194
+ const parts = source.split('/');
195
+ const firstPart = parts[0];
196
+
197
+ let packageName: string;
198
+ let version: string | undefined;
199
+ let path: string | undefined;
200
+
201
+ const versionMatch = firstPart.match(/^(.+?)(@(.+))?$/);
202
+ if (!versionMatch) {
203
+ return null;
204
+ }
205
+
206
+ packageName = versionMatch[1];
207
+ version = versionMatch[3];
208
+
209
+ if (parts.length > 1) {
210
+ path = parts.slice(1).join('/');
211
+ }
212
+
213
+ return {
214
+ type: 'npm',
215
+ package: packageName,
216
+ version,
217
+ path
218
+ };
219
+ }
220
+
221
+ buildEsmShUrl(source: EsmShSource, options?: EsmShOptions): string {
222
+ let url = EsmShService.ESM_SH_BASE;
223
+
224
+ switch (source.type) {
225
+ case 'npm':
226
+ url += `/${source.package}`;
227
+ if (source.version) {
228
+ url += `@${source.version}`;
229
+ }
230
+ if (source.path) {
231
+ url += `/${source.path}`;
232
+ }
233
+ break;
234
+
235
+ case 'github':
236
+ url += `/${EsmShService.GITHUB_PREFIX}${source.owner}/${source.repo}`;
237
+ if (source.version) {
238
+ url += `@${source.version}`;
239
+ }
240
+ if (source.path) {
241
+ url += `/${source.path}`;
242
+ }
243
+ break;
244
+
245
+ case 'jsr':
246
+ url += `/${EsmShService.JSR_PREFIX}${source.package}`;
247
+ if (source.version) {
248
+ url += `@${source.version}`;
249
+ }
250
+ if (source.path) {
251
+ url += `/${source.path}`;
252
+ }
253
+ break;
254
+
255
+ case 'pr':
256
+ url += `/${EsmShService.PR_PREFIX}${source.owner}/${source.repo}`;
257
+ if (source.commit) {
258
+ url += `@${source.commit}`;
259
+ }
260
+ break;
261
+ }
262
+
263
+ const queryParams: string[] = [];
264
+
265
+ if (options?.deps) {
266
+ const depsString = Object.entries(options.deps)
267
+ .map(([pkg, version]) => `${pkg}@${version}`)
268
+ .join(',');
269
+ queryParams.push(`deps=${encodeURIComponent(depsString)}`);
270
+ }
271
+
272
+ if (options?.target) {
273
+ queryParams.push(`target=${encodeURIComponent(options.target)}`);
274
+ }
275
+
276
+ if (options?.dev) {
277
+ queryParams.push('dev');
278
+ }
279
+
280
+ if (options?.bundle === false) {
281
+ queryParams.push('bundle=false');
282
+ } else if (options?.bundle === true) {
283
+ queryParams.push('bundle');
284
+ }
285
+
286
+ if (queryParams.length > 0) {
287
+ url += `?${queryParams.join('&')}`;
288
+ }
289
+
290
+ return url;
291
+ }
292
+
293
+ normalizeToEsmSh(source: string, options?: EsmShOptions): string {
294
+ if (this.isEsmShUrl(source)) {
295
+ return source;
296
+ }
297
+
298
+ if (this.isHttpUrl(source)) {
299
+ return source;
300
+ }
301
+
302
+ const parsed = this.parseSource(source);
303
+ if (!parsed) {
304
+ logger.warn(`Could not parse source identifier: ${source}`);
305
+ return source;
306
+ }
307
+
308
+ return this.buildEsmShUrl(parsed, options);
309
+ }
310
+
311
+ extractPackageName(source: string): string | null {
312
+ const parsed = this.parseSource(source);
313
+ if (!parsed) {
314
+ return null;
315
+ }
316
+
317
+ switch (parsed.type) {
318
+ case 'npm':
319
+ return parsed.package || null;
320
+ case 'github':
321
+ return `${parsed.owner}/${parsed.repo}`;
322
+ case 'jsr':
323
+ return parsed.package || null;
324
+ case 'pr':
325
+ return `${parsed.owner}/${parsed.repo}`;
326
+ }
327
+ }
328
+
329
+ isGitHubUrl(url: string): boolean {
330
+ try {
331
+ const urlObj = new URL(url);
332
+ return urlObj.hostname === 'github.com' || urlObj.hostname === 'www.github.com';
333
+ } catch {
334
+ return url.startsWith('https://github.com/') || url.startsWith('http://github.com/');
335
+ }
336
+ }
337
+
338
+ convertGitHubUrlToSource(githubUrl: string): string {
339
+ try {
340
+ const urlObj = new URL(githubUrl);
341
+ const pathParts = urlObj.pathname.split('/').filter(p => p);
342
+
343
+ if (pathParts.length < 2) {
344
+ throw new Error('Invalid GitHub URL format');
345
+ }
346
+
347
+ const owner = pathParts[0];
348
+ let repo = pathParts[1].replace(/\.git$/, '');
349
+ let ref: string | undefined;
350
+ let filePath: string | undefined;
351
+
352
+ if (pathParts.length > 2) {
353
+ if (pathParts[2] === 'blob' || pathParts[2] === 'tree') {
354
+ ref = pathParts[3] || 'main';
355
+ if (pathParts[2] === 'blob' && pathParts.length > 4) {
356
+ filePath = pathParts.slice(4).join('/');
357
+ }
358
+ } else if (pathParts[2] === 'commit') {
359
+ ref = pathParts[3];
360
+ } else {
361
+ filePath = pathParts.slice(2).join('/');
362
+ }
363
+ }
364
+
365
+ let ghUrl = `${EsmShService.GITHUB_PREFIX}${owner}/${repo}`;
366
+ if (ref) {
367
+ ghUrl += `@${ref}`;
368
+ }
369
+ if (filePath) {
370
+ ghUrl += `/${filePath}`;
371
+ }
372
+
373
+ return ghUrl;
374
+ } catch {
375
+ const urlMatch = githubUrl.match(/github\.com\/([^\/]+)\/([^\/]+)/);
376
+ if (urlMatch) {
377
+ return `${EsmShService.GITHUB_PREFIX}${urlMatch[1]}/${urlMatch[2].replace(/\.git$/, '')}`;
378
+ }
379
+ return githubUrl;
380
+ }
381
+ }
382
+
383
+ async fetchGitHubPackageJson(source: EsmShSource): Promise<any> {
384
+ if (source.type !== 'github') {
385
+ throw new Error('Source must be a GitHub source');
386
+ }
387
+
388
+ const owner = source.owner!;
389
+ const repo = source.repo!;
390
+ const ref = source.version || 'main';
391
+
392
+ const packageJsonUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/package.json`;
393
+
394
+ const response = await fetch(packageJsonUrl);
395
+ if (!response.ok) {
396
+ throw new Error(`Failed to fetch package.json: ${response.statusText}`);
397
+ }
398
+
399
+ return await response.json();
400
+ }
401
+ }
402
+
403
+ export const esmShService = new EsmShService();
404
+ rootContext.put("esmShService", esmShService);