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.
Files changed (146) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +2 -404
  3. package/config/.try.mjs +87 -0
  4. package/config/addon-main.cjs +7 -0
  5. package/config/attw.json +7 -0
  6. package/config/babel.publish.config.cjs +29 -0
  7. package/config/ember-cli-update.json +21 -0
  8. package/config/rollup.config.mjs +44 -0
  9. package/config/testem.cjs +35 -0
  10. package/config/tsconfig.publish.json +15 -0
  11. package/config/vite.config.mjs +36 -0
  12. package/declarations/compile/Compiled.d.ts +7 -0
  13. package/declarations/compile/Compiled.d.ts.map +1 -0
  14. package/declarations/compile/compile.d.ts +17 -0
  15. package/declarations/compile/compile.d.ts.map +1 -0
  16. package/declarations/compile/state.d.ts +43 -0
  17. package/declarations/compile/state.d.ts.map +1 -0
  18. package/declarations/compile/types.d.ts +5 -12
  19. package/declarations/compile/types.d.ts.map +1 -1
  20. package/declarations/index.d.ts +6 -2
  21. package/declarations/index.d.ts.map +1 -1
  22. package/declarations/services/compiler.d.ts +94 -0
  23. package/declarations/services/compiler.d.ts.map +1 -0
  24. package/declarations/services/known-modules.d.ts +7 -0
  25. package/declarations/services/known-modules.d.ts.map +1 -0
  26. package/declarations/setup.d.ts +7 -0
  27. package/declarations/setup.d.ts.map +1 -0
  28. package/declarations/test-support.d.ts +20 -0
  29. package/declarations/test-support.d.ts.map +1 -0
  30. package/dist/_commonjsHelpers-BAGoDD49.js +37 -0
  31. package/dist/_commonjsHelpers-BAGoDD49.js.map +1 -0
  32. package/dist/babel-8wMrbxkT.js +110427 -0
  33. package/dist/babel-8wMrbxkT.js.map +1 -0
  34. package/dist/blank-line-Bzg2Qt4K.js +482 -0
  35. package/dist/blank-line-Bzg2Qt4K.js.map +1 -0
  36. package/dist/compile/Compiled.js +26 -0
  37. package/dist/compile/Compiled.js.map +1 -0
  38. package/dist/compile/compile.js +62 -0
  39. package/dist/compile/compile.js.map +1 -0
  40. package/dist/compile/state.js +75 -0
  41. package/dist/compile/state.js.map +1 -0
  42. package/dist/compile/utils.js +213 -2
  43. package/dist/compile/utils.js.map +1 -1
  44. package/dist/default-CoqAuVeH.js +4 -0
  45. package/dist/default-CoqAuVeH.js.map +1 -0
  46. package/dist/index-BTx1k6gT.js +323 -0
  47. package/dist/index-BTx1k6gT.js.map +1 -0
  48. package/dist/index-Bxzjtr16.js +87 -0
  49. package/dist/index-Bxzjtr16.js.map +1 -0
  50. package/dist/index-C371bO_b.js +1553 -0
  51. package/dist/index-C371bO_b.js.map +1 -0
  52. package/dist/index-C4AyeeIa.js +5721 -0
  53. package/dist/index-C4AyeeIa.js.map +1 -0
  54. package/dist/index-C8S2G0FH.js +1953 -0
  55. package/dist/index-C8S2G0FH.js.map +1 -0
  56. package/dist/index-CCcIVEUK.js +409 -0
  57. package/dist/index-CCcIVEUK.js.map +1 -0
  58. package/dist/index-CDSIcg03.js +9070 -0
  59. package/dist/index-CDSIcg03.js.map +1 -0
  60. package/dist/index-D8szzCn3.js +2 -0
  61. package/dist/index-D8szzCn3.js.map +1 -0
  62. package/dist/index-DBBNT106.js +2644 -0
  63. package/dist/index-DBBNT106.js.map +1 -0
  64. package/dist/index-DP_Su7Zc.js +362 -0
  65. package/dist/index-DP_Su7Zc.js.map +1 -0
  66. package/dist/index-DejgrVqh.js +11299 -0
  67. package/dist/index-DejgrVqh.js.map +1 -0
  68. package/dist/index-Dr5iYoKt.js +1551 -0
  69. package/dist/index-Dr5iYoKt.js.map +1 -0
  70. package/dist/index-DxolpiGq.js +3336 -0
  71. package/dist/index-DxolpiGq.js.map +1 -0
  72. package/dist/index-ZyJlPFQY.js +249 -0
  73. package/dist/index-ZyJlPFQY.js.map +1 -0
  74. package/dist/index-k6CfLgeq.js +26 -0
  75. package/dist/index-k6CfLgeq.js.map +1 -0
  76. package/dist/index.js +4 -1
  77. package/dist/index.js.map +1 -1
  78. package/dist/services/compiler.js +329 -0
  79. package/dist/services/compiler.js.map +1 -0
  80. package/dist/services/known-modules.js +123 -0
  81. package/dist/services/known-modules.js.map +1 -0
  82. package/dist/setup.js +15 -0
  83. package/dist/setup.js.map +1 -0
  84. package/dist/test-support.js +33 -0
  85. package/dist/test-support.js.map +1 -0
  86. package/package.json +117 -138
  87. package/src/compile/Compiled.ts +45 -0
  88. package/src/compile/compile.ts +89 -0
  89. package/src/compile/state.ts +88 -0
  90. package/src/compile/types.ts +14 -13
  91. package/src/index.ts +6 -2
  92. package/src/services/compiler.ts +401 -0
  93. package/src/services/known-modules.ts +130 -0
  94. package/src/setup.ts +26 -0
  95. package/src/test-support.ts +64 -0
  96. package/addon-main.cjs +0 -5
  97. package/declarations/__PRIVATE__.d.ts +0 -2
  98. package/declarations/__PRIVATE__.d.ts.map +0 -1
  99. package/declarations/compile/formats/gjs/babel.d.ts +0 -7
  100. package/declarations/compile/formats/gjs/babel.d.ts.map +0 -1
  101. package/declarations/compile/formats/gjs/eval.d.ts +0 -8
  102. package/declarations/compile/formats/gjs/eval.d.ts.map +0 -1
  103. package/declarations/compile/formats/gjs/index.d.ts +0 -24
  104. package/declarations/compile/formats/gjs/index.d.ts.map +0 -1
  105. package/declarations/compile/formats/gjs/known-modules.d.ts +0 -48
  106. package/declarations/compile/formats/gjs/known-modules.d.ts.map +0 -1
  107. package/declarations/compile/formats/hbs.d.ts +0 -17
  108. package/declarations/compile/formats/hbs.d.ts.map +0 -1
  109. package/declarations/compile/formats/markdown.d.ts +0 -22
  110. package/declarations/compile/formats/markdown.d.ts.map +0 -1
  111. package/declarations/compile/formats.d.ts +0 -17
  112. package/declarations/compile/formats.d.ts.map +0 -1
  113. package/declarations/compile/index.d.ts +0 -80
  114. package/declarations/compile/index.d.ts.map +0 -1
  115. package/declarations/test-support/index.d.ts +0 -2
  116. package/declarations/test-support/index.d.ts.map +0 -1
  117. package/dist/__PRIVATE__.js +0 -2
  118. package/dist/__PRIVATE__.js.map +0 -1
  119. package/dist/compile/formats/gjs/babel.js +0 -2
  120. package/dist/compile/formats/gjs/babel.js.map +0 -1
  121. package/dist/compile/formats/gjs/eval.js +0 -19
  122. package/dist/compile/formats/gjs/eval.js.map +0 -1
  123. package/dist/compile/formats/gjs/index.js +0 -122
  124. package/dist/compile/formats/gjs/index.js.map +0 -1
  125. package/dist/compile/formats/gjs/known-modules.js +0 -52
  126. package/dist/compile/formats/gjs/known-modules.js.map +0 -1
  127. package/dist/compile/formats/hbs.js +0 -93
  128. package/dist/compile/formats/hbs.js.map +0 -1
  129. package/dist/compile/formats/markdown.js +0 -266
  130. package/dist/compile/formats/markdown.js.map +0 -1
  131. package/dist/compile/formats.js +0 -173
  132. package/dist/compile/formats.js.map +0 -1
  133. package/dist/compile/index.js +0 -113
  134. package/dist/compile/index.js.map +0 -1
  135. package/dist/test-support/index.js +0 -8
  136. package/dist/test-support/index.js.map +0 -1
  137. package/src/__PRIVATE__.ts +0 -1
  138. package/src/compile/formats/gjs/babel.ts +0 -7
  139. package/src/compile/formats/gjs/eval.ts +0 -29
  140. package/src/compile/formats/gjs/index.ts +0 -153
  141. package/src/compile/formats/gjs/known-modules.ts +0 -49
  142. package/src/compile/formats/hbs.ts +0 -100
  143. package/src/compile/formats/markdown.ts +0 -345
  144. package/src/compile/formats.ts +0 -178
  145. package/src/compile/index.ts +0 -219
  146. 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
+ }
@@ -1,26 +1,27 @@
1
1
  import type { ComponentLike } from '@glint/template';
2
- import type { Pluggable } from 'unified';
3
2
 
4
- export interface EvalImportMap {
5
- [moduleName: string]: ScopeMap;
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 type UnifiedPlugin = Pluggable;
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, Compiled } from './compile/index.ts';
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 { CompileResult, EvalImportMap, ScopeMap, UnifiedPlugin } from './compile/types';
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
+ }