foldkit 0.43.2 → 0.45.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.
Files changed (59) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +2 -1
  4. package/dist/test/apps/counter.d.ts +38 -0
  5. package/dist/test/apps/counter.d.ts.map +1 -0
  6. package/dist/test/apps/counter.js +25 -0
  7. package/dist/test/apps/formChild.d.ts +69 -0
  8. package/dist/test/apps/formChild.d.ts.map +1 -0
  9. package/dist/test/apps/formChild.js +84 -0
  10. package/dist/test/apps/keypress.d.ts +23 -0
  11. package/dist/test/apps/keypress.d.ts.map +1 -0
  12. package/dist/test/apps/keypress.js +39 -0
  13. package/dist/test/apps/login.d.ts +46 -0
  14. package/dist/test/apps/login.d.ts.map +1 -0
  15. package/dist/test/apps/login.js +83 -0
  16. package/dist/test/apps/logoutButton.d.ts +17 -0
  17. package/dist/test/apps/logoutButton.d.ts.map +1 -0
  18. package/dist/test/apps/logoutButton.js +22 -0
  19. package/dist/test/internal.d.ts +25 -0
  20. package/dist/test/internal.d.ts.map +1 -0
  21. package/dist/test/internal.js +39 -0
  22. package/dist/test/matchers.d.ts +94 -0
  23. package/dist/test/matchers.d.ts.map +1 -0
  24. package/dist/test/matchers.js +283 -0
  25. package/dist/test/public.d.ts +2 -2
  26. package/dist/test/public.d.ts.map +1 -1
  27. package/dist/test/public.js +2 -1
  28. package/dist/test/query.d.ts +88 -0
  29. package/dist/test/query.d.ts.map +1 -0
  30. package/dist/test/query.js +227 -0
  31. package/dist/test/scene.d.ts +106 -0
  32. package/dist/test/scene.d.ts.map +1 -0
  33. package/dist/test/scene.js +373 -0
  34. package/dist/test/{index.d.ts → story.d.ts} +13 -17
  35. package/dist/test/story.d.ts.map +1 -0
  36. package/dist/test/{index.js → story.js} +8 -36
  37. package/dist/test/vitest-setup.d.ts +19 -0
  38. package/dist/test/vitest-setup.d.ts.map +1 -0
  39. package/dist/test/vitest-setup.js +3 -0
  40. package/dist/ui/input/index.d.ts +0 -2
  41. package/dist/ui/input/index.d.ts.map +1 -1
  42. package/dist/ui/input/index.js +2 -5
  43. package/dist/ui/input/public.d.ts +1 -1
  44. package/dist/ui/input/public.d.ts.map +1 -1
  45. package/dist/ui/input/public.js +1 -1
  46. package/dist/ui/select/index.d.ts +0 -2
  47. package/dist/ui/select/index.d.ts.map +1 -1
  48. package/dist/ui/select/index.js +2 -5
  49. package/dist/ui/select/public.d.ts +1 -1
  50. package/dist/ui/select/public.d.ts.map +1 -1
  51. package/dist/ui/select/public.js +1 -1
  52. package/dist/ui/textarea/index.d.ts +0 -2
  53. package/dist/ui/textarea/index.d.ts.map +1 -1
  54. package/dist/ui/textarea/index.js +2 -5
  55. package/dist/ui/textarea/public.d.ts +1 -1
  56. package/dist/ui/textarea/public.d.ts.map +1 -1
  57. package/dist/ui/textarea/public.js +1 -1
  58. package/package.json +5 -5
  59. package/dist/test/index.d.ts.map +0 -1
