UNPKG

10.6 kBJavaScriptView Raw
1const TokenTypes = require('./token-type');
2const SourceTag = Symbol('SourceTag');
3class Token {
4 constructor(type, source) {
5 this.$type = type;
6 if (source) {
7 this[SourceTag] = source;
8 }
9 }
10 toJSON() {
11 return `*${this.$type}*`;
12 }
13 toString() {
14 return `*${this.$type}*`;
15 }
16}
17
18class WrappedPrimitive {
19 constructor(value) {
20 this.$primitive = value;
21 }
22 toJSON() {
23 return this.$primitive;
24 }
25}
26
27function cloneToken(token) {
28 return new Token(token.$type, token[SourceTag]);
29}
30
31/*eslint no-use-before-define:0*/
32function Clone(model) {
33 if (model instanceof Token) {
34 return cloneToken(model);
35 } else if (model instanceof Expression) {
36 return new Expression(...model.map(Clone));
37 }
38 return model;
39}
40
41const TokenTypeData = {
42 and: new TokenTypes({nonChained: true, len: [2, Number.MAX_SAFE_INTEGER]}),
43 or: new TokenTypes({nonChained: true, len: [2, Number.MAX_SAFE_INTEGER]}),
44 array: new TokenTypes({nonChained: true, private: true, tryToHoist: true, stable: true}),
45 object: new TokenTypes({nonChained: true, private: true, tryToHoist: true, stable: true}),
46 not: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2]}),
47 ternary: new TokenTypes({nonChained: true, chainIndex: 1, len: [4, 4]}),
48 trace: new TokenTypes({chainIndex: 2, len: [2, 4]}),
49 get: new TokenTypes({chainIndex: 2, len: [3, 3]}),
50 root: new TokenTypes({nonVerb: true}),
51 topLevel: new TokenTypes({nonVerb: true, private: true}),
52 mapValues: new TokenTypes({collectionVerb: true, chainIndex: 2, len: [3, 4], stable: true}),
53 map: new TokenTypes({collectionVerb: true, chainIndex: 2, arrayVerb: true, len: [3, 4], stable: true}),
54 recursiveMapValues: new TokenTypes({collectionVerb: true, chainIndex: 2, recursive: true, len: [3, 4], stable: true}),
55 recursiveMap: new TokenTypes({collectionVerb: true, chainIndex: 2, arrayVerb: true, recursive: true, len: [3, 4], stable: true}),
56 any: new TokenTypes({
57 collectionVerb: true,
58 chainIndex: 2,
59 arrayVerb: true,
60 len: [3, 4]
61 }),
62 keyBy: new TokenTypes({
63 collectionVerb: true,
64 chainIndex: 2,
65 arrayVerb: true,
66 len: [3, 4],
67 stable: true
68 }),
69 filter: new TokenTypes({
70 collectionVerb: true,
71 chainIndex: 2,
72 arrayVerb: true,
73 len: [3, 4],
74 stable: true
75 }),
76 anyValues: new TokenTypes({
77 collectionVerb: true,
78 chainIndex: 2,
79 len: [3, 4]
80 }),
81 filterBy: new TokenTypes({collectionVerb: true, chainIndex: 2, len: [3, 4], stable: true}),
82 mapKeys: new TokenTypes({collectionVerb: true, chainIndex: 2, len: [3, 4], stable: true}),
83 groupBy: new TokenTypes({collectionVerb: true, chainIndex: 2, len: [3, 4], stable: true}),
84 values: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 2], expectedTypes: ['object'], stable: true}),
85 keys: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 2], expectedTypes: ['object'], stable: true}),
86 flatten: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 2], expectedTypes: ['array'], stable: true}),
87 size: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 2], expectedTypes: ['array', 'object']}),
88 isEmpty: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 2], expectedTypes: ['array', 'object']}),
89 last: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 2], expectedTypes: ['array']}),
90 sum: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 2], expectedTypes: ['array']}),
91 range: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 4], stable: true}),
92 assign: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 2], expectedTypes: ['array'], stable: true}),
93 defaults: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 2], expectedTypes: ['array'], stable: true}),
94 loop: new TokenTypes({nonVerb: true}),
95 recur: new TokenTypes({chainIndex: 2, len: [3, 3]}),
96 context: new TokenTypes({nonVerb: true}),
97 func: new TokenTypes({private: true, len: [2, 2]}),
98 invoke: new TokenTypes({private: true, len: [2, Number.MAX_SAFE_INTEGER]}),
99 val: new TokenTypes({nonVerb: true}),
100 key: new TokenTypes({nonVerb: true}),
101 null: new TokenTypes({nonVerb: true, private: true}),
102 arg0: new TokenTypes({nonVerb: true}),
103 arg1: new TokenTypes({nonVerb: true}),
104 arg2: new TokenTypes({nonVerb: true}),
105 arg3: new TokenTypes({nonVerb: true}),
106 arg4: new TokenTypes({nonVerb: true}),
107 arg5: new TokenTypes({nonVerb: true}),
108 arg6: new TokenTypes({nonVerb: true}),
109 arg7: new TokenTypes({nonVerb: true}),
110 arg8: new TokenTypes({nonVerb: true}),
111 arg9: new TokenTypes({nonVerb: true}),
112 cond: new TokenTypes({private: true}),
113 eq: new TokenTypes({chainIndex: 1, len: [3, 3]}),
114 gt: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
115 lt: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
116 gte: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
117 lte: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
118 plus: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number', 'string']}),
119 minus: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
120 mult: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
121 div: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
122 mod: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
123 breakpoint: new TokenTypes({chainIndex: 1, len: [2, 2]}),
124 call: new TokenTypes({nonChained: true, chainIndex: 2, len: [3, Number.MAX_SAFE_INTEGER], tryToHoist: true}),
125 bind: new TokenTypes({nonChained: true, chainIndex: 2, len: [2, Number.MAX_SAFE_INTEGER], tryToHoist: true, stable: true}),
126 effect: new TokenTypes({nonChained: true, chainIndex: 2, len: [3, Number.MAX_SAFE_INTEGER]}),
127 startsWith: new TokenTypes({nonChained: true, chainIndex: 1, len: [3, 3], expectedTypes: ['string']}),
128 endsWith: new TokenTypes({nonChained: true, chainIndex: 1, len: [3, 3], expectedTypes: ['string']}),
129 toUpperCase: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['string']}),
130 toLowerCase: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['string']}),
131 stringLength: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['string']}),
132 floor: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['number']}),
133 ceil: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['number']}),
134 round: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['number']}),
135 parseInt: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 3], expectedTypes: ['string']}),
136 parseFloat: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['string']}),
137 substring: new TokenTypes({nonChained: true, chainIndex: 1, len: [4, 4], expectedTypes: ['string']}),
138 split: new TokenTypes({nonChained: true, chainIndex: 1, len: [3, 3]}),
139 isUndefined: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2]}),
140 isBoolean: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2]}),
141 isString: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2]}),
142 isNumber: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2]}),
143 isArray: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2]}),
144 abstract: new TokenTypes({nonChained: true, len: [3, 3], private: true}),
145 quote: new TokenTypes({nonChained: true, len: [2, 2], private: true}),
146 trackPath: new TokenTypes({nonChained: true, len: [3, Number.MAX_SAFE_INTEGER], private: true})
147};
148
149const AllTokens = Object.keys(TokenTypeData).reduce((acc, k) => {
150 acc[k[0].toUpperCase() + k.slice(1)] = new Token(k);
151 return acc;
152}, {});
153
154class Expression extends Array {}
155
156class SetterExpression extends Array {
157 toJSON() {
158 return ['*setter*'].concat(this)
159 }
160 setterType() {
161 return 'set'
162 }
163}
164class SpliceSetterExpression extends SetterExpression {
165 toJSON() {
166 return ['*splice*'].concat(this)
167 }
168
169 setterType() {
170 return 'splice'
171 }
172}
173class PushSetterExpression extends SetterExpression {
174 toJSON() {
175 return ['*push*'].concat(this)
176 }
177
178 setterType() {
179 return 'push'
180 }
181}
182
183AllTokens.Token = Token;
184AllTokens.Expr = (...args) => new Expression(Clone(args[0]), ...args.slice(1));
185
186function validatePathSegmentArguments(args) {
187 const invalidArgs = args.filter(arg =>
188 typeof arg !== 'string' &&
189 typeof arg !== 'number' &&
190 !(arg instanceof Token &&
191 (arg.$type === 'arg0' || arg.$type === 'arg1' || arg.$type === 'arg2')));
192
193 if (invalidArgs.length > 0) {
194 throw new Error(`Invalid arguments for setter/splice/push - can only accept path (use arg0/arg1/arg2 - to define placeholders in the path), received [${args}]`);
195 }
196}
197
198AllTokens.Setter = (...args) => {
199 if (args.length === 0) {
200 throw new Error('Invalid arguments for setter/splice - must receive a path');
201 }
202 validatePathSegmentArguments(args);
203 return new SetterExpression(...args);
204};
205AllTokens.Splice = (...args) => {
206 validatePathSegmentArguments(args);
207 return new SpliceSetterExpression(...args, new Token('key'));
208}
209AllTokens.Push = (...args) => {
210 validatePathSegmentArguments(args);
211 return new PushSetterExpression(...args);
212}
213
214AllTokens.withName = (name, val) => {
215 if (val instanceof Expression) {
216 const tokenType = val[0].$type;
217 const tokenData = TokenTypeData[tokenType];
218 if (tokenData.collectionVerb && tokenData.chainIndex === 2) {
219 name = name.replace(/[\W_]+/g, '');
220 val[0][SourceTag] = `${val[0][SourceTag]}:${name}`;
221 } else {
222 throw new Error(`can only name collection functions:${name}`);
223 }
224 return val;
225 }
226}
227
228AllTokens.Expression = Expression;
229AllTokens.TokenTypeData = TokenTypeData; //AllTokensList;
230AllTokens.SetterExpression = SetterExpression;
231AllTokens.SpliceSetterExpression = SpliceSetterExpression;
232AllTokens.PushSetterExpression = PushSetterExpression;
233
234AllTokens.isSetterExpression = expression => expression instanceof SetterExpression;
235AllTokens.isSpliceExpression = expression => expression instanceof SpliceSetterExpression;
236AllTokens.isPushExpression = expression => expression instanceof PushSetterExpression;
237AllTokens.isExpression = expression => expression instanceof Expression;
238AllTokens.isToken = token => token instanceof Token;
239
240AllTokens.Clone = Clone;
241AllTokens.cloneToken = cloneToken;
242AllTokens.SourceTag = SourceTag;
243AllTokens.WrappedPrimitive = WrappedPrimitive;
244AllTokens.UnwrappedExpr = Symbol('UnwrappedExpr');
245module.exports = AllTokens;