ember-repl 2.0.63 → 3.0.0-beta.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 (108) hide show
  1. package/README.md +200 -35
  2. package/addon-main.cjs +5 -0
  3. package/dist/browser/cjs/eval.d.ts +10 -0
  4. package/dist/browser/cjs/eval.d.ts.map +1 -0
  5. package/dist/browser/cjs/eval.js +22 -0
  6. package/dist/browser/cjs/eval.js.map +1 -0
  7. package/dist/browser/cjs/index.d.ts +7 -0
  8. package/dist/browser/cjs/index.js +43 -0
  9. package/dist/browser/cjs/index.js.map +1 -0
  10. package/dist/browser/compile/formats.d.ts +15 -0
  11. package/dist/browser/compile/formats.js +169 -0
  12. package/dist/browser/compile/formats.js.map +1 -0
  13. package/dist/browser/compile/index.d.ts +32 -0
  14. package/dist/browser/compile/index.js +90 -0
  15. package/dist/browser/compile/index.js.map +1 -0
  16. package/dist/browser/compile/markdown-to-ember.d.ts +18 -0
  17. package/dist/browser/compile/markdown-to-ember.js +237 -0
  18. package/dist/browser/compile/markdown-to-ember.js.map +1 -0
  19. package/dist/browser/compile/types.d.ts +7 -0
  20. package/dist/browser/compile/types.js +2 -0
  21. package/dist/browser/compile/types.js.map +1 -0
  22. package/dist/browser/esm/index.d.ts +8 -0
  23. package/dist/browser/esm/index.js +67 -0
  24. package/dist/browser/esm/index.js.map +1 -0
  25. package/dist/browser/eti/babel-plugin.d.ts +54 -0
  26. package/dist/browser/eti/babel-plugin.js +95 -0
  27. package/dist/browser/eti/babel-plugin.js.map +1 -0
  28. package/dist/browser/eti/debug.d.ts +2 -0
  29. package/dist/browser/eti/debug.js +9 -0
  30. package/dist/browser/eti/debug.js.map +1 -0
  31. package/dist/browser/eti/parse-templates.d.ts +56 -0
  32. package/dist/browser/eti/parse-templates.js +181 -0
  33. package/dist/browser/eti/parse-templates.js.map +1 -0
  34. package/dist/browser/eti/preprocess.d.ts +57 -0
  35. package/dist/browser/eti/preprocess.js +270 -0
  36. package/dist/browser/eti/preprocess.js.map +1 -0
  37. package/dist/browser/eti/template-tag-transform.d.ts +15 -0
  38. package/dist/browser/eti/template-tag-transform.js +46 -0
  39. package/dist/browser/eti/template-tag-transform.js.map +1 -0
  40. package/dist/browser/eti/util.d.ts +14 -0
  41. package/dist/browser/eti/util.js +39 -0
  42. package/dist/browser/eti/util.js.map +1 -0
  43. package/dist/browser/gjs.d.ts +4 -0
  44. package/dist/browser/gjs.js +40 -0
  45. package/dist/browser/gjs.js.map +1 -0
  46. package/{hbs.d.ts → dist/browser/hbs.d.ts} +7 -7
  47. package/dist/browser/hbs.js +91 -0
  48. package/dist/browser/hbs.js.map +1 -0
  49. package/dist/browser/index.d.ts +6 -0
  50. package/dist/browser/index.js +6 -0
  51. package/dist/browser/index.js.map +1 -0
  52. package/{js.d.ts → dist/browser/js.d.ts} +3 -6
  53. package/dist/browser/js.js +38 -0
  54. package/dist/browser/js.js.map +1 -0
  55. package/{known-modules.d.ts → dist/browser/known-modules.d.ts} +6 -5
  56. package/dist/browser/known-modules.js +46 -0
  57. package/dist/browser/known-modules.js.map +1 -0
  58. package/dist/browser/types.d.ts +21 -0
  59. package/dist/browser/types.js +2 -0
  60. package/dist/browser/types.js.map +1 -0
  61. package/{utils.d.ts → dist/browser/utils.d.ts} +8 -3
  62. package/dist/browser/utils.js +46 -0
  63. package/dist/browser/utils.js.map +1 -0
  64. package/dist/build/ember-cli.cjs +36 -0
  65. package/dist/test-support/index.d.ts +2 -0
  66. package/dist/test-support/index.js +8 -0
  67. package/dist/test-support/index.js.map +1 -0
  68. package/package.json +122 -125
  69. package/{addon → src/browser}/cjs/eval.ts +9 -5
  70. package/src/browser/cjs/index.ts +44 -0
  71. package/src/browser/compile/formats.ts +168 -0
  72. package/src/browser/compile/index.ts +131 -0
  73. package/src/browser/compile/markdown-to-ember.ts +318 -0
  74. package/src/browser/compile/types.ts +7 -0
  75. package/src/browser/esm/index.ts +80 -0
  76. package/src/browser/eti/babel-plugin.ts +105 -0
  77. package/src/browser/eti/debug.ts +7 -0
  78. package/src/browser/eti/parse-templates.ts +284 -0
  79. package/src/browser/eti/preprocess.ts +187 -0
  80. package/src/browser/eti/template-tag-transform.ts +100 -0
  81. package/src/browser/eti/util.ts +72 -0
  82. package/src/browser/gjs.ts +59 -0
  83. package/{addon → src/browser}/hbs.ts +24 -12
  84. package/{addon → src/browser}/index.ts +1 -0
  85. package/{addon → src/browser}/js.ts +6 -2
  86. package/{addon → src/browser}/known-modules.ts +4 -2
  87. package/{addon → src/browser}/types.ts +6 -1
  88. package/{addon → src/browser}/utils.ts +6 -2
  89. package/src/build/ember-cli.cjs +36 -0
  90. package/src/test-support/index.ts +5 -0
  91. package/.github/renovate.json5 +0 -93
  92. package/.github/workflows/ci.yml +0 -120
  93. package/.github/workflows/lint.yml +0 -88
  94. package/.github/workflows/types.yml +0 -30
  95. package/CHANGELOG.md +0 -745
  96. package/addon/cjs/index.ts +0 -100
  97. package/addon/esm/index.ts +0 -131
  98. package/cjs/eval.d.ts +0 -8
  99. package/cjs/index.d.ts +0 -10
  100. package/config/environment.js +0 -5
  101. package/esm/index.d.ts +0 -11
  102. package/index.d.ts +0 -5
  103. package/index.js +0 -105
  104. package/tsconfig.json +0 -56
  105. package/types/dummy/index.d.ts +0 -1
  106. package/types/global.d.ts +0 -43
  107. package/types/overrides.d.ts +0 -18
  108. package/types.d.ts +0 -15
