modern-monaco 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,15 +20,12 @@ Meet the modern version of [Monaco Editor](https://www.npmjs.com/package/monaco-
20
20
 
21
21
  ## Installation
22
22
 
23
- You can install `modern-monaco` from NPM:
23
+ You can install modern-monaco from NPM:
24
24
 
25
25
  ```bash
26
- npm i modern-monaco typescript
26
+ npm i modern-monaco
27
27
  ```
28
28
 
29
- > [!Note]
30
- > The `typescript` package is required by the JavaScript/TypeScript LSP worker. We recommend `typescript@5.5.x` or later.
31
-
32
29
  Or import it from [esm.sh](https://esm.sh/) CDN in the browser without a build step:
33
30
 
34
31
  ```js
@@ -37,7 +34,7 @@ import * from "https://esm.sh/modern-monaco"
37
34
 
38
35
  ## Usage
39
36
 
40
- `modern-monaco` provides three modes to create a browser-based code editor:
37
+ modern-monaco provides three modes to create a browser-based code editor:
41
38
 
42
39
  - **Lazy**: pre-highlight code with Shiki while loading the `editor-core.js` in the background.
43
40
  - **SSR**: render a mock editor on the server side and hydrates it on the client side.
@@ -45,11 +42,11 @@ import * from "https://esm.sh/modern-monaco"
45
42
 
46
43
  ### Lazy Mode
47
44
 
48
- [monaco-editor](https://www.npmjs.com/package/monaco-editor) is a large package with additional CSS/Worker modules that requires `MonacoEnvironment` setup for language service support. `modern-monaco` provides a simple yet smart way to load editor modules on demand.
45
+ [monaco-editor](https://www.npmjs.com/package/monaco-editor) is a large package with additional CSS/Worker modules that requires `MonacoEnvironment` setup for language service support. modern-monaco provides a simple yet smart way to load editor modules on demand.
49
46
 
50
- By pre-highlighting code with Shiki while loading editor modules in the background, `modern-monaco` can significantly reduce loading screen time.
47
+ By pre-highlighting code with Shiki while loading editor modules in the background, modern-monaco can significantly reduce loading screen time.
51
48
 
52
- To create a Monaco editor lazily, you need to add a `<monaco-editor>` custom element in your app's HTML, then call the `lazy` function from modern-monaco. You also need to provide a workspace object to manage files for the editor.
49
+ To create a Monaco editor lazily, you need to add a `<monaco-editor>` custom element in the HTML of your app, then call the `lazy` function provided by modern-monaco. You may also need a `Workspace` object to manage editor models without calling the native Monaco APIs.
53
50
 
54
51
  ```html
55
52
  <!-- index.html -->
@@ -64,8 +61,8 @@ import { lazy, Workspace } from "modern-monaco";
64
61
  // create a workspace with initial files
65
62
  const workspace = new Workspace({
66
63
  initialFiles: {
67
- "index.html": `<html>...</body></html>`,
68
- "main.js": `console.log("Hello, world!")`
64
+ "index.html": `<html><body>...</body></html>`,
65
+ "main.js": `console.log("Hello, world!")`,
69
66
  },
70
67
  entryFile: "index.html",
71
68
  });
@@ -73,8 +70,9 @@ const workspace = new Workspace({
73
70
  // initialize the editor lazily
74
71
  await lazy({ workspace });
75
72
 
76
- // open a file in the workspace
77
- workspace.openTextDocument("main.js");
73
+ // write a file and open it in the editor
74
+ workspace.fs.writeFile("util.js", "export function add(a, b) { return a + b; }");
75
+ workspace.openTextDocument("util.js");
78
76
  ```
79
77
 
80
78
  ### SSR Mode
@@ -86,29 +84,31 @@ import { renderToWebComponent } from "modern-monaco/ssr";
86
84
 
87
85
  export default {
88
86
  async fetch(req) {
89
- const ssrOut = await renderToWebComponent(
87
+ const editorHTML = await renderToWebComponent(
90
88
  `console.log("Hello, world!")`,
91
89
  {
92
- theme: "OneDark-Pro",
93
90
  language: "javascript",
91
+ theme: "vitesse-dark",
94
92
  userAgent: req.headers.get("user-agent"), // detect default font for different platforms
95
93
  },
96
94
  );
97
95
  return new Response(
98
- html`
99
- ${ssrOut}
100
- <script type="module">
101
- import { hydrate } from "https://esm.sh/modern-monaco";
102
- // hydrate the editor
103
- hydrate();
104
- </script>
105
- `,
96
+ /* html */`
97
+ ${editorHTML}
98
+ <script type="module">
99
+ import { hydrate } from "https://esm.sh/modern-monaco";
100
+ // hydrate the editor
101
+ hydrate();
102
+ </script>
103
+ `,
106
104
  { headers: { "Content-Type": "text/html" } },
107
105
  );
108
106
  },
109
107
  };
110
108
  ```
111
109
 
110
+ SSR Demo: https://modern-monaco-demo.vercel.app ([Source](https://github.com/pi0/modern-monaco-demo) by [@pi0](https://github.com/pi0))
111
+
112
112
  ### Manual Mode
113
113
 
114
114
  You can also create a [Monaco editor](https://microsoft.github.io/monaco-editor/docs.html) instance manually. It loads themes and language grammars automatically.
@@ -132,12 +132,12 @@ You can also create a [Monaco editor](https://microsoft.github.io/monaco-editor/
132
132
 
133
133
  ## Using Workspace
134
134
 
135
- `modern-monaco` provides VSCode-like workspace features, such as edit history, file system provider, and more.
135
+ modern-monaco provides VSCode-like workspace features, such as edit history, file system provider, and more.
136
136
 
137
137
  ```js
138
138
  import { lazy, Workspace } from "modern-monaco";
139
139
 
140
- // 1. create a workspace with initial files
140
+ // create a workspace with initial files
141
141
  const workspace = new Workspace({
142
142
  /** The name of the workspace, used for project isolation. Default is "default". */
143
143
  name: "project-name",
@@ -150,94 +150,19 @@ const workspace = new Workspace({
150
150
  entryFile: "index.html",
151
151
  });
152
152
 
153
- // 2. use the workspace in lazy mode
153
+ // use the workspace in lazy mode
154
154
  lazy({ workspace });
155
155
 
156
- // 3. open a file in the workspace
156
+ // open a file in the workspace
157
157
  workspace.openTextDocument("main.js");
158
158
  ```
159
159
 
160
- ### Adding `tsconfig.json`
160
+ ### Custom Workspace FileSystem
161
161
 
162
- You can add a `tsconfig.json` file to configure the TypeScript compiler options for the TypeScript language service.
163
-
164
- ```js
165
- const tsconfig = {
166
- "compilerOptions": {
167
- "strict": true,
168
- "noUnusedLocals": true,
169
- "noUnusedParameters": true,
170
- "noFallthroughCasesInSwitch": true,
171
- },
172
- };
173
- const workspace = new Workspace({
174
- initialFiles: {
175
- "tsconfig.json": JSON.stringify(tsconfig, null, 2),
176
- },
177
- });
178
- ```
179
-
180
- ### Using Import Maps
181
-
182
- `modern-monaco` uses [import maps](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) to resolve **bare specifier** imports in JavaScript/TypeScript. By default, `modern-monaco` detects the `importmap` from the root `index.html` in the workspace.
183
-
184
- ```js
185
- const indexHtml = html`<!DOCTYPE html>
186
- <html>
187
- <head>
188
- <script type="importmap">
189
- {
190
- "imports": {
191
- "react": "https://esm.sh/react@18",
192
- "react-dom/": "https://esm.sh/react-dom@18/"
193
- }
194
- }
195
- </script>
196
- </head>
197
- <body>
198
- <div id="root"></div>
199
- <script type="module" src="app.tsx"></script>
200
- </body>
201
- </html>
202
- `;
203
- const appTsx = `import { createRoot } from "react-dom/client";
204
-
205
- createRoot(document.getElementById("root")).render(<div>Hello, world!</div>);
206
- `;
207
-
208
- const workspace = new Workspace({
209
- initialFiles: {
210
- "index.html": indexHtml,
211
- "app.tsx": appTsx,
212
- },
213
- });
214
- ```
215
-
216
- You can also provide an import map object as the `lsp.typescript.importMap` option in the `lazy`, `init`, or `hydrate` functions.
217
-
218
- ```js
219
- lazy({
220
- lsp: {
221
- typescript: {
222
- importMap: {
223
- "react": "https://esm.sh/react@18",
224
- "react-dom/": "https://esm.sh/react-dom@18/",
225
- },
226
- },
227
- },
228
- });
229
- ```
230
-
231
- > [!Note]
232
- > By default, `modern-monaco` uses `react` or `preact` in the `importmap` script as the `jsxImportSource` option for the TypeScript worker.
233
- > To use a custom `jsxImportSource` option, add the `@jsxRuntime` specifier in the `importmap` script.
234
-
235
- ### Using Custom FileSystem
236
-
237
- You can provide a custom filesystem implementation to override the default IndexedDB filesystem.
162
+ By default, modern-monaco uses `IndexedDB` as the workspace filesystem to persist the editor changes. With a custom filesystem, you can implement your own persistence logic.
238
163
 
239
164
  ```ts
240
- import { lazy, type FileSystem, Workspace } from "modern-monaco";
165
+ import { type FileSystem, lazy, Workspace } from "modern-monaco";
241
166
 
242
167
  class CustomFileSystem implements FileSystem {
243
168
  // Custom FileSystem implementation
@@ -250,35 +175,39 @@ const workspace = new Workspace({
250
175
  },
251
176
  customFS: new CustomFileSystem(),
252
177
  });
178
+
179
+ lazy({ workspace });
253
180
  ```
254
181
 
182
+ Please refer to the [FileSystem](./types/workspace.d.ts#L54) interface for more details.
183
+
255
184
  ## Editor Theme & Language Grammars
256
185
 
257
- `modern-monaco` uses [Shiki](https://shiki.style) for syntax highlighting with extensive grammars and themes. By default, it loads themes and grammars from esm.sh on demand.
186
+ modern-monaco uses [Shiki](https://shiki.style) for syntax highlighting with extensive grammars and themes. By default, it loads themes and grammars from esm.sh on demand.
258
187
 
259
188
  ### Setting the Editor Theme
260
189
 
261
190
  To set the editor theme, you can add a `theme` attribute to the `<monaco-editor>` element.
262
191
 
263
192
  ```html
264
- <monaco-editor theme="OneDark-Pro"></monaco-editor>
193
+ <monaco-editor theme="vitesse-dark"></monaco-editor>
265
194
  ```
266
195
 
267
196
  Or set it in the `lazy`, `init`, or `hydrate` function.
268
197
 
269
198
  ```js
270
199
  lazy({
271
- theme: "OneDark-Pro",
200
+ theme: "vitesse-dark",
272
201
  });
273
202
  ```
274
203
 
275
204
  > [!Note]
276
205
  > The theme ID should be one of the [Shiki Themes](https://shiki.style/themes).
277
206
 
278
- `modern-monaco` loads the theme data from the CDN when a theme ID is provided. You can also use a theme from the `tm-themes` package:
207
+ modern-monaco loads the theme data from the CDN when a theme ID is provided. You can also use a theme from the `tm-themes` package:
279
208
 
280
209
  ```js
281
- import OneDark from "tm-themes/themes/OneDark-Pro.json" with { type: "json" };
210
+ import OneDark from "tm-themes/themes/vitesse-dark.json" with { type: "json" };
282
211
 
283
212
  lazy({
284
213
  theme: OneDark,
@@ -287,14 +216,14 @@ lazy({
287
216
 
288
217
  ### Pre-loading Language Grammars
289
218
 
290
- By default, `modern-monaco` loads language grammars when a specific language mode is attached to the editor. You can also pre-load language grammars by adding the `langs` option to the `lazy`, `init`, or `hydrate` functions. The `langs` option is an array of language grammars, which can be a language grammar object, a language ID, or a URL to the language grammar.
219
+ By default, modern-monaco loads language grammars when a specific language mode is attached to the editor. You can also pre-load language grammars by adding the `langs` option to the `lazy`, `init`, or `hydrate` functions. The `langs` option is an array of language grammars, which can be a language grammar object, a language ID, or a URL to the language grammar.
291
220
 
292
221
  ```js
293
222
  import markdown from "tm-grammars/markdown.json" with { type: "json" };
294
223
 
295
224
  lazy({
296
225
  langs: [
297
- // load language grammars from CDN
226
+ // load language grammars from CDN, these language ids must be defined in the `tm-grammars` package
298
227
  "html",
299
228
  "css",
300
229
  "javascript",
@@ -330,7 +259,7 @@ You can set editor options as attributes in the `<monaco-editor>` element. The e
330
259
 
331
260
  ```html
332
261
  <monaco-editor
333
- theme="OneDark-Pro"
262
+ theme="vitesse-dark"
334
263
  fontFamily="Geist Mono"
335
264
  fontSize="16"
336
265
  ></monaco-editor>
@@ -344,7 +273,7 @@ import { renderToWebComponent } from "modern-monaco/ssr";
344
273
  const html = await renderToWebComponent(
345
274
  `console.log("Hello, world!")`,
346
275
  {
347
- theme: "OneDark-Pro",
276
+ theme: "vitesse-dark",
348
277
  language: "javascript",
349
278
  fontFamily: "Geist Mono",
350
279
  fontSize: 16,
@@ -356,14 +285,14 @@ For manual mode, check [here](https://microsoft.github.io/monaco-editor/docs.htm
356
285
 
357
286
  ## Language Server Protocol (LSP)
358
287
 
359
- `modern-monaco` by default supports full LSP features for the following languages:
288
+ modern-monaco by default supports full LSP features for the following languages:
360
289
 
361
290
  - HTML
362
291
  - CSS/SCSS/LESS
363
292
  - JavaScript/TypeScript
364
293
  - JSON
365
294
 
366
- Additionally, `modern-monaco` supports features like:
295
+ Additionally, modern-monaco supports features like:
367
296
 
368
297
  - File System Provider for import completions
369
298
  - Embedded languages in HTML
@@ -372,7 +301,7 @@ Additionally, `modern-monaco` supports features like:
372
301
 
373
302
  > [!Note]
374
303
  > You don't need to set `MonacoEnvironment.getWorker` for LSP support.
375
- > `modern-monaco` automatically loads the required LSP workers.
304
+ > modern-monaco automatically loads the required LSP workers.
376
305
 
377
306
  ### LSP Language Configuration
378
307
 
@@ -414,9 +343,93 @@ export interface LSPLanguageConfig {
414
343
  }
415
344
  ```
416
345
 
346
+ ### Import Maps
347
+
348
+ modern-monaco uses [import maps](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) to resolve **bare specifier** imports in JavaScript/TypeScript. By default, modern-monaco detects the `importmap` from the root `index.html` in the workspace.
349
+
350
+ ```js
351
+ const indexHtml = /* html */`<!DOCTYPE html>
352
+ <html>
353
+ <head>
354
+ <script type="importmap">
355
+ {
356
+ "imports": {
357
+ "react": "https://esm.sh/react@18",
358
+ "react-dom/": "https://esm.sh/react-dom@18/"
359
+ }
360
+ }
361
+ </script>
362
+ </head>
363
+ <body>
364
+ <div id="root"></div>
365
+ <script type="module" src="app.tsx"></script>
366
+ </body>
367
+ </html>
368
+ `;
369
+ const appTsx = `import { createRoot } from "react-dom/client";
370
+
371
+ createRoot(document.getElementById("root")).render(<div>Hello, world!</div>);
372
+ `;
373
+
374
+ const workspace = new Workspace({
375
+ initialFiles: {
376
+ "index.html": indexHtml,
377
+ "app.tsx": appTsx,
378
+ },
379
+ });
380
+ ```
381
+
382
+ You can also provide an import map object as the `lsp.typescript.importMap` option in the `lazy`, `init`, or `hydrate` functions.
383
+
384
+ ```js
385
+ lazy({
386
+ lsp: {
387
+ typescript: {
388
+ importMap: {
389
+ "react": "https://esm.sh/react@18",
390
+ "react-dom/": "https://esm.sh/react-dom@18/",
391
+ },
392
+ },
393
+ },
394
+ });
395
+ ```
396
+
397
+ ### Adding `tsconfig.json`
398
+
399
+ You can add a `tsconfig.json` file to configure the TypeScript compiler options for the TypeScript language service.
400
+
401
+ ```js
402
+ const tsconfig = {
403
+ "compilerOptions": {
404
+ "target": "ES2022",
405
+ "strict": true,
406
+ },
407
+ };
408
+ const workspace = new Workspace({
409
+ initialFiles: {
410
+ "tsconfig.json": JSON.stringify(tsconfig, null, 2),
411
+ },
412
+ });
413
+ ```
414
+
415
+ You can also manually add the TypeScript compiler options as the `lsp.typescript.compilerOptions` option in the `lazy`, `init`, or `hydrate` functions.
416
+
417
+ ```js
418
+ lazy({
419
+ lsp: {
420
+ typescript: {
421
+ compilerOptions: {
422
+ target: "ES2022",
423
+ strict: true,
424
+ },
425
+ },
426
+ },
427
+ });
428
+ ```
429
+
417
430
  ## Using the `core` Module
418
431
 
419
- `modern-monaco` includes built-in grammars and LSP providers for HTML, CSS, JavaScript/TypeScript, and JSON. If you don't need these features, you can use the `modern-monaco/core` sub-module to reduce the bundle size.
432
+ modern-monaco includes built-in grammars and LSP providers for HTML, CSS, JavaScript/TypeScript, and JSON. If you don't need these features, you can use the `modern-monaco/core` sub-module to reduce the bundle size.
420
433
 
421
434
  ```js
422
435
  import { lazy } from "modern-monaco/core";
package/dist/cache.js CHANGED
@@ -1,24 +1,47 @@
1
1
  // src/cache.ts
2
2
  import { defineProperty, openIDB, promisifyIDBRequest, toURL } from "./util.js";
3
- var Cache = class {
4
- _db = null;
3
+ var IndexedDB = class {
4
+ #db;
5
5
  constructor(name) {
6
- if (globalThis.indexedDB) {
7
- this._db = this._openDB(name);
8
- }
6
+ this.#db = this.#openDB(name);
9
7
  }
10
- _openDB(name) {
11
- return openIDB(
12
- name,
13
- 1,
14
- { name: "store", keyPath: "url" }
15
- ).then((db) => {
8
+ #openDB(name) {
9
+ return openIDB(name, 1, { name: "store", keyPath: "url" }).then((db) => {
16
10
  db.onclose = () => {
17
- this._db = this._openDB(name);
11
+ this.#db = this.#openDB(name);
18
12
  };
19
- return this._db = db;
13
+ return this.#db = db;
20
14
  });
21
15
  }
16
+ async get(url) {
17
+ const db = await this.#db;
18
+ const tx = db.transaction("store", "readonly").objectStore("store");
19
+ return promisifyIDBRequest(tx.get(url));
20
+ }
21
+ async put(file) {
22
+ const db = await this.#db;
23
+ const tx = db.transaction("store", "readwrite").objectStore("store");
24
+ await promisifyIDBRequest(tx.put(file));
25
+ }
26
+ };
27
+ var MemoryCache = class {
28
+ #cache = /* @__PURE__ */ new Map();
29
+ async get(url) {
30
+ return this.#cache.get(url) ?? null;
31
+ }
32
+ async put(file) {
33
+ this.#cache.set(file.url, file);
34
+ }
35
+ };
36
+ var Cache = class {
37
+ _db;
38
+ constructor(name) {
39
+ if (globalThis.indexedDB) {
40
+ this._db = new IndexedDB(name);
41
+ } else {
42
+ this._db = new MemoryCache();
43
+ }
44
+ }
22
45
  async fetch(url) {
23
46
  url = toURL(url);
24
47
  const storedRes = await this.query(url);
@@ -26,17 +49,15 @@ var Cache = class {
26
49
  return storedRes;
27
50
  }
28
51
  const res = await fetch(url);
29
- if (res.ok && this._db) {
30
- const db = await this._db;
52
+ if (res.ok) {
31
53
  const file = {
32
54
  url: url.href,
33
55
  content: null,
34
56
  ctime: Date.now()
35
57
  };
36
58
  if (res.redirected) {
37
- const tx = db.transaction("store", "readwrite").objectStore("store");
38
59
  file.headers = [["location", res.url]];
39
- await promisifyIDBRequest(tx.put(file));
60
+ this._db.put(file);
40
61
  }
41
62
  const content = await res.arrayBuffer();
42
63
  const headers = [...res.headers.entries()].filter(
@@ -45,7 +66,7 @@ var Cache = class {
45
66
  file.url = res.url;
46
67
  file.headers = headers;
47
68
  file.content = content;
48
- await this.store(file);
69
+ this._db.put(file);
49
70
  const resp = new Response(content, { headers });
50
71
  defineProperty(resp, "url", res.url);
51
72
  defineProperty(resp, "redirected", res.redirected);
@@ -54,15 +75,10 @@ var Cache = class {
54
75
  return res;
55
76
  }
56
77
  async query(key) {
57
- if (!this._db) {
58
- return null;
59
- }
60
78
  const url = toURL(key).href;
61
- const db = await this._db;
62
- const tx = db.transaction("store", "readonly").objectStore("store");
63
- const ret = await promisifyIDBRequest(tx.get(url));
64
- if (ret && ret.headers) {
65
- const headers = new Headers(ret.headers);
79
+ const file = await this._db.get(url);
80
+ if (file && file.headers) {
81
+ const headers = new Headers(file.headers);
66
82
  if (headers.has("location")) {
67
83
  const redirectedUrl = headers.get("location");
68
84
  const res2 = await this.query(redirectedUrl);
@@ -71,20 +87,12 @@ var Cache = class {
71
87
  }
72
88
  return res2;
73
89
  }
74
- const res = new Response(ret.content, { headers });
90
+ const res = new Response(file.content, { headers });
75
91
  defineProperty(res, "url", url);
76
92
  return res;
77
93
  }
78
94
  return null;
79
95
  }
80
- async store(file) {
81
- if (!this._db) {
82
- return;
83
- }
84
- const db = await this._db;
85
- const tx = db.transaction("store", "readwrite").objectStore("store");
86
- await promisifyIDBRequest(tx.put(file));
87
- }
88
96
  };
89
97
  var cache = new Cache("modern-monaco-cache");
90
98
  var cache_default = cache;
package/dist/core.js CHANGED
@@ -11,7 +11,7 @@ function createWebWorker(url, name) {
11
11
  }
12
12
 
13
13
  // src/core.ts
14
- import { getLanguageIdFromPath, initShiki, setDefaultWasmLoader, tmGrammars, tmThemes } from "./shiki.js";
14
+ import { getExtnameFromLanguageId, getLanguageIdFromPath, initShiki, setDefaultWasmLoader, tmGrammars, tmThemes } from "./shiki.js";
15
15
  import { initShikiMonacoTokenizer, registerShikiMonacoTokenizer } from "./shiki.js";
16
16
  import { render } from "./shiki.js";
17
17
  import { getWasmInstance } from "./shiki-wasm.js";
@@ -281,6 +281,10 @@ async function lazy(options, hydrate2) {
281
281
  } catch (error) {
282
282
  if (error instanceof ErrorNotFound) {
283
283
  if (code) {
284
+ const dirname = filename.split("/").slice(0, -1).join("/");
285
+ if (dirname) {
286
+ await workspace.fs.createDirectory(dirname);
287
+ }
284
288
  await workspace.fs.writeFile(filename, code);
285
289
  workspace._openTextDocument(filename, editor);
286
290
  } else {
@@ -355,7 +359,8 @@ async function loadMonaco(highlighter, workspace, lsp, onDidEditorWorkerResolve)
355
359
  }
356
360
  return worker;
357
361
  },
358
- getLanguageIdFromUri: (uri) => getLanguageIdFromPath(uri.path)
362
+ getLanguageIdFromUri: (uri) => getLanguageIdFromPath(uri.path),
363
+ getExtnameFromLanguageId
359
364
  });
360
365
  monaco.editor.registerLinkOpener({
361
366
  async open(link) {
@@ -177729,6 +177729,11 @@ Object.assign(editor, {
177729
177729
  if (!language2 && uri) {
177730
177730
  language2 = MonacoEnvironment.getLanguageIdFromUri?.(uri);
177731
177731
  }
177732
+ if (!uri) {
177733
+ const extname3 = MonacoEnvironment.getExtnameFromLanguageId?.(language2) ?? "txt";
177734
+ const uuid = Math.round((Date.now() + Math.random()) * 1e3).toString(36);
177735
+ uri = "file:///.inmemory/" + uuid + "." + extname3;
177736
+ }
177732
177737
  return createModel2(value, language2, uri);
177733
177738
  },
177734
177739
  getModel: (uri) => {