@@ -0,0 +1,227 @@
1
+ import { Array, Equal, Match, Option, Predicate, Record, String as String_, flow, pipe, } from 'effect';
2
+ import { dual } from 'effect/Function';
3
+ import { evo } from '../struct';
4
+ const ID_PATTERN = /^#([a-zA-Z0-9_-]+)/;
5
+ const CLASS_PATTERN = /^\.([a-zA-Z0-9_-]+)/;
6
+ const ATTRIBUTE_PATTERN = /^\[([a-zA-Z][a-zA-Z0-9_-]*)(?:(\^)?="([^"]*)")?\]/;
7
+ const TAG_PATTERN = /^([a-zA-Z][a-zA-Z0-9-]*)/;
8
+ const WHITESPACE_PATTERN = /\s+/;
9
+ const matchGroup = (regex) => (input) => pipe(input, String_.match(regex), Option.flatMap(match => pipe(match, Array.get(1), Option.map(group => ({
10
+ consumed: match[0],
11
+ group,
12
+ })))));
13
+ const emptySelector = {
14
+ tag: Option.none(),
15
+ id: Option.none(),
16
+ classes: [],
17
+ attributes: [],
18
+ };
19
+ const tryParseId = (input, accumulator) => pipe(input, matchGroup(ID_PATTERN), Option.map(({ consumed, group }) => parseModifiers(input.slice(consumed.length), evo(accumulator, {
20
+ id: () => Option.some(group),
21
+ }))));
22
+ const tryParseClass = (input, accumulator) => pipe(input, matchGroup(CLASS_PATTERN), Option.map(({ consumed, group }) => parseModifiers(input.slice(consumed.length), evo(accumulator, {
23
+ classes: Array.append(group),
24
+ }))));
25
+ const tryParseAttribute = (input, accumulator) => pipe(input, String_.match(ATTRIBUTE_PATTERN), Option.flatMap(match => pipe(match, Array.get(1), Option.map(name => {
26
+ const mode = match[2] === '^' ? 'StartsWith' : 'Exact';
27
+ return parseModifiers(input.slice(match[0].length), evo(accumulator, {
28
+ attributes: Array.append({
29
+ name,
30
+ value: Option.fromNullable(match[3]),
31
+ mode,
32
+ }),
33
+ }));
34
+ }))));
35
+ const parseModifiers = (input, accumulator) => {
36
+ if (String_.isEmpty(input))
37
+ return accumulator;
38
+ return pipe(tryParseId(input, accumulator), Option.orElse(() => tryParseClass(input, accumulator)), Option.orElse(() => tryParseAttribute(input, accumulator)), Option.getOrElse(() => {
39
+ throw new Error(`I could not parse the selector at "${input}".\n\n` +
40
+ 'Supported selectors: tag, #id, .class, [attr], [attr="value"], [attr^="prefix"], ' +
41
+ 'and descendant combinators (space).');
42
+ }));
43
+ };
44
+ const parseCompoundSelector = (segment) => pipe(segment, String_.match(TAG_PATTERN), Option.match({
45
+ onNone: () => parseModifiers(segment, emptySelector),
46
+ onSome: match => parseModifiers(segment.slice(match[0].length), evo(emptySelector, { tag: () => Array.get(match, 1) })),
47
+ }));
48
+ export const parseSelector = (input) => {
49
+ const trimmed = String_.trim(input);
50
+ if (String_.isEmpty(trimmed)) {
51
+ throw new Error('I received an empty selector.\n\n' +
52
+ 'Provide a CSS selector like "button", "#email", or \'[role="tab"]\'.');
53
+ }
54
+ return pipe(trimmed, String_.split(WHITESPACE_PATTERN), Array.map(parseCompoundSelector));
55
+ };
56
+ // NODE UTILITIES
57
+ const lookupAttribute = (name) => (vnode) => pipe(vnode.data?.attrs?.[name], Option.fromNullable, Option.orElse(() => Option.fromNullable(vnode.data?.props?.[name])));
58
+ const lookupStringAttribute = (name) => (vnode) => Option.map(lookupAttribute(name)(vnode), String);
59
+ const isElement = (node) => !Predicate.isUndefined(node.sel);
60
+ const isVNode = (child) => !Predicate.isString(child);
61
+ const vnodeChildren = (vnode) => Array.filterMap(vnode.children ?? [], Option.liftPredicate(isVNode));
62
+ const collectDescendants = (vnode) => Array.flatMap(vnodeChildren(vnode), child => [
63
+ child,
64
+ ...collectDescendants(child),
65
+ ]);
66
+ const FORM_CONTROL_TAGS = ['input', 'select', 'textarea', 'button', 'output'];
67
+ const isFormControl = (node) => pipe(node.sel, Option.fromNullable, Option.exists(sel => Array.contains(FORM_CONTROL_TAGS, sel)));
68
+ const findById = (root) => (id) => Array.findFirst([root, ...collectDescendants(root)], flow(lookupStringAttribute('id'), Option.exists(Equal.equals(id))));
69
+ // MATCHING
70
+ const compareByMode = (mode, expected) => (actual) => Match.value(mode).pipe(Match.when('StartsWith', () => actual.startsWith(expected)), Match.when('Exact', () => actual === expected), Match.exhaustive);
71
+ const matchesValue = (maybeExpected, mode) => (maybeActual) => Option.match(maybeActual, {
72
+ onNone: () => false,
73
+ onSome: actual => Option.match(maybeExpected, {
74
+ onNone: () => true,
75
+ onSome: expected => compareByMode(mode, expected)(actual),
76
+ }),
77
+ });
78
+ const matchesAttribute = (vnode) => ({ name, value, mode }) => {
79
+ if (name === 'key') {
80
+ return pipe(vnode.key, Option.fromNullable, Option.map(key => typeof key === 'symbol' ? key.toString() : String(key)), matchesValue(value, mode));
81
+ }
82
+ return pipe(vnode, lookupAttribute(name), Option.filter(actual => actual !== false), Option.map(String), matchesValue(value, mode));
83
+ };
84
+ const matchesSimpleSelector = (selector) => (vnode) => isElement(vnode) &&
85
+ Option.match(selector.tag, {
86
+ onNone: () => true,
87
+ onSome: tag => vnode.sel === tag,
88
+ }) &&
89
+ Option.match(selector.id, {
90
+ onNone: () => true,
91
+ onSome: id => pipe(vnode, lookupStringAttribute('id'), Option.exists(Equal.equals(id))),
92
+ }) &&
93
+ Array.every(selector.classes, className => vnode.data?.class?.[className] === true) &&
94
+ Array.every(selector.attributes, matchesAttribute(vnode));
95
+ // IMPLICIT ROLES
96
+ const IMPLICIT_ROLE_MAP = {
97
+ a: 'link',
98
+ article: 'article',
99
+ button: 'button',
100
+ form: 'form',
101
+ h1: 'heading',
102
+ h2: 'heading',
103
+ h3: 'heading',
104
+ h4: 'heading',
105
+ h5: 'heading',
106
+ h6: 'heading',
107
+ li: 'listitem',
108
+ nav: 'navigation',
109
+ ol: 'list',
110
+ option: 'option',
111
+ select: 'combobox',
112
+ table: 'table',
113
+ textarea: 'textbox',
114
+ ul: 'list',
115
+ };
116
+ const INPUT_TYPE_ROLE_MAP = {
117
+ checkbox: 'checkbox',
118
+ number: 'spinbutton',
119
+ radio: 'radio',
120
+ range: 'slider',
121
+ reset: 'button',
122
+ search: 'searchbox',
123
+ submit: 'button',
124
+ };
125
+ const inputRole = (vnode) => pipe(vnode, lookupStringAttribute('type'), Option.getOrElse(() => 'text'), Option.liftPredicate(typeString => typeString !== 'hidden'), Option.map(typeString => pipe(INPUT_TYPE_ROLE_MAP, Record.get(typeString), Option.getOrElse(() => 'textbox'))));
126
+ const implicitRole = (vnode) => pipe(vnode.sel, Option.fromNullable, Option.flatMap(tag => tag === 'input' ? inputRole(vnode) : Record.get(IMPLICIT_ROLE_MAP, tag)));
127
+ const resolveRole = (vnode) => pipe(vnode, lookupStringAttribute('role'), Option.orElse(() => implicitRole(vnode)));
128
+ // ACCESSIBLE NAME
129
+ const nonEmptyString = (value) => Option.filter(Option.some(String(value)), String_.isNonEmpty);
130
+ const nameFromLabelledBy = (root) => (vnode) => pipe(vnode, lookupAttribute('aria-labelledby'), Option.flatMap(nonEmptyString), Option.map(labelledBy => pipe(labelledBy, String_.split(WHITESPACE_PATTERN), Array.filterMap(flow(findById(root), Option.map(textContent))), Array.join(' '))), Option.filter(String_.isNonEmpty));
131
+ const nameFromAriaLabel = (vnode) => pipe(vnode, lookupAttribute('aria-label'), Option.flatMap(nonEmptyString));
132
+ const nameFromLabelFor = (vnode, root) => pipe(vnode, lookupStringAttribute('id'), Option.flatMap(idString => pipe([root, ...collectDescendants(root)], Array.findFirst(node => node.sel === 'label' &&
133
+ pipe(node, lookupStringAttribute('for'), Option.exists(Equal.equals(idString)))), Option.map(textContent))));
134
+ const nameFromTextContent = (vnode) => Option.filter(Option.some(textContent(vnode)), String_.isNonEmpty);
135
+ const nameFromTitle = (vnode) => pipe(vnode, lookupAttribute('title'), Option.flatMap(nonEmptyString));
136
+ const accessibleName = (vnode, root) => pipe(vnode, nameFromLabelledBy(root), Option.orElse(() => nameFromAriaLabel(vnode)), Option.orElse(() => nameFromLabelFor(vnode, root)), Option.orElse(() => nameFromTextContent(vnode)), Option.orElse(() => nameFromTitle(vnode)), Option.getOrElse(() => ''));
137
+ // PUBLIC API
138
+ const findAllImpl = (selectorString) => (html) => {
139
+ const selector = parseSelector(selectorString);
140
+ const allNodes = [html, ...collectDescendants(html)];
141
+ return pipe(Array.head(selector), Option.map(firstSegment => Array.reduce(Array.drop(selector, 1), Array.filter(allNodes, matchesSimpleSelector(firstSegment)), (candidates, segment) => Array.filter(Array.flatMap(candidates, collectDescendants), matchesSimpleSelector(segment)))), Option.getOrElse(() => []));
142
+ };
143
+ /** Finds the first VNode matching the CSS selector. */
144
+ export const find = dual(2, (html, selectorString) => pipe(html, findAllImpl(selectorString), Array.head));
145
+ /** Finds all VNodes matching the CSS selector. */
146
+ export const findAll = dual(2, (html, selectorString) => findAllImpl(selectorString)(html));
147
+ /** Extracts all text content from a VNode tree, depth-first. */
148
+ export const textContent = (vnode) => {
149
+ if (Predicate.isString(vnode.text))
150
+ return vnode.text;
151
+ return pipe(vnode.children ?? [], Array.map(child => Predicate.isString(child) ? child : textContent(child)), Array.join(''));
152
+ };
153
+ const attrImpl = (vnode, name) => {
154
+ if (name === 'class') {
155
+ return pipe(vnode.data?.class, Option.fromNullable, Option.map(flow(Record.toEntries, Array.filter(([, isActive]) => isActive), Array.map(([className]) => className), Array.join(' '))), Option.filter(String_.isNonEmpty));
156
+ }
157
+ return lookupStringAttribute(name)(vnode);
158
+ };
159
+ /** Reads an attribute or prop value from a VNode. */
160
+ export const attr = dual(2, attrImpl);
161
+ // ACCESSIBLE LOCATORS
162
+ /** Finds the first element with the given ARIA role and optional accessible name. */
163
+ export const getByRole = (role, options) => (html) => {
164
+ const maybeName = Option.fromNullable(options?.name);
165
+ return Array.findFirst([html, ...collectDescendants(html)], node => pipe(node, resolveRole, Option.exists(Equal.equals(role))) &&
166
+ Option.match(maybeName, {
167
+ onNone: () => true,
168
+ onSome: name => accessibleName(node, html) === name,
169
+ }));
170
+ };
171
+ /** Finds all elements with the given ARIA role and optional accessible name. */
172
+ export const getAllByRole = (html, role, options) => {
173
+ const maybeName = Option.fromNullable(options?.name);
174
+ return Array.filter([html, ...collectDescendants(html)], node => pipe(node, resolveRole, Option.exists(Equal.equals(role))) &&
175
+ Option.match(maybeName, {
176
+ onNone: () => true,
177
+ onSome: Equal.equals(accessibleName(node, html)),
178
+ }));
179
+ };
180
+ /** Finds the most specific element matching the given text content.
181
+ * Skips text VNodes (sel undefined) — only returns actual DOM elements. */
182
+ export const getByText = (target, options) => (html) => {
183
+ const exact = options?.exact !== false;
184
+ const textMatches = (node) => {
185
+ const nodeText = textContent(node);
186
+ return exact ? nodeText === target : String_.includes(target)(nodeText);
187
+ };
188
+ return pipe([html, ...collectDescendants(html)], Array.filter(node => isElement(node) && textMatches(node)), Array.findFirst(match => !Array.some(Array.filter(collectDescendants(match), isElement), textMatches)));
189
+ };
190
+ /** Finds the first element with the given placeholder attribute. */
191
+ export const getByPlaceholder = (placeholderValue) => (html) => Array.findFirst([html, ...collectDescendants(html)], flow(lookupStringAttribute('placeholder'), Option.exists(Equal.equals(placeholderValue))));
192
+ /** Finds the first element with the given label text. Checks `aria-label`
193
+ * first, then `<label for="id">` association, then `<label>` nesting,
194
+ * then `aria-labelledby` reverse lookup. */
195
+ export const getByLabel = (labelValue) => (html) => {
196
+ const allNodes = [html, ...collectDescendants(html)];
197
+ return pipe(Array.findFirst(allNodes, flow(lookupStringAttribute('aria-label'), Option.exists(Equal.equals(labelValue)))), Option.orElse(() => pipe(Array.filter(allNodes, node => node.sel === 'label' && textContent(node) === labelValue), Array.filterMap(labelNode => pipe(lookupStringAttribute('for')(labelNode), Option.flatMap(findById(html)), Option.orElse(() => Array.findFirst(collectDescendants(labelNode), isFormControl)))), Array.head)), Option.orElse(() => Array.findFirst(allNodes, flow(nameFromLabelledBy(html), Option.exists(Equal.equals(labelValue))))));
198
+ };
199
+ const makeLocator = (resolve, description) => Object.assign(resolve, { description });
200
+ /** Creates a Locator that finds an element by ARIA role and optional accessible name. */
201
+ export const role = (roleValue, options) => makeLocator(getByRole(roleValue, options), Option.match(Option.fromNullable(options?.name), {
202
+ onNone: () => roleValue,
203
+ onSome: name => `${roleValue} "${name}"`,
204
+ }));
205
+ /** Creates a Locator that finds an element by placeholder attribute. */
206
+ export const placeholder = (placeholderValue) => makeLocator(getByPlaceholder(placeholderValue), `placeholder "${placeholderValue}"`);
207
+ /** Creates a Locator that finds an element by aria-label. */
208
+ export const label = (labelValue) => makeLocator(getByLabel(labelValue), `label "${labelValue}"`);
209
+ /** Creates a Locator that finds the most specific element matching the given text content. */
210
+ export const text = (target, options) => makeLocator(getByText(target, options), `text "${target}"`);
211
+ /** Creates a Locator that wraps a CSS selector. Escape hatch for cases
212
+ * where no accessible attribute is available. */
213
+ export const selector = (css) => makeLocator(flow(findAllImpl(css), Array.head), `"${css}"`);
214
+ /** Creates a scoped Locator that finds the child within the parent.
215
+ * Composes via `Option.flatMap` — the parent is resolved first, then
216
+ * the child is searched within the parent's subtree. */
217
+ export const within = dual(2, (parent, child) => makeLocator(flow(parent, Option.flatMap(child)), `${child.description} within ${parent.description}`));
218
+ /** Resolves a target (CSS selector string or Locator) against a VNode tree. */
219
+ export const resolveTarget = (html, target) => {
220
+ if (typeof target === 'string') {
221
+ return {
222
+ maybeElement: pipe(html, findAllImpl(target), Array.head),
223
+ description: `"${target}"`,
224
+ };
225
+ }
226
+ return { maybeElement: target(html), description: target.description };
227
+ };
@@ -0,0 +1,106 @@
1
+ import type { CommandDefinition } from '../command';
2
+ import type { Html, KeyboardModifiers } from '../html';
3
+ import type { VNode } from '../vdom';
4
+ import type { AnyCommand, ResolverPair } from './internal';
5
+ import type { Locator } from './query';
6
+ export type { AnyCommand, ResolverPair };
7
+ export type { Locator } from './query';
8
+ export { find, findAll, textContent, attr, getByRole, getAllByRole, getByText, getByPlaceholder, getByLabel, role, placeholder, label, selector, text, within, } from './query';
9
+ export { sceneMatchers } from './matchers';
10
+ /** An immutable test simulation that includes the rendered VNode tree.
11
+ * The Model and Message are intentionally opaque — Scene tests assert
12
+ * through the view, not the model. Use Story for model-level assertions. */
13
+ export type SceneSimulation<Model, Message, OutMessage = undefined> = Readonly<{
14
+ /** @internal Phantom type — preserves Model and Message for step chain inference. */
15
+ _phantom: [Model, Message];
16
+ commands: ReadonlyArray<AnyCommand>;
17
+ outMessage: OutMessage;
18
+ html: VNode;
19
+ }>;
20
+ /** A callable step that sets the initial Model. Carries phantom type for compile-time validation. */
21
+ type WithStep<Model> = Readonly<{
22
+ _phantomModel: Model;
23
+ }> & (<M, Message, OutMessage = undefined>(simulation: SceneSimulation<M, Message, OutMessage>) => SceneSimulation<M, Message, OutMessage>);
24
+ /** A single step in a scene — either a `with` step or a scene simulation transform. */
25
+ export type SceneStep<Model, Message, OutMessage> = WithStep<NoInfer<Model>> | ((simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>);
26
+ /** Sets the initial Model for a scene test. */
27
+ export { with_ as with };
28
+ declare const with_: <Model>(model: Model) => WithStep<Model>;
29
+ /** Resolves a specific pending Command with the given result Message. */
30
+ export declare const resolve: {
31
+ <Name extends string, ResultMessage>(definition: CommandDefinition<Name, ResultMessage>, resultMessage: ResultMessage): <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
32
+ <Name extends string, ResultMessage, ParentMessage>(definition: CommandDefinition<Name, ResultMessage>, resultMessage: ResultMessage, toParentMessage: (message: ResultMessage) => ParentMessage): <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
33
+ };
34
+ /** Resolves all listed Commands with their result Messages. Handles cascading resolution. */
35
+ export declare const resolveAll: (pairs: ReadonlyArray<ResolverPair>) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
36
+ /** Runs a function for side effects (e.g. assertions) without breaking the step chain. */
37
+ export declare const tap: <Model, Message, OutMessage = undefined>(f: (simulation: SceneSimulation<Model, Message, OutMessage>) => void) => (simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
38
+ /** Simulates a click on the element matching the target. */
39
+ export declare const click: (target: string | Locator) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
40
+ /** Simulates form submission on the element matching the target. */
41
+ export declare const submit: (target: string | Locator) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
42
+ /** Simulates typing a value into the input matching the target.
43
+ * Dual: `type(target, value)` or `type(value)` for data-last piping. */
44
+ export { type_ as type };
45
+ declare const type_: {
46
+ (target: string | Locator, value: string): <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
47
+ (value: string): (target: string | Locator) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
48
+ };
49
+ /** Simulates a keydown event on the element matching the target.
50
+ * Dual: `keydown(target, key, modifiers?)` or `keydown(key, modifiers?)` for data-last piping. */
51
+ export declare const keydown: {
52
+ (target: string | Locator, key: string): <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
53
+ (target: string | Locator, key: string, modifiers: Partial<KeyboardModifiers>): <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
54
+ (key: string): (target: string | Locator) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
55
+ (key: string, modifiers: Partial<KeyboardModifiers>): (target: string | Locator) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
56
+ };
57
+ /** Creates an inline assertion step. Resolves the Locator against
58
+ * the current view and asserts on the result. */
59
+ export { expect_ as expect };
60
+ declare const expect_: (locator: Locator) => {
61
+ not: {
62
+ toExist: () => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
63
+ toBeAbsent: () => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
64
+ toHaveText: (expected: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
65
+ toContainText: (expected: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
66
+ toHaveAttr: (name: string, value?: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
67
+ toHaveClass: (expected: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
68
+ toHaveStyle: (name: string, value?: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
69
+ toHaveHook: (name: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
70
+ toHaveHandler: (name: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
71
+ toHaveValue: (expected: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
72
+ toBeDisabled: () => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
73
+ toBeEnabled: () => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
74
+ toBeChecked: () => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
75
+ };
76
+ toExist: () => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
77
+ toBeAbsent: () => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
78
+ toHaveText: (expected: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
79
+ toContainText: (expected: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
80
+ toHaveAttr: (name: string, value?: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
81
+ toHaveClass: (expected: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
82
+ toHaveStyle: (name: string, value?: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
83
+ toHaveHook: (name: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
84
+ toHaveHandler: (name: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
85
+ toHaveValue: (expected: string) => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
86
+ toBeDisabled: () => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
87
+ toBeEnabled: () => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
88
+ toBeChecked: () => <Model, Message, OutMessage = undefined>(simulation: SceneSimulation<Model, Message, OutMessage>) => SceneSimulation<Model, Message, OutMessage>;
89
+ };
90
+ /** Adapts a submodel view for Scene testing. In the Submodel pattern, the view
91
+ * takes a `toParentMessage` function that maps child Messages to parent Messages.
92
+ * Scene tests the child in isolation, so `childView` passes the identity function
93
+ * and erases the parent type. */
94
+ export declare const childView: <Model>(viewFn: (model: Model, toParentMessage: (message: any) => any) => Html) => ((model: Model) => Html);
95
+ /** Executes a scene test. Throws if any Commands remain unresolved. */
96
+ export declare const scene: {
97
+ <Model, Message, OutMessage>(config: Readonly<{
98
+ update: (model: Model, message: Message) => readonly [Model, ReadonlyArray<AnyCommand>, OutMessage];
99
+ view: (model: Model) => Html;
100
+ }>, ...steps: ReadonlyArray<SceneStep<Model, Message, OutMessage>>): void;
101
+ <Model, Message>(config: Readonly<{
102
+ update: (model: Model, message: Message) => readonly [Model, ReadonlyArray<AnyCommand>];
103
+ view: (model: Model) => Html;
104
+ }>, ...steps: ReadonlyArray<SceneStep<Model, Message, undefined>>): void;
105
+ };
106
+ //# sourceMappingURL=scene.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene.d.ts","sourceRoot":"","sources":["../../src/test/scene.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AACnD,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,KAAK,EAAE,UAAU,EAAgB,YAAY,EAAE,MAAM,YAAY,CAAA;AAMxE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAGtC,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,CAAA;AAExC,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EACL,IAAI,EACJ,OAAO,EACP,WAAW,EACX,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,IAAI,EACJ,WAAW,EACX,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,MAAM,GACP,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C;;6EAE6E;AAC7E,MAAM,MAAM,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,IAAI,QAAQ,CAAC;IAC7E,qFAAqF;IACrF,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IAC1B,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,CAAA;IACnC,UAAU,EAAE,UAAU,CAAA;IACtB,IAAI,EAAE,KAAK,CAAA;CACZ,CAAC,CAAA;AAEF,qGAAqG;AACrG,KAAK,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC;IAAE,aAAa,EAAE,KAAK,CAAA;CAAE,CAAC,GACvD,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EAClC,UAAU,EAAE,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,KAChD,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAA;AAE/C,uFAAuF;AACvF,MAAM,MAAM,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,IAC5C,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GACxB,CAAC,CACC,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACpD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAA;AAgKrD,+CAA+C;AAC/C,OAAO,EAAE,KAAK,IAAI,IAAI,EAAE,CAAA;AACxB,QAAA,MAAM,KAAK,GAAI,KAAK,EAAE,OAAO,KAAK,KAAG,QAAQ,CAAC,KAAK,CAiBlD,CAAA;AAED,yEAAyE;AACzE,eAAO,MAAM,OAAO,EAAE;IACpB,CAAC,IAAI,SAAS,MAAM,EAAE,aAAa,EACjC,UAAU,EAAE,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,EAClD,aAAa,EAAE,aAAa,GAC3B,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EACxC,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACpD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;IAChD,CAAC,IAAI,SAAS,MAAM,EAAE,aAAa,EAAE,aAAa,EAChD,UAAU,EAAE,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,EAClD,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,aAAa,GACzD,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EACxC,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACpD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;CAsC/C,CAAA;AAEH,6FAA6F;AAC7F,eAAO,MAAM,UAAU,GACpB,OAAO,aAAa,CAAC,YAAY,CAAC,MAClC,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EACrC,YAAY,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CA+C5C,CAAA;AAEH,0FAA0F;AAC1F,eAAO,MAAM,GAAG,GACb,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EACrC,GAAG,CAAC,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KAAK,IAAI,MAGpE,YAAY,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAG5C,CAAA;AAIH,4DAA4D;AAC5D,eAAO,MAAM,KAAK,GACf,QAAQ,MAAM,GAAG,OAAO,MACxB,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EACrC,YAAY,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAGzC,CAAA;AAEN,oEAAoE;AACpE,eAAO,MAAM,MAAM,GAChB,QAAQ,MAAM,GAAG,OAAO,MACxB,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EACrC,YAAY,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAGzC,CAAA;AAEN;yEACyE;AACzE,OAAO,EAAE,KAAK,IAAI,IAAI,EAAE,CAAA;AACxB,QAAA,MAAM,KAAK,EAAE;IACX,CACE,MAAM,EAAE,MAAM,GAAG,OAAO,EACxB,KAAK,EAAE,MAAM,GACZ,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EACxC,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACpD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;IAChD,CACE,KAAK,EAAE,MAAM,GACZ,CACD,MAAM,EAAE,MAAM,GAAG,OAAO,KACrB,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EAC1C,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACpD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;CAUjD,CAAA;AAED;mGACmG;AACnG,eAAO,MAAM,OAAO,EAAE;IACpB,CACE,MAAM,EAAE,MAAM,GAAG,OAAO,EACxB,GAAG,EAAE,MAAM,GACV,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EACxC,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACpD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;IAChD,CACE,MAAM,EAAE,MAAM,GAAG,OAAO,EACxB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,OAAO,CAAC,iBAAiB,CAAC,GACpC,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EACxC,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACpD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;IAChD,CACE,GAAG,EAAE,MAAM,GACV,CACD,MAAM,EAAE,MAAM,GAAG,OAAO,KACrB,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EAC1C,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACpD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;IAChD,CACE,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,OAAO,CAAC,iBAAiB,CAAC,GACpC,CACD,MAAM,EAAE,MAAM,GAAG,OAAO,KACrB,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EAC1C,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACpD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;CAmBjD,CAAA;AAgPD;kDACkD;AAClD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,CAAA;AAC5B,QAAA,MAAM,OAAO,GAAI,SAAS,OAAO;;wBAvO9B,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;2BAF7C,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;+BA6MvB,MAAM,MA/M5B,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;kCA+MpB,MAAM,MAjN/B,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;2BAiN3B,MAAM,UAAU,MAAM,MAnNxC,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;gCAmNtB,MAAM,MArN7B,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;4BAqN1B,MAAM,UAAU,MAAM,MAvNzC,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;2BAuN3B,MAAM,MAzNxB,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;8BAyNxB,MAAM,MA3N3B,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;gCA2NtB,MAAM,MA7N7B,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;6BAF7C,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;4BAF7C,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;4BAF7C,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;;oBAF7C,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;uBAF7C,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;2BA6MvB,MAAM,MA/M5B,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;8BA+MpB,MAAM,MAjN/B,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;uBAiN3B,MAAM,UAAU,MAAM,MAnNxC,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;4BAmNtB,MAAM,MArN7B,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;wBAqN1B,MAAM,UAAU,MAAM,MAvNzC,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;uBAuN3B,MAAM,MAzNxB,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;0BAyNxB,MAAM,MA3N3B,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;4BA2NtB,MAAM,MA7N7B,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;yBAF7C,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;wBAF7C,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;wBAF7C,KAAK,EAAE,OAAO,EAAE,UAAU,0BACb,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,KACtD,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC;CAwO9C,CAAA;AAIF;;;kCAGkC;AAClC,eAAO,MAAM,SAAS,GACnB,KAAK,EACJ,QAAQ,CACN,KAAK,EAAE,KAAK,EAEZ,eAAe,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,GAAG,KACnC,IAAI,KACR,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAES,CAAA;AAIrC,uEAAuE;AACvE,eAAO,MAAM,KAAK,EAAE;IAClB,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EACzB,MAAM,EAAE,QAAQ,CAAC;QACf,MAAM,EAAE,CACN,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,KACb,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,CAAA;QAC5D,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;KAC7B,CAAC,EACF,GAAG,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,GAC7D,IAAI,CAAA;IACP,CAAC,KAAK,EAAE,OAAO,EACb,MAAM,EAAE,QAAQ,CAAC;QACf,MAAM,EAAE,CACN,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,KACb,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC,CAAA;QAChD,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;KAC7B,CAAC,EACF,GAAG,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,GAC5D,IAAI,CAAA;CAmDR,CAAA"}