apprun 3.38.0 → 6.0.0-rc.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/CHANGELOG.md +12 -1
- package/README.md +18 -10
- package/apprun.d.ts +67 -23
- package/dist/apprun-code.js +1 -1
- package/dist/apprun-code.js.map +1 -1
- package/dist/apprun-dev-tools.js +1 -1
- package/dist/apprun-dev-tools.js.map +1 -1
- package/dist/apprun-html.esm.js +7 -7
- package/dist/apprun-html.esm.js.map +1 -1
- package/dist/apprun-html.js +1 -1
- package/dist/apprun-html.js.map +1 -1
- package/dist/apprun-play.js +1 -1
- package/dist/apprun-play.js.map +1 -1
- package/dist/apprun.esm.js +1 -1
- package/dist/apprun.esm.js.map +1 -1
- package/dist/apprun.js +1 -1
- package/dist/apprun.js.map +1 -1
- package/esm/add-components.js +7 -7
- package/esm/add-components.js.map +1 -1
- package/esm/app.js +81 -32
- package/esm/app.js.map +1 -1
- package/esm/apprun-code.js +8 -2
- package/esm/apprun-code.js.map +1 -1
- package/esm/apprun-html.js +14 -9
- package/esm/apprun-html.js.map +1 -1
- package/esm/apprun-play.js +7 -1
- package/esm/apprun-play.js.map +1 -1
- package/esm/apprun.js +38 -19
- package/esm/apprun.js.map +1 -1
- package/esm/component.js +90 -37
- package/esm/component.js.map +1 -1
- package/esm/directive.js +1 -1
- package/esm/directive.js.map +1 -1
- package/esm/router.js +73 -19
- package/esm/router.js.map +1 -1
- package/esm/types.js +2 -1
- package/esm/types.js.map +1 -1
- package/esm/vdom-my.js +52 -52
- package/esm/vdom-my.js.map +1 -1
- package/esm/vdom-to-html.js +8 -1
- package/esm/vdom-to-html.js.map +1 -1
- package/esm/vdom.js +3 -3
- package/esm/vdom.js.map +1 -1
- package/esm/version.js +1 -1
- package/esm/version.js.map +1 -1
- package/esm/web-component.js +23 -6
- package/esm/web-component.js.map +1 -1
- package/jsx-runtime.js +1 -1
- package/jsx-runtime.js.map +1 -1
- package/package.json +62 -2
- package/.clinerules +0 -1
- package/.travis.yml +0 -10
- package/BACKERS.md +0 -8
- package/CNAME +0 -1
- package/WHATSNEW.md +0 -367
- package/ai/apprun-html.prompt.md +0 -290
- package/ai/apprun.prompt.md +0 -602
- package/apprun-book.jpg +0 -0
- package/dist/apprun-dev-tools-tests.js +0 -1
- package/dist/apprun-dev-tools.js.LICENSE.txt +0 -1
- package/dist/apprun-play-html.esm.js +0 -34
- package/dist/apprun-play-html.esm.js.map +0 -1
- package/error.log +0 -0
- package/esm/apprun-play-html.js +0 -210
- package/esm/apprun-play-html.js.map +0 -1
- package/esm/shadow.js +0 -8
- package/esm/shadow.js.map +0 -1
- package/esm/vdom-html.js +0 -22
- package/esm/vdom-html.js.map +0 -1
- package/esm/vdom-my-new.js +0 -327
- package/esm/vdom-my-new.js.map +0 -1
- package/esm/vdom-patch.js +0 -103
- package/esm/vdom-patch.js.map +0 -1
- package/index.html +0 -87
- package/jest.config.js +0 -57
- package/jest.setup.js +0 -73
- package/logo.png +0 -0
- package/react.js +0 -13
- package/rollup.config.js +0 -62
- package/src/add-components.ts +0 -103
- package/src/app.ts +0 -173
- package/src/apprun-code.tsx +0 -177
- package/src/apprun-dev-tools-tests.tsx +0 -101
- package/src/apprun-dev-tools.tsx +0 -307
- package/src/apprun-html.ts +0 -25
- package/src/apprun-play.tsx +0 -249
- package/src/apprun.ts +0 -238
- package/src/component.ts +0 -388
- package/src/createState.ts +0 -11
- package/src/decorator.ts +0 -98
- package/src/directive.ts +0 -303
- package/src/global.d.ts +0 -22
- package/src/router.ts +0 -311
- package/src/shadow.tsx +0 -8
- package/src/tsconfig.json +0 -16
- package/src/type-utils.ts +0 -130
- package/src/types.ts +0 -151
- package/src/vdom-html.ts_ +0 -20
- package/src/vdom-lit-html.ts +0 -67
- package/src/vdom-my-new.ts +0 -311
- package/src/vdom-my-prop-attr.ts +0 -241
- package/src/vdom-my.ts +0 -286
- package/src/vdom-patch.ts +0 -108
- package/src/vdom-to-html.tsx +0 -49
- package/src/vdom.ts +0 -28
- package/src/version.ts +0 -16
- package/src/web-component.ts +0 -154
- package/tsconfig.jest.json +0 -49
- package/tsconfig.json +0 -16
- package/tslint.json +0 -114
- package/typescriptreact.json +0 -87
- package/viewEngine.js +0 -54
- package/webpack.config.cjs +0 -41
package/src/app.ts
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core AppRun application class and singleton instance
|
|
3
|
-
*
|
|
4
|
-
* This file provides:
|
|
5
|
-
* 1. App class - The core event system implementation with pub/sub capabilities
|
|
6
|
-
* - on(): Subscribe to events with options (once, delay, global)
|
|
7
|
-
* - off(): Unsubscribe from events with proper cleanup
|
|
8
|
-
* - run(): Publish events synchronously with error handling
|
|
9
|
-
* - runAsync(): Publish events asynchronously with Promise support, returns handler values
|
|
10
|
-
* - query(): Deprecated alias for runAsync() - use runAsync() instead
|
|
11
|
-
*
|
|
12
|
-
* 2. Default app singleton - Global event bus instance
|
|
13
|
-
* - Created once and reused across the application
|
|
14
|
-
* - Stored in global scope (window/global) with version tracking
|
|
15
|
-
* - Prevents duplicate instances across different versions
|
|
16
|
-
*
|
|
17
|
-
* Features:
|
|
18
|
-
* - Event wildcards support (events ending with '*')
|
|
19
|
-
* - Delayed event execution with timeout management
|
|
20
|
-
* - Once-only event subscriptions
|
|
21
|
-
* - Async event handling with Promise.all
|
|
22
|
-
* - Global event bus shared across components
|
|
23
|
-
* - Memory leak prevention with proper cleanup
|
|
24
|
-
*
|
|
25
|
-
* Type Safety Improvements (v3.35.1):
|
|
26
|
-
* - Added validation for event handler functions
|
|
27
|
-
* - Enhanced error handling in event execution
|
|
28
|
-
* - Improved null checks in delayed event handling
|
|
29
|
-
* - Better error reporting for invalid handlers
|
|
30
|
-
*
|
|
31
|
-
* Usage:
|
|
32
|
-
* ```ts
|
|
33
|
-
* // Subscribe to events
|
|
34
|
-
* app.on('event-name', (state, ...args) => {
|
|
35
|
-
* // Handle event
|
|
36
|
-
* });
|
|
37
|
-
*
|
|
38
|
-
* // Publish events (fire-and-forget)
|
|
39
|
-
* app.run('event-name', ...args);
|
|
40
|
-
*
|
|
41
|
-
* // Get return values from event handlers
|
|
42
|
-
* app.runAsync('event-name', data).then(results => {
|
|
43
|
-
* // Handle results array
|
|
44
|
-
* });
|
|
45
|
-
* ```
|
|
46
|
-
*/
|
|
47
|
-
|
|
48
|
-
import { EventOptions } from './types'
|
|
49
|
-
import { APPRUN_VERSION_GLOBAL } from './version'
|
|
50
|
-
|
|
51
|
-
export class App {
|
|
52
|
-
|
|
53
|
-
_events: { [key: string]: Array<{ fn: (...args: any[]) => any, options: EventOptions }> };
|
|
54
|
-
|
|
55
|
-
constructor() {
|
|
56
|
-
this._events = {} as { [key: string]: Array<{ fn: (...args: any[]) => any, options: EventOptions }> };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
on(name: string, fn: (...args: any[]) => any, options: EventOptions = {}): void {
|
|
60
|
-
this._events[name] = this._events[name] || [];
|
|
61
|
-
this._events[name].push({ fn, options });
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
off(name: string, fn: (...args: any[]) => any): void {
|
|
65
|
-
const subscribers = this._events[name] || [];
|
|
66
|
-
|
|
67
|
-
this._events[name] = subscribers.filter((sub) => sub.fn !== fn);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
find(name: string): any {
|
|
71
|
-
return this._events[name];
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
run(name: string, ...args: any[]): number {
|
|
75
|
-
const subscribers = this.getSubscribers(name, this._events);
|
|
76
|
-
console.assert(subscribers && subscribers.length > 0, 'No subscriber for event: ' + name);
|
|
77
|
-
subscribers.forEach((sub) => {
|
|
78
|
-
const { fn, options } = sub;
|
|
79
|
-
if (!fn || typeof fn !== 'function') {
|
|
80
|
-
console.error(`AppRun event handler for '${name}' is not a function:`, fn);
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
if (options.delay) {
|
|
84
|
-
this.delay(name, fn, args, options);
|
|
85
|
-
} else {
|
|
86
|
-
try {
|
|
87
|
-
Object.keys(options).length > 0 ? fn.apply(this, [...args, options]) : fn.apply(this, args);
|
|
88
|
-
} catch (error) {
|
|
89
|
-
console.error(`Error in event handler for '${name}':`, error);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return !sub.options.once;
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
return subscribers.length;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
once(name: string, fn: (...args: any[]) => any, options: EventOptions = {}): void {
|
|
99
|
-
this.on(name, fn, { ...options, once: true });
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private delay(name: string, fn: (...args: any[]) => any, args: any[], options: EventOptions): void {
|
|
103
|
-
if (options._t) clearTimeout(options._t);
|
|
104
|
-
options._t = setTimeout(() => {
|
|
105
|
-
clearTimeout(options._t);
|
|
106
|
-
try {
|
|
107
|
-
Object.keys(options).length > 0 ? fn.apply(this, [...args, options]) : fn.apply(this, args);
|
|
108
|
-
} catch (error) {
|
|
109
|
-
console.error(`Error in delayed event handler for '${name}':`, error);
|
|
110
|
-
}
|
|
111
|
-
}, options.delay);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
runAsync(name: string, ...args: any[]): Promise<any[]> {
|
|
115
|
-
const subscribers = this.getSubscribers(name, this._events);
|
|
116
|
-
console.assert(subscribers && subscribers.length > 0, 'No subscriber for event: ' + name);
|
|
117
|
-
const promises = subscribers.map(sub => {
|
|
118
|
-
const { fn, options } = sub;
|
|
119
|
-
if (!fn || typeof fn !== 'function') {
|
|
120
|
-
console.error(`AppRun async event handler for '${name}' is not a function:`, fn);
|
|
121
|
-
return Promise.resolve(null);
|
|
122
|
-
}
|
|
123
|
-
try {
|
|
124
|
-
return Object.keys(options).length > 0 ? fn.apply(this, [...args, options]) : fn.apply(this, args);
|
|
125
|
-
} catch (error) {
|
|
126
|
-
console.error(`Error in async event handler for '${name}':`, error);
|
|
127
|
-
return Promise.reject(error);
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
return Promise.all(promises);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* @deprecated Use runAsync() instead. app.query() will be removed in a future version.
|
|
135
|
-
*/
|
|
136
|
-
query(name: string, ...args: any[]): Promise<any[]> {
|
|
137
|
-
console.warn('app.query() is deprecated. Use app.runAsync() instead.');
|
|
138
|
-
return this.runAsync(name, ...args);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
private getSubscribers(name: string, events: { [key: string]: Array<{ fn: (...args: any[]) => any, options: EventOptions }> }): Array<{ fn: (...args: any[]) => any, options: EventOptions }> {
|
|
142
|
-
const subscribers = events[name] || [];
|
|
143
|
-
|
|
144
|
-
// Update the list of subscribers by pulling out those which will run once.
|
|
145
|
-
// We must do this update prior to running any of the events in case they
|
|
146
|
-
// cause additional events to be turned off or on.
|
|
147
|
-
events[name] = subscribers.filter((sub) => {
|
|
148
|
-
return !sub.options.once;
|
|
149
|
-
});
|
|
150
|
-
Object.keys(events).filter(evt => evt.endsWith('*') && name.startsWith(evt.replace('*', '')))
|
|
151
|
-
.sort((a, b) => b.length - a.length)
|
|
152
|
-
.forEach(evt => subscribers.push(...events[evt].map(sub => ({
|
|
153
|
-
...sub,
|
|
154
|
-
options: { ...sub.options, event: name }
|
|
155
|
-
}))));
|
|
156
|
-
return subscribers;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const AppRunVersions = APPRUN_VERSION_GLOBAL;
|
|
161
|
-
let _app: App;
|
|
162
|
-
const root = (typeof window !== 'undefined' ? window :
|
|
163
|
-
typeof global !== 'undefined' ? global :
|
|
164
|
-
typeof self !== 'undefined' ? self : {}) as any;
|
|
165
|
-
|
|
166
|
-
if (root.app && root._AppRunVersions) {
|
|
167
|
-
_app = root.app;
|
|
168
|
-
} else {
|
|
169
|
-
_app = new App();
|
|
170
|
-
root.app = _app;
|
|
171
|
-
root._AppRunVersions = AppRunVersions;
|
|
172
|
-
}
|
|
173
|
-
export default _app;
|
package/src/apprun-code.tsx
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { app, Component } from './apprun';
|
|
2
|
-
|
|
3
|
-
declare var CodeMirror;
|
|
4
|
-
|
|
5
|
-
const styles = `
|
|
6
|
-
.CodeMirror, .apprun-play iframe {
|
|
7
|
-
height: 100%;
|
|
8
|
-
border: dotted gray 1px;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.apprun-play {
|
|
12
|
-
height: 100%;
|
|
13
|
-
display: flex;
|
|
14
|
-
font-size: 1.1rem;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.apprun-play .col {
|
|
18
|
-
margin: 2px;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.apprun-play .editor, .apprun-play .preview {
|
|
22
|
-
width: 100%;
|
|
23
|
-
height: 100%;
|
|
24
|
-
}
|
|
25
|
-
`;
|
|
26
|
-
|
|
27
|
-
const encodeHTML = code => {
|
|
28
|
-
return code.replace(/&/g, '&')
|
|
29
|
-
.replace(/</g, '<')
|
|
30
|
-
.replace(/>/g, '>')
|
|
31
|
-
.replace(/"/g, '"')
|
|
32
|
-
.replace(/'/g, ''');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const code_html = code => `<!DOCTYPE html>
|
|
36
|
-
<html lang="en">
|
|
37
|
-
<head>
|
|
38
|
-
<meta charset="UTF-8">
|
|
39
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
40
|
-
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
41
|
-
<title>AppRun Playground</title>
|
|
42
|
-
<style>
|
|
43
|
-
body {
|
|
44
|
-
font-family: "Benton Sans", "Helvetica Neue", helvetica, arial, sans-serif;
|
|
45
|
-
margin: 2em;
|
|
46
|
-
}
|
|
47
|
-
</style>
|
|
48
|
-
<script src="https://cdn.jsdelivr.net/npm/typescript@latest"></script>
|
|
49
|
-
<script src="dist/apprun-html.js"></script>
|
|
50
|
-
</head>
|
|
51
|
-
<body>
|
|
52
|
-
<pre id="code" style="display:none">${encodeHTML(code)}</pre>
|
|
53
|
-
<script type="module">
|
|
54
|
-
const code = document.getElementById('code').innerText;
|
|
55
|
-
const compiled = ts.transpileModule(code, {
|
|
56
|
-
compilerOptions: {
|
|
57
|
-
"jsx": "react",
|
|
58
|
-
"jsxFactory": "app.h",
|
|
59
|
-
"jsxFragmentFactory": "app.Fragment",
|
|
60
|
-
"target": "es2020",
|
|
61
|
-
"module": "esnext",
|
|
62
|
-
},
|
|
63
|
-
reportDiagnostics: true,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (compiled.diagnostics && compiled.diagnostics.length) {
|
|
67
|
-
const pre = document.createElement('pre');
|
|
68
|
-
pre.style = 'font-size: 10px;';
|
|
69
|
-
pre.innerText = compiled.diagnostics.map(d => {
|
|
70
|
-
const start = d.start;
|
|
71
|
-
const end = d.start + d.length;
|
|
72
|
-
const line = code.substring(0, end).split('\\n').length;
|
|
73
|
-
const column = code.substring(0, end).split('\\n').pop().length;
|
|
74
|
-
return \`Line: \${line}, Column: \${column}, \${d.messageText}\`;
|
|
75
|
-
}).join('\\n');
|
|
76
|
-
document.body.appendChild(pre);
|
|
77
|
-
} else {
|
|
78
|
-
window.onerror = function () {
|
|
79
|
-
const pre = document.createElement('pre');
|
|
80
|
-
pre.style = 'font-size: 10px;';
|
|
81
|
-
pre.innerText = compiled.outputText;;
|
|
82
|
-
document.body.appendChild(pre);
|
|
83
|
-
};
|
|
84
|
-
const script = document.createElement('script');
|
|
85
|
-
script.type = 'module';
|
|
86
|
-
script.text = compiled.outputText;
|
|
87
|
-
document.body.appendChild(script);
|
|
88
|
-
}
|
|
89
|
-
</script>
|
|
90
|
-
</body>
|
|
91
|
-
</html>`;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
class Play extends Component {
|
|
95
|
-
view = ({ code, hide_code }) => {
|
|
96
|
-
return <>
|
|
97
|
-
<style>{styles}</style>
|
|
98
|
-
{hide_code ?
|
|
99
|
-
<div class="apprun-play">
|
|
100
|
-
<iframe class="preview" />
|
|
101
|
-
</div>
|
|
102
|
-
:
|
|
103
|
-
<div class="apprun-play">
|
|
104
|
-
<div class="col" style="width:75%" >
|
|
105
|
-
<textarea class="editor">{code}</textarea>
|
|
106
|
-
</div>
|
|
107
|
-
<div class="col" style="flex:1" >
|
|
108
|
-
<iframe class="preview" />
|
|
109
|
-
</div>
|
|
110
|
-
</div>}
|
|
111
|
-
</>;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
mounted = props => {
|
|
115
|
-
const element = this['element'];
|
|
116
|
-
const code_id = props['code-id'];
|
|
117
|
-
const hide_code = props['hide-code'];
|
|
118
|
-
const code_width = props['code-width'];
|
|
119
|
-
|
|
120
|
-
let code_area;
|
|
121
|
-
if (code_id) {
|
|
122
|
-
code_area = document.getElementById(code_id);
|
|
123
|
-
} else {
|
|
124
|
-
code_area = element.previousElementSibling ||
|
|
125
|
-
element.parentElement.previousElementSibling;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const code = code_area?.innerText // from div
|
|
129
|
-
|| code_area?.value // from textarea
|
|
130
|
-
|| element.textContent // from child node
|
|
131
|
-
|
|
132
|
-
if (code_area) code_area.style.display = 'none';
|
|
133
|
-
|
|
134
|
-
return { code, hide_code, code_width };
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
rendered = ({ code, hide_code, code_width }) => {
|
|
139
|
-
const element = this['element'];
|
|
140
|
-
|
|
141
|
-
const textarea = element.querySelector(".apprun-play .editor") as any;
|
|
142
|
-
let iframe = element.querySelector('.apprun-play .preview');
|
|
143
|
-
if (!iframe || !textarea) return;
|
|
144
|
-
|
|
145
|
-
const run_code = code => {
|
|
146
|
-
const iframe_clone = iframe.cloneNode();
|
|
147
|
-
iframe.parentNode?.replaceChild(iframe_clone, iframe);
|
|
148
|
-
iframe = iframe_clone;
|
|
149
|
-
const doc = iframe.contentWindow?.document;
|
|
150
|
-
if (!doc) return;
|
|
151
|
-
doc.open();
|
|
152
|
-
if (code.indexOf('<html') >= 0)
|
|
153
|
-
doc.write(code);
|
|
154
|
-
else
|
|
155
|
-
doc.write(code_html(code));
|
|
156
|
-
doc.close();
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (code) run_code(code);
|
|
160
|
-
if (hide_code || !textarea) return;
|
|
161
|
-
|
|
162
|
-
if (code_width) textarea.parentElement.style.width = code_width;
|
|
163
|
-
|
|
164
|
-
if (typeof CodeMirror === 'undefined') {
|
|
165
|
-
textarea.onkeyup = () => run_code(textarea.value);
|
|
166
|
-
} else {
|
|
167
|
-
const editor = CodeMirror.fromTextArea(textarea, {
|
|
168
|
-
lineNumbers: true,
|
|
169
|
-
mode: 'jsx'
|
|
170
|
-
});
|
|
171
|
-
editor.setValue(code);
|
|
172
|
-
editor.on('change', (cm) => run_code(cm.getValue()));
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
app.webComponent('apprun-code', Play);
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
declare var app;
|
|
2
|
-
let win;
|
|
3
|
-
app['debug'] = true;
|
|
4
|
-
|
|
5
|
-
function openWin(name) {
|
|
6
|
-
win = window.open('', name);
|
|
7
|
-
win.document.write(`<html>
|
|
8
|
-
<title>AppRun Analyzer | ${document.location.href}</title>
|
|
9
|
-
<style>
|
|
10
|
-
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI" }
|
|
11
|
-
</style>
|
|
12
|
-
<body><pre>`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function write(text) {
|
|
16
|
-
win.document.write(text + '\n');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function closeWin() {
|
|
20
|
-
win.document.write(`</pre>
|
|
21
|
-
</body>
|
|
22
|
-
</html>`);
|
|
23
|
-
win.document.close();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const print_component_test = component => {
|
|
27
|
-
write(`import ${component.constructor.name} from '../src/${component.constructor.name}'`);
|
|
28
|
-
write(`describe('${component.constructor.name}', ()=>{`);
|
|
29
|
-
component._actions.forEach(action => {
|
|
30
|
-
if (action.name !== '.') {
|
|
31
|
-
write(` it ('should handle event: ${action.name}', (done)=>{`);
|
|
32
|
-
write(` const component = new ${component.constructor.name}().mount();`);
|
|
33
|
-
write(` component.run('${action.name}');`);
|
|
34
|
-
write(` setTimeout(() => {`);
|
|
35
|
-
write(` \/\/expect(?).toHaveBeenCalled();`);
|
|
36
|
-
write(` \/\/expect(component.state).toBe(?);`);
|
|
37
|
-
write(` done();`);
|
|
38
|
-
write(` })`);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
write(`});`);
|
|
42
|
-
};
|
|
43
|
-
export const _createEventTests = () => {
|
|
44
|
-
const o = { components: {} };
|
|
45
|
-
app.run('get-components', o);
|
|
46
|
-
const { components } = o;
|
|
47
|
-
openWin('');
|
|
48
|
-
if (components instanceof Map) {
|
|
49
|
-
for (let [key, comps] of components) {
|
|
50
|
-
comps.forEach(print_component_test);
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
Object.keys(components).forEach(el => {
|
|
54
|
-
components[el].forEach(print_component_test);
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
closeWin();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let recording = false;
|
|
61
|
-
let events = [];
|
|
62
|
-
|
|
63
|
-
app.on('debug', p => {
|
|
64
|
-
if (recording && p.vdom) {
|
|
65
|
-
events.push(p);
|
|
66
|
-
console.log(`* ${events.length} state(s) recorded.`);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
export const _createStateTests = (s) => {
|
|
71
|
-
|
|
72
|
-
const printTests = () => {
|
|
73
|
-
if (events.length === 0) {
|
|
74
|
-
console.log('* No state recorded.');
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
openWin('');
|
|
78
|
-
events.forEach((event, idx) => {
|
|
79
|
-
write(` it ('view snapshot: #${idx + 1}', ()=>{`);
|
|
80
|
-
write(` const component = new ${event.component.constructor.name}()`);
|
|
81
|
-
write(` const state = ${JSON.stringify(event.state, undefined, 2)};`);
|
|
82
|
-
write(` const vdom = component['view'](state);`);
|
|
83
|
-
write(` expect(JSON.stringify(vdom)).toMatchSnapshot();`);
|
|
84
|
-
write(` })`);
|
|
85
|
-
});
|
|
86
|
-
closeWin();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (s === 'start') {
|
|
90
|
-
events = [];
|
|
91
|
-
recording = true;
|
|
92
|
-
console.log('* State logging started.');
|
|
93
|
-
} else if (s === 'stop') {
|
|
94
|
-
printTests();
|
|
95
|
-
recording = false;
|
|
96
|
-
events = [];
|
|
97
|
-
console.log('* State logging stopped.');
|
|
98
|
-
} else {
|
|
99
|
-
console.log('create-state-tests <start|stop>');
|
|
100
|
-
}
|
|
101
|
-
}
|