@interactors/core 0.3.0 → 1.0.0-effection.1
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/dist/cjs/constructor.js +66 -143
- package/dist/cjs/constructor.js.map +1 -1
- package/dist/cjs/converge.js +3 -5
- package/dist/cjs/converge.js.map +1 -1
- package/dist/cjs/format.js +50 -0
- package/dist/cjs/format.js.map +1 -0
- package/dist/cjs/index.js +1 -20
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/inspector.js +3 -2
- package/dist/cjs/inspector.js.map +1 -1
- package/dist/cjs/interaction.js +43 -35
- package/dist/cjs/interaction.js.map +1 -1
- package/dist/cjs/match.js +17 -7
- package/dist/cjs/match.js.map +1 -1
- package/dist/cjs/matcher.js +13 -1
- package/dist/cjs/matcher.js.map +1 -1
- package/dist/cjs/matchers/and.js +3 -0
- package/dist/cjs/matchers/and.js.map +1 -1
- package/dist/cjs/matchers/every.js +3 -0
- package/dist/cjs/matchers/every.js.map +1 -1
- package/dist/cjs/matchers/including.js +4 -0
- package/dist/cjs/matchers/including.js.map +1 -1
- package/dist/cjs/matchers/matching.js +4 -0
- package/dist/cjs/matchers/matching.js.map +1 -1
- package/dist/cjs/matchers/not.js +3 -0
- package/dist/cjs/matchers/not.js.map +1 -1
- package/dist/cjs/matchers/or.js +3 -0
- package/dist/cjs/matchers/or.js.map +1 -1
- package/dist/cjs/matchers/some.js +3 -0
- package/dist/cjs/matchers/some.js.map +1 -1
- package/dist/cjs/resolvers.js +98 -0
- package/dist/cjs/resolvers.js.map +1 -0
- package/dist/cjs/serialize.js +48 -0
- package/dist/cjs/serialize.js.map +1 -0
- package/dist/constructor.d.ts +3 -10
- package/dist/constructor.d.ts.map +1 -1
- package/dist/converge.d.ts +2 -1
- package/dist/converge.d.ts.map +1 -1
- package/dist/esm/constructor.js +64 -134
- package/dist/esm/constructor.js.map +1 -1
- package/dist/esm/converge.js +3 -5
- package/dist/esm/converge.js.map +1 -1
- package/dist/esm/{format-table.js → format.js} +19 -1
- package/dist/esm/format.js.map +1 -0
- package/dist/esm/index.js +0 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/inspector.js +3 -2
- package/dist/esm/inspector.js.map +1 -1
- package/dist/esm/interaction.js +40 -29
- package/dist/esm/interaction.js.map +1 -1
- package/dist/esm/match.js +17 -7
- package/dist/esm/match.js.map +1 -1
- package/dist/esm/matcher.js +11 -0
- package/dist/esm/matcher.js.map +1 -1
- package/dist/esm/matchers/and.js +4 -1
- package/dist/esm/matchers/and.js.map +1 -1
- package/dist/esm/matchers/every.js +4 -1
- package/dist/esm/matchers/every.js.map +1 -1
- package/dist/esm/matchers/including.js +4 -0
- package/dist/esm/matchers/including.js.map +1 -1
- package/dist/esm/matchers/matching.js +4 -0
- package/dist/esm/matchers/matching.js.map +1 -1
- package/dist/esm/matchers/not.js +4 -1
- package/dist/esm/matchers/not.js.map +1 -1
- package/dist/esm/matchers/or.js +4 -1
- package/dist/esm/matchers/or.js.map +1 -1
- package/dist/esm/matchers/some.js +4 -1
- package/dist/esm/matchers/some.js.map +1 -1
- package/dist/esm/resolvers.js +88 -0
- package/dist/esm/resolvers.js.map +1 -0
- package/dist/esm/serialize.js +43 -0
- package/dist/esm/serialize.js.map +1 -0
- package/dist/format.d.ts +10 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/index.d.ts +4 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/inspector.d.ts +2 -2
- package/dist/inspector.d.ts.map +1 -1
- package/dist/interaction.d.ts +38 -10
- package/dist/interaction.d.ts.map +1 -1
- package/dist/match.d.ts +5 -5
- package/dist/match.d.ts.map +1 -1
- package/dist/matcher.d.ts +2 -0
- package/dist/matcher.d.ts.map +1 -1
- package/dist/matchers/and.d.ts.map +1 -1
- package/dist/matchers/every.d.ts.map +1 -1
- package/dist/matchers/including.d.ts.map +1 -1
- package/dist/matchers/matching.d.ts.map +1 -1
- package/dist/matchers/not.d.ts.map +1 -1
- package/dist/matchers/or.d.ts.map +1 -1
- package/dist/matchers/some.d.ts.map +1 -1
- package/dist/resolvers.d.ts +9 -0
- package/dist/resolvers.d.ts.map +1 -0
- package/dist/serialize.d.ts +13 -0
- package/dist/serialize.d.ts.map +1 -0
- package/dist/specification.d.ts +49 -51
- package/dist/specification.d.ts.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/constructor.ts +76 -160
- package/src/converge.ts +3 -6
- package/src/format.ts +58 -0
- package/src/index.ts +4 -6
- package/src/inspector.ts +5 -4
- package/src/interaction.ts +85 -36
- package/src/match.ts +23 -15
- package/src/matcher.ts +11 -0
- package/src/matchers/and.ts +4 -1
- package/src/matchers/every.ts +4 -1
- package/src/matchers/including.ts +4 -1
- package/src/matchers/matching.ts +4 -1
- package/src/matchers/not.ts +4 -1
- package/src/matchers/or.ts +4 -1
- package/src/matchers/some.ts +4 -1
- package/src/resolvers.ts +100 -0
- package/src/serialize.ts +54 -0
- package/src/specification.ts +58 -61
- package/CHANGELOG.md +0 -14
- package/dist/cjs/dispatch.js +0 -34
- package/dist/cjs/dispatch.js.map +0 -1
- package/dist/cjs/element/fill-in.js +0 -71
- package/dist/cjs/element/fill-in.js.map +0 -1
- package/dist/cjs/focused.js +0 -47
- package/dist/cjs/focused.js.map +0 -1
- package/dist/cjs/format-table.js +0 -30
- package/dist/cjs/format-table.js.map +0 -1
- package/dist/cjs/perform.js +0 -13
- package/dist/cjs/perform.js.map +0 -1
- package/dist/dispatch.d.ts +0 -6
- package/dist/dispatch.d.ts.map +0 -1
- package/dist/element/fill-in.d.ts +0 -12
- package/dist/element/fill-in.d.ts.map +0 -1
- package/dist/esm/dispatch.js +0 -26
- package/dist/esm/dispatch.js.map +0 -1
- package/dist/esm/element/fill-in.js +0 -67
- package/dist/esm/element/fill-in.js.map +0 -1
- package/dist/esm/focused.js +0 -41
- package/dist/esm/focused.js.map +0 -1
- package/dist/esm/format-table.js.map +0 -1
- package/dist/esm/perform.js +0 -9
- package/dist/esm/perform.js.map +0 -1
- package/dist/focused.d.ts +0 -30
- package/dist/focused.d.ts.map +0 -1
- package/dist/format-table.d.ts +0 -6
- package/dist/format-table.d.ts.map +0 -1
- package/dist/perform.d.ts +0 -3
- package/dist/perform.d.ts.map +0 -1
- package/src/dispatch.ts +0 -24
- package/src/element/fill-in.ts +0 -76
- package/src/focused.ts +0 -43
- package/src/format-table.ts +0 -34
- package/src/perform.ts +0 -11
package/src/match.ts
CHANGED
|
@@ -9,7 +9,6 @@ const check = (value: unknown): string => value ? "✓" : "⨯";
|
|
|
9
9
|
export class Match<E extends Element, F extends Filters<E>> {
|
|
10
10
|
public matchLocator?: MatchLocator<E>;
|
|
11
11
|
public matchFilter: MatchFilter<E, F>;
|
|
12
|
-
public matches: boolean;
|
|
13
12
|
|
|
14
13
|
constructor(
|
|
15
14
|
public element: E,
|
|
@@ -18,7 +17,10 @@ export class Match<E extends Element, F extends Filters<E>> {
|
|
|
18
17
|
) {
|
|
19
18
|
this.matchLocator = locator && new MatchLocator(element, locator);
|
|
20
19
|
this.matchFilter = new MatchFilter(element, filterSet);
|
|
21
|
-
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get matches(): boolean {
|
|
23
|
+
return (this.matchLocator ? this.matchLocator.matches : true) && this.matchFilter.matches;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
asTableHeader(name: string): string[] {
|
|
@@ -51,7 +53,6 @@ export class Match<E extends Element, F extends Filters<E>> {
|
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
export class MatchLocator<E extends Element> {
|
|
54
|
-
public matches: boolean;
|
|
55
56
|
public expected: MaybeMatcher<string> | null;
|
|
56
57
|
public actual: string | null;
|
|
57
58
|
|
|
@@ -61,7 +62,10 @@ export class MatchLocator<E extends Element> {
|
|
|
61
62
|
) {
|
|
62
63
|
this.expected = locator.value;
|
|
63
64
|
this.actual = locator.apply(element);
|
|
64
|
-
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get matches(): boolean {
|
|
68
|
+
return applyMatcher(this.expected, this.actual)
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
formatActual(): string {
|
|
@@ -78,7 +82,6 @@ export class MatchLocator<E extends Element> {
|
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
export class MatchFilter<E extends Element, F extends Filters<E>> {
|
|
81
|
-
public matches: boolean;
|
|
82
85
|
public items: MatchFilterItem<unknown, E, F>[];
|
|
83
86
|
|
|
84
87
|
constructor(
|
|
@@ -88,7 +91,10 @@ export class MatchFilter<E extends Element, F extends Filters<E>> {
|
|
|
88
91
|
this.items = Object.entries(filter.all).map(([key, expected]) => {
|
|
89
92
|
return new MatchFilterItem(element, filter, key, expected)
|
|
90
93
|
});
|
|
91
|
-
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get matches(): boolean {
|
|
97
|
+
return this.items.every((match) => match.matches)
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
asTableRow(): string[] {
|
|
@@ -114,23 +120,25 @@ export function applyFilter<T>(definition: FilterDefinition<T, any>, element: El
|
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
export class MatchFilterItem<T, E extends Element, F extends Filters<E>> {
|
|
117
|
-
public actual: T;
|
|
118
|
-
public matches: boolean;
|
|
119
|
-
|
|
120
123
|
constructor(
|
|
121
124
|
public element: E,
|
|
122
125
|
public filter: FilterSet<E, F>,
|
|
123
126
|
public key: string,
|
|
124
127
|
public expected: MaybeMatcher<T>,
|
|
125
|
-
) {
|
|
126
|
-
|
|
128
|
+
) {}
|
|
129
|
+
|
|
130
|
+
get matches(): boolean {
|
|
131
|
+
return applyMatcher(this.expected, this.actual);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
get actual(): T {
|
|
135
|
+
if (this.filter.specification.filters && this.filter.specification.filters[this.key]) {
|
|
127
136
|
let definition = this.filter.specification.filters[this.key];
|
|
128
|
-
if(typeof
|
|
129
|
-
|
|
137
|
+
if (typeof definition === 'function') {
|
|
138
|
+
return definition(this.element) as T;
|
|
130
139
|
} else {
|
|
131
|
-
|
|
140
|
+
return definition.apply(this.element) as T;
|
|
132
141
|
}
|
|
133
|
-
this.matches = applyMatcher(this.expected, this.actual);
|
|
134
142
|
} else {
|
|
135
143
|
throw new Error(`interactor does not define a filter named ${JSON.stringify(this.key)}`);
|
|
136
144
|
}
|
package/src/matcher.ts
CHANGED
|
@@ -3,6 +3,7 @@ import isEqual from 'lodash.isequal';
|
|
|
3
3
|
export interface Matcher<T> {
|
|
4
4
|
match(actual: T): boolean;
|
|
5
5
|
description(): string;
|
|
6
|
+
code?(): string;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
export type MaybeMatcher<T> = Matcher<T> | T;
|
|
@@ -26,3 +27,13 @@ export function applyMatcher<T>(value: MaybeMatcher<T>, actual: T): boolean {
|
|
|
26
27
|
return isEqual(value, actual);
|
|
27
28
|
}
|
|
28
29
|
}
|
|
30
|
+
|
|
31
|
+
export function matcherCode<T>(value: MaybeMatcher<T>): string {
|
|
32
|
+
if (isMatcher(value) && value.code) {
|
|
33
|
+
return value.code();
|
|
34
|
+
} else if (value instanceof RegExp) {
|
|
35
|
+
return value.toString();
|
|
36
|
+
} else {
|
|
37
|
+
return JSON.stringify(value);
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/matchers/and.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Matcher, MaybeMatcher, matcherDescription, applyMatcher } from '../matcher';
|
|
1
|
+
import { Matcher, MaybeMatcher, matcherDescription, applyMatcher, matcherCode } from '../matcher';
|
|
2
2
|
|
|
3
3
|
export function and<T>(...args: MaybeMatcher<T>[]): Matcher<T> {
|
|
4
4
|
return {
|
|
@@ -8,5 +8,8 @@ export function and<T>(...args: MaybeMatcher<T>[]): Matcher<T> {
|
|
|
8
8
|
description(): string {
|
|
9
9
|
return args.map(matcherDescription).join(' and ');
|
|
10
10
|
},
|
|
11
|
+
code(): string {
|
|
12
|
+
return `and(${args.map(arg => matcherCode(arg)).join(', ')})`
|
|
13
|
+
}
|
|
11
14
|
}
|
|
12
15
|
}
|
package/src/matchers/every.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Matcher, MaybeMatcher, applyMatcher, matcherDescription } from '../matcher';
|
|
1
|
+
import { Matcher, MaybeMatcher, applyMatcher, matcherDescription, matcherCode } from '../matcher';
|
|
2
2
|
|
|
3
3
|
export function every<T>(expected: MaybeMatcher<T>): Matcher<Iterable<T>> {
|
|
4
4
|
return {
|
|
@@ -8,5 +8,8 @@ export function every<T>(expected: MaybeMatcher<T>): Matcher<Iterable<T>> {
|
|
|
8
8
|
description(): string {
|
|
9
9
|
return `every item ${matcherDescription(expected)}`;
|
|
10
10
|
},
|
|
11
|
+
code(): string {
|
|
12
|
+
return `every(${matcherCode(expected)})`
|
|
13
|
+
}
|
|
11
14
|
}
|
|
12
15
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Matcher } from '../matcher';
|
|
1
|
+
import { Matcher, matcherCode} from '../matcher';
|
|
2
2
|
|
|
3
3
|
export function including(subString: string): Matcher<string> {
|
|
4
4
|
return {
|
|
@@ -8,5 +8,8 @@ export function including(subString: string): Matcher<string> {
|
|
|
8
8
|
description(): string {
|
|
9
9
|
return `including ${JSON.stringify(subString)}`;
|
|
10
10
|
},
|
|
11
|
+
code(): string {
|
|
12
|
+
return `including(${matcherCode(subString)})`
|
|
13
|
+
}
|
|
11
14
|
}
|
|
12
15
|
}
|
package/src/matchers/matching.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Matcher } from '../matcher';
|
|
1
|
+
import { Matcher, matcherCode } from '../matcher';
|
|
2
2
|
|
|
3
3
|
export function matching(regexp: RegExp): Matcher<string> {
|
|
4
4
|
return {
|
|
@@ -8,5 +8,8 @@ export function matching(regexp: RegExp): Matcher<string> {
|
|
|
8
8
|
description(): string {
|
|
9
9
|
return `matching ${regexp}`;
|
|
10
10
|
},
|
|
11
|
+
code(): string {
|
|
12
|
+
return `matching(${matcherCode(regexp)})`
|
|
13
|
+
}
|
|
11
14
|
}
|
|
12
15
|
}
|
package/src/matchers/not.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Matcher, MaybeMatcher, matcherDescription, applyMatcher } from '../matcher';
|
|
1
|
+
import { Matcher, MaybeMatcher, matcherDescription, applyMatcher, matcherCode } from '../matcher';
|
|
2
2
|
|
|
3
3
|
export function not<T>(matcher: MaybeMatcher<T>): Matcher<T> {
|
|
4
4
|
return {
|
|
@@ -8,5 +8,8 @@ export function not<T>(matcher: MaybeMatcher<T>): Matcher<T> {
|
|
|
8
8
|
description(): string {
|
|
9
9
|
return `not ${matcherDescription(matcher)}`;
|
|
10
10
|
},
|
|
11
|
+
code(): string {
|
|
12
|
+
return `not(${matcherCode(matcher)})`
|
|
13
|
+
}
|
|
11
14
|
}
|
|
12
15
|
}
|
package/src/matchers/or.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Matcher, MaybeMatcher, matcherDescription, applyMatcher } from '../matcher';
|
|
1
|
+
import { Matcher, MaybeMatcher, matcherDescription, applyMatcher, matcherCode } from '../matcher';
|
|
2
2
|
|
|
3
3
|
export function or<T>(...args: MaybeMatcher<T>[]): Matcher<T> {
|
|
4
4
|
return {
|
|
@@ -8,5 +8,8 @@ export function or<T>(...args: MaybeMatcher<T>[]): Matcher<T> {
|
|
|
8
8
|
description(): string {
|
|
9
9
|
return args.map(matcherDescription).join(' or ');
|
|
10
10
|
},
|
|
11
|
+
code(): string {
|
|
12
|
+
return `or(${args.map(arg => matcherCode(arg)).join(', ')})`
|
|
13
|
+
}
|
|
11
14
|
}
|
|
12
15
|
}
|
package/src/matchers/some.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Matcher, MaybeMatcher, applyMatcher, matcherDescription } from '../matcher';
|
|
1
|
+
import { Matcher, MaybeMatcher, applyMatcher, matcherDescription, matcherCode } from '../matcher';
|
|
2
2
|
|
|
3
3
|
export function some<T>(expected: MaybeMatcher<T>): Matcher<Iterable<T>> {
|
|
4
4
|
return {
|
|
@@ -8,5 +8,8 @@ export function some<T>(expected: MaybeMatcher<T>): Matcher<Iterable<T>> {
|
|
|
8
8
|
description(): string {
|
|
9
9
|
return `some item ${matcherDescription(expected)}`;
|
|
10
10
|
},
|
|
11
|
+
code(): string {
|
|
12
|
+
return `some(${matcherCode(expected)})`
|
|
13
|
+
}
|
|
11
14
|
}
|
|
12
15
|
}
|
package/src/resolvers.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
|
|
4
|
+
import { globals } from '@interactors/globals';
|
|
5
|
+
import { Match } from './match';
|
|
6
|
+
import { NoSuchElementError, NotAbsentError, AmbiguousElementError } from './errors';
|
|
7
|
+
import { formatDescription, formatMatchesTable } from './format';
|
|
8
|
+
import { InteractorOptions } from './specification';
|
|
9
|
+
|
|
10
|
+
const defaultSelector = 'div';
|
|
11
|
+
|
|
12
|
+
export function findElements<E extends Element>(parentElement: Element, interactor: InteractorOptions<any, any, any>): E[] {
|
|
13
|
+
if (!interactor.name) {
|
|
14
|
+
throw new Error('One of your interactors was created without a name. Please provide a label for your interactor:\n\tHTML.extend(\'my interactor\') || createInteractor(\'my interactor\')');
|
|
15
|
+
}
|
|
16
|
+
if (typeof interactor.specification.selector === 'function') {
|
|
17
|
+
return interactor.specification.selector(parentElement);
|
|
18
|
+
} else if (interactor.specification.selector === ':root') {
|
|
19
|
+
// this is a bit of a hack, because otherwise there isn't a good way of selecting the root element
|
|
20
|
+
return [parentElement.ownerDocument.querySelector(':root') as E];
|
|
21
|
+
} else {
|
|
22
|
+
return Array.from(parentElement.querySelectorAll(interactor.specification.selector || defaultSelector));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function findMatches(parentElement: Element, interactor: InteractorOptions<any, any, any>): Match<Element, any>[] {
|
|
27
|
+
return findElements(parentElement, interactor).map((e) => new Match(e, interactor.filter, interactor.locator));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function throwNoSuchElementError(matches: Match<Element, any>[], interactor: InteractorOptions<any, any, any>): never {
|
|
31
|
+
if (matches.length === 0) {
|
|
32
|
+
throw new NoSuchElementError(`did not find ${formatDescription(interactor)}`);
|
|
33
|
+
} else {
|
|
34
|
+
throw new NoSuchElementError(`did not find ${formatDescription(interactor)}, did you mean one of:\n\n${formatMatchesTable(interactor, matches)}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function findFirstMatch(parentElement: Element, interactor: InteractorOptions<any, any, any>): Match<Element, any> {
|
|
39
|
+
let matches: Match<Element, any>[] = []
|
|
40
|
+
for (let element of findElements(parentElement, interactor)) {
|
|
41
|
+
let match = new Match(element, interactor.filter, interactor.locator)
|
|
42
|
+
matches.push(match)
|
|
43
|
+
if (match.matches) {
|
|
44
|
+
return match
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
throwNoSuchElementError(matches, interactor);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function hasMatchMatching(parentElement: Element, interactor: InteractorOptions<any, any, any>): boolean {
|
|
51
|
+
return findElements(parentElement, interactor).some(element => new Match(element, interactor.filter, interactor.locator).matches);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function findMatchesNonEmpty(parentElement: Element, interactor: InteractorOptions<any, any, any>): Match<Element, any>[] {
|
|
55
|
+
let matches = findMatches(parentElement, interactor);
|
|
56
|
+
let matching = matches.filter((m) => m.matches);
|
|
57
|
+
if (matching.length > 0) {
|
|
58
|
+
return matching;
|
|
59
|
+
}
|
|
60
|
+
throwNoSuchElementError(matches, interactor);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Given a parent element, and an interactor, find exactly one matching element
|
|
64
|
+
// and return it. If no elements match, raise an error. If more than one
|
|
65
|
+
// element matches, raise an error.
|
|
66
|
+
export function resolveUnique(parentElement: Element, interactor: InteractorOptions<any, any, any>): Element {
|
|
67
|
+
let matching = findMatchesNonEmpty(parentElement, interactor);
|
|
68
|
+
|
|
69
|
+
if (matching.length === 1) {
|
|
70
|
+
return matching[0].element;
|
|
71
|
+
} else {
|
|
72
|
+
let alternatives = matching.map((m) => '- ' + m.elementDescription());
|
|
73
|
+
throw new AmbiguousElementError(`${formatDescription(interactor)} matches multiple elements:\n\n${alternatives.join('\n')}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Given a parent element, and an interactor, find the first matching element and
|
|
78
|
+
// return it. If no elements match, raise an error.
|
|
79
|
+
export function resolveFirst(parentElement: Element, interactor: InteractorOptions<any, any, any>): Element {
|
|
80
|
+
return findFirstMatch(parentElement, interactor).element
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Given a parent element, and an interactor, check if there are any matching
|
|
84
|
+
// elements, and throw an error if there are. Otherwise return undefined.
|
|
85
|
+
export function resolveEmpty(parentElement: Element, interactor: InteractorOptions<any, any, any>): void {
|
|
86
|
+
let matching = findMatches(parentElement, interactor).filter((m) => m.matches)
|
|
87
|
+
|
|
88
|
+
if (matching.length !== 0) {
|
|
89
|
+
let alternatives = matching.map((m) => '- ' + m.elementDescription());
|
|
90
|
+
throw new NotAbsentError(`${formatDescription(interactor)} exists but should not:\n\n${alternatives.join('\n')}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function unsafeSyncResolveParent(options: InteractorOptions<any, any, any>): Element {
|
|
95
|
+
return options.ancestors.reduce(resolveUnique, globals.document.documentElement);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function unsafeSyncResolveUnique<E extends Element>(options: InteractorOptions<E, any, any>): E {
|
|
99
|
+
return resolveUnique(unsafeSyncResolveParent(options), options) as E;
|
|
100
|
+
}
|
package/src/serialize.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { InteractionOptions as SerializedInteractionOptions, InteractionType } from "@interactors/globals";
|
|
3
|
+
import { pascalCase } from "change-case";
|
|
4
|
+
import { InteractionOptions } from "./interaction";
|
|
5
|
+
import { matcherCode } from "./matcher";
|
|
6
|
+
import { InteractorOptions } from "./specification";
|
|
7
|
+
|
|
8
|
+
export function serializeInteractorOptions(options: InteractorOptions<any, any, any>): {
|
|
9
|
+
interactor: string;
|
|
10
|
+
filter: { [name: string]: unknown };
|
|
11
|
+
locator: string;
|
|
12
|
+
code: () => string;
|
|
13
|
+
} {
|
|
14
|
+
let locator = matcherCode(options.locator?.value);
|
|
15
|
+
return {
|
|
16
|
+
interactor: options.name,
|
|
17
|
+
filter: options.filter.all,
|
|
18
|
+
locator,
|
|
19
|
+
code() {
|
|
20
|
+
let interactorName = pascalCase(options.name);
|
|
21
|
+
let filters = Object.entries(options.filter.all).map(([name, filter]) => `"${name}": ${matcherCode(filter)}`);
|
|
22
|
+
return `${interactorName}(${[locator, filters.length && `{ ${filters.join(", ")} }`]
|
|
23
|
+
.filter(Boolean)
|
|
24
|
+
.join(", ")})`;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function serializeInteractionOptions<E extends Element, T>(
|
|
30
|
+
type: InteractionType,
|
|
31
|
+
{ name, interactor: { options }, args, filters }: InteractionOptions<E, T>
|
|
32
|
+
): SerializedInteractionOptions {
|
|
33
|
+
let interactor = serializeInteractorOptions(options);
|
|
34
|
+
let ancestors = options.ancestors.map((ancestor) => serializeInteractorOptions(ancestor));
|
|
35
|
+
return {
|
|
36
|
+
...interactor,
|
|
37
|
+
ancestors,
|
|
38
|
+
name,
|
|
39
|
+
type,
|
|
40
|
+
args: filters ? [filters] : args ? args : undefined,
|
|
41
|
+
code() {
|
|
42
|
+
let serializedArgs = "";
|
|
43
|
+
if (filters) {
|
|
44
|
+
let serializedFilters = Object.entries(filters).map(([name, filter]) => `"${name}": ${matcherCode(filter)}`);
|
|
45
|
+
serializedArgs = `{ ${serializedFilters.join(", ")} }`;
|
|
46
|
+
} else if (args) {
|
|
47
|
+
serializedArgs = args.map((arg) => JSON.stringify(arg)).join(", ");
|
|
48
|
+
}
|
|
49
|
+
return `${[...ancestors, interactor]
|
|
50
|
+
.map(({ code }, index) => (index == 0 ? code() : `${code()})`))
|
|
51
|
+
.join(".find(")}.${name}(${serializedArgs})`;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
package/src/specification.ts
CHANGED
|
@@ -1,49 +1,28 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
|
|
3
|
+
import { Operation } from '@effection/core';
|
|
3
4
|
import { FilterSet } from './filter-set';
|
|
4
5
|
import { Locator } from './locator';
|
|
5
|
-
import {
|
|
6
|
+
import { ActionInteraction, AssertionInteraction } from './interaction';
|
|
6
7
|
import { MergeObjects } from './merge-objects';
|
|
7
8
|
import { MaybeMatcher } from './matcher';
|
|
8
9
|
|
|
9
10
|
export type EmptyObject = Record<never, never>;
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* ## Example
|
|
18
|
-
*
|
|
19
|
-
* ``` typescript
|
|
20
|
-
* await Link('Next').exists();
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
exists(): ReadonlyInteraction<void> & FilterObject<boolean, Element>;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* An assertion which checks that an element matching the interactor does not
|
|
27
|
-
* exist. Throws an error if the element exists.
|
|
28
|
-
*
|
|
29
|
-
* ## Example
|
|
30
|
-
*
|
|
31
|
-
* ``` typescript
|
|
32
|
-
* await Link('Next').absent();
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
absent(): ReadonlyInteraction<void> & FilterObject<boolean, Element>;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface BaseInteractor<E extends Element, F extends FilterParams<any, any>> {
|
|
12
|
+
/**
|
|
13
|
+
* Instances of an interactor returned by an {@link InteractorConstructor}, use
|
|
14
|
+
* this class as its base. They are also extended with any additional actions
|
|
15
|
+
* defined in their {@link InteractorSpecification}.
|
|
16
|
+
*/
|
|
17
|
+
export interface Interactor<E extends Element, F extends FilterParams<any, any>> {
|
|
39
18
|
/**
|
|
40
19
|
* @hidden
|
|
41
20
|
*/
|
|
42
21
|
options: InteractorOptions<E, any, any>;
|
|
43
22
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
23
|
+
/**
|
|
24
|
+
* @returns a human readable description of this interactor
|
|
25
|
+
*/
|
|
47
26
|
description: string;
|
|
48
27
|
|
|
49
28
|
/**
|
|
@@ -60,7 +39,7 @@ export interface BaseInteractor<E extends Element, F extends FilterParams<any, a
|
|
|
60
39
|
* await Link('Next').perform((e) => e.click());
|
|
61
40
|
* ```
|
|
62
41
|
*/
|
|
63
|
-
perform(fn: (element: E) => void):
|
|
42
|
+
perform(fn: (element: E) => void): ActionInteraction<E, void>;
|
|
64
43
|
|
|
65
44
|
/**
|
|
66
45
|
* Perform a one-off assertion on the given interactor. Takes a function which
|
|
@@ -76,7 +55,31 @@ export interface BaseInteractor<E extends Element, F extends FilterParams<any, a
|
|
|
76
55
|
* await Link('Next').assert((e) => assert(e.tagName === 'A'));
|
|
77
56
|
* ```
|
|
78
57
|
*/
|
|
79
|
-
assert(fn: (element: E) => void):
|
|
58
|
+
assert(fn: (element: E) => void): AssertionInteraction<E, void>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* An assertion which checks that an element matching the interactor exists.
|
|
62
|
+
* Throws an error if the element does not exist.
|
|
63
|
+
*
|
|
64
|
+
* ## Example
|
|
65
|
+
*
|
|
66
|
+
* ``` typescript
|
|
67
|
+
* await Link('Next').exists();
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
exists(): AssertionInteraction<E, void> & FilterObject<boolean, Element>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* An assertion which checks that an element matching the interactor does not
|
|
74
|
+
* exist. Throws an error if the element exists.
|
|
75
|
+
*
|
|
76
|
+
* ## Example
|
|
77
|
+
*
|
|
78
|
+
* ``` typescript
|
|
79
|
+
* await Link('Next').absent();
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
absent(): AssertionInteraction<E, void> & FilterObject<boolean, Element>;
|
|
80
83
|
|
|
81
84
|
/**
|
|
82
85
|
* Checks that there is one element matching the interactor, and that this
|
|
@@ -89,7 +92,7 @@ export interface BaseInteractor<E extends Element, F extends FilterParams<any, a
|
|
|
89
92
|
* await Link('Home').has({ href: '/' })
|
|
90
93
|
* ```
|
|
91
94
|
*/
|
|
92
|
-
has(filters: F):
|
|
95
|
+
has(filters: F): AssertionInteraction<E, void>;
|
|
93
96
|
|
|
94
97
|
/**
|
|
95
98
|
* Identical to {@link has}, but reads better with some filters.
|
|
@@ -100,20 +103,8 @@ export interface BaseInteractor<E extends Element, F extends FilterParams<any, a
|
|
|
100
103
|
* await CheckBox('Accept conditions').is({ checked: true })
|
|
101
104
|
* ```
|
|
102
105
|
*/
|
|
103
|
-
is(filters: F):
|
|
106
|
+
is(filters: F): AssertionInteraction<E, void>;
|
|
104
107
|
|
|
105
|
-
/**
|
|
106
|
-
* @hidden
|
|
107
|
-
*/
|
|
108
|
-
apply: FilterFn<string, Element>;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Instances of an interactor returned by an {@link InteractorConstructor}, use
|
|
113
|
-
* this class as its base. They are also extended with any additional actions
|
|
114
|
-
* defined in their {@link InteractorSpecification}.
|
|
115
|
-
*/
|
|
116
|
-
export interface Interactor<E extends Element, F extends FilterParams<any, any>> extends BaseInteractor<E, F>, ExistsAssertionsImplementation {
|
|
117
108
|
/**
|
|
118
109
|
* Returns a copy of the given interactor which is scoped to this interactor.
|
|
119
110
|
* When there are multiple matches for an interactor, this makes it possible
|
|
@@ -130,10 +121,15 @@ export interface Interactor<E extends Element, F extends FilterParams<any, any>>
|
|
|
130
121
|
* @returns a scoped copy of the initial interactor
|
|
131
122
|
* @typeParam T the type of the interactor that we are going to scope
|
|
132
123
|
*/
|
|
133
|
-
|
|
124
|
+
find<T extends Interactor<any, any>>(interactor: T): T;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @hidden
|
|
128
|
+
*/
|
|
129
|
+
apply: FilterFn<string, Element>;
|
|
134
130
|
}
|
|
135
131
|
|
|
136
|
-
export type ActionFn<E extends Element
|
|
132
|
+
export type ActionFn<E extends Element, I extends Interactor<E, any>> = (interactor: I, ...args: any[]) => Operation<unknown>;
|
|
137
133
|
|
|
138
134
|
export type FilterFn<T, E extends Element> = (element: E) => T;
|
|
139
135
|
|
|
@@ -146,11 +142,11 @@ export type FilterDefinition<T, E extends Element> = FilterFn<T, E> | FilterObje
|
|
|
146
142
|
|
|
147
143
|
export type Filters<E extends Element> = Record<string, FilterDefinition<unknown, E>>;
|
|
148
144
|
|
|
149
|
-
export type Actions<E extends Element
|
|
145
|
+
export type Actions<E extends Element, I extends Interactor<E, any>> = Record<string, ActionFn<E, I>>;
|
|
150
146
|
|
|
151
147
|
export type SelectorFn<E extends Element> = (parentElement: Element) => E[];
|
|
152
148
|
|
|
153
|
-
export type InteractorSpecification<E extends Element, F extends Filters<E>, A extends Actions<E
|
|
149
|
+
export type InteractorSpecification<E extends Element, F extends Filters<E>, A extends Actions<E, Interactor<E, EmptyObject>>> = {
|
|
154
150
|
/**
|
|
155
151
|
* The CSS selector that this interactor uses to find matching elements
|
|
156
152
|
*/
|
|
@@ -166,16 +162,16 @@ export type InteractorSpecification<E extends Element, F extends Filters<E>, A e
|
|
|
166
162
|
locator?: FilterDefinition<string, E>;
|
|
167
163
|
}
|
|
168
164
|
|
|
169
|
-
export type ActionMethods<E extends Element, A extends Actions<E>> = {
|
|
170
|
-
[P in keyof A]: A[P] extends ((interactor:
|
|
171
|
-
? ((...args: TArgs) =>
|
|
165
|
+
export type ActionMethods<E extends Element, A extends Actions<E, I>, I extends Interactor<E, any>> = {
|
|
166
|
+
[P in keyof A]: A[P] extends ((interactor: I, ...args: infer TArgs) => Operation<infer TReturn>)
|
|
167
|
+
? ((...args: TArgs) => ActionInteraction<E, TReturn>)
|
|
172
168
|
: never;
|
|
173
169
|
}
|
|
174
170
|
|
|
175
171
|
export type FilterMethods<E extends Element, F extends Filters<E>> = {
|
|
176
172
|
[P in keyof F]:
|
|
177
|
-
F[P] extends FilterFn<infer TReturn, any> ? (() =>
|
|
178
|
-
F[P] extends FilterObject<infer TReturn, any> ? (() =>
|
|
173
|
+
F[P] extends FilterFn<infer TReturn, any> ? (() => AssertionInteraction<E, TReturn> & FilterObject<TReturn, Element>) :
|
|
174
|
+
F[P] extends FilterObject<infer TReturn, any> ? (() => AssertionInteraction<E, TReturn> & FilterObject<TReturn, Element>) :
|
|
179
175
|
never;
|
|
180
176
|
}
|
|
181
177
|
|
|
@@ -202,11 +198,11 @@ export type FilterParams<E extends Element, F extends Filters<E>> = keyof F exte
|
|
|
202
198
|
* @typeParam F the filters of this interactor, this is usually inferred from the specification
|
|
203
199
|
* @typeParam A the actions of this interactor, this is usually inferred from the specification
|
|
204
200
|
*/
|
|
205
|
-
export interface InteractorConstructor<E extends Element, FP extends FilterParams<any, any>, FM extends FilterMethods<any, any>, AM extends ActionMethods<any, any>> {
|
|
201
|
+
export interface InteractorConstructor<E extends Element, FP extends FilterParams<any, any>, FM extends FilterMethods<any, any>, AM extends ActionMethods<any, any, any>> {
|
|
206
202
|
selector(value: string | SelectorFn<E>): InteractorConstructor<E, FP, FM, AM>;
|
|
207
203
|
locator(value: FilterDefinition<string, E>): InteractorConstructor<E, FP, FM, AM>;
|
|
208
204
|
filters<FR extends Filters<E>>(filters: FR): InteractorConstructor<E, MergeObjects<FP, FilterParams<E, FR>>, MergeObjects<FM, FilterMethods<E, FR>>, AM>;
|
|
209
|
-
actions<AR extends Actions<E>>(actions: AR): InteractorConstructor<E, FP, FM, MergeObjects<AM, ActionMethods<E, AR>>>;
|
|
205
|
+
actions<I extends Interactor<E, FP> & FM & AM, AR extends Actions<E, I>>(actions: AR): InteractorConstructor<E, FP, FM, MergeObjects<AM, ActionMethods<E, AR, I>>>;
|
|
210
206
|
extend<ER extends E = E>(name: string): InteractorConstructor<ER, FP, FM, AM>;
|
|
211
207
|
|
|
212
208
|
/**
|
|
@@ -230,6 +226,7 @@ export interface InteractorConstructor<E extends Element, FP extends FilterParam
|
|
|
230
226
|
*
|
|
231
227
|
* ``` typescript
|
|
232
228
|
* Link('Home');
|
|
229
|
+
* Link(/^home/i);
|
|
233
230
|
* ```
|
|
234
231
|
*
|
|
235
232
|
* Or with a locator and options:
|
|
@@ -241,10 +238,10 @@ export interface InteractorConstructor<E extends Element, FP extends FilterParam
|
|
|
241
238
|
* @param value The locator value, which should match the value of applying the locator function defined in the {@link InteractorSpecification} to the element.
|
|
242
239
|
* @param filters An object describing a set of filters to apply, which should match the value of applying the filters defined in the {@link InteractorSpecification} to the element.
|
|
243
240
|
*/
|
|
244
|
-
(value: MaybeMatcher<string
|
|
241
|
+
(value: MaybeMatcher<string> | RegExp, filters?: FP): Interactor<E, FP> & FM & AM;
|
|
245
242
|
}
|
|
246
243
|
|
|
247
|
-
export type InteractorOptions<E extends Element, F extends Filters<E>, A extends Actions<E
|
|
244
|
+
export type InteractorOptions<E extends Element, F extends Filters<E>, A extends Actions<E, Interactor<E, EmptyObject>>> = {
|
|
248
245
|
name: string;
|
|
249
246
|
specification: InteractorSpecification<E, F, A>;
|
|
250
247
|
locator?: Locator<E>;
|
package/CHANGELOG.md
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# @interactors/core
|
|
2
|
-
|
|
3
|
-
## 0.3.0
|
|
4
|
-
|
|
5
|
-
### Minor Changes
|
|
6
|
-
|
|
7
|
-
- 53dea63: Enable delegation to locator of an interactor if no filter given
|
|
8
|
-
|
|
9
|
-
## 0.2.0
|
|
10
|
-
|
|
11
|
-
### Minor Changes
|
|
12
|
-
|
|
13
|
-
- 0c96dab: Add locator delegation. Locators can be delegated to another delegator.
|
|
14
|
-
- f4949ac: Selector can be a function to return arbitrary elements
|
package/dist/cjs/dispatch.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.dispatchClick = exports.dispatchKeyUp = exports.dispatchKeyDown = exports.dispatchInput = exports.dispatchChange = void 0;
|
|
4
|
-
function dispatchChange(element) {
|
|
5
|
-
var _a;
|
|
6
|
-
let Event = ((_a = element.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.Event) || window.Event;
|
|
7
|
-
return element.dispatchEvent(new Event('change', { bubbles: true, cancelable: false }));
|
|
8
|
-
}
|
|
9
|
-
exports.dispatchChange = dispatchChange;
|
|
10
|
-
function dispatchInput(element, options = {}) {
|
|
11
|
-
var _a;
|
|
12
|
-
let InputEvent = ((_a = element.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.InputEvent) || window.InputEvent;
|
|
13
|
-
return element.dispatchEvent(new InputEvent('input', Object.assign({ bubbles: true, cancelable: false }, options)));
|
|
14
|
-
}
|
|
15
|
-
exports.dispatchInput = dispatchInput;
|
|
16
|
-
function dispatchKeyDown(element, options = {}) {
|
|
17
|
-
var _a;
|
|
18
|
-
let KeyboardEvent = ((_a = element.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.KeyboardEvent) || window.KeyboardEvent;
|
|
19
|
-
return element.dispatchEvent(new KeyboardEvent('keydown', Object.assign({ bubbles: true, cancelable: true }, options)));
|
|
20
|
-
}
|
|
21
|
-
exports.dispatchKeyDown = dispatchKeyDown;
|
|
22
|
-
function dispatchKeyUp(element, options = {}) {
|
|
23
|
-
var _a;
|
|
24
|
-
let KeyboardEvent = ((_a = element.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.KeyboardEvent) || window.KeyboardEvent;
|
|
25
|
-
return element.dispatchEvent(new KeyboardEvent('keyup', Object.assign({ bubbles: true, cancelable: true }, options)));
|
|
26
|
-
}
|
|
27
|
-
exports.dispatchKeyUp = dispatchKeyUp;
|
|
28
|
-
function dispatchClick(element, options = {}) {
|
|
29
|
-
var _a;
|
|
30
|
-
let MouseEvent = ((_a = element.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.MouseEvent) || window.MouseEvent;
|
|
31
|
-
return element.dispatchEvent(new MouseEvent('click', Object.assign({ bubbles: true, cancelable: true }, options)));
|
|
32
|
-
}
|
|
33
|
-
exports.dispatchClick = dispatchClick;
|
|
34
|
-
//# sourceMappingURL=dispatch.js.map
|
package/dist/cjs/dispatch.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/dispatch.ts"],"names":[],"mappings":";;;AAAA,SAAgB,cAAc,CAAC,OAAoB;;IACjD,IAAI,KAAK,GAAG,CAAA,MAAA,OAAO,CAAC,aAAa,CAAC,WAAW,0CAAE,KAAK,KAAI,MAAM,CAAC,KAAK,CAAC;IACrE,OAAO,OAAO,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAC1F,CAAC;AAHD,wCAGC;AAED,SAAgB,aAAa,CAAC,OAAoB,EAAE,UAA0B,EAAE;;IAC9E,IAAI,UAAU,GAAG,CAAA,MAAA,OAAO,CAAC,aAAa,CAAC,WAAW,0CAAE,UAAU,KAAI,MAAM,CAAC,UAAU,CAAC;IACpF,OAAO,OAAO,CAAC,aAAa,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AACtH,CAAC;AAHD,sCAGC;AAED,SAAgB,eAAe,CAAC,OAAoB,EAAE,UAA6B,EAAE;;IACnF,IAAI,aAAa,GAAG,CAAA,MAAA,OAAO,CAAC,aAAa,CAAC,WAAW,0CAAE,aAAa,KAAI,MAAM,CAAC,aAAa,CAAC;IAC7F,OAAO,OAAO,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AAC1H,CAAC;AAHD,0CAGC;AAED,SAAgB,aAAa,CAAC,OAAoB,EAAE,UAA6B,EAAE;;IACjF,IAAI,aAAa,GAAG,CAAA,MAAA,OAAO,CAAC,aAAa,CAAC,WAAW,0CAAE,aAAa,KAAI,MAAM,CAAC,aAAa,CAAC;IAC7F,OAAO,OAAO,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AACxH,CAAC;AAHD,sCAGC;AAED,SAAgB,aAAa,CAAC,OAAoB,EAAE,UAA0B,EAAE;;IAC9E,IAAI,UAAU,GAAG,CAAA,MAAA,OAAO,CAAC,aAAa,CAAC,WAAW,0CAAE,UAAU,KAAI,MAAM,CAAC,UAAU,CAAC;IACpF,OAAO,OAAO,CAAC,aAAa,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AACrH,CAAC;AAHD,sCAGC"}
|