@pleger/esa-js 0.2.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/esa.js ADDED
@@ -0,0 +1,904 @@
1
+ function createESA(AspectScript) {
2
+ function OwnArrayEnv() {
3
+ for (let i = 0; i < arguments.length; i += 1) {
4
+ this.push(arguments[i]);
5
+ }
6
+ }
7
+ OwnArrayEnv.prototype = Object.create(Array.prototype);
8
+ OwnArrayEnv.prototype.constructor = OwnArrayEnv;
9
+
10
+ const ESA = {};
11
+
12
+ const emptyEnv = ESA.emptyEnv = {
13
+ bind(name, value) {
14
+ const env = Object.create(this);
15
+ if (env[name] === undefined) {
16
+ env[name] = value;
17
+ } else if (env[name] instanceof OwnArrayEnv) {
18
+ env[name].push(value);
19
+ } else {
20
+ env[name] = new OwnArrayEnv(env[name], value);
21
+ }
22
+ return env;
23
+ },
24
+ unbind(name) {
25
+ const env = Object.create(this);
26
+ env[name] = undefined;
27
+ return env;
28
+ },
29
+ replace(name, value) {
30
+ const env = Object.create(this);
31
+ env[name] = value;
32
+ return env;
33
+ },
34
+ };
35
+
36
+ const SKIPPED_ENV_KEYS = {
37
+ bind: true,
38
+ unbind: true,
39
+ replace: true,
40
+ toString: true,
41
+ };
42
+
43
+ function isEnv(result) {
44
+ return result === true || result === emptyEnv || emptyEnv.isPrototypeOf(result);
45
+ }
46
+
47
+ function applyFluentInterface(fun) {
48
+ if (fun.and && fun.or && fun.inCFlowOf && fun.not) {
49
+ return fun;
50
+ }
51
+
52
+ fun.and = function and(right) {
53
+ const left = this;
54
+ return wrapPattern(function andPattern(jp, env) {
55
+ const newEnv = left.call(this, jp, env);
56
+ if (!newEnv) {
57
+ return false;
58
+ }
59
+ return right.call(this, jp, newEnv);
60
+ });
61
+ };
62
+
63
+ fun.or = function or(right) {
64
+ const left = this;
65
+ return wrapPattern(function orPattern(jp, env) {
66
+ const newEnv = left.call(this, jp, env);
67
+ if (!newEnv) {
68
+ return right.call(this, jp, env);
69
+ }
70
+ return newEnv;
71
+ });
72
+ };
73
+
74
+ fun.not = function not() {
75
+ const left = this;
76
+ return wrapPattern(function notPattern(jp, env) {
77
+ const result = left.call(this, jp, env);
78
+ return result ? false : env;
79
+ });
80
+ };
81
+
82
+ fun.inCFlowOf = function inCFlowOf(pc) {
83
+ return this.and(PTs.cflow(pc));
84
+ };
85
+
86
+ return fun;
87
+ }
88
+
89
+ function wrapPattern(pattern) {
90
+ return applyFluentInterface(function wrappedPattern(jp, env) {
91
+ const currentEnv = env || emptyEnv;
92
+ const result = pattern.call(this, jp, currentEnv);
93
+ if (isEnv(result)) {
94
+ return result === true ? currentEnv : result;
95
+ }
96
+ return result ? currentEnv : false;
97
+ });
98
+ }
99
+
100
+ function functionNameMatch(jp, expected) {
101
+ if (expected === "*") {
102
+ return true;
103
+ }
104
+ if (typeof expected === "string") {
105
+ return (jp.methods || []).indexOf(expected) >= 0 ||
106
+ jp.name === expected ||
107
+ (jp.fun && jp.fun.__asDeclaredName === expected);
108
+ }
109
+ return jp.fun === expected;
110
+ }
111
+
112
+ let PTs = {
113
+ within(target) {
114
+ return wrapPattern(function withinPattern(jp) {
115
+ let parent = jp.parent;
116
+ while (parent != null) {
117
+ if (parent.target === target) {
118
+ return true;
119
+ }
120
+ parent = parent.parent;
121
+ }
122
+ return false;
123
+ });
124
+ },
125
+
126
+ get(target, name) {
127
+ if (arguments.length === 1) {
128
+ name = target;
129
+ return wrapPattern(function getVarPattern(jp, env) {
130
+ const internal = jp.__asInternal || jp;
131
+ if (internal.kind !== "varGet") {
132
+ return false;
133
+ }
134
+ return internal.name === name || name === "*" ? env : false;
135
+ });
136
+ }
137
+
138
+ return wrapPattern(function getPattern(jp, env) {
139
+ if (!jp.isPropRead()) {
140
+ return false;
141
+ }
142
+ if ((target !== "*" && jp.target !== target) ||
143
+ (name !== "*" && jp.name !== name)) {
144
+ return false;
145
+ }
146
+ return env;
147
+ });
148
+ },
149
+
150
+ set(target, name) {
151
+ if (arguments.length === 1) {
152
+ name = target;
153
+ return wrapPattern(function setVarPattern(jp, env) {
154
+ const internal = jp.__asInternal || jp;
155
+ if (internal.kind !== "varSet") {
156
+ return false;
157
+ }
158
+ return internal.name === name || name === "*" ? env : false;
159
+ });
160
+ }
161
+
162
+ return wrapPattern(function setPattern(jp, env) {
163
+ if (!jp.isPropWrite()) {
164
+ return false;
165
+ }
166
+ if ((target !== "*" && jp.target !== target) ||
167
+ (name !== "*" && jp.name !== name)) {
168
+ return false;
169
+ }
170
+ return env;
171
+ });
172
+ },
173
+
174
+ creation(fun) {
175
+ return wrapPattern(function creationPattern(jp, env) {
176
+ return jp.isCreation() && functionNameMatch(jp, fun) ? env : false;
177
+ });
178
+ },
179
+
180
+ init(fun) {
181
+ return wrapPattern(function initPattern(jp, env) {
182
+ return jp.isInit() && functionNameMatch(jp, fun) ? env : false;
183
+ });
184
+ },
185
+
186
+ call(arg) {
187
+ return wrapPattern(function callPattern(jp, env) {
188
+ return jp.isCall() && functionNameMatch(jp, arg) ? env : false;
189
+ });
190
+ },
191
+
192
+ exec(arg) {
193
+ return wrapPattern(function execPattern(jp, env) {
194
+ return jp.isExec() && functionNameMatch(jp, arg) ? env : false;
195
+ });
196
+ },
197
+
198
+ event(type) {
199
+ return wrapPattern(function eventPattern(jp, env) {
200
+ return jp.isEvent() && jp.eventType === type ? env : false;
201
+ });
202
+ },
203
+
204
+ target(obj) {
205
+ return wrapPattern(function targetPattern(jp, env) {
206
+ if (obj === "*" && jp.target !== undefined) {
207
+ return env;
208
+ }
209
+ return jp.target === obj ? env : false;
210
+ });
211
+ },
212
+
213
+ cflow(pc) {
214
+ return wrapPattern(function cflowPattern(jp, env) {
215
+ let current = jp;
216
+ while (current != null) {
217
+ const result = pc(current, env);
218
+ if (result) {
219
+ return result;
220
+ }
221
+ current = current.parent;
222
+ }
223
+ return false;
224
+ });
225
+ },
226
+
227
+ cflowbelow(pc) {
228
+ return wrapPattern(function cflowBelowPattern(jp, env) {
229
+ return jp && jp.parent ? PTs.cflow(pc)(jp.parent, env) : false;
230
+ });
231
+ },
232
+
233
+ not(pc) {
234
+ return wrapPattern(function notPattern(jp, env) {
235
+ return pc(jp, env) ? false : env;
236
+ });
237
+ },
238
+
239
+ seq(left, right) {
240
+ return function seqPattern(jp, env) {
241
+ const res = left(jp, env);
242
+ if (resultLib.isEnv(res)) {
243
+ return [right, res === true ? env : res];
244
+ }
245
+
246
+ if (resultLib.isPair(res)) {
247
+ return [PTs.seq(res[0], right), res[1] === true ? env : res[1]];
248
+ }
249
+
250
+ return false;
251
+ };
252
+ },
253
+
254
+ seqN() {
255
+ if (arguments.length === 2 && typeof arguments[1] === "number") {
256
+ const subSeq = arguments[0];
257
+ const n = arguments[1];
258
+
259
+ let mainSeq = subSeq;
260
+ for (let i = 0; i < n - 1; i += 1) {
261
+ mainSeq = PTs.seq(subSeq, mainSeq);
262
+ }
263
+
264
+ return mainSeq;
265
+ }
266
+
267
+ const args = Array.prototype.slice.call(arguments);
268
+ return args.reduce(function reduceSeq(previous, current) {
269
+ return PTs.seq(previous, current);
270
+ });
271
+ },
272
+
273
+ or(left, right) {
274
+ return function orPattern(jp, env) {
275
+ const resL = left(jp, env);
276
+ if (resultLib.isEnv(resL)) {
277
+ return resL;
278
+ }
279
+
280
+ const resR = right(jp, env);
281
+ if (resultLib.isEnv(resR)) {
282
+ return resR;
283
+ }
284
+
285
+ if (resultLib.isPair(resL) || resultLib.isPair(resR)) {
286
+ const newLeft = resultLib.isPair(resL) ? resL[0] : left;
287
+ const newRight = resultLib.isPair(resR) ? resR[0] : right;
288
+ const newEnv = envLib.resultsToJoinedEnv(resL, resR);
289
+ return [PTs.or(newLeft, newRight), newEnv];
290
+ }
291
+
292
+ return false;
293
+ };
294
+ },
295
+
296
+ anyOrder(sequences) {
297
+ return function anyOrderPattern(jp, env) {
298
+ if (sequences.length === 1) {
299
+ return sequences[0](jp, env);
300
+ }
301
+
302
+ const results = sequences.map(function mapResult(seqExp) {
303
+ return seqExp(jp, env);
304
+ });
305
+
306
+ let newEnv = env;
307
+ const newSeqExps = [];
308
+
309
+ results.forEach(function eachResult(result, index) {
310
+ if (resultLib.isEnv(result)) {
311
+ newEnv = envLib.join(newEnv, result);
312
+ } else if (resultLib.isPair(result)) {
313
+ newEnv = envLib.join(newEnv, result[1]);
314
+ newSeqExps.push(result[0]);
315
+ } else {
316
+ newSeqExps.push(sequences[index]);
317
+ }
318
+ });
319
+
320
+ return newSeqExps.length > 0 ? [PTs.anyOrder(newSeqExps), newEnv] : false;
321
+ };
322
+ },
323
+
324
+ starUntil(star, until) {
325
+ function starUntilPattern(jp, env) {
326
+ const resultUntil = until(jp, env);
327
+ if (resultLib.isEnv(resultUntil)) {
328
+ return resultUntil;
329
+ }
330
+
331
+ const resultStar = star(jp, env);
332
+ if (resultLib.isEnv(resultStar)) {
333
+ return [starUntilPattern, resultStar];
334
+ }
335
+
336
+ return false;
337
+ }
338
+
339
+ return starUntilPattern;
340
+ },
341
+
342
+ plusUntil(plus, until) {
343
+ return PTs.seq(plus, PTs.starUntil(plus, until));
344
+ },
345
+
346
+ repeatUntil(repeat, until, repeatInitial) {
347
+ const initial = repeatInitial === undefined ? repeat : repeatInitial;
348
+
349
+ return function repeatUntilPattern(jp, env) {
350
+ let newUntil;
351
+ let newRepeat;
352
+ let newEnv;
353
+
354
+ const resU = until(jp, env);
355
+ if (resultLib.isEnv(resU)) {
356
+ return envLib.join(env, resU);
357
+ }
358
+
359
+ const resR = repeat(jp, env);
360
+ if (resultLib.isEnv(resR)) {
361
+ newUntil = resultLib.isPair(resU) ? resU[0] : until;
362
+ newEnv = resultLib.isPair(resU) ? envLib.join(resR, resU[1]) : resR;
363
+ return [PTs.repeatUntil(repeat, newUntil, initial), resR];
364
+ }
365
+
366
+ if (resultLib.isPair(resR) || resultLib.isPair(resU)) {
367
+ newRepeat = resultLib.isPair(resR) ? resR[0] : repeat;
368
+ newUntil = resultLib.isPair(resU) ? resU[0] : until;
369
+ newEnv = envLib.resultsToJoinedEnv(resR, resU);
370
+ return [PTs.repeatUntil(newRepeat, newUntil, initial), newEnv];
371
+ }
372
+
373
+ return false;
374
+ };
375
+ },
376
+
377
+ repeatUntil_paperExample(repeat, until) {
378
+ return function repeatUntilPaper(jp, env) {
379
+ const resultUntil = until(jp, env);
380
+ if (resultLib.isEnv(resultUntil)) {
381
+ return resultUntil;
382
+ }
383
+
384
+ const resultRepeat = repeat(jp, env);
385
+ if (resultLib.isEnv(resultRepeat)) {
386
+ return [PTs.repeatUntil_paperExample(repeat, until), resultRepeat];
387
+ }
388
+
389
+ return false;
390
+ };
391
+ },
392
+ };
393
+
394
+ const PTsShim = function PTsShim() {
395
+ return PTs.call(this);
396
+ };
397
+ Object.assign(PTsShim, PTs);
398
+ PTs = PTsShim;
399
+ ESA.Pointcuts = PTs;
400
+ ESA.Patterns = PTs;
401
+ ESA.Sequences = PTs;
402
+
403
+ const Cell = function Cell(pattern, env, creator) {
404
+ this.pattern = pattern;
405
+ this.env = env;
406
+ this.creator = creator;
407
+ };
408
+
409
+ Cell.prototype.isMatch = function isMatch() {
410
+ return this.pattern === null;
411
+ };
412
+
413
+ Cell.prototype.isSeed = function isSeed() {
414
+ return this.creator === null;
415
+ };
416
+
417
+ Cell.prototype.react = function react(jp, creation) {
418
+ const result = this.pattern(jp, this.env);
419
+
420
+ if (resultLib.isEnv(result)) {
421
+ const finalEnv = result === true ? this.env : result;
422
+ return new Cell(null, creation(finalEnv, null, this), this);
423
+ }
424
+
425
+ if (resultLib.isPair(result)) {
426
+ const finalEnv = result[1] === true ? this.env : result[1];
427
+ return new Cell(result[0], creation(finalEnv, result[0], this), this);
428
+ }
429
+
430
+ return this;
431
+ };
432
+
433
+ function weave(statefulAspect, jp) {
434
+ const tempCells = statefulAspect.matching(statefulAspect.cells, jp);
435
+ statefulAspect.cells = cellLib.noMatchCells(tempCells);
436
+ return cellLib.matchCells(tempCells);
437
+ }
438
+
439
+ function patternOf(statefulAspect) {
440
+ return statefulAspect.pattern || statefulAspect.sequence;
441
+ }
442
+
443
+ function statefulAspectToAspect(statefulAspect) {
444
+ let matchCells = [];
445
+ return {
446
+ kind: statefulAspect.kind,
447
+ pointcut(jp) {
448
+ matchCells = weave(statefulAspect, jp);
449
+ return matchCells.length > 0;
450
+ },
451
+ advice(jp) {
452
+ return statefulAspect.advising(matchCells, jp, statefulAspect.advice);
453
+ },
454
+ };
455
+ }
456
+
457
+ ESA.deploy = function deploy(statefulAspect) {
458
+ const pattern = patternOf(statefulAspect);
459
+ if (!pattern) {
460
+ throw new Error("Stateful aspect requires a 'pattern' (or legacy 'sequence').");
461
+ }
462
+
463
+ statefulAspect.pattern = pattern;
464
+ statefulAspect.matching = statefulAspect.matching || matching.oneAtATime(pattern);
465
+ statefulAspect.advising = statefulAspect.advising || advising.single;
466
+ statefulAspect.cells = [cellLib.seed(pattern)];
467
+
468
+ return AspectScript.deploy(statefulAspectToAspect(statefulAspect));
469
+ };
470
+
471
+ ESA.undeploy = function undeploy(handler) {
472
+ AspectScript.undeploy(handler);
473
+ };
474
+
475
+ const rules = ESA.rules = {
476
+ applyReaction(creation) {
477
+ const cellCreation = creation || function defaultCreation(env) {
478
+ return env;
479
+ };
480
+ return function applyReactionRule(cells, jp) {
481
+ const reactedCells = cells.map(function reactCell(cell) {
482
+ return cell.react(jp, cellCreation);
483
+ });
484
+ return cellLib.removeDuplicates(reactedCells.concat(cells));
485
+ };
486
+ },
487
+
488
+ killCreators(rule) {
489
+ return function killCreatorsRule(cells, jp) {
490
+ const nextCells = rule(cells, jp);
491
+ return cellLib.difference(nextCells, cellLib.creators(nextCells, cells));
492
+ };
493
+ },
494
+
495
+ addSeed(pattern) {
496
+ return function addSeedRule(rule) {
497
+ return function addSeedInner(cells, jp) {
498
+ const nextCells = rule(cells, jp);
499
+ return nextCells.length === 0 || cellLib.onlyMatchCells(nextCells)
500
+ ? nextCells.concat([cellLib.seed(pattern)])
501
+ : nextCells;
502
+ };
503
+ };
504
+ },
505
+
506
+ keepSeed(pattern) {
507
+ return function keepSeedRule(rule) {
508
+ return function keepSeedInner(cells, jp) {
509
+ const nextCells = rule(cells, jp);
510
+ return cellLib.countSeed(nextCells) > 0 ? nextCells : nextCells.concat([cellLib.seed(pattern)]);
511
+ };
512
+ };
513
+ },
514
+
515
+ traceLifeTime(delta) {
516
+ return function traceLifeTimeRule(rule) {
517
+ return function traceLifeTimeInner(cells, jp) {
518
+ const nextCells = rule(cells, jp);
519
+ return nextCells.filter(function filterByTime(cell) {
520
+ return Date.now() - cell.env.time <= delta;
521
+ });
522
+ };
523
+ };
524
+ },
525
+
526
+ differentBindings(rule) {
527
+ return function differentBindingsRule(cells, jp) {
528
+ const nextCells = rule(cells, jp);
529
+ const newCells = cellLib.difference(nextCells, cells);
530
+
531
+ const filteredNewCells = newCells.filter(function filterNewCell(newCell) {
532
+ if (newCell.creator && newCell.creator.tag > 1) {
533
+ return true;
534
+ }
535
+
536
+ const sisterCells = cellLib.sisters(newCell, cells);
537
+ return sisterCells.some(function sisterHasSameEnv(sisterCell) {
538
+ return !newCell.creator.isSeed() && envLib.equal(newCell.env, sisterCell.env);
539
+ });
540
+ });
541
+
542
+ return cellLib.difference(nextCells, filteredNewCells);
543
+ };
544
+ },
545
+
546
+ tracematchApplyReaction(alphabet) {
547
+ const creation = function creation(env) {
548
+ return env;
549
+ };
550
+
551
+ return function tracematchRule(cells, jp) {
552
+ const nextCells = [];
553
+
554
+ for (let i = 0; i < cells.length; i += 1) {
555
+ if (alphabet.some(function isInAlphabet(sym) {
556
+ return resultLib.isEnv(sym(jp, cells[i].env));
557
+ })) {
558
+ const nextCell = cells[i].react(jp, creation);
559
+ if (nextCell !== cells[i]) {
560
+ nextCells.push(cells[i]);
561
+ nextCells.push(nextCell);
562
+ if (nextCell.isMatch() && envLib.equal(cells[i].env, nextCell.env)) {
563
+ cells[i].tag = cells[i].tag ? cells[i].tag + 1 : 1;
564
+ }
565
+ }
566
+ } else {
567
+ nextCells.push(cells[i]);
568
+ }
569
+ }
570
+
571
+ return nextCells;
572
+ };
573
+ },
574
+ };
575
+
576
+ const matching = ESA.matching = {
577
+ multiple: rules.applyReaction(),
578
+
579
+ oneAtATime(pattern) {
580
+ return rules.addSeed(pattern)(rules.killCreators(rules.applyReaction()));
581
+ },
582
+
583
+ singleMatch: rules.killCreators(rules.applyReaction()),
584
+
585
+ alwaysBeginAMatch(pattern) {
586
+ return rules.keepSeed(pattern)(rules.killCreators(rules.applyReaction()));
587
+ },
588
+
589
+ timingToMatch(pattern, delta) {
590
+ return rules.addSeed(pattern)(
591
+ rules.traceLifeTime(delta)(
592
+ rules.killCreators(
593
+ rules.applyReaction(function createTimedEnv(env, seq, creator) {
594
+ void seq;
595
+ return creator.isSeed() ? env.bind("time", Date.now()) : creator.env;
596
+ }),
597
+ ),
598
+ ),
599
+ );
600
+ },
601
+
602
+ tracematch(pattern, alphabet) {
603
+ return rules.keepSeed(pattern)(rules.differentBindings(rules.tracematchApplyReaction(alphabet)));
604
+ },
605
+ };
606
+
607
+ const advising = ESA.advising = {
608
+ single(matchCells, jp, advice) {
609
+ return advice.call(this, jp, matchCells[0].env);
610
+ },
611
+
612
+ simultaneous(matchCells, jp, advice) {
613
+ return matchCells.map(function eachMatch(matchCell) {
614
+ return advice.call(this, jp, matchCell.env);
615
+ }).pop();
616
+ },
617
+
618
+ differentBindings(matchCells, jp, advice) {
619
+ function bindingWeight(env) {
620
+ let weight = 0;
621
+ for (const name in env) {
622
+ if (SKIPPED_ENV_KEYS[name]) {
623
+ continue;
624
+ }
625
+ const value = env[name];
626
+ if (value instanceof Array) {
627
+ weight += value.length + 1;
628
+ } else if (value !== undefined) {
629
+ weight += 1;
630
+ }
631
+ }
632
+ return weight;
633
+ }
634
+
635
+ const ordered = matchCells.slice().sort(function bySpecificity(a, b) {
636
+ return bindingWeight(b.env) - bindingWeight(a.env);
637
+ });
638
+
639
+ const filteredMatchCells = [];
640
+ ordered.forEach(function eachMatch(matchCell) {
641
+ if (!filteredMatchCells.some(function hasContained(filteredMatchCell) {
642
+ return envLib.isContained(filteredMatchCell.env, matchCell.env);
643
+ })) {
644
+ filteredMatchCells.push(matchCell);
645
+ }
646
+ });
647
+ return advising.simultaneous(filteredMatchCells, jp, advice);
648
+ },
649
+ };
650
+
651
+ const envLib = ESA.envLib = {
652
+ join(accEnv, newEnv) {
653
+ if (!newEnv || newEnv === true) {
654
+ return accEnv;
655
+ }
656
+
657
+ let joined = accEnv || emptyEnv;
658
+ for (const name in newEnv) {
659
+ if (SKIPPED_ENV_KEYS[name]) {
660
+ continue;
661
+ }
662
+
663
+ if (joined[name] !== newEnv[name]) {
664
+ if (newEnv[name] instanceof OwnArrayEnv) {
665
+ for (let i = 0; i < newEnv[name].length; i += 1) {
666
+ joined = joined.bind(name, newEnv[name][i]);
667
+ }
668
+ } else {
669
+ joined = joined.bind(name, newEnv[name]);
670
+ }
671
+ }
672
+ }
673
+ return joined;
674
+ },
675
+
676
+ isContained(envContainer, containedEnv) {
677
+ function valueContains(containerValue, containedValue) {
678
+ if (containerValue === containedValue) {
679
+ return true;
680
+ }
681
+ if (containerValue instanceof Array) {
682
+ if (containedValue instanceof Array) {
683
+ return containedValue.every(function eachValue(value) {
684
+ return containerValue.indexOf(value) >= 0;
685
+ });
686
+ }
687
+ return containerValue.indexOf(containedValue) >= 0;
688
+ }
689
+ return false;
690
+ }
691
+
692
+ for (const name in containedEnv) {
693
+ if (SKIPPED_ENV_KEYS[name]) {
694
+ continue;
695
+ }
696
+ if (!valueContains(envContainer[name], containedEnv[name])) {
697
+ return false;
698
+ }
699
+ }
700
+ return true;
701
+ },
702
+
703
+ equal(env1, env2) {
704
+ return this.isContained(env1, env2) && this.isContained(env2, env1);
705
+ },
706
+
707
+ resultsToJoinedEnv(result1, result2) {
708
+ if (resultLib.isPair(result1) && resultLib.isPair(result2)) {
709
+ return this.join(result1[1], result2[1]);
710
+ }
711
+ if (resultLib.isPair(result1)) {
712
+ return result1[1];
713
+ }
714
+ return result2[1];
715
+ },
716
+ };
717
+
718
+ const cellLib = ESA.cellLib = {
719
+ seed(pattern) {
720
+ return new Cell(pattern, emptyEnv, null);
721
+ },
722
+
723
+ removeDuplicates(array) {
724
+ const newArray = [];
725
+ for (let i = 0; i < array.length; i += 1) {
726
+ let duplicated = false;
727
+ for (let j = 0; j < newArray.length; j += 1) {
728
+ if (array[i] === newArray[j]) {
729
+ duplicated = true;
730
+ break;
731
+ }
732
+ }
733
+
734
+ if (!duplicated) {
735
+ newArray.push(array[i]);
736
+ }
737
+ }
738
+ return newArray;
739
+ },
740
+
741
+ onlyMatchCells(cells) {
742
+ for (let i = 0; i < cells.length; i += 1) {
743
+ if (!cells[i].isMatch()) {
744
+ return false;
745
+ }
746
+ }
747
+ return true;
748
+ },
749
+
750
+ matchCells(cells) {
751
+ return cells.filter(function isMatchCell(cell) {
752
+ return cell.isMatch();
753
+ });
754
+ },
755
+
756
+ noMatchCells(cells) {
757
+ return cells.filter(function isNoMatchCell(cell) {
758
+ return !cell.isMatch();
759
+ });
760
+ },
761
+
762
+ creators(nextCells, cells) {
763
+ return cellLib.parents(cellLib.difference(nextCells, cells));
764
+ },
765
+
766
+ countSeed(cells) {
767
+ return cells.filter(function isSeedCell(cell) {
768
+ return cell.isSeed();
769
+ }).length;
770
+ },
771
+
772
+ difference(cells1, cells2) {
773
+ return cells1.filter(function onlyInFirst(cell1) {
774
+ return !cells2.some(function existsInSecond(cell2) {
775
+ return cell1 === cell2;
776
+ });
777
+ });
778
+ },
779
+
780
+ parents(cells) {
781
+ return cells.map(function parentOf(cell) {
782
+ return cell.creator === null ? cell : cell.creator;
783
+ });
784
+ },
785
+
786
+ envs(cells) {
787
+ return cells.map(function envOf(cell) {
788
+ return cell.env;
789
+ });
790
+ },
791
+
792
+ hasDifferentBindings(aCell, cells) {
793
+ return !cells.some(function sameBinding(cell) {
794
+ return aCell !== cell && envLib.equal(aCell.env, cell.env);
795
+ });
796
+ },
797
+
798
+ removeSeeds(cells) {
799
+ return cells.filter(function notSeed(cell) {
800
+ return !cell.isSeed();
801
+ });
802
+ },
803
+
804
+ children(cells, creator) {
805
+ return cells.filter(function isChild(cell) {
806
+ return cell.creator === creator;
807
+ });
808
+ },
809
+
810
+ sisters(cell, cells) {
811
+ return cells.filter(function isSister(aCell) {
812
+ return aCell !== cell && aCell.creator === cell.creator;
813
+ });
814
+ },
815
+ };
816
+
817
+ const resultLib = ESA.resultLib = {
818
+ isSeq(fun) {
819
+ return fun instanceof Function;
820
+ },
821
+
822
+ isEnv,
823
+
824
+ isPair(result) {
825
+ return result instanceof Array && this.isSeq(result[0]) && this.isEnv(result[1]);
826
+ },
827
+ };
828
+
829
+ const tracematchLib = ESA.tracematchLib = {
830
+ restrictIdentifier(oldValue, value) {
831
+ return !oldValue || oldValue === value;
832
+ },
833
+
834
+ chainAdvice(matchCells, kind, advice) {
835
+ const envs = cellLib.envs(matchCells);
836
+
837
+ return function chainAdviceImpl(jp) {
838
+ if (envs.length === 0) {
839
+ return kind === ESA.AROUND ? jp.proceed() : undefined;
840
+ }
841
+
842
+ const originalProceed = jp.proceed;
843
+
844
+ function makeJPView(proceedFn) {
845
+ const clone = {};
846
+ for (const key in jp) {
847
+ clone[key] = jp[key];
848
+ }
849
+ clone.proceed = proceedFn;
850
+ return clone;
851
+ }
852
+
853
+ function invoke(index) {
854
+ const hasNext = index + 1 < envs.length;
855
+ const proceedFn = function chainedProceed() {
856
+ if (hasNext) {
857
+ return invoke(index + 1);
858
+ }
859
+ if (kind === ESA.AROUND) {
860
+ return originalProceed();
861
+ }
862
+ return undefined;
863
+ };
864
+
865
+ const jpView = makeJPView(proceedFn);
866
+ const result = advice(jpView, envs[index]);
867
+
868
+ if (kind === ESA.BEFORE || kind === ESA.AFTER) {
869
+ return proceedFn();
870
+ }
871
+
872
+ return result;
873
+ }
874
+
875
+ return invoke(0);
876
+ };
877
+ },
878
+
879
+ deploy(statefulAspect, alphabet) {
880
+ const pattern = patternOf(statefulAspect);
881
+ statefulAspect.pattern = pattern;
882
+ statefulAspect.matching = ESA.matching.tracematch(pattern, alphabet);
883
+ statefulAspect.advising = ESA.advising.differentBindings;
884
+ return ESA.deploy(statefulAspect);
885
+ },
886
+ };
887
+
888
+ ESA.BEFORE = AspectScript.BEFORE;
889
+ ESA.AROUND = AspectScript.AROUND;
890
+ ESA.AFTER = AspectScript.AFTER;
891
+ ESA.globalObject = AspectScript.globalObject;
892
+
893
+ return ESA;
894
+ }
895
+
896
+ if (typeof globalThis !== "undefined") {
897
+ globalThis.createESA = createESA;
898
+ }
899
+
900
+ if (typeof module !== "undefined" && module.exports) {
901
+ module.exports = {
902
+ createESA,
903
+ };
904
+ }