repl-sdk 0.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 NullVoxPopuli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # REPL SDK
2
+
3
+ A Runtime compiler for anything that you could want to build a lighting fast REPL with.
4
+
5
+
6
+ Features:
7
+ - Uses [es-module-shims](https://github.com/guybedford/es-module-shims)
8
+ - Built in support for JavaScript, Mermaid, React, Vue, Svelte, Ember, Markdown
9
+ - On-Demand Runtime: only pay for what you compile for - the async APIs mean that your users only load what they need.
10
+ - Supports nested languages (for markdown)
11
+ - Add any additional compiler/renderer at any time -- the flexible API allows for new libraries/frameworks to be added easily
12
+
13
+ ## Usage
14
+
15
+
@@ -0,0 +1,73 @@
1
+ export declare class Compiler {
2
+ constructor(options?: Options);
3
+
4
+ compile(format: string, text: string): Promise<HTMLElement>;
5
+ }
6
+
7
+ export declare const defaultFormats: Options['formats'];
8
+
9
+ export declare const defaults: Options;
10
+
11
+ declare interface Options {
12
+ formats: {
13
+ [fileExtension: string]: {
14
+ /**
15
+ * When using this file extension in markdown documents,
16
+ * should we only evaluate the code block if the "live"
17
+ * meta is attached to the codefence?
18
+ *
19
+ * If you don't use markdown-embedded rendering,
20
+ * you can ignore this option. Default behavior is "false",
21
+ * but it doesn't matter if you don't render markdown anyway.
22
+ *
23
+ * For example, with `needsLiveMeta: false`:
24
+ * \`\`\`js
25
+ * console.log('hello');
26
+ * \`\`\`
27
+ * will be evaluated and log to the console.
28
+ * However, with `needsLiveMeta: true`, the above snippet would not
29
+ * be evaluated. To evaluate a snippet with `needsLiveMeta: true`:
30
+ * \`\`\`js live
31
+ * console.log('hello');
32
+ * \`\`\`
33
+ */
34
+ needsLiveMeta?: boolean;
35
+ compiler: () => Promise<{
36
+ /**
37
+ * Convert a string from "fileExtension" to standard JavaScript.
38
+ * This will be loaded as a module and then passed to the render method.
39
+ */
40
+ compile: (text: string) => Promise<string>;
41
+ /**
42
+ * For the root of a node rendered for this compiler,
43
+ * how will this particular library / framework
44
+ * render in to the given element?
45
+ *
46
+ * Example:
47
+ * ```js
48
+ * {
49
+ * async compiler() {
50
+ * const { createRoot } = await import('react-dom/client');
51
+ *
52
+ * return {
53
+ * render(element, defaultExport) {
54
+ * const root = createRoot(element);
55
+ *
56
+ * root.render(defaultExport);
57
+ * },
58
+ * // ...
59
+ * }
60
+ * }
61
+ * }
62
+ * ```
63
+ *
64
+ * @param {HTMLElement} the element to render in to, this is provided by repl-sdk.
65
+ * @param {any} the default export from the compiled module.
66
+ */
67
+ render: (element: HTMLElement, defaultExport: any) => void;
68
+ }>;
69
+ };
70
+ };
71
+ }
72
+
73
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,107 @@
1
+ function assert(message, test) {
2
+ if (!test) {
3
+ throw new Error(message);
4
+ }
5
+ }
6
+ assert(`There is no document. repl-sdk is meant to be ran in a browser`, globalThis.document);
7
+ const defaultFormats = {
8
+ mermaid: {
9
+ compiler: async () => {
10
+ return {
11
+ compile: async (text) => {
12
+ }
13
+ };
14
+ }
15
+ }
16
+ };
17
+ const defaults = {
18
+ formats: defaultFormats
19
+ };
20
+ const secret = Symbol.for("__repl-sdk__compiler__");
21
+ assert(
22
+ `There is already an instance of repl-sdk, and there can only be one. Make sure that your dependency graph is correct.`,
23
+ !globalThis[secret]
24
+ );
25
+ class Compiler {
26
+ /** @type {Options} */
27
+ #options;
28
+ /**
29
+ * Options may be passed to the compiler to add to its behavior.
30
+ */
31
+ constructor(options = defaults) {
32
+ this.#options = options;
33
+ globalThis[secret] = this;
34
+ globalThis.window.esmsInitOptions = {
35
+ shimMode: true,
36
+ skip: `https://esm.sh/`,
37
+ revokeBlobURLs: true,
38
+ // default false
39
+ // Permit overrides to import maps
40
+ mapOverrides: true,
41
+ // default false
42
+ // Hook all module resolutions
43
+ resolve: (id, parentUrl, resolve) => {
44
+ if (id.startsWith("blob:")) return id;
45
+ if (id.startsWith("https://")) return id;
46
+ console.log("Resolving", id);
47
+ return `https://esm.sh/*${id}`;
48
+ },
49
+ // Hook source fetch function
50
+ fetch: async (url, options2) => {
51
+ console.log(`Fetching`, url);
52
+ if (url.endsWith("example.js")) {
53
+ const transformed = `export const js = 'transformed'`;
54
+ return new Response(new Blob([transformed], { type: "application/javascript" }));
55
+ }
56
+ const response = await fetch(url, options2);
57
+ return response;
58
+ }
59
+ };
60
+ }
61
+ /**
62
+ * @param {string} format
63
+ * @param {string} text
64
+ */
65
+ async compile(format, text) {
66
+ await import("es-module-shims");
67
+ const compiler = await this.#getCompiler(format);
68
+ const compiledText = await compiler.compile(text);
69
+ const asBlobUrl = textToBlobUrl(compiledText);
70
+ const { default: defaultExport } = await importShim(
71
+ /* @vite-ignore */
72
+ asBlobUrl
73
+ );
74
+ return this.#render(compiler, defaultExport);
75
+ }
76
+ async #getCompiler(format) {
77
+ const config = this.#options.formats[format];
78
+ assert(
79
+ `${format} is not a configured format. The currently configured formats are ${Object.keys(this.#options.formats).join(", ")}`,
80
+ config
81
+ );
82
+ const compiler = await config.compiler();
83
+ return compiler;
84
+ }
85
+ async #render(compiler, whatToRender) {
86
+ const div = this.#createDiv();
87
+ await compiler.render(div, whatToRender);
88
+ return div;
89
+ }
90
+ #createDiv() {
91
+ let div = document.createElement("div");
92
+ div.setAttribute("data-repl-output", "");
93
+ div.id = "some-random-string";
94
+ return div;
95
+ }
96
+ }
97
+ function textToBlobUrl(text) {
98
+ const blob = new Blob([text], { type: "text/javascript" });
99
+ const blobUrl = URL.createObjectURL(blob);
100
+ return blobUrl;
101
+ }
102
+ export {
103
+ Compiler,
104
+ defaultFormats,
105
+ defaults
106
+ };
107
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/utils.js","../src/index.js"],"sourcesContent":["/**\n * @param {string} message\n * @param {unknown} test\n * @asserts test\n */\nexport function assert(message, test) {\n if (!test) {\n throw new Error(message);\n }\n}\n","/**\n * @typedef {import(\"./types.ts\").Options} Options\n */\nimport { assert } from './utils.js';\n\nassert(`There is no document. repl-sdk is meant to be ran in a browser`, globalThis.document);\n\nexport const defaultFormats = {\n mermaid: {\n compiler: async () => {\n return {\n compile: async (text) => {},\n };\n },\n },\n};\n\nexport const defaults = {\n formats: defaultFormats,\n};\n\nconst secret = Symbol.for('__repl-sdk__compiler__');\n\nassert(\n `There is already an instance of repl-sdk, and there can only be one. Make sure that your dependency graph is correct.`,\n !globalThis[secret]\n);\n\nexport class Compiler {\n /** @type {Options} */\n #options;\n\n /**\n * Options may be passed to the compiler to add to its behavior.\n */\n constructor(options = defaults) {\n this.#options = options;\n\n globalThis[secret] = this;\n globalThis.window.esmsInitOptions = {\n shimMode: true,\n skip: `https://esm.sh/`,\n revokeBlobURLs: true, // default false\n // Permit overrides to import maps\n mapOverrides: true, // default false\n // Hook all module resolutions\n resolve: (id, parentUrl, resolve) => {\n if (id.startsWith('blob:')) return id;\n if (id.startsWith('https://')) return id;\n\n console.log('Resolving', id);\n /**\n * TODO: locally defined scope\n * vs\n * proxy to esm.sh\n */\n\n /**\n * For esm.sh, we want all imports to declare they don't want\n * their dependencies bundled. We want to have every import go\n * through this resolve/fetch combo of things so we have a chance\n * to compile if we need to.\n */\n return `https://esm.sh/*${id}`;\n },\n // Hook source fetch function\n fetch: async (url, options) => {\n console.log(`Fetching`, url);\n /**\n * Do transformations here based on file extension\n */\n if (url.endsWith('example.js')) {\n const transformed = `export const js = 'transformed'`;\n return new Response(new Blob([transformed], { type: 'application/javascript' }));\n }\n\n const response = await fetch(url, options);\n\n // if (response.url.endsWith('.ts')) {\n // const source = await response.body();\n // const transformed = tsCompile(source);\n // return new Response(new Blob([transformed], { type: 'application/javascript' }));\n // }\n return response;\n },\n };\n // addShim();\n }\n\n /**\n * @param {string} format\n * @param {string} text\n */\n async compile(format, text) {\n await import('es-module-shims');\n\n const compiler = await this.#getCompiler(format);\n\n // TODO: pass this through es-module-shims\n // for getting the actual module back\n const compiledText = await compiler.compile(text);\n\n const asBlobUrl = textToBlobUrl(compiledText);\n\n const { default: defaultExport } = await importShim(/* @vite-ignore */ asBlobUrl);\n\n return this.#render(compiler, defaultExport);\n }\n\n async #getCompiler(format) {\n const config = this.#options.formats[format];\n\n assert(\n `${format} is not a configured format. ` +\n `The currently configured formats are ${Object.keys(this.#options.formats).join(', ')}`,\n config\n );\n\n const compiler = await config.compiler();\n\n return compiler;\n }\n\n async #render(compiler, whatToRender) {\n const div = this.#createDiv();\n\n await compiler.render(div, whatToRender);\n\n return div;\n }\n\n #createDiv() {\n let div = document.createElement('div');\n div.setAttribute('data-repl-output', '');\n div.id = 'some-random-string';\n return div;\n }\n}\n\nfunction addShim() {\n let url = 'https://ga.jspm.io/npm:es-module-shims@1.10.0/dist/es-module-shims.js';\n\n if (document.querySelector('script[src=\"${url}\"]')) {\n // Shim is already present\n return;\n }\n\n let script = document.createElement('script');\n // script.setAttribute('async', '');\n script.setAttribute('src', `<script async src=\"${url}\"></script>`);\n\n document.head.appendChild(script);\n}\n\n/**\n * @param {string} text\n */\nfunction textToBlobUrl(text) {\n const blob = new Blob([text], { type: 'text/javascript' });\n\n const blobUrl = URL.createObjectURL(blob);\n return blobUrl;\n}\n"],"names":["options"],"mappings":"AAKO,SAAS,OAAO,SAAS,MAAM;AACpC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,OAAO;AAAA,EACxB;AACH;ACJA,OAAO,kEAAkE,WAAW,QAAQ;AAEhF,MAAC,iBAAiB;AAAA,EAC5B,SAAS;AAAA,IACP,UAAU,YAAY;AACpB,aAAO;AAAA,QACL,SAAS,OAAO,SAAS;AAAA,QAAE;AAAA,MACnC;AAAA,IACK;AAAA,EACF;AACH;AAEY,MAAC,WAAW;AAAA,EACtB,SAAS;AACX;AAEA,MAAM,SAAS,OAAO,IAAI,wBAAwB;AAElD;AAAA,EACE;AAAA,EACA,CAAC,WAAW,MAAM;AACpB;AAEO,MAAM,SAAS;AAAA;AAAA,EAEpB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,UAAU,UAAU;AAC9B,SAAK,WAAW;AAEhB,eAAW,MAAM,IAAI;AACrB,eAAW,OAAO,kBAAkB;AAAA,MAClC,UAAU;AAAA,MACV,MAAM;AAAA,MACN,gBAAgB;AAAA;AAAA;AAAA,MAEhB,cAAc;AAAA;AAAA;AAAA,MAEd,SAAS,CAAC,IAAI,WAAW,YAAY;AACnC,YAAI,GAAG,WAAW,OAAO,EAAG,QAAO;AACnC,YAAI,GAAG,WAAW,UAAU,EAAG,QAAO;AAEtC,gBAAQ,IAAI,aAAa,EAAE;AAa3B,eAAO,mBAAmB,EAAE;AAAA,MAC7B;AAAA;AAAA,MAED,OAAO,OAAO,KAAKA,aAAY;AAC7B,gBAAQ,IAAI,YAAY,GAAG;AAI3B,YAAI,IAAI,SAAS,YAAY,GAAG;AAC9B,gBAAM,cAAc;AACpB,iBAAO,IAAI,SAAS,IAAI,KAAK,CAAC,WAAW,GAAG,EAAE,MAAM,yBAA0B,CAAA,CAAC;AAAA,QAChF;AAED,cAAM,WAAW,MAAM,MAAM,KAAKA,QAAO;AAOzC,eAAO;AAAA,MACR;AAAA,IACP;AAAA,EAEG;AAAA;AAAA;AAAA;AAAA;AAAA,EAMD,MAAM,QAAQ,QAAQ,MAAM;AAC1B,UAAM,OAAO,iBAAiB;AAE9B,UAAM,WAAW,MAAM,KAAK,aAAa,MAAM;AAI/C,UAAM,eAAe,MAAM,SAAS,QAAQ,IAAI;AAEhD,UAAM,YAAY,cAAc,YAAY;AAE5C,UAAM,EAAE,SAAS,cAAa,IAAK,MAAM;AAAA;AAAA,MAA8B;AAAA,IAAS;AAEhF,WAAO,KAAK,QAAQ,UAAU,aAAa;AAAA,EAC5C;AAAA,EAED,MAAM,aAAa,QAAQ;AACzB,UAAM,SAAS,KAAK,SAAS,QAAQ,MAAM;AAE3C;AAAA,MACE,GAAG,MAAM,qEACiC,OAAO,KAAK,KAAK,SAAS,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvF;AAAA,IACN;AAEI,UAAM,WAAW,MAAM,OAAO;AAE9B,WAAO;AAAA,EACR;AAAA,EAED,MAAM,QAAQ,UAAU,cAAc;AACpC,UAAM,MAAM,KAAK;AAEjB,UAAM,SAAS,OAAO,KAAK,YAAY;AAEvC,WAAO;AAAA,EACR;AAAA,EAED,aAAa;AACX,QAAI,MAAM,SAAS,cAAc,KAAK;AACtC,QAAI,aAAa,oBAAoB,EAAE;AACvC,QAAI,KAAK;AACT,WAAO;AAAA,EACR;AACH;AAoBA,SAAS,cAAc,MAAM;AAC3B,QAAM,OAAO,IAAI,KAAK,CAAC,IAAI,GAAG,EAAE,MAAM,kBAAiB,CAAE;AAEzD,QAAM,UAAU,IAAI,gBAAgB,IAAI;AACxC,SAAO;AACT;"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "repl-sdk",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": {
7
+ "types": "./declarations/index.d.ts",
8
+ "default": "./dist/index.js"
9
+ }
10
+ },
11
+ "keywords": [
12
+ "repl",
13
+ "playground",
14
+ "SDK",
15
+ "render",
16
+ "play",
17
+ "javascript",
18
+ "live",
19
+ "interactive"
20
+ ],
21
+ "author": "NullVoxPopuli",
22
+ "files": [
23
+ "dist",
24
+ "declarations",
25
+ "src"
26
+ ],
27
+ "license": "MIT",
28
+ "devDependencies": {
29
+ "@tsconfig/ember": "^3.0.7",
30
+ "prettier": "^3.2.5",
31
+ "typescript": "^5.4.5",
32
+ "vite": "^5.2.11",
33
+ "vite-plugin-dts": "4.0.0-beta.1"
34
+ },
35
+ "dependencies": {
36
+ "es-module-shims": "^1.10.0"
37
+ },
38
+ "scripts": {
39
+ "start": "vite build --watch"
40
+ }
41
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import type { Options } from "./types.ts";
2
+
3
+ export const defaultFormats: Options['formats'];
4
+ export const defaults: Options;
5
+
6
+ export class Compiler {
7
+ constructor(options?: Options);
8
+
9
+ compile(format: string, text: string): Promise<HTMLElement>;
10
+ }
package/src/index.js ADDED
@@ -0,0 +1,163 @@
1
+ /**
2
+ * @typedef {import("./types.ts").Options} Options
3
+ */
4
+ import { assert } from './utils.js';
5
+
6
+ assert(`There is no document. repl-sdk is meant to be ran in a browser`, globalThis.document);
7
+
8
+ export const defaultFormats = {
9
+ mermaid: {
10
+ compiler: async () => {
11
+ return {
12
+ compile: async (text) => {},
13
+ };
14
+ },
15
+ },
16
+ };
17
+
18
+ export const defaults = {
19
+ formats: defaultFormats,
20
+ };
21
+
22
+ const secret = Symbol.for('__repl-sdk__compiler__');
23
+
24
+ assert(
25
+ `There is already an instance of repl-sdk, and there can only be one. Make sure that your dependency graph is correct.`,
26
+ !globalThis[secret]
27
+ );
28
+
29
+ export class Compiler {
30
+ /** @type {Options} */
31
+ #options;
32
+
33
+ /**
34
+ * Options may be passed to the compiler to add to its behavior.
35
+ */
36
+ constructor(options = defaults) {
37
+ this.#options = options;
38
+
39
+ globalThis[secret] = this;
40
+ globalThis.window.esmsInitOptions = {
41
+ shimMode: true,
42
+ skip: `https://esm.sh/`,
43
+ revokeBlobURLs: true, // default false
44
+ // Permit overrides to import maps
45
+ mapOverrides: true, // default false
46
+ // Hook all module resolutions
47
+ resolve: (id, parentUrl, resolve) => {
48
+ if (id.startsWith('blob:')) return id;
49
+ if (id.startsWith('https://')) return id;
50
+
51
+ console.log('Resolving', id);
52
+ /**
53
+ * TODO: locally defined scope
54
+ * vs
55
+ * proxy to esm.sh
56
+ */
57
+
58
+ /**
59
+ * For esm.sh, we want all imports to declare they don't want
60
+ * their dependencies bundled. We want to have every import go
61
+ * through this resolve/fetch combo of things so we have a chance
62
+ * to compile if we need to.
63
+ */
64
+ return `https://esm.sh/*${id}`;
65
+ },
66
+ // Hook source fetch function
67
+ fetch: async (url, options) => {
68
+ console.log(`Fetching`, url);
69
+ /**
70
+ * Do transformations here based on file extension
71
+ */
72
+ if (url.endsWith('example.js')) {
73
+ const transformed = `export const js = 'transformed'`;
74
+ return new Response(new Blob([transformed], { type: 'application/javascript' }));
75
+ }
76
+
77
+ const response = await fetch(url, options);
78
+
79
+ // if (response.url.endsWith('.ts')) {
80
+ // const source = await response.body();
81
+ // const transformed = tsCompile(source);
82
+ // return new Response(new Blob([transformed], { type: 'application/javascript' }));
83
+ // }
84
+ return response;
85
+ },
86
+ };
87
+ // addShim();
88
+ }
89
+
90
+ /**
91
+ * @param {string} format
92
+ * @param {string} text
93
+ */
94
+ async compile(format, text) {
95
+ await import('es-module-shims');
96
+
97
+ const compiler = await this.#getCompiler(format);
98
+
99
+ // TODO: pass this through es-module-shims
100
+ // for getting the actual module back
101
+ const compiledText = await compiler.compile(text);
102
+
103
+ const asBlobUrl = textToBlobUrl(compiledText);
104
+
105
+ const { default: defaultExport } = await importShim(/* @vite-ignore */ asBlobUrl);
106
+
107
+ return this.#render(compiler, defaultExport);
108
+ }
109
+
110
+ async #getCompiler(format) {
111
+ const config = this.#options.formats[format];
112
+
113
+ assert(
114
+ `${format} is not a configured format. ` +
115
+ `The currently configured formats are ${Object.keys(this.#options.formats).join(', ')}`,
116
+ config
117
+ );
118
+
119
+ const compiler = await config.compiler();
120
+
121
+ return compiler;
122
+ }
123
+
124
+ async #render(compiler, whatToRender) {
125
+ const div = this.#createDiv();
126
+
127
+ await compiler.render(div, whatToRender);
128
+
129
+ return div;
130
+ }
131
+
132
+ #createDiv() {
133
+ let div = document.createElement('div');
134
+ div.setAttribute('data-repl-output', '');
135
+ div.id = 'some-random-string';
136
+ return div;
137
+ }
138
+ }
139
+
140
+ function addShim() {
141
+ let url = 'https://ga.jspm.io/npm:es-module-shims@1.10.0/dist/es-module-shims.js';
142
+
143
+ if (document.querySelector('script[src="${url}"]')) {
144
+ // Shim is already present
145
+ return;
146
+ }
147
+
148
+ let script = document.createElement('script');
149
+ // script.setAttribute('async', '');
150
+ script.setAttribute('src', `<script async src="${url}"></script>`);
151
+
152
+ document.head.appendChild(script);
153
+ }
154
+
155
+ /**
156
+ * @param {string} text
157
+ */
158
+ function textToBlobUrl(text) {
159
+ const blob = new Blob([text], { type: 'text/javascript' });
160
+
161
+ const blobUrl = URL.createObjectURL(blob);
162
+ return blobUrl;
163
+ }
package/src/types.ts ADDED
@@ -0,0 +1,62 @@
1
+ export interface Options {
2
+ formats: {
3
+ [fileExtension: string]: {
4
+ /**
5
+ * When using this file extension in markdown documents,
6
+ * should we only evaluate the code block if the "live"
7
+ * meta is attached to the codefence?
8
+ *
9
+ * If you don't use markdown-embedded rendering,
10
+ * you can ignore this option. Default behavior is "false",
11
+ * but it doesn't matter if you don't render markdown anyway.
12
+ *
13
+ * For example, with `needsLiveMeta: false`:
14
+ * \`\`\`js
15
+ * console.log('hello');
16
+ * \`\`\`
17
+ * will be evaluated and log to the console.
18
+ * However, with `needsLiveMeta: true`, the above snippet would not
19
+ * be evaluated. To evaluate a snippet with `needsLiveMeta: true`:
20
+ * \`\`\`js live
21
+ * console.log('hello');
22
+ * \`\`\`
23
+ */
24
+ needsLiveMeta?: boolean;
25
+ compiler: () => Promise<{
26
+ /**
27
+ * Convert a string from "fileExtension" to standard JavaScript.
28
+ * This will be loaded as a module and then passed to the render method.
29
+ */
30
+ compile: (text: string) => Promise<string>;
31
+ /**
32
+ * For the root of a node rendered for this compiler,
33
+ * how will this particular library / framework
34
+ * render in to the given element?
35
+ *
36
+ * Example:
37
+ * ```js
38
+ * {
39
+ * async compiler() {
40
+ * const { createRoot } = await import('react-dom/client');
41
+ *
42
+ * return {
43
+ * render(element, defaultExport) {
44
+ * const root = createRoot(element);
45
+ *
46
+ * root.render(defaultExport);
47
+ * },
48
+ * // ...
49
+ * }
50
+ * }
51
+ * }
52
+ * ```
53
+ *
54
+ * @param {HTMLElement} the element to render in to, this is provided by repl-sdk.
55
+ * @param {any} the default export from the compiled module.
56
+ */
57
+ render: (element: HTMLElement, defaultExport: any) => void;
58
+ }>;
59
+ }
60
+ }
61
+ }
62
+
package/src/utils.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @param {string} message
3
+ * @param {unknown} test
4
+ * @asserts test
5
+ */
6
+ export function assert(message, test) {
7
+ if (!test) {
8
+ throw new Error(message);
9
+ }
10
+ }