ember-repl 3.0.0-beta.0 → 3.0.0-beta.2

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 (38) hide show
  1. package/README.md +176 -42
  2. package/dist/browser/compile/formats.d.ts +16 -0
  3. package/dist/browser/compile/formats.js +170 -0
  4. package/dist/browser/compile/formats.js.map +1 -0
  5. package/dist/browser/compile/index.d.ts +33 -0
  6. package/dist/browser/compile/index.js +90 -0
  7. package/dist/browser/compile/index.js.map +1 -0
  8. package/dist/browser/compile/markdown-to-ember.d.ts +18 -0
  9. package/dist/browser/compile/markdown-to-ember.js +237 -0
  10. package/dist/browser/compile/markdown-to-ember.js.map +1 -0
  11. package/dist/browser/compile/types.d.ts +7 -0
  12. package/dist/browser/compile/types.js +2 -0
  13. package/dist/browser/compile/types.js.map +1 -0
  14. package/dist/browser/eti/preprocess.js +0 -1
  15. package/dist/browser/eti/preprocess.js.map +1 -1
  16. package/dist/browser/hbs.d.ts +5 -2
  17. package/dist/browser/hbs.js +2 -5
  18. package/dist/browser/hbs.js.map +1 -1
  19. package/dist/browser/index.d.ts +1 -0
  20. package/dist/browser/index.js +1 -0
  21. package/dist/browser/index.js.map +1 -1
  22. package/dist/browser/known-modules.d.ts +0 -2
  23. package/dist/browser/known-modules.js +0 -2
  24. package/dist/browser/known-modules.js.map +1 -1
  25. package/dist/browser/types.d.ts +4 -0
  26. package/dist/test-support/index.d.ts +2 -0
  27. package/dist/test-support/index.js +8 -0
  28. package/dist/test-support/index.js.map +1 -0
  29. package/package.json +37 -13
  30. package/src/browser/compile/formats.ts +170 -0
  31. package/src/browser/compile/index.ts +132 -0
  32. package/src/browser/compile/markdown-to-ember.ts +318 -0
  33. package/src/browser/compile/types.ts +7 -0
  34. package/src/browser/hbs.ts +7 -7
  35. package/src/browser/index.ts +1 -0
  36. package/src/browser/known-modules.ts +0 -2
  37. package/src/browser/types.ts +4 -0
  38. package/src/test-support/index.ts +5 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-repl",
3
- "version": "3.0.0-beta.0",
3
+ "version": "3.0.0-beta.2",
4
4
  "description": "Addon for enabling REPL and Playground creation with Ember/Glimmer",
