@quenk/wml 2.13.11 → 2.14.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/lib/cli.d.ts +8 -8
- package/lib/cli.js +1 -3
- package/lib/cli.js.map +1 -1
- package/lib/cli.ts +48 -60
- package/lib/compile/codegen.d.ts +4 -9
- package/lib/compile/codegen.js +162 -367
- package/lib/compile/codegen.js.map +1 -1
- package/lib/compile/codegen.ts +644 -952
- package/lib/compile/index.d.ts +2 -2
- package/lib/compile/index.js +4 -4
- package/lib/compile/index.js.map +1 -1
- package/lib/compile/index.ts +14 -17
- package/lib/compile/transform.d.ts +1 -1
- package/lib/compile/transform.js +9 -11
- package/lib/compile/transform.js.map +1 -1
- package/lib/compile/transform.ts +136 -143
- package/lib/{dom.d.ts → dom/index.d.ts} +8 -2
- package/lib/{dom.js → dom/index.js} +84 -70
- package/lib/dom/index.js.map +1 -0
- package/lib/dom/index.ts +425 -0
- package/lib/dom/monitor.d.ts +33 -0
- package/lib/dom/monitor.js +60 -0
- package/lib/dom/monitor.js.map +1 -0
- package/lib/dom/monitor.ts +75 -0
- package/lib/index.d.ts +10 -95
- package/lib/index.js +10 -10
- package/lib/index.js.map +1 -1
- package/lib/index.ts +57 -182
- package/lib/main.js +17 -17
- package/lib/main.js.map +1 -1
- package/lib/main.ts +38 -44
- package/lib/parse/ast.d.ts +2 -2
- package/lib/parse/ast.js +52 -53
- package/lib/parse/ast.js.map +1 -1
- package/lib/parse/ast.ts +396 -483
- package/lib/parse/generated.d.ts +3 -5
- package/lib/parse/generated.js +9504 -9264
- package/lib/parse/index.d.ts +2 -3
- package/lib/parse/index.js.map +1 -1
- package/lib/parse/index.ts +7 -9
- package/lib/parse/test.js +194 -192
- package/lib/parse/test.js.map +1 -1
- package/lib/parse/test.ts +294 -404
- package/lib/parse/wml.y +4 -0
- package/lib/tsconfig.json +19 -20
- package/lib/util.d.ts +10 -0
- package/lib/util.js +21 -0
- package/lib/util.js.map +1 -0
- package/lib/util.ts +39 -0
- package/lib/view/frame.d.ts +103 -0
- package/lib/view/frame.js +206 -0
- package/lib/view/frame.js.map +1 -0
- package/lib/view/frame.ts +249 -0
- package/lib/view/index.d.ts +58 -0
- package/lib/view/index.js +48 -0
- package/lib/view/index.js.map +1 -0
- package/lib/view/index.ts +97 -0
- package/package.json +3 -3
- package/lib/dom.js.map +0 -1
- package/lib/dom.ts +0 -479
package/lib/compile/codegen.ts
CHANGED
|
@@ -4,63 +4,33 @@
|
|
|
4
4
|
|
|
5
5
|
/** imports */
|
|
6
6
|
|
|
7
|
-
import * as ast from
|
|
7
|
+
import * as ast from "../parse/ast";
|
|
8
8
|
|
|
9
|
-
import { set } from
|
|
9
|
+
import { set } from "@quenk/noni/lib/data/record/path";
|
|
10
10
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} from
|
|
17
|
-
import { contains, empty, find, partition } from
|
|
11
|
+
Record,
|
|
12
|
+
merge,
|
|
13
|
+
mapTo,
|
|
14
|
+
reduce,
|
|
15
|
+
isRecord,
|
|
16
|
+
} from "@quenk/noni/lib/data/record";
|
|
17
|
+
import { contains, empty, find, partition } from "@quenk/noni/lib/data/array";
|
|
18
18
|
|
|
19
|
-
import { transformTree } from
|
|
19
|
+
import { transformTree } from "./transform";
|
|
20
20
|
|
|
21
|
-
export const CONTEXT =
|
|
22
|
-
export const VIEW =
|
|
23
|
-
export const WML =
|
|
24
|
-
export const DOCUMENT =
|
|
25
|
-
export const
|
|
21
|
+
export const CONTEXT = "__context";
|
|
22
|
+
export const VIEW = "__view";
|
|
23
|
+
export const WML = "__wml";
|
|
24
|
+
export const DOCUMENT = "__document";
|
|
25
|
+
export const UTILS = "__utils";
|
|
26
|
+
export const THIS = "__this";
|
|
27
|
+
export const VIEW_FRAME = "__viewFrame";
|
|
26
28
|
|
|
27
|
-
const
|
|
29
|
+
const VIEW_CLASS = "BaseView";
|
|
30
|
+
const VIEW_FRAME_CLASS = "ViewFrame";
|
|
28
31
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
const FROM_ARRAY = '__fromArray';
|
|
32
|
-
|
|
33
|
-
const NODE_PARAMS = `tag:string, attrs:${WML}.Attrs, ` +
|
|
34
|
-
`children: ${WML}.Content[]`;
|
|
35
|
-
|
|
36
|
-
const WIDGET_PARAMS =
|
|
37
|
-
`w: ${WML}.Widget, attrs:${WML}.Attrs`;
|
|
38
|
-
|
|
39
|
-
const REGISTER_VIEW_PARAMS = `v:${WML}.View`;
|
|
40
|
-
|
|
41
|
-
const REGISTER_PARAMS = `e:${WML}.WMLElement, ` +
|
|
42
|
-
`attrs:${WML}.Attributes<any>`;
|
|
43
|
-
|
|
44
|
-
const THROW_INVALIDATE_ERR = ` throw new Error('invalidate(): cannot ` +
|
|
45
|
-
`invalidate this view, it has no parent node!');`;
|
|
46
|
-
|
|
47
|
-
const IGNORE_UNUSED = '//@ts-ignore:6192';
|
|
48
|
-
|
|
49
|
-
const RECORD = '__Record<A>';
|
|
50
|
-
|
|
51
|
-
const IF = '__if';
|
|
52
|
-
|
|
53
|
-
const IFARG = `__IfArg`;
|
|
54
|
-
|
|
55
|
-
const FOR_OF = '__forOf';
|
|
56
|
-
|
|
57
|
-
const FOR_IN = '__forIn';
|
|
58
|
-
|
|
59
|
-
const FOR_ALT_TYPE = '__ForAlt';
|
|
60
|
-
|
|
61
|
-
const FOR_IN_BODY = '__ForInBody<A>';
|
|
62
|
-
|
|
63
|
-
const FOR_OF_BODY = '__ForOfBody<A>';
|
|
32
|
+
const FOR_OF = `${UTILS}.forOf`;
|
|
33
|
+
const FOR_IN = `${UTILS}.forIn`;
|
|
64
34
|
|
|
65
35
|
/**
|
|
66
36
|
* TypeScript code.
|
|
@@ -75,59 +45,55 @@ export type TypeOrMap = TypeScript | ExpandedTypeMap;
|
|
|
75
45
|
/**
|
|
76
46
|
* TypeMap contains a recursive map of dotted paths to Type nodes.
|
|
77
47
|
*/
|
|
78
|
-
export interface TypeMap extends Record<ast.Type> {
|
|
48
|
+
export interface TypeMap extends Record<ast.Type> {}
|
|
79
49
|
|
|
80
50
|
/**
|
|
81
51
|
* ExpandedTypeMap is an expanded version of TypeMap.
|
|
82
52
|
*
|
|
83
|
-
* Each dotted path is expanded recursively into records
|
|
53
|
+
* Each dotted path is expanded recursively into records
|
|
84
54
|
* so that no path contain dots.
|
|
85
55
|
*/
|
|
86
|
-
export interface ExpandedTypeMap extends Record<TypeOrMap> {
|
|
56
|
+
export interface ExpandedTypeMap extends Record<TypeOrMap> {}
|
|
87
57
|
|
|
88
58
|
const prims = [
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
59
|
+
"String",
|
|
60
|
+
"Boolean",
|
|
61
|
+
"Number",
|
|
62
|
+
"Object",
|
|
63
|
+
"Undefined",
|
|
64
|
+
"Null",
|
|
65
|
+
"Void",
|
|
66
|
+
"Never",
|
|
67
|
+
"Any",
|
|
98
68
|
];
|
|
99
69
|
|
|
100
|
-
const casters = [
|
|
70
|
+
const casters = ["String", "Boolean", "Number", "Object"];
|
|
101
71
|
|
|
102
72
|
const operators: { [key: string]: string } = {
|
|
73
|
+
"==": "===",
|
|
103
74
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
'!=': '!=='
|
|
107
|
-
|
|
108
|
-
}
|
|
75
|
+
"!=": "!==",
|
|
76
|
+
};
|
|
109
77
|
|
|
110
78
|
/**
|
|
111
79
|
* CodeGeneratorOptions
|
|
112
80
|
*/
|
|
113
81
|
export interface CodeGeneratorOptions {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
EOL: string
|
|
130
|
-
|
|
82
|
+
/**
|
|
83
|
+
* module path that wml types will be imported from in the output.
|
|
84
|
+
*/
|
|
85
|
+
module: string;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* dom is the module path that the wml DOM api will be imported from in the
|
|
89
|
+
* output.
|
|
90
|
+
*/
|
|
91
|
+
dom: string;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* EOL character to use when terminating lines.
|
|
95
|
+
*/
|
|
96
|
+
EOL: string;
|
|
131
97
|
}
|
|
132
98
|
|
|
133
99
|
/**
|
|
@@ -138,294 +104,182 @@ export interface CodeGeneratorOptions {
|
|
|
138
104
|
* provide a typescript module.
|
|
139
105
|
*/
|
|
140
106
|
export class CodeGenerator {
|
|
107
|
+
constructor(public options: CodeGeneratorOptions) {}
|
|
141
108
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return new CodeGenerator(opts);
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* generate a Typescript module from an WML AST.
|
|
155
|
-
*/
|
|
156
|
-
generate(tree: ast.Module): TypeScript {
|
|
157
|
-
|
|
158
|
-
tree = transformTree(tree);
|
|
109
|
+
/**
|
|
110
|
+
* create a new CodeGenerator instance.
|
|
111
|
+
*/
|
|
112
|
+
static create(opts: CodeGeneratorOptions): CodeGenerator {
|
|
113
|
+
return new CodeGenerator(opts);
|
|
114
|
+
}
|
|
159
115
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
importStatements2TS(this, tree.imports),
|
|
166
|
-
eol(this),
|
|
167
|
-
typeDefinitions(this),
|
|
168
|
-
eol(this),
|
|
169
|
-
`// @ts-ignore 6192`,
|
|
170
|
-
`const text = ${DOCUMENT}.text;`,
|
|
171
|
-
`// @ts-ignore 6192`,
|
|
172
|
-
`const unsafe = ${DOCUMENT}.unsafe`,
|
|
173
|
-
`// @ts-ignore 6192`,
|
|
174
|
-
`const isSet = (value:any) => value != null`,
|
|
175
|
-
exports2TS(this, tree.exports)
|
|
176
|
-
|
|
177
|
-
].join(eol(this));
|
|
178
|
-
|
|
179
|
-
}
|
|
116
|
+
/**
|
|
117
|
+
* generate a Typescript module from an WML AST.
|
|
118
|
+
*/
|
|
119
|
+
generate(tree: ast.Module): TypeScript {
|
|
120
|
+
tree = transformTree(tree);
|
|
180
121
|
|
|
122
|
+
return [
|
|
123
|
+
`// @ts-ignore 6192`,
|
|
124
|
+
`import * as ${WML} from '${this.options.module}';`,
|
|
125
|
+
`// @ts-ignore 6192`,
|
|
126
|
+
`import * as ${DOCUMENT} from '${this.options.module}/lib/dom';`,
|
|
127
|
+
`// @ts-ignore 6192`,
|
|
128
|
+
`import * as ${UTILS} from '${this.options.module}/lib/util';`,
|
|
129
|
+
importStatements2TS(this, tree.imports),
|
|
130
|
+
eol(this),
|
|
131
|
+
`// @ts-ignore 6192`,
|
|
132
|
+
`const text = ${DOCUMENT}.text;`,
|
|
133
|
+
`// @ts-ignore 6192`,
|
|
134
|
+
`const unsafe = ${DOCUMENT}.unsafe`,
|
|
135
|
+
`// @ts-ignore 6192`,
|
|
136
|
+
`const isSet = ${UTILS}.isSet`,
|
|
137
|
+
exports2TS(this, tree.exports),
|
|
138
|
+
].join(eol(this));
|
|
139
|
+
}
|
|
181
140
|
}
|
|
182
141
|
|
|
183
142
|
const eol = (ctx: CodeGenerator) => `${ctx.options.EOL}`;
|
|
184
143
|
|
|
185
|
-
const imports = (ctx: CodeGenerator) => [
|
|
186
|
-
`//@ts-ignore: 6192`,
|
|
187
|
-
`import {`,
|
|
188
|
-
`Maybe as ${MAYBE},`,
|
|
189
|
-
`fromNullable as ${FROM_NULLABLE},`,
|
|
190
|
-
`fromArray as ${FROM_ARRAY}`,
|
|
191
|
-
`}`,
|
|
192
|
-
`from '@quenk/noni/lib/data/maybe';`
|
|
193
|
-
].join(eol(ctx));
|
|
194
|
-
|
|
195
|
-
const typeDefinitions = (ctx: CodeGenerator) => [
|
|
196
|
-
`${IGNORE_UNUSED}`,
|
|
197
|
-
`type ${IFARG} = ()=>${WML}.Content[]`,
|
|
198
|
-
``,
|
|
199
|
-
`${IGNORE_UNUSED}`,
|
|
200
|
-
`type ${FOR_ALT_TYPE} = ()=> ${WML}.Content[]`,
|
|
201
|
-
``,
|
|
202
|
-
`${IGNORE_UNUSED}`,
|
|
203
|
-
`type ${FOR_IN_BODY} =(val:A, idx:number, all:A[])=>` +
|
|
204
|
-
`${WML}.Content[]`,
|
|
205
|
-
``,
|
|
206
|
-
`${IGNORE_UNUSED}`,
|
|
207
|
-
`type ${FOR_OF_BODY} = (val:A, key:string, all:object) =>` +
|
|
208
|
-
`${WML}.Content[]`,
|
|
209
|
-
``,
|
|
210
|
-
`${IGNORE_UNUSED}`,
|
|
211
|
-
`interface ${RECORD} {`,
|
|
212
|
-
``,
|
|
213
|
-
` [key:string]: A`,
|
|
214
|
-
``,
|
|
215
|
-
`}`,
|
|
216
|
-
``,
|
|
217
|
-
`${IGNORE_UNUSED}`,
|
|
218
|
-
`const ${IF} = (__expr:boolean, __conseq:${IFARG},__alt?:${IFARG}) ` +
|
|
219
|
-
`: Content[]=>`,
|
|
220
|
-
`(__expr) ? __conseq() : __alt ? __alt() : [];`,
|
|
221
|
-
``,
|
|
222
|
-
`${IGNORE_UNUSED}`,
|
|
223
|
-
`const ${FOR_IN} = <A>(list:A[], f:${FOR_IN_BODY}, alt:` +
|
|
224
|
-
`${FOR_ALT_TYPE}) : ${WML}.Content[] => {`,
|
|
225
|
-
``,
|
|
226
|
-
` let ret:${WML}.Content[] = [];`,
|
|
227
|
-
``,
|
|
228
|
-
` for(let i=0; i<list.length; i++)`,
|
|
229
|
-
` ret = ret.concat(f(list[i], i, list));`,
|
|
230
|
-
``,
|
|
231
|
-
` return ret.length === 0 ? alt() : ret;`,
|
|
232
|
-
``,
|
|
233
|
-
`}`,
|
|
234
|
-
`${IGNORE_UNUSED}`,
|
|
235
|
-
`const ${FOR_OF} = <A>(o:${RECORD}, f:${FOR_OF_BODY},` +
|
|
236
|
-
`alt:${FOR_ALT_TYPE}) : ${WML}.Content[] => {`,
|
|
237
|
-
``,
|
|
238
|
-
` let ret:${WML}.Content[] = [];`,
|
|
239
|
-
``,
|
|
240
|
-
` for(let key in o)`,
|
|
241
|
-
` if(o.hasOwnProperty(key)) `,
|
|
242
|
-
` ret = ret.concat(f((o)[key], key, o));`,
|
|
243
|
-
``,
|
|
244
|
-
` return ret.length === 0 ? alt(): ret;`,
|
|
245
|
-
``,
|
|
246
|
-
`}`
|
|
247
|
-
|
|
248
|
-
].join(eol(ctx));
|
|
249
|
-
|
|
250
144
|
/**
|
|
251
145
|
* importStatements2TS converts a list of ImportStatements into typescript.
|
|
252
146
|
*/
|
|
253
|
-
export const importStatements2TS =
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
147
|
+
export const importStatements2TS = (
|
|
148
|
+
ctx: CodeGenerator,
|
|
149
|
+
list: ast.ImportStatement[],
|
|
150
|
+
): TypeScript =>
|
|
151
|
+
list
|
|
152
|
+
.map(importStatement2TS)
|
|
153
|
+
.filter((stmt, idx, list) => list.indexOf(stmt) == idx)
|
|
154
|
+
.join(`;${eol(ctx)}`);
|
|
259
155
|
|
|
260
156
|
/**
|
|
261
|
-
* importStatement2TS
|
|
157
|
+
* importStatement2TS
|
|
262
158
|
*/
|
|
263
159
|
export const importStatement2TS = (n: ast.ImportStatement): TypeScript =>
|
|
264
|
-
|
|
160
|
+
`import ${importMember2TS(n.member)} from '${n.module.value.trim()}'; `;
|
|
265
161
|
|
|
266
162
|
/**
|
|
267
163
|
* importMember2TS
|
|
268
164
|
*/
|
|
269
165
|
export const importMember2TS = (n: ast.ImportMember): string => {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
else if (n instanceof ast.CompositeMember)
|
|
276
|
-
return compositeMember2TS(n);
|
|
277
|
-
else
|
|
278
|
-
return '';
|
|
279
|
-
|
|
280
|
-
}
|
|
166
|
+
if (n instanceof ast.AggregateMember) return aggregateMember2TS(n);
|
|
167
|
+
else if (n instanceof ast.AliasedMember) return aliasedMember2TS(n);
|
|
168
|
+
else if (n instanceof ast.CompositeMember) return compositeMember2TS(n);
|
|
169
|
+
else return "";
|
|
170
|
+
};
|
|
281
171
|
|
|
282
172
|
/**
|
|
283
173
|
* aggregateMember2TS
|
|
284
174
|
*/
|
|
285
175
|
export const aggregateMember2TS = (n: ast.AggregateMember): string =>
|
|
286
|
-
|
|
176
|
+
`* as ${identifierOrConstructor2TS(n.id)} `;
|
|
287
177
|
|
|
288
178
|
/**
|
|
289
179
|
* aliasedMember2TS
|
|
290
180
|
*/
|
|
291
181
|
export const aliasedMember2TS = (n: ast.AliasedMember): string =>
|
|
292
|
-
|
|
293
|
-
|
|
182
|
+
`${identifierOrConstructor2TS(n.member)} ` +
|
|
183
|
+
`as ${identifierOrConstructor2TS(n.alias)} `;
|
|
294
184
|
|
|
295
185
|
/**
|
|
296
|
-
* compositeMember2TS
|
|
186
|
+
* compositeMember2TS
|
|
297
187
|
*/
|
|
298
188
|
export const compositeMember2TS = (n: ast.CompositeMember): string =>
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
189
|
+
"{" +
|
|
190
|
+
n.members
|
|
191
|
+
.map((m) =>
|
|
192
|
+
m instanceof ast.AliasedMember
|
|
193
|
+
? aliasedMember2TS(m)
|
|
194
|
+
: identifierOrConstructor2TS(m),
|
|
195
|
+
)
|
|
196
|
+
.join(",") +
|
|
197
|
+
"}";
|
|
302
198
|
|
|
303
199
|
/**
|
|
304
200
|
* exports2TS converts a list of exports to typescript.
|
|
305
201
|
*/
|
|
306
202
|
export const exports2TS = (ctx: CodeGenerator, list: ast.Export[]) =>
|
|
307
|
-
|
|
203
|
+
list.map((e) => export2TS(ctx, e)).join(";" + eol(ctx));
|
|
308
204
|
|
|
309
205
|
/**
|
|
310
|
-
* export2TS
|
|
206
|
+
* export2TS
|
|
311
207
|
*/
|
|
312
208
|
export const export2TS = (ctx: CodeGenerator, n: ast.Export) => {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
return funStatement2TS(ctx, n);
|
|
322
|
-
else if (n instanceof ast.ViewStatement)
|
|
323
|
-
return viewStatement2TS(ctx, n);
|
|
324
|
-
else if ((n instanceof ast.Widget) || (n instanceof ast.Node))
|
|
325
|
-
return tag2TS(ctx, n);
|
|
326
|
-
else
|
|
327
|
-
return '';
|
|
328
|
-
|
|
329
|
-
}
|
|
209
|
+
if (n instanceof ast.AliasStatement) return aliasStatement2TS(n);
|
|
210
|
+
else if (n instanceof ast.ContextStatement) return contextStatement2TS(n);
|
|
211
|
+
else if (n instanceof ast.LetStatement) return letStatement2TS(ctx, n);
|
|
212
|
+
else if (n instanceof ast.ViewStatement) return viewStatement2TS(ctx, n);
|
|
213
|
+
else if (n instanceof ast.Widget || n instanceof ast.Node)
|
|
214
|
+
return tag2TS(ctx, n);
|
|
215
|
+
else return "";
|
|
216
|
+
};
|
|
330
217
|
|
|
331
218
|
/**
|
|
332
219
|
* aliasStatement2TS
|
|
333
220
|
*/
|
|
334
221
|
export const aliasStatement2TS = (n: ast.AliasStatement) => {
|
|
222
|
+
let typeArgs =
|
|
223
|
+
n.typeParameters.length > 0 ? typeParameters2TS(n.typeParameters) : "";
|
|
335
224
|
|
|
336
|
-
|
|
337
|
-
typeParameters2TS(n.typeParameters) : '';
|
|
338
|
-
|
|
339
|
-
let preamble = `export type ${n.id.value}${typeArgs}`;
|
|
340
|
-
|
|
341
|
-
let members = n.members.map(m => type2TS(m)).join('|');
|
|
225
|
+
let preamble = `export type ${n.id.value}${typeArgs}`;
|
|
342
226
|
|
|
343
|
-
|
|
227
|
+
let members = n.members.map((m) => type2TS(m)).join("|");
|
|
344
228
|
|
|
345
|
-
}
|
|
229
|
+
return `${preamble} = ${members};`;
|
|
230
|
+
};
|
|
346
231
|
|
|
347
232
|
/**
|
|
348
233
|
* contextStatement2TS
|
|
349
234
|
*/
|
|
350
235
|
export const contextStatement2TS = (n: ast.ContextStatement) => {
|
|
236
|
+
let preamble = `export interface ${n.id.value}`;
|
|
351
237
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
let typeArgs = (n.typeParameters.length > 0) ?
|
|
355
|
-
typeParameters2TS(n.typeParameters) : '';
|
|
238
|
+
let typeArgs =
|
|
239
|
+
n.typeParameters.length > 0 ? typeParameters2TS(n.typeParameters) : "";
|
|
356
240
|
|
|
357
|
-
|
|
358
|
-
|
|
241
|
+
let [parents, members] = partition(
|
|
242
|
+
n.members,
|
|
243
|
+
(member) => member instanceof ast.ConstructorType,
|
|
244
|
+
);
|
|
359
245
|
|
|
360
|
-
|
|
361
|
-
|
|
246
|
+
let parentList = (<ast.ConstructorType[]>parents)
|
|
247
|
+
.map(constructorType2TS)
|
|
248
|
+
.join(",");
|
|
362
249
|
|
|
363
|
-
|
|
250
|
+
parentList = parentList !== "" ? ` extends ${parentList}` : "";
|
|
364
251
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}
|
|
252
|
+
return [
|
|
253
|
+
preamble,
|
|
254
|
+
typeArgs,
|
|
255
|
+
parentList,
|
|
256
|
+
"{",
|
|
257
|
+
memberDeclarations2TS(<ast.MemberDeclaration[]>members),
|
|
258
|
+
"}",
|
|
259
|
+
].join("");
|
|
260
|
+
};
|
|
375
261
|
|
|
376
262
|
/**
|
|
377
263
|
* letStatement2TS
|
|
378
264
|
*/
|
|
379
|
-
export const letStatement2TS =
|
|
380
|
-
|
|
381
|
-
_setStatement2TS(ctx, n, 'export const');
|
|
382
|
-
|
|
383
|
-
const _setStatement2TS =
|
|
384
|
-
(ctx: CodeGenerator, n: ast.LetStatement, preamble: string) => {
|
|
385
|
-
|
|
386
|
-
let id = identifier2TS(n.id);
|
|
265
|
+
export const letStatement2TS = (ctx: CodeGenerator, n: ast.LetStatement) =>
|
|
266
|
+
_setStatement2TS(ctx, n, "export const");
|
|
387
267
|
|
|
388
|
-
|
|
268
|
+
const _setStatement2TS = (
|
|
269
|
+
ctx: CodeGenerator,
|
|
270
|
+
n: ast.LetStatement,
|
|
271
|
+
preamble: string,
|
|
272
|
+
) => {
|
|
273
|
+
let id = identifier2TS(n.id);
|
|
389
274
|
|
|
390
|
-
|
|
275
|
+
let cons = constructorType2TS(n.cons);
|
|
391
276
|
|
|
392
|
-
|
|
277
|
+
preamble = `${preamble} ${id}:${cons}`;
|
|
393
278
|
|
|
394
|
-
|
|
279
|
+
let value = expression2TS(ctx, n.expression);
|
|
395
280
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* funStatement2TS generates Typescript output for fun statements.
|
|
400
|
-
*
|
|
401
|
-
* This is a curried function that first accepts zero or more arguments then
|
|
402
|
-
* a single Registry, finally the content.
|
|
403
|
-
*/
|
|
404
|
-
export const funStatement2TS = (ctx: CodeGenerator, n: ast.FunStatement) => {
|
|
405
|
-
|
|
406
|
-
let id = unqualifiedIdentifier2TS(n.id);
|
|
407
|
-
|
|
408
|
-
let typeParams = typeParameters2TS(n.typeParameters);
|
|
409
|
-
|
|
410
|
-
let params = parameters2TS(n.parameters);
|
|
411
|
-
|
|
412
|
-
let factory = `(${THIS}:${WML}.Registry) : ${WML}.Content[] =>`;
|
|
413
|
-
|
|
414
|
-
let body = children2TS(ctx, n.body);
|
|
415
|
-
|
|
416
|
-
return [
|
|
417
|
-
|
|
418
|
-
`export const ${id} = `,
|
|
419
|
-
``,
|
|
420
|
-
`${typeParams}(${params})=>${factory} {`,
|
|
421
|
-
``,
|
|
422
|
-
` return ${body};`,
|
|
423
|
-
``,
|
|
424
|
-
`};`
|
|
425
|
-
|
|
426
|
-
].join(eol(ctx));
|
|
427
|
-
|
|
428
|
-
}
|
|
281
|
+
return `${preamble} = ${value}`;
|
|
282
|
+
};
|
|
429
283
|
|
|
430
284
|
/**
|
|
431
285
|
* viewStatement2TS converts a ViewStatement to its typescript form.
|
|
@@ -433,247 +287,117 @@ export const funStatement2TS = (ctx: CodeGenerator, n: ast.FunStatement) => {
|
|
|
433
287
|
* This is a class with template and various useful helpers.
|
|
434
288
|
*/
|
|
435
289
|
export const viewStatement2TS = (ctx: CodeGenerator, n: ast.ViewStatement) => {
|
|
290
|
+
let instances = n.directives
|
|
291
|
+
.map((i) => _setStatement2TS(ctx, i, "let"))
|
|
292
|
+
.join(`;${ctx.options.EOL}`);
|
|
436
293
|
|
|
437
|
-
|
|
438
|
-
_setStatement2TS(ctx, i, 'let')).join(`;${ctx.options.EOL}`);
|
|
294
|
+
let id = n.id ? constructor2TS(n.id) : "Main";
|
|
439
295
|
|
|
440
|
-
|
|
296
|
+
let typeParams = typeParameters2TS(n.typeParameters);
|
|
441
297
|
|
|
442
|
-
|
|
298
|
+
let context = n.context
|
|
299
|
+
? type2TS(
|
|
300
|
+
n.context instanceof ast.ContextFromStatement
|
|
301
|
+
? n.context.cons
|
|
302
|
+
: <ast.ConstructorType>n.context,
|
|
303
|
+
)
|
|
304
|
+
: "object";
|
|
443
305
|
|
|
444
|
-
|
|
445
|
-
n.context.cons : <ast.ConstructorType>n.context);
|
|
306
|
+
let defaultContext = n.context ? "" : "={}";
|
|
446
307
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
return [
|
|
308
|
+
let template = tag2TS(ctx, n.root);
|
|
450
309
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
` widgets: ${WML}.Widget[] = [];`,
|
|
472
|
-
``,
|
|
473
|
-
` tree: Node = <Node>${DOCUMENT}.createElement('div');`,
|
|
474
|
-
``,
|
|
475
|
-
` template: ${WML}.Template;`,
|
|
476
|
-
``,
|
|
477
|
-
` registerView(${REGISTER_VIEW_PARAMS}) : ${WML}.View {`,
|
|
478
|
-
``,
|
|
479
|
-
` this.views.push(v);`,
|
|
480
|
-
``,
|
|
481
|
-
` return v;`,
|
|
482
|
-
``,
|
|
483
|
-
`}`,
|
|
484
|
-
` register(${REGISTER_PARAMS}) : ${WML}.WMLElement {`,
|
|
485
|
-
``,
|
|
486
|
-
` let attrsMap = (<${WML}.Attrs><any>attrs)`,
|
|
487
|
-
``,
|
|
488
|
-
` if(attrsMap.wml) {`,
|
|
489
|
-
``,
|
|
490
|
-
` let {id, group} = attrsMap.wml;`,
|
|
491
|
-
``,
|
|
492
|
-
` if(id != null) {`,
|
|
493
|
-
``,
|
|
494
|
-
` if (this.ids.hasOwnProperty(id))`,
|
|
495
|
-
` throw new Error(\`Duplicate id '\${id}' detected!\`);`,
|
|
496
|
-
``,
|
|
497
|
-
` this.ids[id] = e;`,
|
|
498
|
-
``,
|
|
499
|
-
` }`,
|
|
500
|
-
``,
|
|
501
|
-
` if(group != null) {`,
|
|
502
|
-
``,
|
|
503
|
-
` this.groups[group] = this.groups[group] || [];`,
|
|
504
|
-
` this.groups[group].push(e);`,
|
|
505
|
-
``,
|
|
506
|
-
` }`,
|
|
507
|
-
``,
|
|
508
|
-
` }`,
|
|
509
|
-
` return e;`,
|
|
510
|
-
`}`,
|
|
511
|
-
``,
|
|
512
|
-
` node(${NODE_PARAMS}): ${WML}.Content {`,
|
|
513
|
-
``,
|
|
514
|
-
` let asDOMAttrs = <${DOCUMENT}.WMLDOMAttrs><object>attrs`,
|
|
515
|
-
``,
|
|
516
|
-
` let e = ${DOCUMENT}.createElement(tag, asDOMAttrs, children,`,
|
|
517
|
-
` attrs.wml && attrs.wml.ns || '');`,
|
|
518
|
-
``,
|
|
519
|
-
` this.register(e, attrs);`,
|
|
520
|
-
``,
|
|
521
|
-
` return e;`,
|
|
522
|
-
``,
|
|
523
|
-
` }`,
|
|
524
|
-
``,
|
|
525
|
-
``,
|
|
526
|
-
` widget(${WIDGET_PARAMS}) : ${WML}.Content {`,
|
|
527
|
-
``,
|
|
528
|
-
` this.register(w, attrs);`,
|
|
529
|
-
``,
|
|
530
|
-
` this.widgets.push(w);`,
|
|
531
|
-
``,
|
|
532
|
-
` return w.render();`,
|
|
533
|
-
``,
|
|
534
|
-
` }`,
|
|
535
|
-
``,
|
|
536
|
-
` findById<E extends ${WML}.WMLElement>(id: string): ${MAYBE}<E> {`,
|
|
537
|
-
``,
|
|
538
|
-
` let mW:${MAYBE}<E> = ${FROM_NULLABLE}<E>(<E>this.ids[id])`,
|
|
539
|
-
``,
|
|
540
|
-
` return this.views.reduce((p,c)=>`,
|
|
541
|
-
` p.isJust() ? p : c.findById(id), mW);`,
|
|
542
|
-
``,
|
|
543
|
-
` }`,
|
|
544
|
-
``,
|
|
545
|
-
` findGroupById<E extends ${WML}.WMLElement>(name: string): E[] {` +
|
|
546
|
-
``,
|
|
547
|
-
` return this.groups.hasOwnProperty(name) ?`,
|
|
548
|
-
` <E[]>this.groups[name] : [];`,
|
|
549
|
-
``,
|
|
550
|
-
` }`,
|
|
551
|
-
``,
|
|
552
|
-
` invalidate() : void {`,
|
|
553
|
-
``,
|
|
554
|
-
` let {tree} = this;`,
|
|
555
|
-
` let parent = <Node>tree.parentNode;`,
|
|
556
|
-
``,
|
|
557
|
-
` if (tree == null)`,
|
|
558
|
-
` return console.warn('invalidate(): '+` +
|
|
559
|
-
` 'Missing DOM tree!');`,
|
|
560
|
-
``,
|
|
561
|
-
` if (tree.parentNode == null)`,
|
|
562
|
-
` ${THROW_INVALIDATE_ERR}`,
|
|
563
|
-
``,
|
|
564
|
-
` parent.replaceChild(<Node>this.render(), tree) `,
|
|
565
|
-
``,
|
|
566
|
-
` }`,
|
|
567
|
-
``,
|
|
568
|
-
` render(): ${WML}.Content {`,
|
|
569
|
-
``,
|
|
570
|
-
` this.ids = {};`,
|
|
571
|
-
` this.widgets.forEach(w => w.removed());`,
|
|
572
|
-
` this.widgets = [];`,
|
|
573
|
-
` this.views = [];`,
|
|
574
|
-
` this.tree = <Node>this.template(this);`,
|
|
575
|
-
``,
|
|
576
|
-
` this.ids['root'] = (this.ids['root']) ?`,
|
|
577
|
-
` this.ids['root'] : `,
|
|
578
|
-
` this.tree;`,
|
|
579
|
-
``,
|
|
580
|
-
` this.widgets.forEach(w => w.rendered());`,
|
|
581
|
-
``,
|
|
582
|
-
` return this.tree;`,
|
|
583
|
-
``,
|
|
584
|
-
` }`,
|
|
585
|
-
``,
|
|
586
|
-
`}`
|
|
587
|
-
|
|
588
|
-
].join(eol(ctx))
|
|
589
|
-
|
|
590
|
-
}
|
|
310
|
+
return [
|
|
311
|
+
`export class ${id} ${typeParams} extends ${WML}.${VIEW_CLASS} {`,
|
|
312
|
+
``,
|
|
313
|
+
` constructor(${CONTEXT}: ${context} ${defaultContext}) {`,
|
|
314
|
+
``,
|
|
315
|
+
` super(${CONTEXT}, (${THIS}:${WML}.${VIEW_FRAME_CLASS}) => {`,
|
|
316
|
+
``,
|
|
317
|
+
` ${instances}`,
|
|
318
|
+
``,
|
|
319
|
+
` ${THIS}.root(${template});`,
|
|
320
|
+
``,
|
|
321
|
+
` return ${THIS};`,
|
|
322
|
+
``,
|
|
323
|
+
` });`,
|
|
324
|
+
``,
|
|
325
|
+
` }`,
|
|
326
|
+
``,
|
|
327
|
+
`}`,
|
|
328
|
+
].join(eol(ctx));
|
|
329
|
+
};
|
|
591
330
|
|
|
592
331
|
/**
|
|
593
|
-
* typeParameters2TS converts a list of typeParameters2TS into the a list of
|
|
332
|
+
* typeParameters2TS converts a list of typeParameters2TS into the a list of
|
|
594
333
|
* typescript typeParameters2TS.
|
|
595
334
|
*/
|
|
596
335
|
export const typeParameters2TS = (ns: ast.TypeParameter[]): string =>
|
|
597
|
-
|
|
336
|
+
ns.length === 0 ? "" : `<${ns.map(typeParameter2TS).join(",")}> `;
|
|
598
337
|
|
|
599
338
|
/**
|
|
600
339
|
* typeParameter2TS converts a type parameter into a typescript type parameter.
|
|
601
340
|
*/
|
|
602
341
|
export const typeParameter2TS = (n: ast.TypeParameter) =>
|
|
603
|
-
|
|
604
|
-
|
|
342
|
+
`${toPrim(identifierOrConstructor2TS(n.id))} ` +
|
|
343
|
+
`${n.constraint ? "extends " + type2TS(n.constraint) : ""} `;
|
|
605
344
|
|
|
606
345
|
/**
|
|
607
|
-
* type2TS
|
|
346
|
+
* type2TS
|
|
608
347
|
*/
|
|
609
348
|
export const type2TS = (n: ast.Type): TypeScript => {
|
|
349
|
+
if (n instanceof ast.ConstructorType) return constructorType2TS(n);
|
|
350
|
+
else if (n instanceof ast.RecordType) return recordType2Ts(n);
|
|
351
|
+
else if (n instanceof ast.ListType) return listType2TS(n);
|
|
352
|
+
else if (n instanceof ast.TupleType) return tupleType2TS(n);
|
|
353
|
+
else if (n instanceof ast.StringLiteral) return string2TS(n);
|
|
354
|
+
else if (n instanceof ast.NumberLiteral) return number2TS(n);
|
|
355
|
+
else if (n instanceof ast.BooleanLiteral) return boolean2TS(n);
|
|
356
|
+
else if (n instanceof ast.FunctionType) return functionType2TS(n);
|
|
610
357
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
else if (n instanceof ast.RecordType)
|
|
614
|
-
return recordType2Ts(n);
|
|
615
|
-
else if (n instanceof ast.ListType)
|
|
616
|
-
return listType2TS(n);
|
|
617
|
-
else if (n instanceof ast.TupleType)
|
|
618
|
-
return tupleType2TS(n);
|
|
619
|
-
else if (n instanceof ast.StringLiteral)
|
|
620
|
-
return string2TS(n);
|
|
621
|
-
else if (n instanceof ast.NumberLiteral)
|
|
622
|
-
return number2TS(n);
|
|
623
|
-
else if (n instanceof ast.BooleanLiteral)
|
|
624
|
-
return boolean2TS(n);
|
|
625
|
-
else if (n instanceof ast.FunctionType)
|
|
626
|
-
return functionType2TS(n);
|
|
627
|
-
|
|
628
|
-
return '<error>';
|
|
629
|
-
|
|
630
|
-
}
|
|
358
|
+
return "void";
|
|
359
|
+
};
|
|
631
360
|
|
|
632
361
|
/**
|
|
633
362
|
* constructorType2TS converts a ConstructorType into its id.
|
|
634
363
|
*
|
|
635
364
|
* If the node is generic, the type parameters will be generated as well.
|
|
636
365
|
*/
|
|
637
|
-
export const constructorType2TS =
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
let id = toPrim(identifierOrConstructor2TS(n.id));
|
|
366
|
+
export const constructorType2TS = (n: ast.ConstructorType) => {
|
|
367
|
+
let id = toPrim(identifierOrConstructor2TS(n.id));
|
|
641
368
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
369
|
+
return n.typeParameters.length > 0
|
|
370
|
+
? id + typeParameters2TS(n.typeParameters)
|
|
371
|
+
: id;
|
|
372
|
+
};
|
|
646
373
|
|
|
647
374
|
/**
|
|
648
375
|
* functionType2TS
|
|
649
376
|
*/
|
|
650
377
|
export const functionType2TS = (n: ast.FunctionType) => {
|
|
378
|
+
let params = n.parameters.map((t, k) => `$${k}:${type2TS(t)}`).join(",");
|
|
379
|
+
let ret = type2TS(n.returnType);
|
|
651
380
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
return `(${params}) => ${ret}`
|
|
656
|
-
|
|
657
|
-
}
|
|
381
|
+
return `(${params}) => ${ret}`;
|
|
382
|
+
};
|
|
658
383
|
|
|
659
384
|
/**
|
|
660
385
|
* listType2TS
|
|
661
386
|
*/
|
|
662
|
-
export const listType2TS = (n: ast.ListType) =>
|
|
663
|
-
`(${type2TS(n.elementType)})[]`;
|
|
387
|
+
export const listType2TS = (n: ast.ListType) => `(${type2TS(n.elementType)})[]`;
|
|
664
388
|
|
|
665
389
|
/**
|
|
666
390
|
* tupleType2TS
|
|
667
391
|
*/
|
|
668
392
|
export const tupleType2TS = (n: ast.TupleType) =>
|
|
669
|
-
|
|
393
|
+
`[${n.members.map(type2TS).join(",")}]`;
|
|
670
394
|
|
|
671
395
|
/**
|
|
672
396
|
* recordType2TS converts the RecordType node to the body of a TypeScript
|
|
673
397
|
* record interface.
|
|
674
398
|
*/
|
|
675
399
|
export const recordType2Ts = (n: ast.RecordType) =>
|
|
676
|
-
|
|
400
|
+
"{" + memberDeclarations2TS(n.members) + "}";
|
|
677
401
|
|
|
678
402
|
/**
|
|
679
403
|
* memberDeclarations2TS converts a list of MemberDeclarations to TypeScript.
|
|
@@ -682,36 +406,32 @@ export const recordType2Ts = (n: ast.RecordType) =>
|
|
|
682
406
|
* using the "<path1>.<path2>.<path3>" syntax occur as nested records.
|
|
683
407
|
*/
|
|
684
408
|
export const memberDeclarations2TS = (n: ast.MemberDeclaration[]) =>
|
|
685
|
-
|
|
409
|
+
typeMap2TS(expandTypeMap(typeMapFromMemberDecs(n)));
|
|
686
410
|
|
|
687
411
|
/**
|
|
688
412
|
* typeMapFromMemberDecs creates a TypeMap from a list of memberDeclarations.
|
|
689
413
|
*
|
|
690
414
|
* This works recursively and any RecordTypes encountered will be flattened.
|
|
691
415
|
*/
|
|
692
|
-
export const typeMapFromMemberDecs =
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
let paths = m.path.map(p => p.value);
|
|
697
|
-
|
|
698
|
-
if (m.kind instanceof ast.RecordType) {
|
|
699
|
-
|
|
700
|
-
return typeMapFromRecordType(m.kind, p, paths);
|
|
701
|
-
|
|
702
|
-
} else {
|
|
416
|
+
export const typeMapFromMemberDecs = (list: ast.MemberDeclaration[]) =>
|
|
417
|
+
list.reduce(
|
|
418
|
+
(p, m) => {
|
|
419
|
+
let paths = m.path.map((p) => p.value);
|
|
703
420
|
|
|
704
|
-
|
|
421
|
+
if (m.kind instanceof ast.RecordType) {
|
|
422
|
+
return typeMapFromRecordType(m.kind, p, paths);
|
|
423
|
+
} else {
|
|
424
|
+
let path = paths2String(paths);
|
|
705
425
|
|
|
706
|
-
|
|
426
|
+
path = m.optional ? `${path}?` : path;
|
|
707
427
|
|
|
708
|
-
|
|
428
|
+
p[path] = m.kind;
|
|
709
429
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
430
|
+
return p;
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
<TypeMap>{},
|
|
434
|
+
);
|
|
715
435
|
|
|
716
436
|
/**
|
|
717
437
|
* typeMapFromRecordType produces a map of node.Type instances from
|
|
@@ -719,136 +439,114 @@ export const typeMapFromMemberDecs =
|
|
|
719
439
|
*
|
|
720
440
|
* Any encountered RecordTypes will be flattened.
|
|
721
441
|
*/
|
|
722
|
-
export const typeMapFromRecordType =
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
return typeMapFromRecordType(m.kind, init, path);
|
|
731
|
-
|
|
732
|
-
} else {
|
|
733
|
-
|
|
734
|
-
p[paths2String(path)] = m.kind;
|
|
442
|
+
export const typeMapFromRecordType = (
|
|
443
|
+
n: ast.RecordType,
|
|
444
|
+
init: TypeMap,
|
|
445
|
+
prefix: string[],
|
|
446
|
+
): TypeMap =>
|
|
447
|
+
n.members.reduce((p, m) => {
|
|
448
|
+
let path = [...prefix, ...m.path.map((p) => p.value)];
|
|
735
449
|
|
|
736
|
-
|
|
450
|
+
if (m.kind instanceof ast.RecordType) {
|
|
451
|
+
return typeMapFromRecordType(m.kind, init, path);
|
|
452
|
+
} else {
|
|
453
|
+
p[paths2String(path)] = m.kind;
|
|
737
454
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
455
|
+
return p;
|
|
456
|
+
}
|
|
457
|
+
}, init);
|
|
741
458
|
|
|
742
|
-
const paths2String = (paths: string[]) => paths.join(
|
|
459
|
+
const paths2String = (paths: string[]) => paths.join(".");
|
|
743
460
|
|
|
744
461
|
/**
|
|
745
462
|
* expandTypeMap to an ExpandedTypeMap.
|
|
746
463
|
*/
|
|
747
464
|
export const expandTypeMap = (m: TypeMap): ExpandedTypeMap =>
|
|
748
|
-
|
|
749
|
-
|
|
465
|
+
reduce(m, <ExpandedTypeMap>{}, (p, c, k) =>
|
|
466
|
+
set<TypeOrMap, ExpandedTypeMap>(k, type2TS(c), p),
|
|
467
|
+
);
|
|
750
468
|
|
|
751
469
|
/**
|
|
752
470
|
* typeMap2TS converts a map of type values to TypeScript.
|
|
753
471
|
*/
|
|
754
472
|
export const typeMap2TS = (m: ExpandedTypeMap): TypeScript =>
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
return `${k} : ${t}`;
|
|
765
|
-
|
|
766
|
-
}
|
|
767
|
-
}).join(',\n');
|
|
473
|
+
mapTo(m, (t, k) => {
|
|
474
|
+
if (isRecord(t)) {
|
|
475
|
+
let key = isOptional(t) ? `${k}?` : `${k}`;
|
|
476
|
+
return `${key}: {${typeMap2TS(t)}}`;
|
|
477
|
+
} else {
|
|
478
|
+
return `${k} : ${t}`;
|
|
479
|
+
}
|
|
480
|
+
}).join(",\n");
|
|
768
481
|
|
|
769
482
|
const isOptional = (m: ExpandedTypeMap) =>
|
|
770
|
-
|
|
483
|
+
reduce(m, false, (p, _, k) => (p ? p : k.indexOf("?") > -1));
|
|
771
484
|
|
|
772
485
|
/**
|
|
773
486
|
* parameters2TS converts a list Parameter nodes into an parameter list
|
|
774
487
|
* (without parens).
|
|
775
488
|
*/
|
|
776
489
|
export const parameters2TS = (list: ast.Parameter[]) =>
|
|
777
|
-
|
|
490
|
+
list.map((p) => parameter2TS(p)).join(",");
|
|
778
491
|
|
|
779
492
|
/**
|
|
780
|
-
* parameter2TS
|
|
493
|
+
* parameter2TS
|
|
781
494
|
*/
|
|
782
495
|
export const parameter2TS = (n: ast.Parameter) => {
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
return untypedParameter2TS(n)
|
|
788
|
-
else
|
|
789
|
-
return '';
|
|
790
|
-
|
|
791
|
-
}
|
|
496
|
+
if (n instanceof ast.TypedParameter) return typedParameter2TS(n);
|
|
497
|
+
else if (n instanceof ast.UntypedParameter) return untypedParameter2TS(n);
|
|
498
|
+
else return "";
|
|
499
|
+
};
|
|
792
500
|
|
|
793
501
|
/**
|
|
794
|
-
* typedParameter2TS
|
|
502
|
+
* typedParameter2TS
|
|
795
503
|
*/
|
|
796
504
|
export const typedParameter2TS = (n: ast.TypedParameter) =>
|
|
797
|
-
|
|
505
|
+
`${identifier2TS(n.id)}: ${type2TS(n.hint)} `;
|
|
798
506
|
|
|
799
507
|
/**
|
|
800
|
-
* untypedParameter2TS
|
|
508
|
+
* untypedParameter2TS
|
|
801
509
|
*/
|
|
802
510
|
export const untypedParameter2TS = (n: ast.UntypedParameter) =>
|
|
803
|
-
|
|
511
|
+
`${identifier2TS(n.id)} `;
|
|
804
512
|
|
|
805
513
|
/**
|
|
806
514
|
* children2TS
|
|
807
515
|
*/
|
|
808
516
|
export const children2TS = (ctx: CodeGenerator, list: ast.Child[]) =>
|
|
809
|
-
|
|
810
|
-
${list.map(l => child2TS(ctx, l)).join(
|
|
517
|
+
`[${ctx.options.EOL}
|
|
518
|
+
${list.map((l) => child2TS(ctx, l)).join("," + ctx.options.EOL)}
|
|
811
519
|
]`;
|
|
812
520
|
|
|
813
521
|
/**
|
|
814
522
|
* child2TS converts children to typescript.
|
|
815
523
|
*/
|
|
816
524
|
export const child2TS = (ctx: CodeGenerator, n: ast.Child): string => {
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
else if (n instanceof ast.UnqualifiedConstructor)
|
|
837
|
-
return unqualifiedConstructor2TS(n);
|
|
838
|
-
else if (n instanceof ast.UnqualifiedIdentifier)
|
|
839
|
-
return unqualifiedIdentifier2TS(n);
|
|
840
|
-
else if (n instanceof ast.QualifiedIdentifier)
|
|
841
|
-
return qualifiedIdentifier2TS(n);
|
|
842
|
-
else
|
|
843
|
-
return '';
|
|
844
|
-
|
|
845
|
-
}
|
|
525
|
+
if (n instanceof ast.Node || n instanceof ast.Widget) return tag2TS(ctx, n);
|
|
526
|
+
else if (n instanceof ast.Interpolation) return interpolation2TS(ctx, n);
|
|
527
|
+
else if (n instanceof ast.IfStatement) return ifStatement2TS(ctx, n);
|
|
528
|
+
else if (n instanceof ast.ForInStatement) return forInStatement2TS(ctx, n);
|
|
529
|
+
else if (n instanceof ast.ForOfStatement) return forOfStatement2TS(ctx, n);
|
|
530
|
+
else if (n instanceof ast.ForFromStatement)
|
|
531
|
+
return forFromStatement2TS(ctx, n);
|
|
532
|
+
else if (n instanceof ast.Characters) return characters2TS(n);
|
|
533
|
+
else if (n instanceof ast.ContextProperty) return contextProperty2TS(n);
|
|
534
|
+
else if (n instanceof ast.QualifiedConstructor)
|
|
535
|
+
return qualifiedConstructor2TS(n);
|
|
536
|
+
else if (n instanceof ast.UnqualifiedConstructor)
|
|
537
|
+
return unqualifiedConstructor2TS(n);
|
|
538
|
+
else if (n instanceof ast.UnqualifiedIdentifier)
|
|
539
|
+
return unqualifiedIdentifier2TS(n);
|
|
540
|
+
else if (n instanceof ast.QualifiedIdentifier)
|
|
541
|
+
return qualifiedIdentifier2TS(n);
|
|
542
|
+
else return "";
|
|
543
|
+
};
|
|
846
544
|
|
|
847
545
|
/**
|
|
848
546
|
* tag2TS converts a tag to typescript.
|
|
849
547
|
*/
|
|
850
548
|
export const tag2TS = (ctx: CodeGenerator, n: ast.Tag) =>
|
|
851
|
-
|
|
549
|
+
n instanceof ast.Widget ? widget2TS(ctx, n) : node2TS(ctx, n);
|
|
852
550
|
|
|
853
551
|
/**
|
|
854
552
|
* widget2TS converts a Widget node into its typescript representation.
|
|
@@ -856,16 +554,16 @@ export const tag2TS = (ctx: CodeGenerator, n: ast.Tag) =>
|
|
|
856
554
|
* This is simply a call to the View's widget method.
|
|
857
555
|
*/
|
|
858
556
|
export const widget2TS = (ctx: CodeGenerator, n: ast.Widget) => {
|
|
557
|
+
let name = constructor2TS(n.open);
|
|
558
|
+
let typeParams = typeArgs2TS(n.typeArgs);
|
|
559
|
+
let attrs = attrs2String(ctx, n.attributes);
|
|
560
|
+
let childs = children2TS(ctx, n.children);
|
|
859
561
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
return `${THIS}.widget(new ${name}${typeParams}(${attrs}, ${childs}),` +
|
|
866
|
-
`<${WML}.Attrs>${attrs})`;
|
|
867
|
-
|
|
868
|
-
}
|
|
562
|
+
return (
|
|
563
|
+
`${THIS}.widget(new ${name}${typeParams}(${attrs}, ${childs}),` +
|
|
564
|
+
`<${WML}.Attrs>${attrs})`
|
|
565
|
+
);
|
|
566
|
+
};
|
|
869
567
|
|
|
870
568
|
/**
|
|
871
569
|
* node2TS converts a Node into its typescript representation.
|
|
@@ -873,388 +571,387 @@ export const widget2TS = (ctx: CodeGenerator, n: ast.Widget) => {
|
|
|
873
571
|
* This is simply a call to the View's node method.
|
|
874
572
|
*/
|
|
875
573
|
export const node2TS = (ctx: CodeGenerator, n: ast.Node) => {
|
|
574
|
+
let name = identifier2TS(n.open);
|
|
575
|
+
let attrs = attrs2String(ctx, n.attributes);
|
|
576
|
+
let childs = children2TS(ctx, n.children);
|
|
876
577
|
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
let childs = children2TS(ctx, n.children);
|
|
880
|
-
|
|
881
|
-
return `${THIS}.node('${name}', <${WML}.Attrs>${attrs}, ${childs})`;
|
|
882
|
-
|
|
883
|
-
}
|
|
578
|
+
return `${THIS}.node('${name}', <${WML}.Attrs>${attrs}, ${childs})`;
|
|
579
|
+
};
|
|
884
580
|
|
|
885
581
|
/**
|
|
886
|
-
* attribute2Value
|
|
582
|
+
* attribute2Value
|
|
887
583
|
*/
|
|
888
584
|
export const attribute2TS = (ctx: CodeGenerator, n: ast.Attribute) =>
|
|
889
|
-
|
|
585
|
+
`${attributeName2TS(ctx, n)} : ${attributeValue2TS(ctx, n)} `;
|
|
890
586
|
|
|
891
587
|
/**
|
|
892
588
|
* attributeValue2TS
|
|
893
589
|
*/
|
|
894
|
-
export const attributeValue2TS =
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
literal2TS(ctx, n.value);
|
|
590
|
+
export const attributeValue2TS = (ctx: CodeGenerator, n: ast.Attribute) =>
|
|
591
|
+
n.value instanceof ast.Interpolation
|
|
592
|
+
? interpolation2TS(ctx, n.value)
|
|
593
|
+
: literal2TS(ctx, n.value);
|
|
899
594
|
|
|
900
595
|
/**
|
|
901
596
|
* attributeName2TS
|
|
902
597
|
*/
|
|
903
598
|
export const attributeName2TS = (_: CodeGenerator, n: ast.Attribute) =>
|
|
904
|
-
|
|
599
|
+
`'${unqualifiedIdentifier2TS(n.name)}'`;
|
|
905
600
|
|
|
906
601
|
/**
|
|
907
|
-
* attrs2String
|
|
602
|
+
* attrs2String
|
|
908
603
|
*/
|
|
909
604
|
export const attrs2String = (ctx: CodeGenerator, attrs: ast.Attribute[]) => {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
605
|
+
// Check for the special wml:attrs attribute.
|
|
606
|
+
|
|
607
|
+
let mallAttrs = find(
|
|
608
|
+
attrs,
|
|
609
|
+
(attr) => attr.namespace.value === "wml" && attr.name.value === "attrs",
|
|
610
|
+
);
|
|
611
|
+
|
|
612
|
+
if (mallAttrs.isJust()) return attributeValue2TS(ctx, mallAttrs.get());
|
|
613
|
+
|
|
614
|
+
let [nns, ns] = partition(attrs, (a) => a.namespace.value === "");
|
|
615
|
+
|
|
616
|
+
let nso = ns.reduce(
|
|
617
|
+
(p, n) =>
|
|
618
|
+
merge(p, {
|
|
619
|
+
[n.namespace.value]: (p[n.namespace.value] || []).concat(
|
|
620
|
+
attribute2TS(ctx, n),
|
|
621
|
+
),
|
|
622
|
+
}),
|
|
623
|
+
<{ [key: string]: string[] }>{},
|
|
624
|
+
);
|
|
625
|
+
|
|
626
|
+
return _attrs2String(
|
|
627
|
+
nns.reduce(
|
|
628
|
+
(p, n) =>
|
|
629
|
+
merge(p, {
|
|
630
|
+
[attributeName2TS(ctx, n)]: attributeValue2TS(ctx, n),
|
|
631
|
+
}),
|
|
632
|
+
<{ [key: string]: string | string[] }>nso,
|
|
633
|
+
),
|
|
634
|
+
);
|
|
635
|
+
};
|
|
934
636
|
|
|
935
637
|
const _attrs2String = (attrs: { [key: string]: string | string[] }) =>
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
638
|
+
"{" +
|
|
639
|
+
Object.keys(attrs).map((name) =>
|
|
640
|
+
Array.isArray(attrs[name])
|
|
641
|
+
? `${name} : { ${(<string[]>attrs[name]).join(",")} }`
|
|
642
|
+
: `${name}: ${attrs[name]}`,
|
|
643
|
+
) +
|
|
644
|
+
"}";
|
|
942
645
|
|
|
943
646
|
/**
|
|
944
|
-
* interpolation2TS
|
|
647
|
+
* interpolation2TS
|
|
945
648
|
*/
|
|
946
649
|
export const interpolation2TS = (ctx: CodeGenerator, n: ast.Interpolation) =>
|
|
947
|
-
|
|
948
|
-
|
|
650
|
+
n.filters.reduce(
|
|
651
|
+
(p, c) => `${expression2TS(ctx, c)} (${p})`,
|
|
652
|
+
expression2TS(ctx, n.expression),
|
|
653
|
+
);
|
|
949
654
|
|
|
950
655
|
/**
|
|
951
656
|
* ifStatementTS converts an IfStatement to its typescript representation.
|
|
952
657
|
*/
|
|
953
|
-
export const ifStatement2TS =
|
|
954
|
-
|
|
658
|
+
export const ifStatement2TS = (
|
|
659
|
+
ctx: CodeGenerator,
|
|
660
|
+
n: ast.IfStatement,
|
|
661
|
+
): TypeScript => {
|
|
662
|
+
let condition = expression2TS(ctx, n.condition);
|
|
663
|
+
let conseq = children2TS(ctx, n.then);
|
|
955
664
|
|
|
956
|
-
|
|
957
|
-
|
|
665
|
+
let alt =
|
|
666
|
+
n.elseClause instanceof ast.ElseIfClause
|
|
667
|
+
? `[${ifStatement2TS(ctx, n.elseClause)}]`
|
|
668
|
+
: n.elseClause instanceof ast.ElseClause
|
|
669
|
+
? children2TS(ctx, n.elseClause.children)
|
|
670
|
+
: "[]";
|
|
958
671
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
return [
|
|
966
|
-
`...((${condition}) ?`,
|
|
967
|
-
`(()=>(${conseq}))() :`,
|
|
968
|
-
`(()=>(${alt}))())`
|
|
969
|
-
].join(ctx.options.EOL);
|
|
970
|
-
|
|
971
|
-
}
|
|
672
|
+
return [
|
|
673
|
+
`...((${condition}) ?`,
|
|
674
|
+
`(()=>(${conseq}))() :`,
|
|
675
|
+
`(()=>(${alt}))())`,
|
|
676
|
+
].join(ctx.options.EOL);
|
|
677
|
+
};
|
|
972
678
|
|
|
973
679
|
/**
|
|
974
680
|
* forInStatement2TS converts a ForInStatement to its typescript representation.
|
|
975
681
|
*/
|
|
976
|
-
export const forInStatement2TS = (
|
|
682
|
+
export const forInStatement2TS = (
|
|
683
|
+
ctx: CodeGenerator,
|
|
684
|
+
n: ast.ForInStatement,
|
|
685
|
+
) => {
|
|
686
|
+
let expr = expression2TS(ctx, n.expression);
|
|
977
687
|
|
|
978
|
-
|
|
688
|
+
let value = parameter2TS(n.variables[0]);
|
|
979
689
|
|
|
980
|
-
|
|
690
|
+
let key = n.variables.length > 1 ? parameter2TS(n.variables[1]) : "_$$i";
|
|
981
691
|
|
|
982
|
-
|
|
692
|
+
let all = n.variables.length > 2 ? parameter2TS(n.variables[2]) : "_$$all";
|
|
983
693
|
|
|
984
|
-
|
|
694
|
+
let body = children2TS(ctx, n.body);
|
|
985
695
|
|
|
986
|
-
|
|
696
|
+
let alt = n.otherwise.length > 0 ? children2TS(ctx, n.otherwise) : "[]";
|
|
987
697
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
].join(ctx.options.EOL);
|
|
995
|
-
|
|
996
|
-
}
|
|
698
|
+
return [
|
|
699
|
+
`...${FOR_IN} (${expr}, (${value}, ${key}, ${all})=> `,
|
|
700
|
+
`(${body}), `,
|
|
701
|
+
`()=> (${alt}))`,
|
|
702
|
+
].join(ctx.options.EOL);
|
|
703
|
+
};
|
|
997
704
|
|
|
998
705
|
/**
|
|
999
706
|
* forOfStatement2TS
|
|
1000
707
|
*/
|
|
1001
|
-
export const forOfStatement2TS = (
|
|
708
|
+
export const forOfStatement2TS = (
|
|
709
|
+
ctx: CodeGenerator,
|
|
710
|
+
n: ast.ForOfStatement,
|
|
711
|
+
) => {
|
|
712
|
+
let expr = expression2TS(ctx, n.expression);
|
|
1002
713
|
|
|
1003
|
-
|
|
714
|
+
let value = parameter2TS(n.variables[0]);
|
|
1004
715
|
|
|
1005
|
-
|
|
716
|
+
let key = n.variables.length > 1 ? parameter2TS(n.variables[1]) : "_$$k";
|
|
1006
717
|
|
|
1007
|
-
|
|
718
|
+
let all = n.variables.length > 2 ? parameter2TS(n.variables[2]) : "_$$all";
|
|
1008
719
|
|
|
1009
|
-
|
|
720
|
+
let body = children2TS(ctx, n.body);
|
|
1010
721
|
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
let alt = n.otherwise.length > 0 ? children2TS(ctx, n.otherwise) : '[]';
|
|
1014
|
-
|
|
1015
|
-
return [
|
|
1016
|
-
`...${FOR_OF} (${expr}, (${value}, ${key}, ${all}) => `,
|
|
1017
|
-
` (${body}), `,
|
|
1018
|
-
` ()=> (${alt}))`
|
|
1019
|
-
].join(eol(ctx));
|
|
722
|
+
let alt = n.otherwise.length > 0 ? children2TS(ctx, n.otherwise) : "[]";
|
|
1020
723
|
|
|
1021
|
-
|
|
724
|
+
return [
|
|
725
|
+
`...${FOR_OF} (${expr}, (${value}, ${key}, ${all}) => `,
|
|
726
|
+
` (${body}), `,
|
|
727
|
+
` ()=> (${alt}))`,
|
|
728
|
+
].join(eol(ctx));
|
|
729
|
+
};
|
|
1022
730
|
|
|
1023
731
|
/**
|
|
1024
732
|
* forFromStatement2TS
|
|
1025
733
|
*/
|
|
1026
|
-
export const forFromStatement2TS =
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
734
|
+
export const forFromStatement2TS = (
|
|
735
|
+
ctx: CodeGenerator,
|
|
736
|
+
node: ast.ForFromStatement,
|
|
737
|
+
) => {
|
|
738
|
+
let value = parameter2TS(node.variable);
|
|
1030
739
|
|
|
1031
|
-
|
|
740
|
+
let start = expression2TS(ctx, node.start);
|
|
1032
741
|
|
|
1033
|
-
|
|
742
|
+
let end = expression2TS(ctx, node.end);
|
|
1034
743
|
|
|
1035
|
-
|
|
744
|
+
let body = children2TS(ctx, node.body);
|
|
1036
745
|
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
}
|
|
746
|
+
return [
|
|
747
|
+
`...(function forFrom() {`,
|
|
748
|
+
` let result:${WML}.Content[] = [];`,
|
|
749
|
+
` for(let ${value}:number=${start}; ${value}<=${end}; ${value}++)`,
|
|
750
|
+
` result.push(`,
|
|
751
|
+
` ...${body}`,
|
|
752
|
+
` );`,
|
|
753
|
+
` return result;`,
|
|
754
|
+
`})()`,
|
|
755
|
+
].join(eol(ctx));
|
|
756
|
+
};
|
|
1049
757
|
|
|
1050
758
|
/**
|
|
1051
759
|
* characters2TS converts character text to a typescript string.
|
|
1052
760
|
*/
|
|
1053
761
|
export const characters2TS = (n: ast.Characters) =>
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
const breakLines = (str: string) => str.split(
|
|
1057
|
-
|
|
1058
|
-
/**
|
|
1059
|
-
* expression2TS
|
|
1060
|
-
*/
|
|
1061
|
-
export const expression2TS = (
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
`${THIS}.registerView(${expression2TS(ctx, n.expression)}).render()`;
|
|
1156
|
-
|
|
1157
|
-
/**
|
|
1158
|
-
* funApplication2TS
|
|
762
|
+
`${DOCUMENT}.createTextNode('${breakLines(n.value)}')`;
|
|
763
|
+
|
|
764
|
+
const breakLines = (str: string) => str.split("\n").join("\\u000a");
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* expression2TS
|
|
768
|
+
*/
|
|
769
|
+
export const expression2TS = (
|
|
770
|
+
ctx: CodeGenerator,
|
|
771
|
+
n: ast.Expression,
|
|
772
|
+
): string => {
|
|
773
|
+
if (n instanceof ast.IfThenExpression) return ifThenExpression2TS(ctx, n);
|
|
774
|
+
else if (n instanceof ast.BinaryExpression)
|
|
775
|
+
return binaryExpression2TS(ctx, n);
|
|
776
|
+
else if (n instanceof ast.UnaryExpression) return unaryExpression2TS(ctx, n);
|
|
777
|
+
else if (n instanceof ast.ViewConstruction)
|
|
778
|
+
return viewConstruction2TS(ctx, n);
|
|
779
|
+
else if (n instanceof ast.FunApplication) return funApplication2TS(ctx, n);
|
|
780
|
+
else if (n instanceof ast.ConstructExpression)
|
|
781
|
+
return constructExpression2TS(ctx, n);
|
|
782
|
+
else if (n instanceof ast.CallExpression) return callExpression2TS(ctx, n);
|
|
783
|
+
else if (n instanceof ast.MemberExpression)
|
|
784
|
+
return memberExpression2TS(ctx, n);
|
|
785
|
+
else if (n instanceof ast.FunctionExpression)
|
|
786
|
+
return functionExpression2TS(ctx, n);
|
|
787
|
+
else if (n instanceof ast.Record) return record2TS(ctx, n);
|
|
788
|
+
else if (n instanceof ast.List) return list2TS(ctx, n);
|
|
789
|
+
else if (n instanceof ast.BooleanLiteral) return boolean2TS(n);
|
|
790
|
+
else if (n instanceof ast.NumberLiteral) return number2TS(n);
|
|
791
|
+
else if (n instanceof ast.StringLiteral) return string2TS(n);
|
|
792
|
+
else if (n instanceof ast.ContextProperty) return contextProperty2TS(n);
|
|
793
|
+
else if (n instanceof ast.QualifiedConstructor)
|
|
794
|
+
return qualifiedConstructor2TS(n);
|
|
795
|
+
else if (n instanceof ast.UnqualifiedConstructor)
|
|
796
|
+
return unqualifiedConstructor2TS(n);
|
|
797
|
+
else if (n instanceof ast.UnqualifiedIdentifier)
|
|
798
|
+
return unqualifiedIdentifier2TS(n);
|
|
799
|
+
else if (n instanceof ast.QualifiedIdentifier)
|
|
800
|
+
return qualifiedIdentifier2TS(n);
|
|
801
|
+
else if (n instanceof ast.ContextVariable) return contextVariable2TS(n);
|
|
802
|
+
else return "";
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* ifThenExpression2TS
|
|
807
|
+
*/
|
|
808
|
+
export const ifThenExpression2TS = (
|
|
809
|
+
ctx: CodeGenerator,
|
|
810
|
+
n: ast.IfThenExpression,
|
|
811
|
+
) => {
|
|
812
|
+
let condition = expression2TS(ctx, n.condition);
|
|
813
|
+
let conseq = expression2TS(ctx, n.iftrue);
|
|
814
|
+
let alt = expression2TS(ctx, n.iffalse);
|
|
815
|
+
|
|
816
|
+
return `(${condition}) ? ${conseq} : ${alt}`;
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* binaryExpression2TS
|
|
821
|
+
*/
|
|
822
|
+
export const binaryExpression2TS = (
|
|
823
|
+
ctx: CodeGenerator,
|
|
824
|
+
n: ast.BinaryExpression,
|
|
825
|
+
) => {
|
|
826
|
+
let left = expression2TS(ctx, n.left);
|
|
827
|
+
|
|
828
|
+
let right =
|
|
829
|
+
n.operator === "as"
|
|
830
|
+
? type2TS(<ast.Type>n.right)
|
|
831
|
+
: expression2TS(ctx, n.right);
|
|
832
|
+
|
|
833
|
+
let op = operators.hasOwnProperty(n.operator)
|
|
834
|
+
? operators[n.operator]
|
|
835
|
+
: n.operator;
|
|
836
|
+
|
|
837
|
+
return n.operator === "as"
|
|
838
|
+
? `<${right}>(${left})`
|
|
839
|
+
: `(${left} ${op} ${right})`;
|
|
840
|
+
};
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* unaryExpression2TS
|
|
844
|
+
*/
|
|
845
|
+
export const unaryExpression2TS = (
|
|
846
|
+
ctx: CodeGenerator,
|
|
847
|
+
n: ast.UnaryExpression,
|
|
848
|
+
) => {
|
|
849
|
+
let expr = expression2TS(ctx, n.expression);
|
|
850
|
+
return `${n.operator}(${expr})`;
|
|
851
|
+
};
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* viewConstruction2TS
|
|
855
|
+
*/
|
|
856
|
+
export const viewConstruction2TS = (
|
|
857
|
+
ctx: CodeGenerator,
|
|
858
|
+
n: ast.ViewConstruction,
|
|
859
|
+
) => `${THIS}.view(${expression2TS(ctx, n.expression)})`;
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* funApplication2TS
|
|
1159
863
|
*/
|
|
1160
864
|
export const funApplication2TS = (ctx: CodeGenerator, n: ast.FunApplication) =>
|
|
1161
|
-
|
|
1162
|
-
|
|
865
|
+
`${expression2TS(ctx, n.target)}${typeArgs2TS(n.typeArgs)} ` +
|
|
866
|
+
`(${args2TS(ctx, n.args)})(${THIS})`;
|
|
1163
867
|
|
|
1164
868
|
/**
|
|
1165
|
-
* constructExpression2TS
|
|
869
|
+
* constructExpression2TS
|
|
1166
870
|
*/
|
|
1167
|
-
export const constructExpression2TS =
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
871
|
+
export const constructExpression2TS = (
|
|
872
|
+
ctx: CodeGenerator,
|
|
873
|
+
n: ast.ConstructExpression,
|
|
874
|
+
) => {
|
|
875
|
+
let cons = constructor2TS(n.cons);
|
|
1171
876
|
|
|
1172
|
-
|
|
877
|
+
let consOriginal = `${cons[0].toUpperCase()}${cons.slice(1)}`;
|
|
1173
878
|
|
|
1174
|
-
|
|
879
|
+
let typeArgs = typeArgs2TS(n.typeArgs);
|
|
1175
880
|
|
|
1176
|
-
|
|
881
|
+
let args = args2TS(ctx, n.args);
|
|
1177
882
|
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
`new ${cons}${typeArgs}(${args})`;
|
|
1183
|
-
|
|
1184
|
-
}
|
|
883
|
+
return contains(casters, consOriginal)
|
|
884
|
+
? `${consOriginal}${typeArgs}(${args})`
|
|
885
|
+
: `new ${cons}${typeArgs}(${args})`;
|
|
886
|
+
};
|
|
1185
887
|
|
|
1186
888
|
/**
|
|
1187
|
-
* callExpression2TS
|
|
889
|
+
* callExpression2TS
|
|
1188
890
|
*/
|
|
1189
|
-
export const callExpression2TS = (
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
891
|
+
export const callExpression2TS = (
|
|
892
|
+
ctx: CodeGenerator,
|
|
893
|
+
n: ast.CallExpression,
|
|
894
|
+
) => {
|
|
895
|
+
let target = expression2TS(ctx, n.target);
|
|
896
|
+
let typeArgs = typeArgs2TS(n.typeArgs);
|
|
897
|
+
let args = args2TS(ctx, n.args);
|
|
1194
898
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
}
|
|
899
|
+
return `${target}${typeArgs}(${args})`;
|
|
900
|
+
};
|
|
1198
901
|
|
|
1199
902
|
/**
|
|
1200
|
-
* typeArgs2TS
|
|
903
|
+
* typeArgs2TS
|
|
1201
904
|
*/
|
|
1202
905
|
export const typeArgs2TS = (ns: ast.Type[]) =>
|
|
1203
|
-
|
|
906
|
+
empty(ns) ? "" : `<${ns.map(type2TS).join(",")}>`;
|
|
1204
907
|
|
|
1205
908
|
/**
|
|
1206
909
|
* args2TS converts a list of arguments to a typescript argument tupple.
|
|
1207
910
|
*/
|
|
1208
911
|
export const args2TS = (ctx: CodeGenerator, ns: ast.Expression[]) =>
|
|
1209
|
-
|
|
912
|
+
ns.length === 0 ? "" : ns.map((e) => expression2TS(ctx, e)).join(",");
|
|
1210
913
|
|
|
1211
914
|
/**
|
|
1212
|
-
* memberExpression2TS
|
|
915
|
+
* memberExpression2TS
|
|
1213
916
|
*/
|
|
1214
|
-
export const memberExpression2TS =
|
|
1215
|
-
|
|
1216
|
-
|
|
917
|
+
export const memberExpression2TS = (
|
|
918
|
+
ctx: CodeGenerator,
|
|
919
|
+
n: ast.MemberExpression,
|
|
920
|
+
) => {
|
|
921
|
+
let target = expression2TS(ctx, n.head);
|
|
1217
922
|
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
923
|
+
return n.tail instanceof ast.StringLiteral
|
|
924
|
+
? `${target}[${string2TS(n.tail)}]`
|
|
925
|
+
: `${target}.${expression2TS(ctx, n.tail)}`;
|
|
926
|
+
};
|
|
1222
927
|
|
|
1223
928
|
/**
|
|
1224
929
|
* functionExpression2TS
|
|
1225
930
|
*/
|
|
1226
|
-
export const functionExpression2TS =
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
return `(${params}) => ${body}`;
|
|
931
|
+
export const functionExpression2TS = (
|
|
932
|
+
ctx: CodeGenerator,
|
|
933
|
+
n: ast.FunctionExpression,
|
|
934
|
+
) => {
|
|
935
|
+
let params = n.parameters.map(parameter2TS).join(",");
|
|
936
|
+
let body = expression2TS(ctx, n.body);
|
|
1233
937
|
|
|
1234
|
-
|
|
938
|
+
return `(${params}) => ${body}`;
|
|
939
|
+
};
|
|
1235
940
|
|
|
1236
941
|
/**
|
|
1237
|
-
* literal2TS
|
|
942
|
+
* literal2TS
|
|
1238
943
|
*/
|
|
1239
944
|
export const literal2TS = (ctx: CodeGenerator, n: ast.Literal) => {
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
else if (n instanceof ast.Record)
|
|
1248
|
-
return record2TS(ctx, n);
|
|
1249
|
-
else if (n instanceof ast.List)
|
|
1250
|
-
return list2TS(ctx, n);
|
|
1251
|
-
else
|
|
1252
|
-
return '';
|
|
1253
|
-
|
|
1254
|
-
}
|
|
945
|
+
if (n instanceof ast.BooleanLiteral) return boolean2TS(n);
|
|
946
|
+
else if (n instanceof ast.StringLiteral) return string2TS(n);
|
|
947
|
+
else if (n instanceof ast.NumberLiteral) return number2TS(n);
|
|
948
|
+
else if (n instanceof ast.Record) return record2TS(ctx, n);
|
|
949
|
+
else if (n instanceof ast.List) return list2TS(ctx, n);
|
|
950
|
+
else return "";
|
|
951
|
+
};
|
|
1255
952
|
|
|
1256
953
|
/**
|
|
1257
|
-
* boolean2TS
|
|
954
|
+
* boolean2TS
|
|
1258
955
|
*/
|
|
1259
956
|
export const boolean2TS = (n: ast.BooleanLiteral) => `${n.value} `;
|
|
1260
957
|
|
|
@@ -1262,10 +959,13 @@ export const boolean2TS = (n: ast.BooleanLiteral) => `${n.value} `;
|
|
|
1262
959
|
* string2TS
|
|
1263
960
|
*/
|
|
1264
961
|
export const string2TS = (n: ast.StringLiteral) =>
|
|
1265
|
-
|
|
962
|
+
n.value
|
|
963
|
+
.split("\n")
|
|
964
|
+
.map((str) => `"${str}"`)
|
|
965
|
+
.join("+");
|
|
1266
966
|
|
|
1267
967
|
/**
|
|
1268
|
-
* number2TS
|
|
968
|
+
* number2TS
|
|
1269
969
|
*/
|
|
1270
970
|
export const number2TS = (n: ast.NumberLiteral) => `${parseFloat(n.value)}`;
|
|
1271
971
|
|
|
@@ -1273,119 +973,111 @@ export const number2TS = (n: ast.NumberLiteral) => `${parseFloat(n.value)}`;
|
|
|
1273
973
|
* record2TS
|
|
1274
974
|
*/
|
|
1275
975
|
export const record2TS = (ctx: CodeGenerator, n: ast.Record) =>
|
|
1276
|
-
|
|
1277
|
-
${n.properties.map(p => property2TS(ctx, p)).join(
|
|
976
|
+
`{${ctx.options.EOL}
|
|
977
|
+
${n.properties.map((p) => property2TS(ctx, p)).join("," + ctx.options.EOL)}
|
|
1278
978
|
}`;
|
|
1279
979
|
|
|
1280
980
|
/**
|
|
1281
981
|
* list2TS
|
|
1282
982
|
*/
|
|
1283
983
|
export const list2TS = (ctx: CodeGenerator, n: ast.List) => {
|
|
984
|
+
let mems = n.members.map((e) => expression2TS(ctx, e));
|
|
1284
985
|
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
return `[${ctx.options.EOL}
|
|
1288
|
-
${mems.join(',' + ctx.options.EOL)}
|
|
986
|
+
return `[${ctx.options.EOL}
|
|
987
|
+
${mems.join("," + ctx.options.EOL)}
|
|
1289
988
|
]`;
|
|
1290
|
-
|
|
1291
|
-
}
|
|
989
|
+
};
|
|
1292
990
|
|
|
1293
991
|
/**
|
|
1294
992
|
* property2TS
|
|
1295
993
|
*/
|
|
1296
994
|
export const property2TS = (ctx: CodeGenerator, n: ast.Property) =>
|
|
1297
|
-
|
|
995
|
+
`'${key2TS(n.key)}' : ${expression2TS(ctx, n.value)}`;
|
|
1298
996
|
|
|
1299
997
|
/**
|
|
1300
|
-
* key2TS
|
|
998
|
+
* key2TS
|
|
1301
999
|
*/
|
|
1302
1000
|
export const key2TS = (n: ast.StringLiteral | ast.UnqualifiedIdentifier) =>
|
|
1303
|
-
|
|
1001
|
+
n instanceof ast.StringLiteral ? string2TS(n) : identifier2TS(n);
|
|
1304
1002
|
|
|
1305
1003
|
/**
|
|
1306
|
-
* contextProperty2TS
|
|
1004
|
+
* contextProperty2TS
|
|
1307
1005
|
*/
|
|
1308
1006
|
export const contextProperty2TS = (n: ast.ContextProperty) => {
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1007
|
+
let member =
|
|
1008
|
+
n.member instanceof ast.StringLiteral
|
|
1009
|
+
? n.member.value
|
|
1010
|
+
: identifier2TS(n.member);
|
|
1312
1011
|
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
}
|
|
1012
|
+
return `${CONTEXT}.${member}`;
|
|
1013
|
+
};
|
|
1316
1014
|
|
|
1317
1015
|
/**
|
|
1318
|
-
* contextVariable2TS
|
|
1016
|
+
* contextVariable2TS
|
|
1319
1017
|
*/
|
|
1320
1018
|
export const contextVariable2TS = (_: ast.ContextVariable) => `${CONTEXT}`;
|
|
1321
1019
|
|
|
1322
1020
|
/**
|
|
1323
1021
|
* identifierOrConstructor2TS
|
|
1324
1022
|
*/
|
|
1325
|
-
export const identifierOrConstructor2TS =
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1023
|
+
export const identifierOrConstructor2TS = (
|
|
1024
|
+
n: ast.Identifier | ast.Constructor,
|
|
1025
|
+
) => {
|
|
1026
|
+
if (
|
|
1027
|
+
n instanceof ast.UnqualifiedIdentifier ||
|
|
1028
|
+
n instanceof ast.QualifiedIdentifier
|
|
1029
|
+
)
|
|
1030
|
+
return identifier2TS(n);
|
|
1031
|
+
else if (
|
|
1032
|
+
n instanceof ast.UnqualifiedConstructor ||
|
|
1033
|
+
n instanceof ast.QualifiedConstructor
|
|
1034
|
+
)
|
|
1035
|
+
return constructor2TS(n);
|
|
1036
|
+
else return "";
|
|
1037
|
+
};
|
|
1038
|
+
|
|
1039
|
+
/**
|
|
1040
|
+
* constructor2TS
|
|
1341
1041
|
*/
|
|
1342
1042
|
export const constructor2TS = (n: ast.Constructor) => {
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
else
|
|
1349
|
-
return '';
|
|
1350
|
-
|
|
1351
|
-
}
|
|
1043
|
+
if (n instanceof ast.QualifiedConstructor) return qualifiedConstructor2TS(n);
|
|
1044
|
+
else if (n instanceof ast.UnqualifiedConstructor)
|
|
1045
|
+
return unqualifiedConstructor2TS(n);
|
|
1046
|
+
else return "";
|
|
1047
|
+
};
|
|
1352
1048
|
|
|
1353
1049
|
/**
|
|
1354
|
-
* unqualifiedConstructor2TS
|
|
1050
|
+
* unqualifiedConstructor2TS
|
|
1355
1051
|
*/
|
|
1356
1052
|
export const unqualifiedConstructor2TS = (n: ast.UnqualifiedConstructor) =>
|
|
1357
|
-
|
|
1053
|
+
toPrim(n.value);
|
|
1358
1054
|
|
|
1359
1055
|
/**
|
|
1360
1056
|
* qualifiedConstructor
|
|
1361
1057
|
*/
|
|
1362
1058
|
export const qualifiedConstructor2TS = (n: ast.QualifiedConstructor) =>
|
|
1363
|
-
|
|
1059
|
+
`${n.qualifier}.${n.member}`;
|
|
1364
1060
|
|
|
1365
1061
|
/**
|
|
1366
1062
|
* identifier2TS
|
|
1367
1063
|
*/
|
|
1368
1064
|
export const identifier2TS = (n: ast.Identifier) => {
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
else
|
|
1375
|
-
return ''
|
|
1376
|
-
|
|
1377
|
-
}
|
|
1065
|
+
if (n instanceof ast.QualifiedIdentifier) return qualifiedIdentifier2TS(n);
|
|
1066
|
+
else if (n instanceof ast.UnqualifiedIdentifier)
|
|
1067
|
+
return unqualifiedIdentifier2TS(n);
|
|
1068
|
+
else return "";
|
|
1069
|
+
};
|
|
1378
1070
|
|
|
1379
1071
|
/**
|
|
1380
|
-
* qualifiedIdentifier2TS
|
|
1072
|
+
* qualifiedIdentifier2TS
|
|
1381
1073
|
*/
|
|
1382
1074
|
export const qualifiedIdentifier2TS = (n: ast.QualifiedIdentifier) =>
|
|
1383
|
-
|
|
1075
|
+
`${n.qualifier}.${n.member}`;
|
|
1384
1076
|
|
|
1385
1077
|
/**
|
|
1386
|
-
* unqualifiedIdentifier2TS
|
|
1078
|
+
* unqualifiedIdentifier2TS
|
|
1387
1079
|
*/
|
|
1388
1080
|
export const unqualifiedIdentifier2TS = (n: ast.UnqualifiedIdentifier) =>
|
|
1389
|
-
|
|
1081
|
+
`${toPrim(n.value)}`;
|
|
1390
1082
|
|
|
1391
|
-
const toPrim = (id: string) => prims.indexOf(id) > -1 ? id.toLowerCase() : id;
|
|
1083
|
+
const toPrim = (id: string) => (prims.indexOf(id) > -1 ? id.toLowerCase() : id);
|