UNPKG

10.3 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 sum: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 2], expectedTypes: ['array']}),
89 range: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 4], stable: true}),
90 assign: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 2], expectedTypes: ['array'], stable: true}),
91 defaults: new TokenTypes({collectionVerb: true, chainIndex: 1, len: [2, 2], expectedTypes: ['array'], stable: true}),
92 loop: new TokenTypes({nonVerb: true}),
93 recur: new TokenTypes({chainIndex: 2, len: [3, 3]}),
94 context: new TokenTypes({nonVerb: true}),
95 func: new TokenTypes({private: true, len: [2, 2]}),
96 invoke: new TokenTypes({private: true, len: [2, Number.MAX_SAFE_INTEGER]}),
97 val: new TokenTypes({nonVerb: true}),
98 key: new TokenTypes({nonVerb: true}),
99 null: new TokenTypes({nonVerb: true, private: true}),
100 arg0: new TokenTypes({nonVerb: true}),
101 arg1: new TokenTypes({nonVerb: true}),
102 arg2: new TokenTypes({nonVerb: true}),
103 arg3: new TokenTypes({nonVerb: true}),
104 arg4: new TokenTypes({nonVerb: true}),
105 arg5: new TokenTypes({nonVerb: true}),
106 arg6: new TokenTypes({nonVerb: true}),
107 arg7: new TokenTypes({nonVerb: true}),
108 arg8: new TokenTypes({nonVerb: true}),
109 arg9: new TokenTypes({nonVerb: true}),
110 cond: new TokenTypes({private: true}),
111 eq: new TokenTypes({chainIndex: 1, len: [3, 3]}),
112 gt: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
113 lt: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
114 gte: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
115 lte: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
116 plus: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number', 'string']}),
117 minus: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
118 mult: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
119 div: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
120 mod: new TokenTypes({chainIndex: 1, len: [3, 3], expectedTypes: ['number']}),
121 breakpoint: new TokenTypes({chainIndex: 1, len: [2, 2]}),
122 call: new TokenTypes({nonChained: true, chainIndex: 2, len: [3, Number.MAX_SAFE_INTEGER], tryToHoist: true}),
123 bind: new TokenTypes({nonChained: true, chainIndex: 2, len: [2, Number.MAX_SAFE_INTEGER], tryToHoist: true, stable: true}),
124 effect: new TokenTypes({nonChained: true, chainIndex: 2, len: [3, Number.MAX_SAFE_INTEGER]}),
125 startsWith: new TokenTypes({nonChained: true, chainIndex: 1, len: [3, 3], expectedTypes: ['string']}),
126 endsWith: new TokenTypes({nonChained: true, chainIndex: 1, len: [3, 3], expectedTypes: ['string']}),
127 toUpperCase: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['string']}),
128 toLowerCase: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['string']}),
129 stringLength: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['string']}),
130 floor: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['number']}),
131 ceil: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['number']}),
132 round: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2], expectedTypes: ['number']}),
133 parseInt: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 3], expectedTypes: ['string']}),
134 substring: new TokenTypes({nonChained: true, chainIndex: 1, len: [4, 4], expectedTypes: ['string']}),
135 split: new TokenTypes({nonChained: true, chainIndex: 1, len: [3, 3]}),
136 isUndefined: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2]}),
137 isBoolean: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2]}),
138 isString: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2]}),
139 isNumber: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2]}),
140 isArray: new TokenTypes({nonChained: true, chainIndex: 1, len: [2, 2]}),
141 abstract: new TokenTypes({nonChained: true, len: [3, 3], private: true}),
142 quote: new TokenTypes({nonChained: true, len: [2, 2], private: true}),
143 trackPath: new TokenTypes({nonChained: true, len: [3, Number.MAX_SAFE_INTEGER], private: true})
144};
145
146const AllTokens = Object.keys(TokenTypeData).reduce((acc, k) => {
147 acc[k[0].toUpperCase() + k.slice(1)] = new Token(k);
148 return acc;
149}, {});
150
151class Expression extends Array {}
152
153class SetterExpression extends Array {
154 toJSON() {
155 return ['*setter*'].concat(this)
156 }
157 setterType() {
158 return 'set'
159 }
160}
161class SpliceSetterExpression extends SetterExpression {
162 toJSON() {
163 return ['*splice*'].concat(this)
164 }
165
166 setterType() {
167 return 'splice'
168 }
169}
170class PushSetterExpression extends SetterExpression {
171 toJSON() {
172 return ['*push*'].concat(this)
173 }
174
175 setterType() {
176 return 'push'
177 }
178}
179
180AllTokens.Token = Token;
181AllTokens.Expr = (...args) => new Expression(Clone(args[0]), ...args.slice(1));
182
183function validatePathSegmentArguments(args) {
184 const invalidArgs = args.filter(arg =>
185 typeof arg !== 'string' &&
186 typeof arg !== 'number' &&
187 !(arg instanceof Token &&
188 (arg.$type === 'arg0' || arg.$type === 'arg1' || arg.$type === 'arg2')));
189
190 if (invalidArgs.length > 0) {
191 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}]`);
192 }
193}
194
195AllTokens.Setter = (...args) => {
196 if (args.length === 0) {
197 throw new Error('Invalid arguments for setter/splice - must receive a path');
198 }
199 validatePathSegmentArguments(args);
200 return new SetterExpression(...args);
201};
202AllTokens.Splice = (...args) => {
203 validatePathSegmentArguments(args);
204 return new SpliceSetterExpression(...args, new Token('key'));
205}
206AllTokens.Push = (...args) => {
207 validatePathSegmentArguments(args);
208 return new PushSetterExpression(...args);
209}
210
211AllTokens.withName = (name, val) => {
212 if (val instanceof Expression) {
213 const tokenType = val[0].$type;
214 const tokenData = TokenTypeData[tokenType];
215 if (tokenData.collectionVerb && tokenData.chainIndex === 2) {
216 name = name.replace(/[\W_]+/g, '');
217 val[0][SourceTag] = `${val[0][SourceTag]}:${name}`;
218 } else {
219 throw new Error(`can only name collection functions:${name}`);
220 }
221 return val;
222 }
223}
224
225AllTokens.Expression = Expression;
226AllTokens.TokenTypeData = TokenTypeData; //AllTokensList;
227AllTokens.SetterExpression = SetterExpression;
228AllTokens.SpliceSetterExpression = SpliceSetterExpression;
229AllTokens.PushSetterExpression = PushSetterExpression;
230
231AllTokens.isSetterExpression = expression => expression instanceof SetterExpression;
232AllTokens.isSpliceExpression = expression => expression instanceof SpliceSetterExpression;
233AllTokens.isPushExpression = expression => expression instanceof PushSetterExpression;
234AllTokens.isExpression = expression => expression instanceof Expression;
235AllTokens.isToken = token => token instanceof Token;
236
237AllTokens.Clone = Clone;
238AllTokens.cloneToken = cloneToken;
239AllTokens.SourceTag = SourceTag;
240AllTokens.WrappedPrimitive = WrappedPrimitive;
241AllTokens.UnwrappedExpr = Symbol('UnwrappedExpr');
242module.exports = AllTokens;