ember-repl 6.0.0 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/README.md +2 -404
- package/config/.try.mjs +87 -0
- package/config/addon-main.cjs +7 -0
- package/config/attw.json +7 -0
- package/config/babel.publish.config.cjs +29 -0
- package/config/ember-cli-update.json +21 -0
- package/config/rollup.config.mjs +44 -0
- package/config/testem.cjs +35 -0
- package/config/tsconfig.publish.json +15 -0
- package/config/vite.config.mjs +36 -0
- package/declarations/compile/Compiled.d.ts +7 -0
- package/declarations/compile/Compiled.d.ts.map +1 -0
- package/declarations/compile/compile.d.ts +17 -0
- package/declarations/compile/compile.d.ts.map +1 -0
- package/declarations/compile/state.d.ts +43 -0
- package/declarations/compile/state.d.ts.map +1 -0
- package/declarations/compile/types.d.ts +5 -12
- package/declarations/compile/types.d.ts.map +1 -1
- package/declarations/index.d.ts +6 -2
- package/declarations/index.d.ts.map +1 -1
- package/declarations/services/compiler.d.ts +94 -0
- package/declarations/services/compiler.d.ts.map +1 -0
- package/declarations/services/known-modules.d.ts +7 -0
- package/declarations/services/known-modules.d.ts.map +1 -0
- package/declarations/setup.d.ts +7 -0
- package/declarations/setup.d.ts.map +1 -0
- package/declarations/test-support.d.ts +20 -0
- package/declarations/test-support.d.ts.map +1 -0
- package/dist/_commonjsHelpers-BAGoDD49.js +37 -0
- package/dist/_commonjsHelpers-BAGoDD49.js.map +1 -0
- package/dist/babel-8wMrbxkT.js +110427 -0
- package/dist/babel-8wMrbxkT.js.map +1 -0
- package/dist/blank-line-Bzg2Qt4K.js +482 -0
- package/dist/blank-line-Bzg2Qt4K.js.map +1 -0
- package/dist/compile/Compiled.js +26 -0
- package/dist/compile/Compiled.js.map +1 -0
- package/dist/compile/compile.js +62 -0
- package/dist/compile/compile.js.map +1 -0
- package/dist/compile/state.js +75 -0
- package/dist/compile/state.js.map +1 -0
- package/dist/compile/utils.js +213 -2
- package/dist/compile/utils.js.map +1 -1
- package/dist/default-CoqAuVeH.js +4 -0
- package/dist/default-CoqAuVeH.js.map +1 -0
- package/dist/index-BTx1k6gT.js +323 -0
- package/dist/index-BTx1k6gT.js.map +1 -0
- package/dist/index-Bxzjtr16.js +87 -0
- package/dist/index-Bxzjtr16.js.map +1 -0
- package/dist/index-C371bO_b.js +1553 -0
- package/dist/index-C371bO_b.js.map +1 -0
- package/dist/index-C4AyeeIa.js +5721 -0
- package/dist/index-C4AyeeIa.js.map +1 -0
- package/dist/index-C8S2G0FH.js +1953 -0
- package/dist/index-C8S2G0FH.js.map +1 -0
- package/dist/index-CCcIVEUK.js +409 -0
- package/dist/index-CCcIVEUK.js.map +1 -0
- package/dist/index-CDSIcg03.js +9070 -0
- package/dist/index-CDSIcg03.js.map +1 -0
- package/dist/index-D8szzCn3.js +2 -0
- package/dist/index-D8szzCn3.js.map +1 -0
- package/dist/index-DBBNT106.js +2644 -0
- package/dist/index-DBBNT106.js.map +1 -0
- package/dist/index-DP_Su7Zc.js +362 -0
- package/dist/index-DP_Su7Zc.js.map +1 -0
- package/dist/index-DejgrVqh.js +11299 -0
- package/dist/index-DejgrVqh.js.map +1 -0
- package/dist/index-Dr5iYoKt.js +1551 -0
- package/dist/index-Dr5iYoKt.js.map +1 -0
- package/dist/index-DxolpiGq.js +3336 -0
- package/dist/index-DxolpiGq.js.map +1 -0
- package/dist/index-ZyJlPFQY.js +249 -0
- package/dist/index-ZyJlPFQY.js.map +1 -0
- package/dist/index-k6CfLgeq.js +26 -0
- package/dist/index-k6CfLgeq.js.map +1 -0
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/services/compiler.js +329 -0
- package/dist/services/compiler.js.map +1 -0
- package/dist/services/known-modules.js +123 -0
- package/dist/services/known-modules.js.map +1 -0
- package/dist/setup.js +15 -0
- package/dist/setup.js.map +1 -0
- package/dist/test-support.js +33 -0
- package/dist/test-support.js.map +1 -0
- package/package.json +117 -138
- package/src/compile/Compiled.ts +45 -0
- package/src/compile/compile.ts +89 -0
- package/src/compile/state.ts +88 -0
- package/src/compile/types.ts +14 -13
- package/src/index.ts +6 -2
- package/src/services/compiler.ts +401 -0
- package/src/services/known-modules.ts +130 -0
- package/src/setup.ts +26 -0
- package/src/test-support.ts +64 -0
- package/addon-main.cjs +0 -5
- package/declarations/__PRIVATE__.d.ts +0 -2
- package/declarations/__PRIVATE__.d.ts.map +0 -1
- package/declarations/compile/formats/gjs/babel.d.ts +0 -7
- package/declarations/compile/formats/gjs/babel.d.ts.map +0 -1
- package/declarations/compile/formats/gjs/eval.d.ts +0 -8
- package/declarations/compile/formats/gjs/eval.d.ts.map +0 -1
- package/declarations/compile/formats/gjs/index.d.ts +0 -24
- package/declarations/compile/formats/gjs/index.d.ts.map +0 -1
- package/declarations/compile/formats/gjs/known-modules.d.ts +0 -48
- package/declarations/compile/formats/gjs/known-modules.d.ts.map +0 -1
- package/declarations/compile/formats/hbs.d.ts +0 -17
- package/declarations/compile/formats/hbs.d.ts.map +0 -1
- package/declarations/compile/formats/markdown.d.ts +0 -22
- package/declarations/compile/formats/markdown.d.ts.map +0 -1
- package/declarations/compile/formats.d.ts +0 -17
- package/declarations/compile/formats.d.ts.map +0 -1
- package/declarations/compile/index.d.ts +0 -80
- package/declarations/compile/index.d.ts.map +0 -1
- package/declarations/test-support/index.d.ts +0 -2
- package/declarations/test-support/index.d.ts.map +0 -1
- package/dist/__PRIVATE__.js +0 -2
- package/dist/__PRIVATE__.js.map +0 -1
- package/dist/compile/formats/gjs/babel.js +0 -2
- package/dist/compile/formats/gjs/babel.js.map +0 -1
- package/dist/compile/formats/gjs/eval.js +0 -19
- package/dist/compile/formats/gjs/eval.js.map +0 -1
- package/dist/compile/formats/gjs/index.js +0 -122
- package/dist/compile/formats/gjs/index.js.map +0 -1
- package/dist/compile/formats/gjs/known-modules.js +0 -52
- package/dist/compile/formats/gjs/known-modules.js.map +0 -1
- package/dist/compile/formats/hbs.js +0 -93
- package/dist/compile/formats/hbs.js.map +0 -1
- package/dist/compile/formats/markdown.js +0 -266
- package/dist/compile/formats/markdown.js.map +0 -1
- package/dist/compile/formats.js +0 -173
- package/dist/compile/formats.js.map +0 -1
- package/dist/compile/index.js +0 -113
- package/dist/compile/index.js.map +0 -1
- package/dist/test-support/index.js +0 -8
- package/dist/test-support/index.js.map +0 -1
- package/src/__PRIVATE__.ts +0 -1
- package/src/compile/formats/gjs/babel.ts +0 -7
- package/src/compile/formats/gjs/eval.ts +0 -29
- package/src/compile/formats/gjs/index.ts +0 -153
- package/src/compile/formats/gjs/known-modules.ts +0 -49
- package/src/compile/formats/hbs.ts +0 -100
- package/src/compile/formats/markdown.ts +0 -345
- package/src/compile/formats.ts +0 -178
- package/src/compile/index.ts +0 -219
- package/src/test-support/index.ts +0 -5
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { CompileState, MissingTextState, REJECT, RESOLVE } from './state.ts';
|
|
2
|
+
import { nameFor } from './utils.ts';
|
|
3
|
+
|
|
4
|
+
import type CompilerService from '../services/compiler.ts';
|
|
5
|
+
import type { CompileResult, Format, Input } from './types.ts';
|
|
6
|
+
import type { ComponentLike } from '@glint/template';
|
|
7
|
+
|
|
8
|
+
export const CACHE = new Map<string, ComponentLike>();
|
|
9
|
+
|
|
10
|
+
interface Options {
|
|
11
|
+
format: Format;
|
|
12
|
+
flavor?: string;
|
|
13
|
+
remarkPlugins?: unknown[];
|
|
14
|
+
rehypePlugins?: unknown[];
|
|
15
|
+
onSuccess?: (component: ComponentLike) => Promise<unknown> | unknown;
|
|
16
|
+
onError?: (error: string) => Promise<unknown> | unknown;
|
|
17
|
+
onCompileStart?: () => Promise<unknown> | unknown;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function compile(service: CompilerService, text: Input, options: Options): CompileState {
|
|
21
|
+
const data = { format: options.format };
|
|
22
|
+
|
|
23
|
+
if (!text) {
|
|
24
|
+
return new MissingTextState(data);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const id = nameFor(`${options.format}:${text}`);
|
|
28
|
+
|
|
29
|
+
const state = new CompileState(data);
|
|
30
|
+
|
|
31
|
+
// Fills the cache as well
|
|
32
|
+
runTheCompiler({ service, text, options, state, id });
|
|
33
|
+
|
|
34
|
+
return state;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function runTheCompiler({
|
|
38
|
+
service,
|
|
39
|
+
text,
|
|
40
|
+
options,
|
|
41
|
+
state,
|
|
42
|
+
id,
|
|
43
|
+
}: {
|
|
44
|
+
service: CompilerService;
|
|
45
|
+
text: string;
|
|
46
|
+
options: Options;
|
|
47
|
+
state: CompileState;
|
|
48
|
+
id: string;
|
|
49
|
+
}) {
|
|
50
|
+
await options?.onCompileStart?.();
|
|
51
|
+
await Promise.resolve();
|
|
52
|
+
|
|
53
|
+
if (!text) {
|
|
54
|
+
state[REJECT](new Error('No Input Document yet'));
|
|
55
|
+
await options?.onError?.('No Input Document yet');
|
|
56
|
+
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let result: CompileResult;
|
|
61
|
+
|
|
62
|
+
// TODO: just use compile, eliminate all this branching
|
|
63
|
+
if (options.format === 'glimdown') {
|
|
64
|
+
result = await service.compile('gmd', text, options as any);
|
|
65
|
+
} else if (options.format === 'gjs') {
|
|
66
|
+
result = await service.compileGJS(text);
|
|
67
|
+
} else if (options.format === 'hbs') {
|
|
68
|
+
result = await service.compileHBS(text, options as any);
|
|
69
|
+
} else {
|
|
70
|
+
result = await service.compile(
|
|
71
|
+
options.format,
|
|
72
|
+
text,
|
|
73
|
+
options as unknown as Record<string, unknown>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (result.error) {
|
|
78
|
+
state[REJECT](result.error);
|
|
79
|
+
await options?.onError?.(state.reason || 'Unknown Error');
|
|
80
|
+
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
CACHE.set(id, result.component as ComponentLike);
|
|
85
|
+
|
|
86
|
+
state[RESOLVE](result.component as ComponentLike);
|
|
87
|
+
|
|
88
|
+
await options?.onSuccess?.(result.component as ComponentLike);
|
|
89
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { tracked } from '@glimmer/tracking';
|
|
2
|
+
|
|
3
|
+
import type { ComponentLike } from '@glint/template';
|
|
4
|
+
|
|
5
|
+
export const RESOLVE = Symbol('CompileState::resolve');
|
|
6
|
+
export const REJECT = Symbol('CompileState::reject');
|
|
7
|
+
|
|
8
|
+
interface State {
|
|
9
|
+
component: ComponentLike | undefined;
|
|
10
|
+
error: Error | undefined;
|
|
11
|
+
isReady: boolean;
|
|
12
|
+
reason: string | undefined;
|
|
13
|
+
promise: Promise<ComponentLike>;
|
|
14
|
+
format: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface Data {
|
|
18
|
+
format: string;
|
|
19
|
+
flavor?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class CompileState implements State {
|
|
23
|
+
@tracked component: undefined | ComponentLike;
|
|
24
|
+
@tracked error: undefined | Error;
|
|
25
|
+
|
|
26
|
+
@tracked isReady = false;
|
|
27
|
+
|
|
28
|
+
#data: Data;
|
|
29
|
+
#resolve: undefined | ((value: ComponentLike) => void);
|
|
30
|
+
#reject: undefined | ((reason?: any) => void);
|
|
31
|
+
#promise = new Promise<ComponentLike>((resolve, reject) => {
|
|
32
|
+
this.#resolve = resolve;
|
|
33
|
+
this.#reject = reject;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
constructor(data: Data) {
|
|
37
|
+
this.#data = data;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get format() {
|
|
41
|
+
return this.#data.format;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get reason() {
|
|
45
|
+
return this.error?.message;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get isWaiting() {
|
|
49
|
+
return !this.isReady && !this.error;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get promise() {
|
|
53
|
+
return this.#promise;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @private
|
|
58
|
+
*/
|
|
59
|
+
[RESOLVE](component: ComponentLike) {
|
|
60
|
+
this.isReady = true;
|
|
61
|
+
this.component = component;
|
|
62
|
+
this.#resolve?.(component);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* @private
|
|
66
|
+
*/
|
|
67
|
+
[REJECT](error: Error) {
|
|
68
|
+
this.error = error;
|
|
69
|
+
this.#reject?.(error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class MissingTextState extends CompileState {}
|
|
74
|
+
|
|
75
|
+
export class CachedCompileState extends CompileState {
|
|
76
|
+
#resolvedPromise: Promise<ComponentLike>;
|
|
77
|
+
constructor(data: Data, component: ComponentLike) {
|
|
78
|
+
super(data);
|
|
79
|
+
|
|
80
|
+
this.component = component;
|
|
81
|
+
this.#resolvedPromise = Promise.resolve(component);
|
|
82
|
+
this.isReady = true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get promise() {
|
|
86
|
+
return this.#resolvedPromise;
|
|
87
|
+
}
|
|
88
|
+
}
|
package/src/compile/types.ts
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
import type { ComponentLike } from '@glint/template';
|
|
2
|
-
import type { Pluggable } from 'unified';
|
|
3
2
|
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
export type Input = string | undefined | null;
|
|
4
|
+
export type Format =
|
|
5
|
+
| 'glimdown'
|
|
6
|
+
| 'jsx'
|
|
7
|
+
| 'md'
|
|
8
|
+
| 'vue'
|
|
9
|
+
| 'svelte'
|
|
10
|
+
| 'gjs'
|
|
11
|
+
| 'hbs'
|
|
12
|
+
| 'mermaid'
|
|
13
|
+
| 'react';
|
|
7
14
|
|
|
8
15
|
export interface ScopeMap {
|
|
9
16
|
[localName: string]: unknown;
|
|
10
17
|
}
|
|
11
18
|
|
|
12
|
-
export
|
|
19
|
+
export interface ModuleMap {
|
|
20
|
+
[key: string]: () => Promise<unknown> | Record<string, unknown>;
|
|
21
|
+
}
|
|
13
22
|
|
|
14
23
|
export interface CompileResult {
|
|
15
24
|
component?: ComponentLike;
|
|
16
25
|
error?: Error;
|
|
17
26
|
name: string;
|
|
18
27
|
}
|
|
19
|
-
|
|
20
|
-
export type Options = {
|
|
21
|
-
/**
|
|
22
|
-
* @internal
|
|
23
|
-
* @deprecated do not use - not under semver
|
|
24
|
-
*/
|
|
25
|
-
skypack?: boolean;
|
|
26
|
-
};
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
export { compile
|
|
1
|
+
export { compile } from './compile/compile.ts';
|
|
2
|
+
export { Compiled } from './compile/Compiled.ts';
|
|
2
3
|
export { invocationName, invocationOf, nameFor } from './compile/utils.ts';
|
|
4
|
+
export { getCompiler } from './services/compiler.ts';
|
|
5
|
+
export { setup as setupCompiler } from './setup.ts';
|
|
3
6
|
|
|
4
7
|
// Public Types
|
|
5
|
-
export type {
|
|
8
|
+
export type { CompileState } from './compile/state.ts';
|
|
9
|
+
export type { Format, ModuleMap, ScopeMap } from './compile/types.ts';
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/* eslint-disable getter-return */
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import { tracked } from '@glimmer/tracking';
|
|
5
|
+
import { setComponentTemplate } from '@ember/component';
|
|
6
|
+
import templateOnly from '@ember/component/template-only';
|
|
7
|
+
import { assert } from '@ember/debug';
|
|
8
|
+
import { registerDestructor } from '@ember/destroyable';
|
|
9
|
+
import { array, concat, fn, get, hash } from '@ember/helper';
|
|
10
|
+
import { on } from '@ember/modifier';
|
|
11
|
+
import { getOwner } from '@ember/owner';
|
|
12
|
+
import { precompileTemplate } from '@ember/template-compilation';
|
|
13
|
+
import { waitFor } from '@ember/test-waiters';
|
|
14
|
+
|
|
15
|
+
import { createStore } from 'ember-primitives/store';
|
|
16
|
+
import { resource } from 'ember-resources';
|
|
17
|
+
import { Compiler } from 'repl-sdk';
|
|
18
|
+
import { visit } from 'unist-util-visit';
|
|
19
|
+
|
|
20
|
+
import { nameFor } from '../compile/utils.ts';
|
|
21
|
+
import { modules } from './known-modules.ts';
|
|
22
|
+
|
|
23
|
+
import type { CompileResult, ModuleMap } from '../compile/types.ts';
|
|
24
|
+
import type { ComponentLike } from '@glint/template';
|
|
25
|
+
import type { EditorView } from 'codemirror';
|
|
26
|
+
import type { ErrorMessage, InfoMessage, Message } from 'repl-sdk';
|
|
27
|
+
|
|
28
|
+
export function getCompiler(context: object) {
|
|
29
|
+
const owner = getOwner(context) ?? context;
|
|
30
|
+
|
|
31
|
+
assert(`Missing owner. Cannot use ember-repl's compiler without an owner.`, owner);
|
|
32
|
+
|
|
33
|
+
return createStore(owner, CompilerService);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Old way to make static components, because
|
|
38
|
+
* https://github.com/emberjs/ember.js/issues/20913
|
|
39
|
+
*
|
|
40
|
+
* The runtime compiler doesn't allow you to catch compiler errors.
|
|
41
|
+
* This particular component doesn't need to be runtime anyway.
|
|
42
|
+
*/
|
|
43
|
+
function rendersElement(x: { element: Element; destroy: () => void }): ComponentLike {
|
|
44
|
+
const render = resource(({ on }) => {
|
|
45
|
+
on.cleanup(() => {
|
|
46
|
+
x.destroy();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return x.element;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return setComponentTemplate(
|
|
53
|
+
precompileTemplate(`{{render}}`, {
|
|
54
|
+
strictMode: true,
|
|
55
|
+
scope: () => ({ render }),
|
|
56
|
+
}),
|
|
57
|
+
templateOnly()
|
|
58
|
+
) as ComponentLike;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface CompilerOptions {
|
|
62
|
+
hbs?: {
|
|
63
|
+
scope?: Record<string, unknown>;
|
|
64
|
+
};
|
|
65
|
+
md?: {
|
|
66
|
+
remarkPlugins?: unknown[];
|
|
67
|
+
rehypePlugins?: unknown[];
|
|
68
|
+
};
|
|
69
|
+
gmd?: {
|
|
70
|
+
scope?: Record<string, unknown>;
|
|
71
|
+
remarkPlugins?: unknown[];
|
|
72
|
+
rehypePlugins?: unknown[];
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Standard for the REPL, not real apps.
|
|
78
|
+
* HBS isn't used in real apps (that are fully up to date)
|
|
79
|
+
*/
|
|
80
|
+
const standardScope = {
|
|
81
|
+
// These are only added here because it's convenient for hbs
|
|
82
|
+
// to have them
|
|
83
|
+
array,
|
|
84
|
+
concat,
|
|
85
|
+
fn,
|
|
86
|
+
get,
|
|
87
|
+
hash,
|
|
88
|
+
on,
|
|
89
|
+
// The default available scope for gjs:
|
|
90
|
+
//
|
|
91
|
+
// We don't use gjs transpilation here, because hbs transpilation
|
|
92
|
+
// doesn't need to go through the babel infra, so it's faster this way,
|
|
93
|
+
// even though it's more "verbose" and could get out of sync from the
|
|
94
|
+
// implementations / source-of-truth.
|
|
95
|
+
//
|
|
96
|
+
// https://github.com/emberjs/babel-plugin-ember-template-compilation/blob/main/src/scope-locals.ts#L16
|
|
97
|
+
//
|
|
98
|
+
// ////////////////
|
|
99
|
+
// namespaces
|
|
100
|
+
// ////////////////
|
|
101
|
+
// TC39
|
|
102
|
+
globalThis,
|
|
103
|
+
Atomics,
|
|
104
|
+
JSON,
|
|
105
|
+
Math,
|
|
106
|
+
Reflect,
|
|
107
|
+
// WHATWG
|
|
108
|
+
localStorage,
|
|
109
|
+
sessionStorage,
|
|
110
|
+
URL,
|
|
111
|
+
// ////////////////
|
|
112
|
+
// functions / utilities
|
|
113
|
+
// ////////////////
|
|
114
|
+
// TC39
|
|
115
|
+
isNaN,
|
|
116
|
+
isFinite,
|
|
117
|
+
parseInt,
|
|
118
|
+
parseFloat,
|
|
119
|
+
decodeURI,
|
|
120
|
+
decodeURIComponent,
|
|
121
|
+
encodeURI,
|
|
122
|
+
encodeURIComponent,
|
|
123
|
+
// WHATWG
|
|
124
|
+
postMessage,
|
|
125
|
+
structuredClone,
|
|
126
|
+
// ////////////////
|
|
127
|
+
// new-less Constructors (still functions)
|
|
128
|
+
// ////////////////
|
|
129
|
+
// TC39
|
|
130
|
+
Array, // different behavior from (array)
|
|
131
|
+
BigInt,
|
|
132
|
+
Boolean,
|
|
133
|
+
Date,
|
|
134
|
+
Number,
|
|
135
|
+
Object, // different behavior from (hash)
|
|
136
|
+
String,
|
|
137
|
+
// ////////////////
|
|
138
|
+
// Values
|
|
139
|
+
// ////////////////
|
|
140
|
+
// TC39
|
|
141
|
+
Infinity,
|
|
142
|
+
NaN,
|
|
143
|
+
// WHATWG
|
|
144
|
+
isSecureContext,
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export default class CompilerService {
|
|
148
|
+
#compiler: Compiler | undefined;
|
|
149
|
+
|
|
150
|
+
constructor() {
|
|
151
|
+
const global = getGlobal();
|
|
152
|
+
|
|
153
|
+
global.REPL ||= {};
|
|
154
|
+
|
|
155
|
+
if (global.REPL.compiler) {
|
|
156
|
+
return global.REPL.compiler;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
global.REPL.compiler = this;
|
|
160
|
+
|
|
161
|
+
registerDestructor(this, () => {
|
|
162
|
+
delete global.REPL?.compiler;
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@tracked messages: Message[] = [];
|
|
167
|
+
|
|
168
|
+
get lastInfo(): InfoMessage | undefined {
|
|
169
|
+
const m = this.messages;
|
|
170
|
+
|
|
171
|
+
for (let i = m.length - 1; i >= 0; i--) {
|
|
172
|
+
const current = m[i];
|
|
173
|
+
|
|
174
|
+
if (current?.type === 'info') return current;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
get lastError(): ErrorMessage | undefined {
|
|
179
|
+
const m = this.messages;
|
|
180
|
+
|
|
181
|
+
for (let i = m.length - 1; i >= 0; i--) {
|
|
182
|
+
const current = m[i];
|
|
183
|
+
|
|
184
|
+
if (current?.type === 'error') return current;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* @param {ModuleMap} [ extraModules ]: map of import paths to modules.
|
|
190
|
+
* These modules are useful if you need to document a library or a any design system or a styleguide or
|
|
191
|
+
* if there are additional modules that could be imported in the passed `code`.
|
|
192
|
+
* @param {object} [options] optional compiler options for each format/flavor
|
|
193
|
+
*
|
|
194
|
+
* Later on, imports that are not present by default (ember/glimmer) or that
|
|
195
|
+
* are not provided by extraModules will be searched on npm to see if a package
|
|
196
|
+
* needs to be downloaded before running the `code` / invoking the component
|
|
197
|
+
*/
|
|
198
|
+
setup = (extraModules: ModuleMap = {}, options: CompilerOptions = {}) => {
|
|
199
|
+
const localModules = modules(extraModules);
|
|
200
|
+
|
|
201
|
+
this.#compiler = new Compiler({
|
|
202
|
+
logging: location.search.includes('debug'),
|
|
203
|
+
resolve: {
|
|
204
|
+
...localModules,
|
|
205
|
+
},
|
|
206
|
+
on: {
|
|
207
|
+
log: (type: Message['type'], message: string) => {
|
|
208
|
+
this.messages.push({ type, message });
|
|
209
|
+
// Waiting on better array primitive
|
|
210
|
+
// eslint-disable-next-line no-self-assign
|
|
211
|
+
this.messages = this.messages;
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
options: {
|
|
215
|
+
...options,
|
|
216
|
+
gjs: {
|
|
217
|
+
// owner: getOwner(this),
|
|
218
|
+
owner: {
|
|
219
|
+
lookup: () => {},
|
|
220
|
+
resolveRegistration: () => {},
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
gmd: {
|
|
224
|
+
...(options.gmd ?? {}),
|
|
225
|
+
scope: {
|
|
226
|
+
...standardScope,
|
|
227
|
+
...(options.gmd?.scope ?? {}),
|
|
228
|
+
},
|
|
229
|
+
remarkPlugins: [
|
|
230
|
+
function defaultHbsToEmber() {
|
|
231
|
+
return function transformer(tree: any) {
|
|
232
|
+
visit(tree, 'code', (node) => {
|
|
233
|
+
if (node.lang === 'hbs') {
|
|
234
|
+
if (!node.meta) {
|
|
235
|
+
node.meta = 'ember';
|
|
236
|
+
} else {
|
|
237
|
+
node.meta += ' ember';
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return node;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
return tree;
|
|
245
|
+
};
|
|
246
|
+
},
|
|
247
|
+
...(options.gmd?.remarkPlugins ?? []),
|
|
248
|
+
],
|
|
249
|
+
},
|
|
250
|
+
hbs: {
|
|
251
|
+
ember: {
|
|
252
|
+
...(options.hbs ?? {}),
|
|
253
|
+
scope: {
|
|
254
|
+
...standardScope,
|
|
255
|
+
...(options.hbs?.scope ?? {}),
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
get compiler(): Compiler {
|
|
264
|
+
/**
|
|
265
|
+
* This is useful for our own testing.
|
|
266
|
+
* not sure if this would be a footgun for consumers' usage
|
|
267
|
+
*/
|
|
268
|
+
if (!this.#compiler) {
|
|
269
|
+
this.setup();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
assert(
|
|
273
|
+
`Expected a compiled to be setup on the compiler service. Use \`compiler.setup()\` first.`,
|
|
274
|
+
this.#compiler
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
return this.#compiler;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async createEditor(
|
|
281
|
+
element: HTMLElement,
|
|
282
|
+
options: {
|
|
283
|
+
text: string | null | undefined;
|
|
284
|
+
format: string;
|
|
285
|
+
handleUpdate: (text: string) => void;
|
|
286
|
+
extensions?: unknown[];
|
|
287
|
+
}
|
|
288
|
+
): Promise<{
|
|
289
|
+
view: EditorView;
|
|
290
|
+
setText: (text: string, format: string) => Promise<void>;
|
|
291
|
+
setFormat: (format: string) => Promise<void>;
|
|
292
|
+
}> {
|
|
293
|
+
return this.compiler.createEditor(element, options);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async #compile(ext: string, text: string, options?: Record<string, unknown>) {
|
|
297
|
+
/**
|
|
298
|
+
* Protect from accidental backtracking-render assertions
|
|
299
|
+
* (infinite loop protection)
|
|
300
|
+
*
|
|
301
|
+
* This function doesn't ready any tracked data, so we don't need to
|
|
302
|
+
* worry about invalidation or anything.
|
|
303
|
+
*/
|
|
304
|
+
await Promise.resolve();
|
|
305
|
+
|
|
306
|
+
this.messages = [];
|
|
307
|
+
|
|
308
|
+
return this.compiler.compile(ext, text, options ?? {});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* @public
|
|
313
|
+
*
|
|
314
|
+
* Defers to the underlying repl-SDK and gives us a component we can render.
|
|
315
|
+
*
|
|
316
|
+
* @param {string} ext the ext/format to be compiled
|
|
317
|
+
* @param {string} text the code to be compiled using the configured compiler for the ext
|
|
318
|
+
*/
|
|
319
|
+
@waitFor
|
|
320
|
+
async compile(ext: string, text: string, options?: Record<string, unknown>) {
|
|
321
|
+
const name = nameFor(text);
|
|
322
|
+
let component: undefined | ComponentLike;
|
|
323
|
+
let error: undefined | Error;
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
if (ext === 'hbs') {
|
|
327
|
+
/**
|
|
328
|
+
* Are there other hbs-using frameworks?
|
|
329
|
+
*/
|
|
330
|
+
options ||= {};
|
|
331
|
+
options.flavor = 'ember';
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const result = await this.#compile(ext, text, options);
|
|
335
|
+
|
|
336
|
+
component = rendersElement(result);
|
|
337
|
+
} catch (e) {
|
|
338
|
+
// Put a breakpoint here to debug
|
|
339
|
+
// debugger;
|
|
340
|
+
console.error(e);
|
|
341
|
+
error = e as Error | undefined;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return { name, component, error };
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* @public
|
|
349
|
+
*
|
|
350
|
+
* Transpiles GlimmerJS (*.gjs) formatted text into and evaluates as a JS Module.
|
|
351
|
+
* The returned component can be invoked explicitly in the consuming project.
|
|
352
|
+
*
|
|
353
|
+
* @param {string} code the code to be compiled
|
|
354
|
+
*/
|
|
355
|
+
compileGJS(code: string): Promise<CompileResult> {
|
|
356
|
+
return this.compile('gjs', code);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* compile a template with an empty scope
|
|
361
|
+
* to use components, helpers, etc, you will need to compile with JS
|
|
362
|
+
*
|
|
363
|
+
* (templates alone do not have a way to import / define complex structures)
|
|
364
|
+
*/
|
|
365
|
+
@waitFor
|
|
366
|
+
async compileHBS(
|
|
367
|
+
source: string,
|
|
368
|
+
options: {
|
|
369
|
+
/**
|
|
370
|
+
* Used for debug viewing
|
|
371
|
+
*/
|
|
372
|
+
moduleName?: string;
|
|
373
|
+
/**
|
|
374
|
+
* Additional values to include in hbs scope.
|
|
375
|
+
* This is a _strict mode_ hbs component.
|
|
376
|
+
*/
|
|
377
|
+
scope?: Record<string, unknown>;
|
|
378
|
+
} = {}
|
|
379
|
+
): Promise<CompileResult> {
|
|
380
|
+
return this.compile('hbs', source, options);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
@waitFor
|
|
384
|
+
compileMD(
|
|
385
|
+
source: string,
|
|
386
|
+
options?: {
|
|
387
|
+
remarkPlugins?: unknown[];
|
|
388
|
+
rehypePlugins?: unknown[];
|
|
389
|
+
}
|
|
390
|
+
): Promise<CompileResult> {
|
|
391
|
+
return this.compile('md', source, options);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function getGlobal() {
|
|
396
|
+
return globalThis as {
|
|
397
|
+
REPL?: {
|
|
398
|
+
compiler?: CompilerService;
|
|
399
|
+
};
|
|
400
|
+
};
|
|
401
|
+
}
|