5
5
  "keywords": [
6
6
  "ember-addon"
@@ -14,6 +14,12 @@
14
14
  "author": "NullVoxPopuli",
15
15
  "typesVersions": {
16
16
  "*": {
17
+ "test-support": [
18
+ "dist/test-support/index.d.ts"
19
+ ],
20
+ "markdown/parse": [
21
+ "./dist/browser/compile/markdown-to-ember.d.ts"
22
+ ],
17
23
  "*": [
18
24
  "dist/browser/*",
19
25
  "dist/browser/*/index.d.ts"
@@ -23,9 +29,11 @@
23
29
  "exports": {
24
30
  ".": "./dist/browser/index.js",
25
31
  "./esm": "./dist/browser/esm/index.js",
32
+ "./markdown/parse": "./dist/browser/compile/markdown-to-ember.js",
26
33
  "./ember-cli": {
27
34
  "require": "./src/build/ember-cli.cjs"
28
35
  },
36
+ "./test-support": "./dist/test-support/index.js",
29
37
  "./addon-main.js": "./addon-main.cjs"
30
38
  },
31
39
  "files": [
@@ -36,24 +44,32 @@
36
44
  "dependencies": {
37
45
  "@babel/helper-plugin-utils": "^7.21.5",
38
46
  "@babel/standalone": "^7.21.8",
39
- "@embroider/addon-shim": "^1.8.4",
40
- "@embroider/macros": "^1.10.0",
47
+ "@embroider/addon-shim": "1.8.5",
48
+ "@embroider/macros": "1.11.0",
41
49
  "babel-import-util": "^1.3.0",
42
- "babel-plugin-ember-template-compilation": "^2.0.2",
50
+ "babel-plugin-ember-template-compilation": "^2.0.3",
43
51
  "broccoli-file-creator": "^2.1.1",
44
52
  "change-case": "^4.1.2",
45
53
  "common-tags": "^1.8.2",
46
54
  "line-column": "^1.0.2",
47
55
  "magic-string": "^0.30.0",
56
+ "mdast": "^3.0.0",
48
57
  "parse-static-imports": "^1.1.0",
49
- "uuid": "^9.0.0"
58
+ "rehype-raw": "^6.1.1",
59
+ "rehype-stringify": "^9.0.3",
60
+ "remark-parse": "^10.0.2",
61
+ "remark-rehype": "^10.1.0",
62
+ "unified": "^10.1.2",
63
+ "unist-util-visit": "^4.1.2",
64
+ "uuid": "^9.0.0",
65
+ "vfile": "^5.3.7"
50
66
  },
51
67
  "devDependencies": {
52
68
  "@babel/core": "^7.21.8",
53
69
  "@babel/types": "^7.21.5",
54
70
  "@ember/test-helpers": "^2.9.3",
55
71
  "@ember/test-waiters": "^3.0.2",
56
- "@embroider/addon-dev": "^3.0.0",
72
+ "@embroider/addon-dev": "3.1.0",
57
73
  "@glimmer/compiler": "^0.84.3",
58
74
  "@glimmer/component": "^1.1.2",
59
75
  "@glimmer/interfaces": "^0.84.3",
@@ -71,20 +87,25 @@
71
87
  "@types/babel__core": "^7.20.0",
72
88
  "@types/babel__standalone": "^7.1.4",
73
89
  "@types/babel__traverse": "^7.18.5",
90
+ "@types/hast": "^2.3.4",
91
+ "@types/mdast": "^3.0.11",
92
+ "@types/unist": "^2.0.6",
74
93
  "@types/uuid": "^9.0.1",
75
- "@typescript-eslint/eslint-plugin": "^5.59.2",
76
- "@typescript-eslint/parser": "^5.59.2",
94
+ "@typescript-eslint/eslint-plugin": "^5.59.6",
95
+ "@typescript-eslint/parser": "^5.59.6",
77
96
  "concurrently": "^8.0.1",
78
- "ember-source": "^4.12.0",
97
+ "ember-resources": "^6.1.0",
98
+ "ember-source": "^5.0.0",
79
99
  "ember-template-imports": "^3.4.2",
80
100
  "ember-template-lint": "^5.7.3",
81
- "eslint": "^8.40.0",
82
- "eslint-plugin-ember": "^11.5.2",
101
+ "eslint": "^8.41.0",
102
+ "eslint-plugin-ember": "^11.7.1",
83
103
  "eslint-plugin-node": "^11.1.0",
84
104
  "eslint-plugin-prettier": "^4.2.1",
85
105
  "prettier": "^2.8.8",
86
106
  "prettier-plugin-ember-template-tag": "^0.3.2",
87
- "rollup": "^3.21.6",
107
+ "publint": "^0.1.12",
108
+ "rollup": "~3.21.0",
88
109
  "rollup-plugin-copy": "^3.4.0",
89
110
  "rollup-plugin-glimmer-template-tag": "^0.4.1",
90
111
  "rollup-plugin-ts": "^3.2.0",
@@ -107,7 +128,9 @@
107
128
  "@glimmer/compiler": "^0.84.3",
108
129
  "@glimmer/component": "^1.1.2",
109
130
  "@glimmer/syntax": "^0.84.3",
110
- "ember-source": "^4.12.0"
131
+ "@glint/template": "^1.0.2",
132
+ "ember-resources": "^6.1.0",
133
+ "ember-source": "^5.0.0"
111
134
  },
112
135
  "scripts": {
113
136
  "build": "rollup --config",
@@ -115,6 +138,7 @@
115
138
  "lint:fix": "pnpm -w exec lint fix",
116
139
  "start": "rollup --config --watch",
117
140
  "lint": "pnpm -w exec lint",
141
+ "lint:package": "pnpm publint",
118
142
  "lint:js": "pnpm -w exec lint js",
119
143
  "lint:js:fix": "pnpm -w exec lint js:fix",
120
144
  "lint:hbs": "pnpm -w exec lint hbs",
@@ -0,0 +1,170 @@
1
+ import { invocationName } from '../utils';
2
+
3
+ import type { CompileResult } from '../types';
4
+ import type { ExtractedCode } from './markdown-to-ember';
5
+ import type { EvalImportMap, ScopeMap } from './types';
6
+
7
+ async function compileAll(js: { code: string }[], importMap?: EvalImportMap) {
8
+ let modules = await Promise.all(
9
+ js.map(async ({ code }) => {
10
+ return await compileGJS(code, importMap);
11
+ })
12
+ );
13
+
14
+ return modules;
15
+ }
16
+
17
+ export async function compileGJS(
18
+ gjsInput: string,
19
+ importMap?: EvalImportMap
20
+ ): Promise<CompileResult> {
21
+ try {
22
+ let { compileJS } = await import('../js');
23
+
24
+ return await compileJS(gjsInput, importMap);
25
+ } catch (error) {
26
+ return { error: error as Error, name: 'unknown' };
27
+ }
28
+ }
29
+
30
+ export async function compileHBS(
31
+ hbsInput: string,
32
+ options?: {
33
+ moduleName?: string;
34
+ scope?: Record<string, unknown>;
35
+ }
36
+ ): Promise<CompileResult> {
37
+ try {
38
+ let { compileHBS } = await import('../hbs');
39
+
40
+ return compileHBS(hbsInput, options);
41
+ } catch (error) {
42
+ return { error: error as Error, name: 'unknown' };
43
+ }
44
+ }
45
+
46
+ async function extractScope(
47
+ liveCode: ExtractedCode[],
48
+ importMap?: EvalImportMap
49
+ ): Promise<CompileResult[]> {
50
+ let scope: CompileResult[] = [];
51
+
52
+ let hbs = liveCode.filter((code) => code.lang === 'hbs');
53
+ let js = liveCode.filter((code) => ['js', 'gjs'].includes(code.lang));
54
+
55
+ if (js.length > 0) {
56
+ let compiled = await compileAll(js, importMap);
57
+
58
+ await Promise.all(
59
+ compiled.map(async (info) => {
60
+ // using web worker + import maps is not available yet (need firefox support)
61
+ // (and to somehow be able to point at npm)
62
+ //
63
+ // if ('importPath' in info) {
64
+ // return scope.push({
65
+ // moduleName: name,
66
+ // component: await import(/* webpackIgnore: true */ info.importPath),
67
+ // });
68
+ // }
69
+
70
+ return scope.push(info);
71
+ })
72
+ );
73
+ }
74
+
75
+ for (let { code } of hbs) {
76
+ let compiled = await compileHBS(code);
77
+
78
+ scope.push(compiled);
79
+ }
80
+
81
+ return scope;
82
+ }
83
+
84
+ export async function compileMD(
85
+ glimdownInput: string,
86
+ options?: {
87
+ importMap?: EvalImportMap;
88
+ topLevelScope?: ScopeMap;
89
+ CopyComponent?: string;
90
+ ShadowComponent?: string;
91
+ }
92
+ ): Promise<CompileResult & { rootTemplate?: string }> {
93
+ let importMap = options?.importMap;
94
+ let topLevelScope = options?.topLevelScope ?? {};
95
+ let rootTemplate: string;
96
+ let liveCode: ExtractedCode[];
97
+ let scope: CompileResult[] = [];
98
+
99
+ /**
100
+ * Step 1: Convert Markdown To HTML (Ember).
101
+ *
102
+ * The remark plugin, remark-code-extra also extracts
103
+ * and transforms the code blocks we care about.
104
+ *
105
+ * These blocks will be compiled through babel and eval'd so the
106
+ * compiled rootTemplate can invoke them
107
+ */
108
+ try {
109
+ let { parseMarkdown } = await import('./markdown-to-ember');
110
+ let { templateOnlyGlimdown, blocks } = await parseMarkdown(glimdownInput, {
111
+ CopyComponent: options?.CopyComponent,
112
+ ShadowComponent: options?.ShadowComponent,
113
+ });
114
+
115
+ rootTemplate = templateOnlyGlimdown;
116
+ liveCode = blocks;
117
+ } catch (error) {
118
+ return { error: error as Error, name: 'unknown' };
119
+ }
120
+
121
+ /**
122
+ * Step 2: Compile the live code samples
123
+ */
124
+ if (liveCode.length > 0) {
125
+ try {
126
+ scope = await extractScope(liveCode, importMap);
127
+ } catch (error) {
128
+ console.info({ scope });
129
+ console.error(error);
130
+
131
+ return { error: error as Error, rootTemplate, name: 'unknown' };
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Make sure non of our snippets errored
137
+ *
138
+ * TODO: for these errors, report them differently so that we
139
+ * can render the 'Ember' and still highlight the correct line?
140
+ * or maybe there is a way to highlight in the editor instead?
141
+ */
142
+ for (let { error, component } of scope) {
143
+ if (!component) {
144
+ if (error) {
145
+ return { error, rootTemplate, name: 'unknown' };
146
+ }
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Step 4: Compile the Ember Template
152
+ */
153
+ try {
154
+ let localScope = scope.reduce((accum, { component, name }) => {
155
+ accum[invocationName(name)] = component;
156
+
157
+ return accum;
158
+ }, {} as Record<string, unknown>);
159
+
160
+ return await compileHBS(rootTemplate, {
161
+ moduleName: 'DynamicRootTemplate',
162
+ scope: {
163
+ ...topLevelScope,
164
+ ...localScope,
165
+ },
166
+ });
167
+ } catch (error) {
168
+ return { error: error as Error, rootTemplate, name: 'unknown' };
169
+ }
170
+ }
@@ -0,0 +1,132 @@
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
+ ShadowComponent?: string;
39
+ topLevelScope?: ScopeMap;
40
+ }
41
+ ) {
42
+ let id = nameFor(text);
43
+
44
+ let existing = CACHE.get(id);
45
+
46
+ if (existing) {
47
+ onSuccess(existing);
48
+
49
+ return;
50
+ }
51
+
52
+ if (!SUPPORTED_FORMATS.includes(format)) {
53
+ await onError(`Unsupported format: ${format}. Supported formats: ${SUPPORTED_FORMATS}`);
54
+
55
+ return;
56
+ }
57
+
58
+ await onCompileStart();
59
+
60
+ if (!text) {
61
+ await onError('No Input Document yet');
62
+
63
+ return;
64
+ }
65
+
66
+ let result: CompileResult;
67
+
68
+ if (format === 'glimdown') {
69
+ result = await processMD(text, options);
70
+ } else if (format === 'gjs') {
71
+ result = await processGJS(text, options.importMap);
72
+ } else if (format === 'hbs') {
73
+ result = await processHBS(text, {
74
+ scope: options.topLevelScope,
75
+ });
76
+ } else {
77
+ await onError(`Unsupported format: ${format}. Supported formats: ${SUPPORTED_FORMATS}`);
78
+
79
+ return;
80
+ }
81
+
82
+ if (result.error) {
83
+ await onError(result.error.message || `${result.error}`);
84
+
85
+ return;
86
+ }
87
+
88
+ CACHE.set(id, result.component as ComponentLike);
89
+
90
+ await onSuccess(result.component as ComponentLike);
91
+ }
92
+
93
+ type Input = string | undefined | null;
94
+
95
+ /**
96
+ * By default, this compiles to `glimdown`. A Markdown format which
97
+ * extracts `live` tagged code snippets and compiles them to components.
98
+ */
99
+ export const Compiled = resourceFactory(
100
+ (markdownText: Input | (() => Input), format?: Format | (() => Format)) => {
101
+ return resource(() => {
102
+ let _format: Format = (typeof format === 'function' ? format() : format) || 'glimdown';
103
+ let input = typeof markdownText === 'function' ? markdownText() : markdownText;
104
+ let ready = cell(false);
105
+ let error = cell();
106
+ let result = cell<ComponentLike>();
107
+
108
+ if (input) {
109
+ compile(input, {
110
+ format: _format,
111
+ onSuccess: async (component) => {
112
+ result.current = component;
113
+ ready.set(true);
114
+ error.set(null);
115
+ },
116
+ onError: async (e) => {
117
+ error.set(e);
118
+ },
119
+ onCompileStart: async () => {
120
+ ready.set(false);
121
+ },
122
+ });
123
+ }
124
+
125
+ return () => ({
126
+ isReady: ready.current,
127
+ error: error.current,
128
+ component: result.current,
129
+ });
130
+ });
131
+ }
132
+ );