@foxy.io/sdk 1.8.2 → 1.9.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.
@@ -1,11 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BooleanSelector = void 0;
4
- var Entity;
5
- (function (Entity) {
6
- Entity[Entity["List"] = 0] = "List";
7
- Entity[Entity["Set"] = 1] = "Set";
8
- })(Entity || (Entity = {}));
9
4
  /**
10
5
  * Boolean selector is an HTML boolean attribute value format that allows
11
6
  * developers to write configurations for elements deep in a shadow DOM. Here's
@@ -57,7 +52,6 @@ class BooleanSelector {
57
52
  * @param value boolean selector value, e.g. `foo:bar baz:not=qux`
58
53
  */
59
54
  constructor(value) {
60
- this.__value = value;
61
55
  this.__tree = BooleanSelector.__parse(value);
62
56
  }
63
57
  /**
@@ -126,24 +120,38 @@ class BooleanSelector {
126
120
  return isFullMatch ? selector === 'not=*' : selector !== '';
127
121
  }
128
122
  /**
129
- * Zooms on the given top-level identifier.
123
+ * Zooms on the given top-level identifier or follows a path.
130
124
  *
131
125
  * @example
126
+ * new BooleanSelector('foo:bar:baz').zoom('foo:bar').toString() // => "baz"
132
127
  * new BooleanSelector('foo:bar:baz').zoom('foo').toString() // => "bar:baz"
133
128
  * new BooleanSelector('not=foo').zoom('bar').toString() // => "not=*"
134
129
  * new BooleanSelector('not=foo').zoom('foo').toString() // => ""
135
130
  *
136
- * @param id identifier to look for
137
- * @returns `true` is current selector includes rules for the given identifier
131
+ * @param path path to look for
132
+ * @returns zoomed BooleanSelector
138
133
  */
