babel-plugin-wallace 0.0.1 → 0.0.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.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Babel-plugin-wallace
2
+
3
+ See https://github.com/andyhasit/wallace
@@ -0,0 +1,356 @@
1
+ /**
2
+ * The object which holds the directive definitions.
3
+ *
4
+ * A directive definition's handler's "this" is a NodeData instance.
5
+ */
6
+ const {RequestsHelp, alwaysUpdate, neverUpdate} = require('../definitions/constants')
7
+ const componentRefVariable = 'c'; // The variable name by which the component will be known.
8
+
9
+
10
+ const old = {
11
+ // What is this for?
12
+ "bind": {
13
+ params: 'watch, event?',
14
+ handle: function(watch, event='change') {
15
+ this.addWatch(watch, undefined, 'value')
16
+ this.addEventListener(event, `${watch} = w.getValue()`)
17
+ }
18
+ },
19
+ "checked": {
20
+ params: 'watch, converter?',
21
+ handle: function(watch, converter) {
22
+ this.addWatch(watch, converter, 'checked')
23
+ }
24
+ },
25
+ "css": {
26
+ params: 'watch, converter?',
27
+ handle: function(watch, converter) {
28
+ this.addWatch(watch, converter, 'css')
29
+ }
30
+ },
31
+ "css-f": {
32
+ params: 'value',
33
+ handle: function(value) {
34
+ this.addWatch(neverUpdate, value, 'css')
35
+ }
36
+ },
37
+ // "el": {
38
+ // handle: function(arg) {
39
+ // this.saveAs = arg
40
+ // }
41
+ // },
42
+ // "hide": {
43
+ // params: 'watch',
44
+ // handle: function(watch) {
45
+ // this.shieldQuery = watch
46
+ // }
47
+ // },
48
+ "helper": {
49
+ handle: function(watch, converter) {
50
+ throw new RequestsHelp(helpTopic)
51
+ }
52
+ },
53
+ "inner": {
54
+ params: 'watch, converter',
55
+ handle: function(watch, converter) {
56
+ this.addWatch(watch, converter, 'inner')
57
+ }
58
+ },
59
+ "items": {
60
+ params: 'watch, converter?',
61
+ handle: function(watch, converter) {
62
+ this.addWatch(watch, converter, 'items', componentRefVariable)
63
+ }
64
+ },
65
+ // "on": {
66
+ // params: 'event, callbackStr',
67
+ // handle: function(event, callbackStr) {
68
+ // this.addEventListener(event, callbackStr)
69
+ // }
70
+ // },
71
+ // "pool": {
72
+ // params: 'poolInstance',
73
+ // handle: function(poolInstance) {
74
+ // this.chainedCalls.push(`pool(${poolInstance})`)
75
+ // }
76
+ // },
77
+ // "props": {
78
+ // params: 'args',
79
+ // handle: function(args) {
80
+ // this.props = this.expandProps(args)
81
+ // }
82
+ // },
83
+ "replace": {
84
+ params: 'componentCls, props?',
85
+ handle: function(componentCls, props) {
86
+ this.replaceWith = componentCls
87
+ if (props) {
88
+ this.props = this.expandProps(props)
89
+ }
90
+ }
91
+ },
92
+ // "show": {
93
+ // params: 'watch',
94
+ // handle: function(watch) {
95
+ // this.shieldQuery = watch
96
+ // this.reverseShield = 1
97
+ // }
98
+ // },
99
+ "stub": {
100
+ params: 'stubName',
101
+ handle: function(stubName) {
102
+ this.stubName = stubName
103
+ }
104
+ },
105
+ "swap": {
106
+ params: 'watch, mappings, fallback?',
107
+ handle: function(watch, mappings, fallback) {
108
+ let args = this.expandDots(mappings)
109
+ if (fallback) {
110
+ args += ', ' + this.expandDots(fallback)
111
+ }
112
+ this.chainedCalls.push(`pool(component.__ic(${args}))`)
113
+ this.addWatch(watch, undefined, 'swap', componentRefVariable)
114
+ }
115
+ },
116
+ // Only for repeat items
117
+ "use": {
118
+ params: 'componentDef, key?',
119
+ handle: function(componentDef, key) {
120
+ this.chainedCalls.push(`pool(${this.buildPoolInit(componentDef, key)})`)
121
+ }
122
+ },
123
+ "value": {
124
+ params: 'watch, converter?',
125
+ handle: function(watch, converter) {
126
+ this.addWatch(watch, converter, 'value')
127
+ }
128
+ },
129
+ "watch": {
130
+ params: 'watch, converter, wrapperMethod?',
131
+ handle: function(watch, converter, wrapperMethod) {
132
+ this.addWatch(watch, converter, wrapperMethod)
133
+ }
134
+ },
135
+ // "wrapper": {
136
+ // params: 'cls, args?',
137
+ // handle: function(cls, args) {
138
+ // this.customWrapperClass = cls
139
+ // this.customWrapperArgs = args
140
+ // }
141
+ // }
142
+ }
143
+
144
+
145
+ const callData = {
146
+ value: "str", // if type str
147
+ args: "str", // if type expr
148
+ qualifier: "str|undefined", // foo:qualifier
149
+ }
150
+
151
+
152
+ const schema = {
153
+ help: "...",
154
+ allowNull: false,
155
+ allowQualifier: false,
156
+ requireQualifier: false,
157
+ requireNull: false,
158
+ handle: "function(nodeData, callData)",
159
+ args: "array", // only if type "expr"
160
+ argSets: "array", // in case it allows multiple args
161
+ }
162
+
163
+ /**
164
+ * Do not create directive which allows or requires null which has the same name as a
165
+ * normal attribute.
166
+ */
167
+ const directives = {
168
+ att: {
169
+ help: `
170
+ Sets an HTML attribute on the element:
171
+
172
+ /h <div _att:hidden="x > 3"></div>
173
+ `,
174
+ requireQualifier: true,
175
+ handle: function(nodeData, attInfo) {
176
+ nodeData.addWatch(attInfo.args[0], undefined, `@${attInfo.qualifier}`)
177
+ }
178
+
179
+ },
180
+ call: {
181
+ help: `
182
+ Watch a value and call a wrapper method if it changes.
183
+
184
+ /h <div _call:method={watch, tranform}></div>
185
+
186
+ Variables for watch: c, p
187
+ Variables for callback: c, p, n, o, w
188
+ `,
189
+ requireQualifier: true,
190
+ handle: function(nodeData, attInfo) {
191
+ nodeData.addWatch(attInfo.args[0], attInfo.args[1], attInfo.qualifier)
192
+ }
193
+ },
194
+ checked: {
195
+ help: `
196
+ Sets the "checked" status of the element:
197
+
198
+ /h <input _checked={c.active} type="checkbox"/>
199
+ `,
200
+ handle: function(nodeData, attInfo) {
201
+ nodeData.addWatch(attInfo.args[0], undefined, 'checked')
202
+ }
203
+ },
204
+ // disabled: {
205
+ // help: `
206
+ // Sets the "disabled" status of the element:
207
+
208
+ // /h <button _disabled={!c.active}>...</button>
209
+ // `,
210
+ // allowedTypes: "expr",
211
+ // handle: function(nodeData, attInfo) {
212
+ // nodeData.addWatch(attInfo.args[0], undefined, 'disabled')
213
+ // }
214
+ // },
215
+ el: {
216
+ help: `
217
+ Gives the wrapper for this element a name so it can be accessed later:
218
+
219
+ /h <div _el:user></div>
220
+
221
+ /j c.el.user.text("Wallace")
222
+ `,
223
+ allowNull: true,
224
+ requireQualifier: true,
225
+ handle: function(nodeData, attInfo) {
226
+ nodeData.saveAs = attInfo.qualifier
227
+ }
228
+ },
229
+ foreach: {
230
+ help: `
231
+ Repeats a nested component:
232
+
233
+ /h <div>
234
+ /h <Child _for={c.items|id} />
235
+ /h </div>
236
+
237
+ `,
238
+ handle: function(nodeData, attInfo) {
239
+ const parent = nodeData.parentNodeData
240
+ if (parent === undefined) {
241
+ // TODO: throw better error, and assert parent has no other chldren.
242
+ throw Error("For must be used under a parent.")
243
+ }
244
+ const componentDef = nodeData.nestedClass
245
+ const data = attInfo.args[0]
246
+ const key = attInfo.args[1]
247
+ parent.chainedCalls.push(`pool(${parent.buildPoolInit(componentDef, key)})`)
248
+ parent.addWatch(alwaysUpdate, data, 'items', componentRefVariable)
249
+ nodeData.isRepeat = true
250
+ }
251
+ },
252
+ hidden: {
253
+ help: `
254
+ Hides an element:
255
+
256
+ /h <div hidden={x > 10}></div>
257
+
258
+ Available args are: c, p
259
+ `,
260
+ handle: function(nodeData, attInfo) {
261
+ nodeData.shieldQuery = attInfo.args[0]
262
+ }
263
+ },
264
+ on: {
265
+ help: `
266
+ Creates an event handler:
267
+
268
+ /h <div on:click={alert('hello')}></div>
269
+
270
+ Available args are: w, e
271
+ `,
272
+ requireQualifier: true,
273
+ handle: function(nodeData, attInfo) {
274
+ nodeData.addEventListener(attInfo.qualifier, attInfo.args[0])
275
+ }
276
+ },
277
+
278
+ // TODO: change this because we may use a special wrapper?
279
+ pool: {
280
+ help: `
281
+ Specify a pool object for repeat items:
282
+
283
+ /h <div pool={poolObject}></div>
284
+
285
+ `,
286
+ handle: function(nodeData, attInfo) {
287
+ nodeData.chainedCalls.push(`pool(${attInfo.args[0]})`)
288
+ }
289
+ },
290
+ props: {
291
+ help: `
292
+ Specify props for a nested component:
293
+
294
+ /h <NestedComponent props={{foo: 'bar'}} />
295
+
296
+ `,
297
+ handle: function(nodeData, attInfo) {
298
+ nodeData.props = nodeData.expandProps(attInfo.args[0])
299
+ }
300
+ },
301
+ show: {
302
+ help: `
303
+ Shows an element:
304
+
305
+ /h <div show={x > 10}></div>
306
+
307
+ Variables are: c, p
308
+ `,
309
+ handle: function(nodeData, attInfo) {
310
+ nodeData.shieldQuery = attInfo.args[0]
311
+ nodeData.reverseShield = 1
312
+ }
313
+ },
314
+ style: {
315
+ help: `
316
+ Sets the style directive:
317
+
318
+ /h <div style:color={p.color}></div>
319
+
320
+ Variables are: c, p
321
+ `,
322
+ requireQualifier: true,
323
+ handle: function(nodeData, attInfo) {
324
+ nodeData.addWatch(attInfo.args[0], undefined, 'style', `'${attInfo.qualifier}'`)
325
+ }
326
+ },
327
+ watch: {
328
+ help: `
329
+ Watch a value and call
330
+
331
+ /h <div watch={watch, callback}></div>
332
+
333
+ Variables for watch: c, p
334
+ Variables for callback: c, p, n, o, w
335
+ `,
336
+ handle: function(nodeData, attInfo) {
337
+ nodeData.addWatch(...attInfo.args)
338
+ }
339
+ },
340
+ wrapper: {
341
+ help: `
342
+ Specify an alternative wrapper class:
343
+
344
+ /h <div wrapper={MyCustomWrapper}></div>
345
+
346
+ Available args are: c, p
347
+ `,
348
+ handle: function(nodeData, attInfo) {
349
+ nodeData.customWrapperClass = attInfo.args[0]
350
+ }
351
+ },
352
+ }
353
+
354
+ // Do not import directly, only through index so we get custom directives too.
355
+ module.exports = {directives}
356
+
@@ -0,0 +1,2 @@
1
+ const {config} = require('./loader');
2
+ module.exports = {config}
@@ -0,0 +1,43 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const {directives} = require('./directives');
4
+
5
+
6
+ const config = {
7
+ options: {
8
+ inlineDelimiters: ['{', '}']
9
+ },
10
+ aliases: {
11
+ '': 'watch'
12
+ },
13
+ directives: directives
14
+ }
15
+
16
+ // Use custom config file if there is one.
17
+ const customConfigFile = path.join(process.cwd(), 'wallace.config.js')
18
+
19
+
20
+ if (fs.existsSync(customConfigFile)) {
21
+
22
+ var customConfig = require(customConfigFile)
23
+ if (customConfig.directives) {
24
+ Object.assign(config.directives, customConfig.directives)
25
+ }
26
+ // TODO: check options are valid.
27
+ if (customConfig.options) {
28
+ Object.assign(config.options, customConfig.options)
29
+ }
30
+ }
31
+
32
+ for (const key of Object.keys(config.directives)) {
33
+ if (key.toLowerCase().startsWith("on") && key !== "on") {
34
+ throw new Error(`Directive "${key}" may not start with 'on' as this is reserved for event handlers.`)
35
+ }
36
+ }
37
+
38
+ // const directives = config.directives
39
+ // for (const [key, value] of Object.entries(config.aliases)) {
40
+ // directives[':' + key] = directives[':' + value]
41
+ // }
42
+
43
+ module.exports = {config}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * This module deals with parsing the directives in the config file,
3
+ * and helping them parse arguments.
4
+ */
5
+
6
+ const {isFunc, isUnd, splitTrim} = require('../utils/misc')
7
+
8
+ /**
9
+ * Used internally to
10
+ *
11
+ * @param {string} directiveName
12
+ * @param {*} directive
13
+ * @param {*} attVal
14
+ */
15
+ const processDirective = (nodeData, directiveName, directive, attVal) => {
16
+ if (!isFunc(directive.handle)) {
17
+ throw new Error('handle must be a function')
18
+ }
19
+ let args = attVal
20
+ if (directive.hasOwnProperty('params')) {
21
+ let params = splitTrim(directive.params, ',')
22
+ args = parseDirectiveArguments(params, attVal)
23
+ directive.handle.apply(nodeData, args)
24
+ } else {
25
+ directive.handle.apply(nodeData, [args])
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Return array of args based on definitions
31
+ *
32
+ * @param {Array} params The parameters as strings
33
+ * @param {String} attVal The raw attribute value.
34
+ */
35
+ const parseDirectiveArguments = (params, attVal) => {
36
+ const args = []
37
+ const chunks = splitTrim(attVal, '|')
38
+ for (let i=0, il=params.length; i<il; i++) {
39
+ let param = params[i]
40
+ let raw = chunks[i]
41
+ let value = parseArgValue(param, raw, i)
42
+ args.push(value)
43
+ }
44
+ return args
45
+ }
46
+
47
+ const parseArgValue = (param, raw, i) => {
48
+ if ((!param.endsWith('?')) && (isUnd(raw))) {
49
+ throw new Error(`Argument ${param} is required`)
50
+ }
51
+ return raw
52
+ }
53
+
54
+ const extractDocumentation = (name, directive) => {
55
+ return {
56
+ name: name,
57
+ params: directive.params
58
+ }
59
+ }
60
+
61
+
62
+
63
+ module.exports = {processDirective, extractDocumentation}