modern-monaco 0.0.0-beta.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.
@@ -0,0 +1,425 @@
1
+ // node_modules/.pnpm/@esm.sh+import-map@0.1.1/node_modules/@esm.sh/import-map/dist/import-map.mjs
2
+ function createBlankImportMap(baseURL) {
3
+ return {
4
+ $baseURL: new URL(baseURL ?? ".", "file:///").href,
5
+ imports: {},
6
+ scopes: {}
7
+ };
8
+ }
9
+ function importMapFrom(v, baseURL) {
10
+ const im = createBlankImportMap(baseURL);
11
+ if (isObject(v)) {
12
+ const { imports, scopes } = v;
13
+ if (isObject(imports)) {
14
+ validateImports(imports);
15
+ im.imports = imports;
16
+ }
17
+ if (isObject(scopes)) {
18
+ validateScopes(scopes);
19
+ im.scopes = scopes;
20
+ }
21
+ }
22
+ return im;
23
+ }
24
+ function parseImportMapFromJson(json, baseURL) {
25
+ const importMap = {
26
+ $baseURL: new URL(baseURL ?? ".", "file:///").href,
27
+ imports: {},
28
+ scopes: {}
29
+ };
30
+ const v = JSON.parse(json);
31
+ if (isObject(v)) {
32
+ const { imports, scopes } = v;
33
+ if (isObject(imports)) {
34
+ validateImports(imports);
35
+ importMap.imports = imports;
36
+ }
37
+ if (isObject(scopes)) {
38
+ validateScopes(scopes);
39
+ importMap.scopes = scopes;
40
+ }
41
+ }
42
+ return importMap;
43
+ }
44
+ function isBlankImportMap(importMap) {
45
+ const { imports, scopes } = importMap;
46
+ if (isObject(imports) && Object.keys(imports).length > 0 || isObject(scopes) && Object.keys(scopes).length > 0) {
47
+ return false;
48
+ }
49
+ return true;
50
+ }
51
+ function isSameImportMap(a, b) {
52
+ if (!isSameImports(a.imports, b.imports)) {
53
+ return false;
54
+ }
55
+ for (const k in a.scopes) {
56
+ if (!(k in b.scopes) || !isObject(b.scopes[k])) {
57
+ return false;
58
+ }
59
+ if (!isSameImports(a.scopes[k], b.scopes[k])) {
60
+ return false;
61
+ }
62
+ }
63
+ return true;
64
+ }
65
+ function validateImports(imports) {
66
+ for (const [k, v] of Object.entries(imports)) {
67
+ if (!v || typeof v !== "string") {
68
+ delete imports[k];
69
+ }
70
+ }
71
+ }
72
+ function validateScopes(imports) {
73
+ for (const [k, v] of Object.entries(imports)) {
74
+ if (isObject(v)) {
75
+ validateImports(v);
76
+ } else {
77
+ delete imports[k];
78
+ }
79
+ }
80
+ }
81
+ function isObject(v) {
82
+ return typeof v === "object" && v !== null && !Array.isArray(v);
83
+ }
84
+ function isSameImports(a, b) {
85
+ if (Object.keys(a).length !== Object.keys(b).length) {
86
+ return false;
87
+ }
88
+ for (const k in a) {
89
+ if (a[k] !== b[k]) {
90
+ return false;
91
+ }
92
+ }
93
+ return true;
94
+ }
95
+
96
+ // src/lsp/typescript/setup.ts
97
+ import { cache } from "../../cache.js";
98
+ import { ErrorNotFound } from "../../workspace.js";
99
+ import * as ls from "../language-service.js";
100
+ var worker = null;
101
+ async function setup2(monaco, languageId, workspace, languageSettings, formattingOptions) {
102
+ if (!worker) {
103
+ worker = createWorker(monaco, workspace, languageSettings, formattingOptions);
104
+ }
105
+ if (worker instanceof Promise) {
106
+ worker = await worker;
107
+ }
108
+ ls.setup(monaco);
109
+ ls.enableBasicFeatures(languageId, worker, [".", "/", '"', "'", "<"], workspace);
110
+ ls.enableAutoComplete(languageId, worker, [">", "/"]);
111
+ ls.enableSignatureHelp(languageId, worker, ["(", ","]);
112
+ ls.enableCodeAction(languageId, worker);
113
+ }
114
+ function getWorkerUrl() {
115
+ const i = () => import("./worker.js");
116
+ const m = getWorkerUrl.toString().match(/import\(['"](.+?)['"]\)/);
117
+ if (!m) throw new Error("worker url not found", { cause: i });
118
+ return new URL(m[1], import.meta.url);
119
+ }
120
+ async function createWorker(monaco, workspace, languageSettings, formattingOptions) {
121
+ const fs = workspace?.fs;
122
+ const defaultCompilerOptions = {
123
+ // set allowJs to true to support embedded javascript in html
124
+ allowJs: true,
125
+ allowImportingTsExtensions: true,
126
+ noEmit: true,
127
+ isolatedModules: true,
128
+ module: "esnext",
129
+ moduleResolution: "bundler",
130
+ moduleDetection: "force",
131
+ skipLibCheck: true,
132
+ target: "esnext",
133
+ useDefineForClassFields: true,
134
+ ...languageSettings?.compilerOptions
135
+ };
136
+ const typesStore = new TypesSet();
137
+ const defaultImportMap = importMapFrom(languageSettings?.importMap);
138
+ const remixImportMap = (im) => {
139
+ if (isBlankImportMap(defaultImportMap)) {
140
+ return im;
141
+ }
142
+ return {
143
+ ...im,
144
+ imports: Object.assign({}, defaultImportMap.imports, im.imports),
145
+ scopes: Object.assign({}, defaultImportMap.scopes, im.scopes)
146
+ };
147
+ };
148
+ let compilerOptions = { ...defaultCompilerOptions };
149
+ let importMap = { ...defaultImportMap };
150
+ if (workspace) {
151
+ await Promise.all([
152
+ loadCompilerOptions(workspace).then((options) => {
153
+ compilerOptions = { ...defaultCompilerOptions, ...options };
154
+ }),
155
+ loadImportMap(workspace, remixImportMap).then((im) => {
156
+ importMap = im;
157
+ })
158
+ ]);
159
+ }
160
+ await typesStore.load(compilerOptions, workspace);
161
+ const { tabSize = 4, trimTrailingWhitespace = true, insertSpaces = true, semicolon = "insert" } = formattingOptions ?? {};
162
+ const createData = {
163
+ compilerOptions,
164
+ formatOptions: {
165
+ tabSize,
166
+ trimTrailingWhitespace,
167
+ semicolons: semicolon,
168
+ indentSize: tabSize,
169
+ convertTabsToSpaces: insertSpaces,
170
+ insertSpaceAfterCommaDelimiter: insertSpaces,
171
+ insertSpaceAfterSemicolonInForStatements: insertSpaces,
172
+ insertSpaceBeforeAndAfterBinaryOperators: insertSpaces,
173
+ insertSpaceAfterKeywordsInControlFlowStatements: insertSpaces,
174
+ insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: insertSpaces
175
+ },
176
+ importMap,
177
+ types: typesStore.types
178
+ };
179
+ const worker2 = monaco.editor.createWebWorker({
180
+ moduleId: "lsp/typescript/worker",
181
+ label: "typescript",
182
+ keepIdleModels: true,
183
+ createData,
184
+ host: {
185
+ openModel: async (uri) => {
186
+ if (!workspace) {
187
+ throw new Error("Workspace is undefined.");
188
+ }
189
+ try {
190
+ await workspace._openTextDocument(uri);
191
+ } catch (error) {
192
+ if (error instanceof ErrorNotFound) {
193
+ return false;
194
+ }
195
+ throw error;
196
+ }
197
+ return true;
198
+ },
199
+ refreshDiagnostics: async (uri) => {
200
+ let model = monaco.editor.getModel(uri);
201
+ if (model && model.uri.path.includes(".(embedded).")) {
202
+ model = monaco.editor.getModel(model.uri.toString(true).split(".(embedded).")[0]);
203
+ }
204
+ if (model) {
205
+ Reflect.get(model, "refreshDiagnostics")?.();
206
+ }
207
+ }
208
+ }
209
+ });
210
+ if (fs) {
211
+ const updateCompilerOptions = async (options) => {
212
+ const proxy = await worker2.getProxy();
213
+ await proxy.updateCompilerOptions(options);
214
+ monaco.editor.getModels().forEach((model) => {
215
+ const langaugeId = model.getLanguageId();
216
+ if (langaugeId === "typescript" || langaugeId === "javascript" || langaugeId === "jsx" || langaugeId === "tsx") {
217
+ Reflect.get(model, "refreshDiagnostics")?.();
218
+ }
219
+ });
220
+ };
221
+ const watchTypes = () => (compilerOptions.$types ?? []).map(
222
+ (url) => fs.watch(url, async (kind) => {
223
+ if (kind === "remove") {
224
+ typesStore.remove(url);
225
+ } else {
226
+ const content = await fs.readTextFile(url);
227
+ typesStore.add(content, url);
228
+ }
229
+ updateCompilerOptions({ types: typesStore.types });
230
+ })
231
+ );
232
+ const watchImportMapJSON = () => {
233
+ const { $src } = importMap;
234
+ if ($src && $src.endsWith(".json")) {
235
+ return fs.watch($src, async (kind) => {
236
+ if (kind === "remove") {
237
+ importMap = { ...defaultImportMap };
238
+ } else {
239
+ try {
240
+ const content = await fs.readTextFile($src);
241
+ const im = parseImportMapFromJson(content);
242
+ im.$src = $src;
243
+ importMap = remixImportMap(im);
244
+ } catch (error) {
245
+ console.error("Failed to parse import map:", error);
246
+ importMap = { ...defaultImportMap };
247
+ }
248
+ }
249
+ updateCompilerOptions({ importMap });
250
+ });
251
+ }
252
+ };
253
+ let unwatchTypes = watchTypes();
254
+ let unwatchImportMap = watchImportMapJSON();
255
+ fs.watch("tsconfig.json", () => {
256
+ unwatchTypes.forEach((dispose) => dispose());
257
+ loadCompilerOptions(workspace).then((options) => {
258
+ const newOptions = { ...defaultCompilerOptions, ...options };
259
+ if (JSON.stringify(newOptions) !== JSON.stringify(compilerOptions)) {
260
+ compilerOptions = newOptions;
261
+ typesStore.load(compilerOptions, workspace).then(() => {
262
+ updateCompilerOptions({ compilerOptions, types: typesStore.types });
263
+ });
264
+ }
265
+ unwatchTypes = watchTypes();
266
+ });
267
+ });
268
+ fs.watch("index.html", () => {
269
+ unwatchImportMap?.();
270
+ loadImportMap(workspace, remixImportMap).then((im) => {
271
+ if (!isSameImportMap(importMap, im)) {
272
+ importMap = im;
273
+ updateCompilerOptions({ importMap });
274
+ }
275
+ unwatchImportMap = watchImportMapJSON();
276
+ });
277
+ });
278
+ }
279
+ monaco.editor.addCommand({
280
+ id: "ts:fetch_http_module",
281
+ run: async (_, url, containingFile) => {
282
+ const proxy = await worker2.getProxy();
283
+ await proxy.fetchHttpModule(url, containingFile);
284
+ }
285
+ });
286
+ return worker2;
287
+ }
288
+ var TypesSet = class {
289
+ _types = {};
290
+ _removedtypes = {};
291
+ get types() {
292
+ return this._types;
293
+ }
294
+ reset(types) {
295
+ const toRemove = Object.keys(this._types).filter(
296
+ (key) => !types[key]
297
+ );
298
+ for (const key of toRemove) {
299
+ this.remove(key);
300
+ }
301
+ for (const [filePath, content] of Object.entries(types)) {
302
+ this.add(content, filePath);
303
+ }
304
+ }
305
+ add(content, filePath) {
306
+ if (this._types[filePath] && this._types[filePath].content === content) {
307
+ return false;
308
+ }
309
+ let version = 1;
310
+ if (this._removedtypes[filePath]) {
311
+ version = this._removedtypes[filePath] + 1;
312
+ }
313
+ if (this._types[filePath]) {
314
+ version = this._types[filePath].version + 1;
315
+ }
316
+ this._types[filePath] = { content, version };
317
+ return true;
318
+ }
319
+ remove(filePath) {
320
+ const lib = this._types[filePath];
321
+ if (lib) {
322
+ delete this._types[filePath];
323
+ this._removedtypes[filePath] = lib.version;
324
+ return true;
325
+ }
326
+ return false;
327
+ }
328
+ /** load types defined in tsconfig.json */
329
+ async load(compilerOptions, workspace) {
330
+ const types = compilerOptions.types;
331
+ if (Array.isArray(types)) {
332
+ delete compilerOptions.types;
333
+ await Promise.all(types.map(async (type) => {
334
+ if (/^https?:\/\//.test(type)) {
335
+ const res = await cache.fetch(type);
336
+ const dtsUrl = res.headers.get("x-typescript-types");
337
+ if (dtsUrl) {
338
+ res.body?.cancel?.();
339
+ const res2 = await cache.fetch(dtsUrl);
340
+ if (res2.ok) {
341
+ return [dtsUrl, await res2.text()];
342
+ } else {
343
+ console.error(
344
+ `Failed to fetch "${dtsUrl}": ` + await res2.text()
345
+ );
346
+ }
347
+ } else if (res.ok) {
348
+ return [type, await res.text()];
349
+ } else {
350
+ console.error(
351
+ `Failed to fetch "${dtsUrl}": ` + await res.text()
352
+ );
353
+ }
354
+ } else if (typeof type === "string" && workspace) {
355
+ const dtsUrl = new URL(type.replace(/\.d\.ts$/, "") + ".d.ts", "file:///").href;
356
+ try {
357
+ return [dtsUrl, await workspace.fs.readTextFile(dtsUrl)];
358
+ } catch (error) {
359
+ console.error(`Failed to read "${dtsUrl}": ` + error.message);
360
+ }
361
+ }
362
+ return null;
363
+ })).then((e) => {
364
+ const entries = e.filter(Boolean);
365
+ if (workspace) {
366
+ compilerOptions.$types = entries.map(([url]) => url).filter((url) => url.startsWith("file://"));
367
+ }
368
+ this.reset(Object.fromEntries(entries));
369
+ });
370
+ }
371
+ }
372
+ };
373
+ async function loadCompilerOptions(workspace) {
374
+ const compilerOptions = {};
375
+ try {
376
+ const tsconfigJson = await workspace.fs.readTextFile("tsconfig.json");
377
+ const tsconfig = parseJsonc(tsconfigJson);
378
+ compilerOptions.$src = "file:///tsconfig.json";
379
+ Object.assign(compilerOptions, tsconfig.compilerOptions);
380
+ } catch (error) {
381
+ if (error instanceof ErrorNotFound) {
382
+ } else {
383
+ console.error(error);
384
+ }
385
+ }
386
+ return compilerOptions;
387
+ }
388
+ async function loadImportMap(workspace, validate) {
389
+ let src;
390
+ try {
391
+ let indexHtml = await workspace.fs.readTextFile("index.html");
392
+ let tplEl = document.createElement("template");
393
+ let scriptEl;
394
+ tplEl.innerHTML = indexHtml;
395
+ scriptEl = tplEl.content.querySelector('script[type="importmap"]');
396
+ if (scriptEl) {
397
+ src = scriptEl.src ? new URL(scriptEl.src, "file:///").href : "file:///index.html";
398
+ const importMap2 = parseImportMapFromJson(scriptEl.src ? await workspace.fs.readTextFile(scriptEl.src) : scriptEl.textContent);
399
+ importMap2.$src = src;
400
+ return validate(importMap2);
401
+ }
402
+ } catch (error) {
403
+ if (error instanceof ErrorNotFound) {
404
+ } else {
405
+ console.error("Failed to parse import map from index.html:", error.message);
406
+ }
407
+ }
408
+ const importMap = createBlankImportMap();
409
+ return validate(importMap);
410
+ }
411
+ function parseJsonc(text) {
412
+ try {
413
+ return JSON.parse(text);
414
+ } catch {
415
+ const stringOrCommentRe = /("(?:\\?[^])*?")|(\/\/.*)|(\/\*[^]*?\*\/)/g;
416
+ const stringOrTrailingCommaRe = /("(?:\\?[^])*?")|(,\s*)(?=]|})/g;
417
+ const fixed = text.replace(stringOrCommentRe, "$1").replace(stringOrTrailingCommaRe, "$1");
418
+ return JSON.parse(fixed);
419
+ }
420
+ }
421
+ export {
422
+ getWorkerUrl,
423
+ loadImportMap,
424
+ setup2 as setup
425
+ };