@@ -0,0 +1,131 @@
1
+ import { cell, resource, resourceFactory } from 'ember-resources';
2
+
3
+ import { nameFor } from '../utils';
4
+ import {
5
+ compileGJS as processGJS,
6
+ compileHBS as processHBS,
7
+ compileMD as processMD,
8
+ } from './formats';
9
+
10
+ import type { CompileResult } from '../types';
11
+ import type { EvalImportMap, ScopeMap } from './types';
12
+ import type { ComponentLike } from '@glint/template';
13
+ type Format = 'glimdown' | 'gjs' | 'hbs';
14
+
15
+ export const CACHE = new Map<string, ComponentLike>();
16
+
17
+ const SUPPORTED_FORMATS = ['glimdown', 'gjs', 'hbs'];
18
+
19
+ /**
20
+ * This compileMD is a more robust version of the raw compiling used in "formats".
21
+ * This function manages cache, and has events for folks building UIs to hook in to
22
+ */
23
+ export async function compile(
24
+ text: string,
25
+ {
26
+ format,
27
+ onSuccess,
28
+ onError,
29
+ onCompileStart,
30
+ ...options
31
+ }: {
32
+ format: Format;
33
+ onSuccess: (component: ComponentLike) => Promise<unknown> | unknown;
34
+ onError: (error: string) => Promise<unknown> | unknown;
35
+ onCompileStart: () => Promise<unknown> | unknown;
36
+ importMap?: EvalImportMap;
37
+ CopyComponent?: string;
38
+ topLevelScope?: ScopeMap;
39
+ }
40
+ ) {
41
+ let id = nameFor(text);
42
+
43
+ let existing = CACHE.get(id);
44
+
45
+ if (existing) {
46
+ onSuccess(existing);
47
+
48
+ return;
49
+ }
50
+
51
+ if (!SUPPORTED_FORMATS.includes(format)) {
52
+ await onError(`Unsupported format: ${format}. Supported formats: ${SUPPORTED_FORMATS}`);
53
+
54
+ return;
55
+ }
56
+
57
+ await onCompileStart();
58
+
59
+ if (!text) {
60
+ await onError('No Input Document yet');
61
+
62
+ return;
63
+ }
64
+
65
+ let result: CompileResult;
66
+
67
+ if (format === 'glimdown') {
68
+ result = await processMD(text, options);
69
+ } else if (format === 'gjs') {
70
+ result = await processGJS(text, options.importMap);
71
+ } else if (format === 'hbs') {
72
+ result = await processHBS(text, {
73
+ scope: options.topLevelScope,
74
+ });
75
+ } else {
76
+ await onError(`Unsupported format: ${format}. Supported formats: ${SUPPORTED_FORMATS}`);
77
+
78
+ return;
79
+ }
80
+
81
+ if (result.error) {
82
+ await onError(result.error.message || `${result.error}`);
83
+
84
+ return;
85
+ }
86
+
87
+ CACHE.set(id, result.component as ComponentLike);
88
+
89
+ await onSuccess(result.component as ComponentLike);
90
+ }
91
+
92
+ type Input = string | undefined | null;
93
+
94
+ /**
95
+ * By default, this compiles to `glimdown`. A Markdown format which
96
+ * extracts `live` tagged code snippets and compiles them to components.
97
+ */
98
+ export const Compiled = resourceFactory(
99
+ (markdownText: Input | (() => Input), format?: Format | (() => Format)) => {
100
+ return resource(() => {
101
+ let _format: Format = (typeof format === 'function' ? format() : format) || 'glimdown';
102
+ let input = typeof markdownText === 'function' ? markdownText() : markdownText;
103
+ let ready = cell(false);
104
+ let error = cell();
105
+ let result = cell<ComponentLike>();
106
+
107
+ if (input) {
108
+ compile(input, {
109
+ format: _format,
110
+ onSuccess: async (component) => {
111
+ result.current = component;
112
+ ready.set(true);
113
+ error.set(null);
114
+ },
115
+ onError: async (e) => {
116
+ error.set(e);
117
+ },
118
+ onCompileStart: async () => {
119
+ ready.set(false);
120
+ },
121
+ });
122
+ }
123
+
124
+ return () => ({
125
+ isReady: ready.current,
126
+ error: error.current,
127
+ component: result.current,
128
+ });
129
+ });
130
+ }
131
+ );
@@ -0,0 +1,318 @@
1
+ import rehypeRaw from 'rehype-raw';
2
+ import rehypeStringify from 'rehype-stringify';
3
+ import remarkParse from 'remark-parse';
4
+ import remarkRehype from 'remark-rehype';
5
+ import { unified } from 'unified';
6
+ import { visit } from 'unist-util-visit';
7
+
8
+ import { invocationOf, nameFor } from '../utils';
9
+
10
+ import type { Node } from 'hast';
11
+ import type { Code, Text } from 'mdast';
12
+ import type { Parent } from 'unist';
13
+ import type { VFile } from 'vfile';
14
+
15
+ export interface ExtractedCode {
16
+ name: string;
17
+ code: string;
18
+ lang: string;
19
+ }
20
+
21
+ export interface LiveCodeExtraction {
22
+ templateOnlyGlimdown: string;
23
+ blocks: ExtractedCode[];
24
+ }
25
+ type LiveData = {
26
+ liveCode?: ExtractedCode[];
27
+ };
28
+ type VFileWithMeta = VFile & {
29
+ data: LiveData;
30
+ };
31
+
32
+ interface Options {
33
+ snippets?: {
34
+ classList?: string[];
35
+ };
36
+ demo?: {
37
+ classList?: string[];
38
+ };
39
+ copyComponent?: string;
40
+ shadowComponent?: string;
41
+ }
42
+
43
+ const GLIMDOWN_PREVIEW = Symbol('__GLIMDOWN_PREVIEW__');
44
+ const GLIMDOWN_RENDER = Symbol('__GLIMDOWN_RENDER__');
45
+ const ALLOWED_LANGUAGES = ['gjs', 'hbs'] as const;
46
+
47
+ type AllowedLanguage = (typeof ALLOWED_LANGUAGES)[number];
48
+ type RelevantCode = Omit<Code, 'lang'> & { lang: AllowedLanguage };
49
+
50
+ const escapeCurlies = (node: Text | Parent) => {
51
+ if ('value' in node && node.value) {
52
+ node.value = node.value.replace(/{{/g, '\\{{');
53
+ }
54
+
55
+ if ('children' in node && node.children) {
56
+ node.children.forEach((child) => escapeCurlies(child as Parent));
57
+ }
58
+
59
+ if (!node.data) {
60
+ return;
61
+ }
62
+
63
+ if ('hChildren' in node.data && Array.isArray(node.data['hChildren'])) {
64
+ node.data['hChildren'].forEach(escapeCurlies);
65
+
66
+ return;
67
+ }
68
+ };
69
+
70
+ function isLive(meta: string) {
71
+ return meta.includes('live');
72
+ }
73
+
74
+ function isPreview(meta: string) {
75
+ return meta.includes('preview');
76
+ }
77
+
78
+ function isBelow(meta: string) {
79
+ return meta.includes('below');
80
+ }
81
+
82
+ // TODO: extract and publish remark plugin
83
+ function liveCodeExtraction(options: Options = {}) {
84
+ let { copyComponent, snippets, demo } = options;
85
+ let { classList: snippetClasses } = snippets || {};
86
+ let { classList: demoClasses } = demo || {};
87
+
88
+ snippetClasses ??= [];
89
+ demoClasses ??= [];
90
+
91
+ function isRelevantCode(node: Code): node is RelevantCode {
92
+ if (node.type !== 'code') return false;
93
+
94
+ let { meta, lang } = node;
95
+
96
+ meta = meta?.trim();
97
+
98
+ if (!meta || !lang) return false;
99
+
100
+ if (!meta.includes('live')) {
101
+ return false;
102
+ }
103
+
104
+ if (!(ALLOWED_LANGUAGES as unknown as string[]).includes(lang)) return false;
105
+
106
+ return true;
107
+ }
108
+
109
+ let copyNode = {
110
+ type: 'html',
111
+ value: copyComponent,
112
+ };
113
+
114
+ function enhance(code: Code) {
115
+ code.data ??= {};
116
+ code.data['hProperties'] ??= {};
117
+ // This is secret-to-us-only API, so we don't really care about the type
118
+ (code.data['hProperties'] as any)[GLIMDOWN_PREVIEW] = true;
119
+
120
+ return {
121
+ data: {
122
+ hProperties: { className: snippetClasses },
123
+ },
124
+ type: 'div',
125
+ hProperties: { className: snippetClasses },
126
+ children: [code, copyNode],
127
+ };
128
+ }
129
+
130
+ function flatReplaceAt<T>(array: T[], index: number, replacement: T[]) {
131
+ array.splice(index, 1, ...replacement);
132
+ }
133
+
134
+ // because we mutate the tree as we iterate,
135
+ // we need to make sure we don't loop forever
136
+ const seen = new Set();
137
+
138
+ return function transformer(tree: Parent, file: VFileWithMeta) {
139
+ visit(tree, ['code'], function (node, index, parent) {
140
+ if (parent === null) return;
141
+ if (index === null) return;
142
+
143
+ if (!isRelevantCode(node as Code)) {
144
+ let enhanced = enhance(node as Code);
145
+
146
+ parent.children[index] = enhanced;
147
+
148
+ return 'skip';
149
+ }
150
+
151
+ if (seen.has(node)) return 'skip';
152
+
153
+ seen.add(node);
154
+
155
+ let { meta, lang, value } = node as Code;
156
+
157
+ if (!meta) return 'skip';
158
+ if (!lang) return 'skip';
159
+
160
+ file.data.liveCode ??= [];
161
+
162
+ let code = value.trim();
163
+ let name = nameFor(code);
164
+ let invocation = invocationOf(name);
165
+
166
+ let shadow = options.shadowComponent;
167
+
168
+ let wrapInShadow = shadow && !meta?.includes('no-shadow');
169
+
170
+ if (wrapInShadow) {
171
+ invocation = `<${shadow}>${invocation}</${shadow}>`;
172
+ }
173
+
174
+ let invokeNode = {
175
+ type: 'html',
176
+ data: {
177
+ hProperties: { [GLIMDOWN_RENDER]: true },
178
+ },
179
+ value: `<div class="${demoClasses}">${invocation}</div>`,
180
+ };
181
+
182
+ let wrapper = enhance(node as Code);
183
+
184
+ file.data.liveCode.push({
185
+ lang,
186
+ name,
187
+ code,
188
+ });
189
+
190
+ let live = isLive(meta);
191
+ let preview = isPreview(meta);
192
+ let below = isBelow(meta);
193
+
194
+ if (live && preview && below) {
195
+ flatReplaceAt(parent.children, index, [wrapper, invokeNode]);
196
+
197
+ return 'skip';
198
+ }
199
+
200
+ if (live && preview) {
201
+ flatReplaceAt(parent.children, index, [invokeNode, wrapper]);
202
+
203
+ return 'skip';
204
+ }
205
+
206
+ if (live) {
207
+ parent.children[index] = invokeNode;
208
+
209
+ return 'skip';
210
+ }
211
+
212
+ parent.children[index] = wrapper;
213
+
214
+ return;
215
+ });
216
+ };
217
+ }
218
+
219
+ function buildCompiler(options: ParseMarkdownOptions) {
220
+ return (
221
+ unified()
222
+ // .use(markdown)
223
+ .use(remarkParse)
224
+ // TODO: we only want to do this when we have pre > code.
225
+ // code can exist inline.
226
+ .use(liveCodeExtraction, {
227
+ snippets: {
228
+ classList: ['glimdown-snippet', 'relative'],
229
+ },
230
+ demo: {
231
+ classList: ['glimdown-render'],
232
+ },
233
+ copyComponent: options?.CopyComponent,
234
+ shadowComponent: options?.ShadowComponent,
235
+ })
236
+ // .use(() => (tree) => visit(tree, (node) => console.log('i', node)))
237
+ // remark rehype is needed to convert markdown to HTML
238
+ // However, it also changes all the nodes, so we need another pass
239
+ // to make sure our Glimmer-aware nodes are in tact
240
+ .use(remarkRehype, { allowDangerousHtml: true })
241
+ // Convert invocables to raw format, so Glimmer can invoke them
242
+ .use(() => (tree: Node) => {
243
+ visit(tree, function (node) {
244
+ // We rely on an implicit transformation of data.hProperties => properties
245
+ let properties = (node as any).properties;
246
+
247
+ if (properties?.[GLIMDOWN_PREVIEW]) {
248
+ // Have to sanitize anything Glimmer could try to render
249
+ escapeCurlies(node as Parent);
250
+
251
+ return 'skip';
252
+ }
253
+
254
+ if (node.type === 'element' || ('tagName' in node && node.tagName === 'code')) {
255
+ if (properties?.[GLIMDOWN_RENDER]) {
256
+ node.type = 'glimmer_raw';
257
+
258
+ return;
259
+ }
260
+
261
+ escapeCurlies(node as Parent);
262
+
263
+ return 'skip';
264
+ }
265
+
266
+ if (node.type === 'text' || node.type === 'raw') {
267
+ // definitively not the better way, but this is supposed to detect "glimmer" nodes
268
+ if (
269
+ 'value' in node &&
270
+ typeof node.value === 'string' &&
271
+ node.value.match(/<\/?[_A-Z:0-9].*>/g)
272
+ ) {
273
+ node.type = 'glimmer_raw';
274
+ }
275
+
276
+ node.type = 'glimmer_raw';
277
+
278
+ return 'skip';
279
+ }
280
+
281
+ return;
282
+ });
283
+ })
284
+ .use(rehypeRaw, { passThrough: ['glimmer_raw', 'raw'] })
285
+ .use(() => (tree) => {
286
+ visit(tree, 'glimmer_raw', (node: Node) => {
287
+ node.type = 'raw';
288
+ });
289
+ })
290
+ .use(rehypeStringify, {
291
+ collapseEmptyAttributes: true,
292
+ closeSelfClosing: true,
293
+ allowParseErrors: true,
294
+ allowDangerousCharacters: true,
295
+ allowDangerousHtml: true,
296
+ })
297
+ );
298
+ }
299
+
300
+ interface ParseMarkdownOptions {
301
+ CopyComponent?: string;
302
+ ShadowComponent?: string;
303
+ }
304
+
305
+ /**
306
+ * @internal not under semver
307
+ */
308
+ export async function parseMarkdown(
309
+ input: string,
310
+ options: ParseMarkdownOptions = {}
311
+ ): Promise<LiveCodeExtraction> {
312
+ let markdownCompiler = buildCompiler(options);
313
+ let processed = await markdownCompiler.process(input);
314
+ let liveCode = (processed.data as LiveData).liveCode || [];
315
+ let templateOnly = processed.toString();
316
+
317
+ return { templateOnlyGlimdown: templateOnly, blocks: liveCode };
318
+ }
@@ -0,0 +1,7 @@
1
+ export interface EvalImportMap {
2
+ [moduleName: string]: ScopeMap;
3
+ }
4
+
5
+ export interface ScopeMap {
6
+ [localName: string]: unknown;
7
+ }
@@ -0,0 +1,80 @@
1
+ import { preprocess, transform } from '../gjs';
2
+ import { modules } from '../known-modules';
3
+ import { nameFor } from '../utils';
4
+
5
+ import type { CompileResult, ExtraModules } from '../types';
6
+ import type Component from '@glimmer/component';
7
+ import type { ComponentLike } from '@glint/template';
8
+
9
+ export interface Info {
10
+ code: string;
11
+ name: string;
12
+ }
13
+
14
+ export async function compileJS(code: string, extraModules?: ExtraModules): Promise<CompileResult> {
15
+ let name = nameFor(code);
16
+ let component: undefined | ComponentLike;
17
+ let error: undefined | Error;
18
+
19
+ try {
20
+ let compiled = await compileGJS({ code: code, name });
21
+
22
+ if (!compiled) {
23
+ throw new Error(`Compiled output is missing`);
24
+ }
25
+
26
+ // NOTE: we cannot `eval` ESM
27
+ compiled = proxyToSkypack(compiled, extraModules);
28
+ component = (await evalSnippet(compiled)) as unknown as ComponentLike;
29
+ } catch (e) {
30
+ error = e as Error | undefined;
31
+ }
32
+
33
+ return { name, component, error };
34
+ }
35
+
36
+ export function proxyToSkypack(code: string, extraModules?: ExtraModules) {
37
+ let knownModules = [...Object.keys(extraModules || {}), ...Object.keys(modules)];
38
+ let origin = location.origin;
39
+
40
+ let result = code.replaceAll(/from ('|")([^"']+)('|")/g, (_, __, modulePath) => {
41
+ if (knownModules.includes(modulePath)) {
42
+ return `from '${origin}/${modulePath}'`;
43
+ }
44
+
45
+ return `from 'https://cdn.skypack.dev/${modulePath}'`;
46
+ });
47
+
48
+ return result;
49
+ }
50
+
51
+ async function evalSnippet(code: string) {
52
+ let encodedJs = encodeURIComponent(code);
53
+ let result = await import(
54
+ /* webpackIgnore: true */ `data:text/javascript;charset=utf-8,${encodedJs}`
55
+ );
56
+
57
+ if (!result.default) {
58
+ throw new Error(`Expected module to have a default export, found ${Object.keys(result)}`);
59
+ }
60
+
61
+ return result as {
62
+ default: Component;
63
+ services?: { [key: string]: unknown };
64
+ };
65
+ }
66
+
67
+ async function compileGJS({ code: input, name }: Info) {
68
+ let preprocessed = preprocess(input, name);
69
+ let result = await transform(preprocessed, name, {
70
+ modules: false,
71
+ });
72
+
73
+ if (!result) {
74
+ return;
75
+ }
76
+
77
+ let { code } = result;
78
+
79
+ return code;
80
+ }
@@ -0,0 +1,105 @@
1
+ import { ImportUtil } from 'babel-import-util';
2
+
3
+ import { transformTemplateTag } from './template-tag-transform';
4
+ import * as util from './util';
5
+
6
+ import type { NodePath } from '@babel/traverse';
7
+ import type { CallExpression, Class, Program } from '@babel/types';
8
+
9
+ /**
10
+ * This Babel plugin takes parseable code emitted by the string-based
11
+ * preprocessor plugin in this package and converts it into calls to
12
+ * the standardized `precompileTemplate` macro from `@ember/template-compilation`.
13
+ *
14
+ * Its goal is to convert code like this:
15
+ *
16
+ * ```js
17
+ * import { hbs } from 'ember-template-imports';
18
+ *
19
+ * const A = hbs(`A`, {...});
20
+ * const B = [__GLIMMER_TEMPLATE(`B`, {...})];
21
+ * class C {
22
+ * template = hbs(`C`, {...});
23
+ * }
24
+ *
25
+ * [__GLIMMER_TEMPLATE(`default`, {...})];
26
+ *
27
+ * class D {
28
+ * [__GLIMMER_TEMPLATE(`D`, {...})]
29
+ * }
30
+ * ```
31
+ *
32
+ * Into this:
33
+ *
34
+ * ```js
35
+ * import { precompileTemplate } from '@ember/template-compilation';
36
+ * import { setComponentTemplate } from '@ember/component';
37
+ * import templateOnlyComponent from '@ember/component/template-only';
38
+ *
39
+ * const A = setComponentTemplate(
40
+ * precompileTemplate(`A`, {...}),
41
+ * templateOnlyComponent('this-module.js', 'A')
42
+ * );
43
+ * const B = setComponentTemplate(
44
+ * precompileTemplate(`B`, {...}),
45
+ * templateOnlyComponent('this-module.js', 'B')
46
+ * );
47
+ * class C {}
48
+ * setComponentTemplate(precompileTemplate(`C`, {...}), C);
49
+ *
50
+ * export default setComponentTemplate(
51
+ * precompileTemplate(`default`, {...}),
52
+ * templateOnlyComponent('this-module.js', '_thisModule')
53
+ * );
54
+ *
55
+ * class D {}
56
+ * setComponentTemplate(precompileTemplate(`D`, {...}), D);
57
+ * ```
58
+ */
59
+ export default function (babel: any) {
60
+ let t = babel.types;
61
+
62
+ let visitor: any = {
63
+ Program: {
64
+ enter(path: NodePath<Program>, state: any) {
65
+ state.importUtil = new ImportUtil(t, path);
66
+ },
67
+ },
68
+
69
+ // Process class bodies before things like class properties get transformed
70
+ // into imperative constructor code that we can't recognize. Taken directly
71
+ // from babel-plugin-htmlbars-inline-precompile https://git.io/JMi1G
72
+ Class(path: NodePath<Class>, state: any) {
73
+ let bodyPath = path.get('body.body');
74
+
75
+ if (!Array.isArray(bodyPath)) return;
76
+
77
+ bodyPath.forEach((path) => {
78
+ if (path.type !== 'ClassProperty') return;
79
+
80
+ let keyPath = path.get('key');
81
+ let valuePath = path.get('value');
82
+
83
+ if (Array.isArray(keyPath)) return;
84
+
85
+ if (keyPath && visitor[keyPath.type]) {
86
+ visitor[keyPath.type](keyPath, state);
87
+ }
88
+
89
+ if (Array.isArray(valuePath)) return;
90
+
91
+ if (valuePath && visitor[valuePath.type]) {
92
+ visitor[valuePath.type](valuePath, state);
93
+ }
94
+ });
95
+ },
96
+
97
+ CallExpression(path: NodePath<CallExpression>, state: any) {
98
+ if (util.isTemplateTag(path)) {
99
+ transformTemplateTag(t, path, state);
100
+ }
101
+ },
102
+ };
103
+
104
+ return { visitor };
105
+ }
@@ -0,0 +1,7 @@
1
+ export function expect<T>(value: T | null | undefined, message: string): T {
2
+ if (value === undefined || value === null) {
3
+ throw new Error(`LIBRARY BUG: ${message}`);
4
+ }
5
+
6
+ return value;
7
+ }