139
- zoom(id) {
140
- const [firstPart, ...rest] = id.split(':');
141
- const { only, not } = this.__tree;
142
- if (only === null || only === void 0 ? void 0 : only[firstPart]) {
143
- const selector = new BooleanSelector(BooleanSelector.__stringify(only[firstPart]));
144
- return rest.length === 0 ? selector : selector.zoom(rest.join(':'));
145
- }
146
- return !not || not.includes(firstPart) ? BooleanSelector.False : BooleanSelector.True;
134
+ zoom(path) {
135
+ const zoomedSelector = new BooleanSelector('');
136
+ zoomedSelector.__tree = path.split(':').reduce((currentTree, id) => {
137
+ let zoomedTree;
138
+ if ('include' in currentTree) {
139
+ zoomedTree = currentTree.include[id];
140
+ if (zoomedTree === undefined)
141
+ return { include: {} };
142
+ if (zoomedTree === true)
143
+ return { exclude: { '*': true } };
144
+ }
145
+ else {
146
+ zoomedTree = currentTree.exclude[id];
147
+ if (zoomedTree === undefined)
148
+ return { exclude: { '*': true } };
149
+ if (zoomedTree === true)
150
+ return { include: {} };
151
+ }
152
+ return zoomedTree;
153
+ }, this.__tree);
154
+ return zoomedSelector;
147
155
  }
148
156
  /**
149
157
  * Converts this selector to string.
@@ -154,7 +162,7 @@ class BooleanSelector {
154
162
  * @returns serialized representation of this selector
155
163
  */
156
164
  toString() {
157
- return this.__value;
165
+ return BooleanSelector.__stringifyTree(this.__tree);
158
166
  }
159
167
  /**
160
168
  * Converts this selector to an attribute value.
@@ -169,104 +177,227 @@ class BooleanSelector {
169
177
  * @returns attribute value representing this selector.
170
178
  */
171
179
  toAttribute(truthyValue = '') {
172
- var _a;
173
- if (((_a = this.__tree.not) === null || _a === void 0 ? void 0 : _a[0]) === '*')
180
+ const serializedSelector = this.toString();
181
+ if (serializedSelector === 'not=*')
174
182
  return truthyValue;
175
- return this.__value.trim().length === 0 ? null : this.toString();
183
+ return serializedSelector.length === 0 ? null : serializedSelector;
176
184
  }
177
- static __stringify(tree, path = '') {
178
- if (tree.only) {
179
- return Object.entries(tree.only).reduce((output, [key, subtree]) => {
180
- const result = BooleanSelector.__stringify(subtree, path.length === 0 ? key : `${path}:${key}`);
181
- return output.length === 0 ? result : `${output} ${result}`;
182
- }, '');
185
+ static __parsePath(path, tree) {
186
+ const firstSeparatorIndex = path.indexOf(':');
187
+ const topLevelId = path.substring(0, firstSeparatorIndex);
188
+ const nestedPath = path.substring(firstSeparatorIndex + 1);
189
+ if ('exclude' in tree) {
190
+ const subTree = tree.exclude[topLevelId];
191
+ if (subTree)
192
+ tree.exclude[topLevelId] = this.__parseListItem(nestedPath, subTree === true ? void 0 : subTree);
193
+ }
194
+ else {
195
+ const subTree = tree.include[topLevelId];
196
+ if (subTree !== true)
197
+ tree.include[topLevelId] = this.__parseListItem(nestedPath, subTree);
183
198
  }
184
- if (tree.not)
185
- return `${path.length === 0 ? '' : `${path}:`}not=${tree.not.join(',')}`;
186
- return path;
199
+ return tree;
200
+ }
201
+ static __parseSet(set, tree) {
202
+ const setItems = set.split(',');
203
+ if ('include' in tree) {
204
+ tree = { exclude: tree.include };
205
+ for (const id in tree.exclude)
206
+ if (!setItems.includes(id))
207
+ delete tree.exclude[id];
208
+ for (const item of setItems) {
209
+ if (item in tree.exclude) {
210
+ delete tree.exclude[item];
211
+ }
212
+ else {
213
+ tree.exclude[item] = true;
214
+ }
215
+ }
216
+ }
217
+ else {
218
+ for (const id in tree.exclude)
219
+ if (!setItems.includes(id))
220
+ delete tree.exclude[id];
221
+ }
222
+ return tree;
223
+ }
224
+ static __parseListItem(listItem, tree = { include: {} }) {
225
+ if (listItem.includes(':'))
226
+ return this.__parsePath(listItem, tree);
227
+ if (listItem.startsWith('not='))
228
+ return this.__parseSet(listItem.substring(4), tree);
229
+ if ('include' in tree) {
230
+ tree.include[listItem] = true;
231
+ }
232
+ else {
233
+ for (const id in tree.exclude)
234
+ if (id === listItem)
235
+ delete tree.exclude[id];
236
+ }
237
+ return tree;
238
+ }
239
+ static __parseList(list, tree = { include: {} }) {
240
+ return list.split(' ').reduce((newTree, listItem) => this.__parseListItem(listItem, newTree), tree);
187
241
  }
188
- static __parse(value) {
189
- const tree = {};
190
- const output = { branch: tree, buffer: '', entity: Entity.List, tree };
191
- Array.from(`${value} `).forEach((character, position) => {
242
+ static __lintList(list) {
243
+ var _a;
244
+ let position = 'list';
245
+ let result = '';
246
+ for (let i = 0; i < list.length; ++i) {
247
+ const character = list.charAt(i);
192
248
  try {
193
- BooleanSelector.__processors[output.entity](output, character);
249
+ if (position === 'list') {
250
+ if (/^\s$/.test(character)) {
251
+ if (!/^\s$/.test((_a = list[i - 1]) !== null && _a !== void 0 ? _a : ' '))
252
+ result += ' ';
253
+ continue;
254
+ }
255
+ if (/^[a-z]$/.test(character)) {
256
+ result += character;
257
+ position = 'path';
258
+ continue;
259
+ }
260
+ throw new SyntaxError(`Expected [a-z] or a whitespace, but got "${character}" instead.`);
261
+ }
262
+ if (position === 'path') {
263
+ if (/^[a-z]$/.test(character)) {
264
+ result += character;
265
+ continue;
266
+ }
267
+ if (character === '-') {
268
+ if (list[i - 1] === '-' || list[i - 1] === ':') {
269
+ throw new SyntaxError(`Expected [a-z], but got "${character}" instead.`);
270
+ }
271
+ else {
272
+ result += character;
273
+ continue;
274
+ }
275
+ }
276
+ if (character === ':') {
277
+ if (list[i - 1] === ':' || list[i - 1] === '-') {
278
+ throw new SyntaxError(`Expected [a-z], but got "${character}" instead.`);
279
+ }
280
+ else {
281
+ result += character;
282
+ continue;
283
+ }
284
+ }
285
+ if (character === '=') {
286
+ if (list[i - 1] === '=' || list[i - 1] === ':' || list[i - 1] === '-') {
287
+ throw new SyntaxError(`Expected [a-z], but got "${character}" instead.`);
288
+ }
289
+ if (result.endsWith('not') && (result.length === 3 || !/[a-z]|-/.test(result[i - 4]))) {
290
+ result += character;
291
+ position = 'set';
292
+ continue;
293
+ }
294
+ else {
295
+ throw new SyntaxError(`Expected [a-z] or ":", but got "${character}" instead.`);
296
+ }
297
+ }
298
+ if (/^\s$/.test(character)) {
299
+ result += ' ';
300
+ position = 'list';
301
+ continue;
302
+ }
303
+ throw new SyntaxError(`Expected [a-z], ",", ":", ":" or a whitespace, but got "${character}" instead.`);
304
+ }
305
+ if (position === 'set') {
306
+ if (/^\s$/.test(character))
307
+ continue;
308
+ if (/^[a-z]|\*$/.test(character)) {
309
+ position = 'set-item';
310
+ result += character;
311
+ continue;
312
+ }
313
+ throw new SyntaxError(`Expected [a-z] or a whitespace, but got "${character}" instead.`);
314
+ }
315
+ if (position === 'set-item') {
316
+ if (list[i - 1] === '*') {
317
+ if (character === ',') {
318
+ result += character;
319
+ position = 'set';
320
+ continue;
321
+ }
322
+ if (/^\s$/.test(character)) {
323
+ if (i !== list.length - 1)
324
+ result += ' ';
325
+ position = 'list';
326
+ continue;
327
+ }
328
+ throw new SyntaxError(`Expected "," or a whitespace, but got "${character}" instead.`);
329
+ }
330
+ else {
331
+ if (/^[a-z]$/.test(character)) {
332
+ result += character;
333
+ continue;
334
+ }
335
+ if (character === '-') {
336
+ if (list[i - 1] === '-' || list[i - 1] === ':' || list[i - 1] === '=') {
337
+ throw new SyntaxError(`Expected [a-z], but got "${character}" instead.`);
338
+ }
339
+ else {
340
+ result += character;
341
+ continue;
342
+ }
343
+ }
344
+ if (character === ',') {
345
+ result += character;
346
+ position = 'set';
347
+ continue;
348
+ }
349
+ if (/^\s$/.test(character)) {
350
+ if (i !== list.length - 1)
351
+ result += ' ';
352
+ position = 'list';
353
+ continue;
354
+ }
355
+ throw new SyntaxError(`Expected [a-z], "," or a whitespace, but got "${character}" instead.`);
356
+ }
357
+ }
194
358
  }
195
359
  catch (err) {
196
360
  const hint = 'This error occured at: ';
197
- const trim = (v) => v.substring(Math.max(0, position - 30), position + 30);
198
- const preview = trim(value);
199
- const pointer = ' '.repeat(hint.length) + trim('^'.padStart(position + 1, ' '));
361
+ const trim = (v) => v.substring(Math.max(0, i - 30), i + 30);
362
+ const preview = trim(list);
363
+ const pointer = ' '.repeat(hint.length) + trim('^'.padStart(i + 1, ' '));
200
364
  throw new SyntaxError([err.message, `${hint}${preview}`, pointer].join('\n'));
201
365
  }
202
- });
203
- return tree;
204
- }
205
- }
206
- exports.BooleanSelector = BooleanSelector;
207
- BooleanSelector.__processors = {
208
- [Entity.List](output, character) {
209
- var _a, _b, _c, _d;
210
- /* istanbul ignore next */
211
- if (Array.isArray(output.branch))
212
- throw new SyntaxError('Paths are not allowed in sets.');
213
- if (character === '=') {
214
- if (output.buffer === 'not') {
215
- const newBranch = (_a = output.branch.not) !== null && _a !== void 0 ? _a : [];
216
- delete output.branch.only;
217
- output.branch.not = newBranch;
218
- output.entity = Entity.Set;
219
- output.branch = newBranch;
220
- output.buffer = '';
221
- return;
222
- }
223
- else {
224
- throw new SyntaxError(`Unknown modifier "${output.buffer}".`);
225
- }
226
366
  }
227
- if (/^\s$/.test(character) || character === ':') {
228
- if (output.buffer.length > 0) {
229
- const selector = output.buffer;
230
- const newBranch = (_c = (_b = output.branch.only) === null || _b === void 0 ? void 0 : _b[selector]) !== null && _c !== void 0 ? _c : {};
231
- if (character !== ':')
232
- newBranch.not = ['*'];
233
- if (((_d = output.branch.not) === null || _d === void 0 ? void 0 : _d.includes('*')) !== true) {
234
- output.branch.only = Object.assign(Object.assign({}, output.branch.only), { [selector]: newBranch });
235
- delete output.branch.not;
367
+ return result.trimEnd();
368
+ }
369
+ static __parse(list) {
370
+ return this.__parseList(this.__lintList(list));
371
+ }
372
+ static __stringifyTree(tree, path) {
373
+ const parts = [];
374
+ if ('include' in tree) {
375
+ for (const id in tree.include) {
376
+ const nestedTree = tree.include[id];
377
+ const newPath = path ? [path, id].join(':') : id;
378
+ if (nestedTree === true) {
379
+ parts.push(newPath);
380
+ }
381
+ else {
382
+ parts.push(this.__stringifyTree(nestedTree, newPath));
236
383
  }
237
- output.branch = character === ':' ? newBranch : output.tree;
238
- output.buffer = '';
239
384
  }
240
- return;
241
- }
242
- if (/^[a-z]|-$/.test(character)) {
243
- output.buffer += character;
244
- return;
245
385
  }
246
- throw new SyntaxError(`Expected [a-z], "-", ":" or a whitespace, but got "${character}" instead.`);
247
- },
248
- [Entity.Set](output, character) {
249
- /* istanbul ignore next */
250
- if (!Array.isArray(output.branch))
251
- throw new SyntaxError('Unexpected set item.');
252
- if (output.buffer.length === 0 && /^\s$/.test(character))
253
- return;
254
- if (character === ',' || character === '*' || /^\s$/.test(character)) {
255
- const newItem = character === '*' ? '*' : output.buffer;
256
- const updatedSet = new Set([...output.branch, newItem]);
257
- const normalizedSet = updatedSet.has('*') ? new Set(['*']) : updatedSet;
258
- output.branch.splice(0, output.branch.length, ...normalizedSet);
259
- output.entity = character === ',' ? Entity.Set : Entity.List;
260
- output.branch = character === ',' ? output.branch : output.tree;
261
- output.buffer = '';
262
- return;
263
- }
264
- if (/^[a-z]|-$/.test(character)) {
265
- output.buffer += character;
266
- return;
386
+ else {
387
+ const ids = [];
388
+ const partsToPush = [];
389
+ for (const id in tree.exclude) {
390
+ const nestedTree = tree.exclude[id];
391
+ const newPath = path ? [path, id].join(':') : id;
392
+ ids.push(id);
393
+ if (nestedTree !== true)
394
+ partsToPush.push(this.__stringifyTree(nestedTree, newPath));
395
+ }
396
+ parts.push(`${path ? `${path}:` : ''}not=${ids.join(',')}`, ...partsToPush);
267
397
  }
268
- throw new SyntaxError(`Expected [a-z], "-", "," or a whitespace, but got "${character}" instead.`);
269
- },
270
- };
398
+ return parts.join(' ');
399
+ }
400
+ }
401
+ exports.BooleanSelector = BooleanSelector;
271
402
  const falseBooleanSelectorSingleton = new BooleanSelector('');
272
403
  const trueBooleanSelectorSingleton = new BooleanSelector('not=*');