@vnejs/plugins.scenario.point_and_click 0.2.1 → 0.2.3

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/index.js CHANGED
@@ -1,13 +1,21 @@
1
1
  import "@vnejs/contracts.scenario.point_and_click";
2
2
  import { regPlugin } from "@vnejs/shared";
3
3
  import { CONSTANTS, PARAMS, PLUGIN_NAME, SUBSCRIBE_EVENTS } from "@vnejs/contracts.scenario.point_and_click";
4
- import { PointAndClick } from "./modules/point_and_click.js";
4
+ import { PointAndClickEmit } from "./modules/emit.js";
5
5
  import { PointAndClickExec } from "./modules/exec.js";
6
+ import { PointAndClickLogs } from "./modules/logs.js";
7
+ import { PointAndClickOption } from "./modules/option.js";
8
+ import { PointAndClickState } from "./modules/point_and_click.js";
6
9
  import { PointAndClickScenario } from "./modules/scenario.block.js";
7
10
  import { PointAndClickScenarioModule } from "./modules/scenario.module.js";
8
11
  import { PointAndClickScenarioOption } from "./modules/scenario.option.js";
12
+ import { PointAndClickSkip } from "./modules/skip.js";
9
13
  regPlugin(PLUGIN_NAME, { constants: CONSTANTS, events: SUBSCRIBE_EVENTS, params: PARAMS }, [
10
- PointAndClick,
14
+ PointAndClickState,
15
+ PointAndClickEmit,
16
+ PointAndClickOption,
17
+ PointAndClickSkip,
18
+ PointAndClickLogs,
11
19
  PointAndClickExec,
12
20
  PointAndClickScenario,
13
21
  PointAndClickScenarioModule,
@@ -0,0 +1,9 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import type { PointAndClickPluginConstants, PointAndClickPluginEvents, PointAndClickPluginParams, PointAndClickPluginSettings } from "../types.js";
3
+ import type { PointAndClickEmitPayload, PointAndClickOption } from "../utils/point-and-click.js";
4
+ export declare class PointAndClickEmit extends ModuleCore<PointAndClickPluginEvents, PointAndClickPluginConstants, PointAndClickPluginSettings, PointAndClickPluginParams> {
5
+ name: string;
6
+ subscribe: () => void;
7
+ onEmit: ({ options, args }?: PointAndClickEmitPayload) => Promise<unknown[] | undefined>;
8
+ mapOptions: ({ optionLine: { line, args }, index }: NonNullable<PointAndClickEmitPayload["options"]>[number]) => Promise<PointAndClickOption>;
9
+ }
@@ -0,0 +1,27 @@
1
+ import { splitLineKeywords, tokenizeExecLine } from "@vnejs/helpers";
2
+ import { ModuleCore } from "@vnejs/module.core";
3
+ export class PointAndClickEmit extends ModuleCore {
4
+ name = "point_and_click.emit";
5
+ subscribe = () => {
6
+ this.on(this.EVENTS.POINT_AND_CLICK.EMIT, this.onEmit);
7
+ };
8
+ onEmit = async ({ options = [], args = {} } = {}) => {
9
+ const mappedOptions = await Promise.all(options.map(this.mapOptions));
10
+ if (!mappedOptions.length || mappedOptions.every((option) => option.hided)) {
11
+ return this.emit(this.EVENTS.POINT_AND_CLICK.SKIP);
12
+ }
13
+ await this.emit(this.EVENTS.POINT_AND_CLICK.STATE_UPDATE, { isShow: true, options: mappedOptions, args });
14
+ return this.emit(this.EVENTS.POINT_AND_CLICK.SHOW);
15
+ };
16
+ mapOptions = async ({ optionLine: { line = "", args = {} }, index }) => {
17
+ const [, , icon, x, y] = tokenizeExecLine(line).map(String);
18
+ const result = { index, coords: [x, y].map(Number), icon, ...args };
19
+ await Promise.all(Object.keys(args).map(async (key) => {
20
+ if (typeof args[key] !== "string" || !args[key].startsWith(this.CONST.SCENARIO.LINE_PREFIXES.MODULE))
21
+ return;
22
+ const { line: execLine = "", module = "", keywords = [] } = splitLineKeywords(String(args[key]));
23
+ result[key] = await this.emitOne(this.EVENTS.POINT_AND_CLICK.EXEC_GET, { line: execLine, module, keywords });
24
+ }));
25
+ return result;
26
+ };
27
+ }
@@ -0,0 +1,12 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import type { PointAndClickPluginConstants, PointAndClickPluginEvents, PointAndClickPluginParams, PointAndClickPluginSettings } from "../types.js";
3
+ import type { PointAndClickEmitPayload, PointAndClickOptionPayload } from "../utils/point-and-click.js";
4
+ export declare class PointAndClickLogs extends ModuleCore<PointAndClickPluginEvents, PointAndClickPluginConstants, PointAndClickPluginSettings, PointAndClickPluginParams> {
5
+ name: string;
6
+ subscribe: () => void;
7
+ onEmit: ({ options, args }?: PointAndClickEmitPayload) => undefined;
8
+ onOption: ({ index }?: PointAndClickOptionPayload) => undefined;
9
+ onSkip: () => void;
10
+ onShow: () => undefined;
11
+ onHide: () => undefined;
12
+ }
@@ -0,0 +1,19 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ export class PointAndClickLogs extends ModuleCore {
3
+ name = "point_and_click.logs";
4
+ subscribe = () => {
5
+ this.on(this.EVENTS.POINT_AND_CLICK.EMIT, this.onEmit, this.CONST.LOGS.FILTER_FROM_RESULT_OPTIONS);
6
+ this.on(this.EVENTS.POINT_AND_CLICK.OPTION, this.onOption, this.CONST.LOGS.FILTER_FROM_RESULT_OPTIONS);
7
+ this.on(this.EVENTS.POINT_AND_CLICK.SKIP, this.onSkip, this.CONST.LOGS.FILTER_FROM_RESULT_OPTIONS);
8
+ this.on(this.EVENTS.POINT_AND_CLICK.SHOW, this.onShow, this.CONST.LOGS.FILTER_FROM_RESULT_OPTIONS);
9
+ this.on(this.EVENTS.POINT_AND_CLICK.HIDE, this.onHide, this.CONST.LOGS.FILTER_FROM_RESULT_OPTIONS);
10
+ };
11
+ onEmit = ({ options = [], args = {} } = {}) => void this.emitLog({ action: this.CONST.POINT_AND_CLICK.LOGS_ACTIONS.EMIT, options, args });
12
+ onOption = ({ index = 0 } = {}) => void this.emitLog({ action: this.CONST.POINT_AND_CLICK.LOGS_ACTIONS.OPTION, index });
13
+ onSkip = () => {
14
+ const { curLine = 0, label } = this.globalState.scenario;
15
+ void this.emitLog({ action: this.CONST.POINT_AND_CLICK.LOGS_ACTIONS.SKIP, label, from: curLine });
16
+ };
17
+ onShow = () => void this.emitLog({ action: this.CONST.POINT_AND_CLICK.LOGS_ACTIONS.SHOW });
18
+ onHide = () => void this.emitLog({ action: this.CONST.POINT_AND_CLICK.LOGS_ACTIONS.HIDE });
19
+ }
@@ -0,0 +1,8 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import type { PointAndClickPluginConstants, PointAndClickPluginEvents, PointAndClickPluginParams, PointAndClickPluginSettings } from "../types.js";
3
+ import type { PointAndClickOptionPayload } from "../utils/point-and-click.js";
4
+ export declare class PointAndClickOption extends ModuleCore<PointAndClickPluginEvents, PointAndClickPluginConstants, PointAndClickPluginSettings, PointAndClickPluginParams> {
5
+ name: string;
6
+ subscribe: () => void;
7
+ onOption: ({ index }?: PointAndClickOptionPayload) => Promise<void>;
8
+ }
@@ -0,0 +1,17 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ export class PointAndClickOption extends ModuleCore {
3
+ name = "point_and_click.option";
4
+ subscribe = () => {
5
+ this.on(this.EVENTS.POINT_AND_CLICK.OPTION, this.onOption);
6
+ };
7
+ onOption = async ({ index = 0 } = {}) => {
8
+ await this.emit(this.EVENTS.POINT_AND_CLICK.HIDE);
9
+ this.globalState.scenario.curLine = this.globalState.point_and_click.options[index].index + 1;
10
+ await this.emit(this.EVENTS.POINT_AND_CLICK.STATE_UPDATE, {
11
+ options: [],
12
+ args: {},
13
+ isShow: false,
14
+ });
15
+ this.emitNext();
16
+ };
17
+ }
@@ -1,14 +1,11 @@
1
1
  import { ModuleCore, type ModuleGlobalStateRegistry } from "@vnejs/module.core";
2
2
  import type { PointAndClickPluginConstants, PointAndClickPluginEvents, PointAndClickPluginParams, PointAndClickPluginSettings } from "../types.js";
3
- import type { PointAndClickEmitPayload, PointAndClickOption, PointAndClickOptionPayload, PointAndClickPluginModelState } from "../utils/point-and-click.js";
4
- export declare class PointAndClick extends ModuleCore<PointAndClickPluginEvents, PointAndClickPluginConstants, PointAndClickPluginSettings, PointAndClickPluginParams, PointAndClickPluginModelState> {
3
+ import type { PointAndClickPluginModelState } from "../utils/point-and-click.js";
4
+ export declare class PointAndClickState extends ModuleCore<PointAndClickPluginEvents, PointAndClickPluginConstants, PointAndClickPluginSettings, PointAndClickPluginParams, PointAndClickPluginModelState> {
5
5
  name: string;
6
6
  subscribe: () => void;
7
- onEmit: ({ options, args }?: PointAndClickEmitPayload) => Promise<unknown[] | undefined>;
8
- onSkip: () => Promise<undefined>;
9
- onOption: ({ index }?: PointAndClickOptionPayload) => Promise<void>;
7
+ onStateUpdate: (state?: Partial<PointAndClickPluginModelState>) => void;
10
8
  onStateSet: (payload: ModuleGlobalStateRegistry) => Promise<unknown[] | undefined>;
11
9
  onStateClear: () => Promise<unknown[]> | undefined;
12
- mapOptions: ({ optionLine: { line, args }, index }: NonNullable<PointAndClickEmitPayload["options"]>[number]) => Promise<PointAndClickOption>;
13
10
  getDefaultState: () => PointAndClickPluginModelState;
14
11
  }
@@ -1,65 +1,22 @@
1
- import { splitLineKeywords, tokenizeExecLine } from "@vnejs/helpers";
2
1
  import { ModuleCore } from "@vnejs/module.core";
3
- export class PointAndClick extends ModuleCore {
2
+ export class PointAndClickState extends ModuleCore {
4
3
  name = "point_and_click";
5
4
  subscribe = () => {
6
- this.on(this.EVENTS.POINT_AND_CLICK.EMIT, this.onEmit);
7
- this.on(this.EVENTS.POINT_AND_CLICK.OPTION, this.onOption);
8
- this.on(this.EVENTS.POINT_AND_CLICK.SKIP, this.onSkip);
5
+ this.on(this.EVENTS.POINT_AND_CLICK.STATE_UPDATE, this.onStateUpdate);
9
6
  this.on(this.EVENTS.STATE.SET, this.onStateSet);
10
7
  this.on(this.EVENTS.STATE.CLEAR, this.onStateClear);
11
8
  };
12
- onEmit = async ({ options = [], args = {} } = {}) => {
13
- this.emitLog({ action: "emit", options, args });
14
- const mappedOptions = await Promise.all(options.map(this.mapOptions));
15
- if (!mappedOptions.length || mappedOptions.every((option) => option.hided)) {
16
- return this.emit(this.EVENTS.POINT_AND_CLICK.SKIP);
17
- }
18
- this.updateState({ isShow: true, options: mappedOptions, args });
19
- return this.emit(this.EVENTS.POINT_AND_CLICK.OPENED);
20
- };
21
- onSkip = async () => {
22
- const { curLine = 0, label } = this.globalState.scenario;
23
- const lines = (await this.emitOne(this.EVENTS.SCENARIO.LINES_GET, { label }));
24
- const parentIndent = lines[curLine]?.indent ?? 0;
25
- let indexShift = 1;
26
- let curLineObj = lines[curLine + indexShift];
27
- while (curLineObj && (curLineObj.indent ?? 0) > parentIndent) {
28
- indexShift++;
29
- curLineObj = lines[curLine + indexShift];
30
- }
31
- this.emitLog({ action: "skip", label, from: curLine, to: curLine + indexShift });
32
- this.globalState.scenario.curLine = curLine + indexShift;
33
- return this.emitNext();
34
- };
35
- onOption = async ({ index = 0 } = {}) => {
36
- this.emitLog({ action: "point_and_click", index });
37
- await this.emit(this.EVENTS.POINT_AND_CLICK.CLOSED);
38
- this.globalState.scenario.curLine = this.state.options[index].index + 1;
39
- this.setDefaultState();
40
- this.emitNext();
41
- };
9
+ onStateUpdate = (state = {}) => this.updateState(state);
42
10
  onStateSet = async (payload) => {
43
11
  const moduleState = this.getStateSlice(payload);
44
12
  if (!moduleState || this.state.isShow === moduleState.isShow)
45
13
  return;
46
14
  const clonedState = await this.emitClone(moduleState);
47
15
  this.setState(clonedState);
48
- return this.emit(clonedState.isShow ? this.EVENTS.POINT_AND_CLICK.OPENED : this.EVENTS.POINT_AND_CLICK.CLOSED, {
16
+ return this.emit(clonedState.isShow ? this.EVENTS.POINT_AND_CLICK.SHOW : this.EVENTS.POINT_AND_CLICK.HIDE, {
49
17
  isForce: true,
50
18
  });
51
19
  };
52
- onStateClear = () => this.emit(this.EVENTS.POINT_AND_CLICK.CLOSED, { isForce: true });
53
- mapOptions = async ({ optionLine: { line = "", args = {} }, index }) => {
54
- const [, , icon, x, y] = tokenizeExecLine(line).map(String);
55
- const result = { index, coords: [x, y].map(Number), icon, ...args };
56
- await Promise.all(Object.keys(args).map(async (key) => {
57
- if (typeof args[key] !== "string" || !args[key].startsWith(this.CONST.SCENARIO.LINE_PREFIXES.MODULE))
58
- return;
59
- const { line: execLine = "", module = "", keywords = [] } = splitLineKeywords(String(args[key]));
60
- result[key] = await this.emitOne(this.EVENTS.POINT_AND_CLICK.EXEC_GET, { line: execLine, module, keywords });
61
- }));
62
- return result;
63
- };
20
+ onStateClear = () => this.emit(this.EVENTS.POINT_AND_CLICK.HIDE, { isForce: true });
64
21
  getDefaultState = () => ({ options: [], args: {}, isShow: false });
65
22
  }
@@ -16,7 +16,7 @@ export class PointAndClickScenarioModule extends ModuleCore {
16
16
  this.globalState.scenario.curLine = curLine + 1;
17
17
  return this.emitNext();
18
18
  }
19
- this.emitLog({ action: this.CONST.POINT_AND_CLICK.EXEC_ACTIONS.REPEAT, label, from: curLine, to: targetIndex });
19
+ this.emitLog({ action: this.CONST.POINT_AND_CLICK.LOGS_ACTIONS.REPEAT, label, from: curLine, to: targetIndex });
20
20
  this.globalState.scenario.curLine = targetIndex;
21
21
  return this.emitNext();
22
22
  };
@@ -0,0 +1,7 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import type { PointAndClickPluginConstants, PointAndClickPluginEvents, PointAndClickPluginParams, PointAndClickPluginSettings } from "../types.js";
3
+ export declare class PointAndClickSkip extends ModuleCore<PointAndClickPluginEvents, PointAndClickPluginConstants, PointAndClickPluginSettings, PointAndClickPluginParams> {
4
+ name: string;
5
+ subscribe: () => void;
6
+ onSkip: () => Promise<undefined>;
7
+ }
@@ -0,0 +1,20 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ export class PointAndClickSkip extends ModuleCore {
3
+ name = "point_and_click.skip";
4
+ subscribe = () => {
5
+ this.on(this.EVENTS.POINT_AND_CLICK.SKIP, this.onSkip);
6
+ };
7
+ onSkip = async () => {
8
+ const { curLine = 0, label } = this.globalState.scenario;
9
+ const lines = (await this.emitOne(this.EVENTS.SCENARIO.LINES_GET, { label }));
10
+ const parentIndent = lines[curLine]?.indent ?? 0;
11
+ let indexShift = 1;
12
+ let curLineObj = lines[curLine + indexShift];
13
+ while (curLineObj && (curLineObj.indent ?? 0) > parentIndent) {
14
+ indexShift++;
15
+ curLineObj = lines[curLine + indexShift];
16
+ }
17
+ this.globalState.scenario.curLine = curLine + indexShift;
18
+ return this.emitNext();
19
+ };
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vnejs/plugins.scenario.point_and_click",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -3,14 +3,22 @@ import "@vnejs/contracts.scenario.point_and_click";
3
3
  import { regPlugin } from "@vnejs/shared";
4
4
  import { CONSTANTS, PARAMS, PLUGIN_NAME, SUBSCRIBE_EVENTS } from "@vnejs/contracts.scenario.point_and_click";
5
5
 
6
- import { PointAndClick } from "./modules/point_and_click.js";
6
+ import { PointAndClickEmit } from "./modules/emit.js";
7
7
  import { PointAndClickExec } from "./modules/exec.js";
8
+ import { PointAndClickLogs } from "./modules/logs.js";
9
+ import { PointAndClickOption } from "./modules/option.js";
10
+ import { PointAndClickState } from "./modules/point_and_click.js";
8
11
  import { PointAndClickScenario } from "./modules/scenario.block.js";
9
12
  import { PointAndClickScenarioModule } from "./modules/scenario.module.js";
10
13
  import { PointAndClickScenarioOption } from "./modules/scenario.option.js";
14
+ import { PointAndClickSkip } from "./modules/skip.js";
11
15
 
12
16
  regPlugin(PLUGIN_NAME, { constants: CONSTANTS, events: SUBSCRIBE_EVENTS, params: PARAMS }, [
13
- PointAndClick,
17
+ PointAndClickState,
18
+ PointAndClickEmit,
19
+ PointAndClickOption,
20
+ PointAndClickSkip,
21
+ PointAndClickLogs,
14
22
  PointAndClickExec,
15
23
  PointAndClickScenario,
16
24
  PointAndClickScenarioModule,
@@ -0,0 +1,47 @@
1
+ import { splitLineKeywords, tokenizeExecLine } from "@vnejs/helpers";
2
+ import { ModuleCore } from "@vnejs/module.core";
3
+
4
+ import type { PointAndClickPluginConstants, PointAndClickPluginEvents, PointAndClickPluginParams, PointAndClickPluginSettings } from "../types.js";
5
+ import type { PointAndClickEmitPayload, PointAndClickExecGetPayload, PointAndClickOption, PointAndClickPluginModelState } from "../utils/point-and-click.js";
6
+
7
+ export class PointAndClickEmit extends ModuleCore<
8
+ PointAndClickPluginEvents,
9
+ PointAndClickPluginConstants,
10
+ PointAndClickPluginSettings,
11
+ PointAndClickPluginParams
12
+ > {
13
+ name = "point_and_click.emit";
14
+
15
+ subscribe = () => {
16
+ this.on(this.EVENTS.POINT_AND_CLICK.EMIT, this.onEmit);
17
+ };
18
+
19
+ onEmit = async ({ options = [], args = {} }: PointAndClickEmitPayload = {}) => {
20
+ const mappedOptions = await Promise.all(options.map(this.mapOptions));
21
+
22
+ if (!mappedOptions.length || mappedOptions.every((option) => option.hided)) {
23
+ return this.emit(this.EVENTS.POINT_AND_CLICK.SKIP);
24
+ }
25
+
26
+ await this.emit(this.EVENTS.POINT_AND_CLICK.STATE_UPDATE, { isShow: true, options: mappedOptions, args } satisfies Partial<PointAndClickPluginModelState>);
27
+
28
+ return this.emit(this.EVENTS.POINT_AND_CLICK.SHOW);
29
+ };
30
+
31
+ mapOptions = async ({ optionLine: { line = "", args = {} }, index }: NonNullable<PointAndClickEmitPayload["options"]>[number]) => {
32
+ const [, , icon, x, y] = tokenizeExecLine(line).map(String);
33
+ const result: PointAndClickOption = { index, coords: [x, y].map(Number), icon, ...args };
34
+
35
+ await Promise.all(
36
+ Object.keys(args).map(async (key) => {
37
+ if (typeof args[key] !== "string" || !args[key].startsWith(this.CONST.SCENARIO.LINE_PREFIXES.MODULE)) return;
38
+
39
+ const { line: execLine = "", module = "", keywords = [] } = splitLineKeywords(String(args[key]));
40
+
41
+ result[key] = await this.emitOne(this.EVENTS.POINT_AND_CLICK.EXEC_GET, { line: execLine, module, keywords } satisfies PointAndClickExecGetPayload);
42
+ }),
43
+ );
44
+
45
+ return result;
46
+ };
47
+ }
@@ -0,0 +1,32 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+
3
+ import type { PointAndClickPluginConstants, PointAndClickPluginEvents, PointAndClickPluginParams, PointAndClickPluginSettings } from "../types.js";
4
+ import type { PointAndClickEmitPayload, PointAndClickOptionPayload } from "../utils/point-and-click.js";
5
+
6
+ export class PointAndClickLogs extends ModuleCore<
7
+ PointAndClickPluginEvents,
8
+ PointAndClickPluginConstants,
9
+ PointAndClickPluginSettings,
10
+ PointAndClickPluginParams
11
+ > {
12
+ name = "point_and_click.logs";
13
+
14
+ subscribe = () => {
15
+ this.on(this.EVENTS.POINT_AND_CLICK.EMIT, this.onEmit, this.CONST.LOGS.FILTER_FROM_RESULT_OPTIONS);
16
+ this.on(this.EVENTS.POINT_AND_CLICK.OPTION, this.onOption, this.CONST.LOGS.FILTER_FROM_RESULT_OPTIONS);
17
+ this.on(this.EVENTS.POINT_AND_CLICK.SKIP, this.onSkip, this.CONST.LOGS.FILTER_FROM_RESULT_OPTIONS);
18
+ this.on(this.EVENTS.POINT_AND_CLICK.SHOW, this.onShow, this.CONST.LOGS.FILTER_FROM_RESULT_OPTIONS);
19
+ this.on(this.EVENTS.POINT_AND_CLICK.HIDE, this.onHide, this.CONST.LOGS.FILTER_FROM_RESULT_OPTIONS);
20
+ };
21
+
22
+ onEmit = ({ options = [], args = {} }: PointAndClickEmitPayload = {}) =>
23
+ void this.emitLog({ action: this.CONST.POINT_AND_CLICK.LOGS_ACTIONS.EMIT, options, args });
24
+ onOption = ({ index = 0 }: PointAndClickOptionPayload = {}) => void this.emitLog({ action: this.CONST.POINT_AND_CLICK.LOGS_ACTIONS.OPTION, index });
25
+ onSkip = () => {
26
+ const { curLine = 0, label } = this.globalState.scenario;
27
+
28
+ void this.emitLog({ action: this.CONST.POINT_AND_CLICK.LOGS_ACTIONS.SKIP, label, from: curLine });
29
+ };
30
+ onShow = () => void this.emitLog({ action: this.CONST.POINT_AND_CLICK.LOGS_ACTIONS.SHOW });
31
+ onHide = () => void this.emitLog({ action: this.CONST.POINT_AND_CLICK.LOGS_ACTIONS.HIDE });
32
+ }
@@ -0,0 +1,31 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+
3
+ import type { PointAndClickPluginConstants, PointAndClickPluginEvents, PointAndClickPluginParams, PointAndClickPluginSettings } from "../types.js";
4
+ import type { PointAndClickOptionPayload, PointAndClickPluginModelState } from "../utils/point-and-click.js";
5
+
6
+ export class PointAndClickOption extends ModuleCore<
7
+ PointAndClickPluginEvents,
8
+ PointAndClickPluginConstants,
9
+ PointAndClickPluginSettings,
10
+ PointAndClickPluginParams
11
+ > {
12
+ name = "point_and_click.option";
13
+
14
+ subscribe = () => {
15
+ this.on(this.EVENTS.POINT_AND_CLICK.OPTION, this.onOption);
16
+ };
17
+
18
+ onOption = async ({ index = 0 }: PointAndClickOptionPayload = {}) => {
19
+ await this.emit(this.EVENTS.POINT_AND_CLICK.HIDE);
20
+
21
+ this.globalState.scenario.curLine = this.globalState.point_and_click.options[index].index + 1;
22
+
23
+ await this.emit(this.EVENTS.POINT_AND_CLICK.STATE_UPDATE, {
24
+ options: [],
25
+ args: {},
26
+ isShow: false,
27
+ } satisfies Partial<PointAndClickPluginModelState>);
28
+
29
+ this.emitNext();
30
+ };
31
+ }
@@ -1,18 +1,9 @@
1
- import { splitLineKeywords, tokenizeExecLine } from "@vnejs/helpers";
2
1
  import { ModuleCore, type ModuleGlobalStateRegistry } from "@vnejs/module.core";
3
2
 
4
3
  import type { PointAndClickPluginConstants, PointAndClickPluginEvents, PointAndClickPluginParams, PointAndClickPluginSettings } from "../types.js";
5
- import type {
6
- PointAndClickEmitPayload,
7
- PointAndClickExecGetPayload,
8
- PointAndClickOption,
9
- PointAndClickOptionLine,
10
- PointAndClickOptionPayload,
11
- PointAndClickPluginModelState,
12
- PointAndClickVisibilityPayload,
13
- } from "../utils/point-and-click.js";
4
+ import type { PointAndClickPluginModelState, PointAndClickVisibilityPayload } from "../utils/point-and-click.js";
14
5
 
15
- export class PointAndClick extends ModuleCore<
6
+ export class PointAndClickState extends ModuleCore<
16
7
  PointAndClickPluginEvents,
17
8
  PointAndClickPluginConstants,
18
9
  PointAndClickPluginSettings,
@@ -22,55 +13,13 @@ export class PointAndClick extends ModuleCore<
22
13
  name = "point_and_click";
23
14
 
24
15
  subscribe = () => {
25
- this.on(this.EVENTS.POINT_AND_CLICK.EMIT, this.onEmit);
26
- this.on(this.EVENTS.POINT_AND_CLICK.OPTION, this.onOption);
27
- this.on(this.EVENTS.POINT_AND_CLICK.SKIP, this.onSkip);
16
+ this.on(this.EVENTS.POINT_AND_CLICK.STATE_UPDATE, this.onStateUpdate);
28
17
 
29
18
  this.on(this.EVENTS.STATE.SET, this.onStateSet);
30
19
  this.on(this.EVENTS.STATE.CLEAR, this.onStateClear);
31
20
  };
32
21
 
33
- onEmit = async ({ options = [], args = {} }: PointAndClickEmitPayload = {}) => {
34
- this.emitLog({ action: "emit", options, args });
35
- const mappedOptions = await Promise.all(options.map(this.mapOptions));
36
-
37
- if (!mappedOptions.length || mappedOptions.every((option) => option.hided)) {
38
- return this.emit(this.EVENTS.POINT_AND_CLICK.SKIP);
39
- }
40
-
41
- this.updateState({ isShow: true, options: mappedOptions, args });
42
-
43
- return this.emit(this.EVENTS.POINT_AND_CLICK.OPENED);
44
- };
45
-
46
- onSkip = async () => {
47
- const { curLine = 0, label } = this.globalState.scenario;
48
- const lines = (await this.emitOne(this.EVENTS.SCENARIO.LINES_GET, { label })) as PointAndClickOptionLine[];
49
- const parentIndent = lines[curLine]?.indent ?? 0;
50
-
51
- let indexShift = 1;
52
- let curLineObj = lines[curLine + indexShift];
53
-
54
- while (curLineObj && (curLineObj.indent ?? 0) > parentIndent) {
55
- indexShift++;
56
- curLineObj = lines[curLine + indexShift];
57
- }
58
-
59
- this.emitLog({ action: "skip", label, from: curLine, to: curLine + indexShift });
60
- this.globalState.scenario.curLine = curLine + indexShift;
61
-
62
- return this.emitNext();
63
- };
64
-
65
- onOption = async ({ index = 0 }: PointAndClickOptionPayload = {}) => {
66
- this.emitLog({ action: "point_and_click", index });
67
-
68
- await this.emit(this.EVENTS.POINT_AND_CLICK.CLOSED);
69
-
70
- this.globalState.scenario.curLine = this.state.options[index].index + 1;
71
- this.setDefaultState();
72
- this.emitNext();
73
- };
22
+ onStateUpdate = (state: Partial<PointAndClickPluginModelState> = {}) => this.updateState(state);
74
23
 
75
24
  onStateSet = async (payload: ModuleGlobalStateRegistry) => {
76
25
  const moduleState = this.getStateSlice(payload);
@@ -81,29 +30,12 @@ export class PointAndClick extends ModuleCore<
81
30
 
82
31
  this.setState(clonedState);
83
32
 
84
- return this.emit(clonedState.isShow ? this.EVENTS.POINT_AND_CLICK.OPENED : this.EVENTS.POINT_AND_CLICK.CLOSED, {
33
+ return this.emit(clonedState.isShow ? this.EVENTS.POINT_AND_CLICK.SHOW : this.EVENTS.POINT_AND_CLICK.HIDE, {
85
34
  isForce: true,
86
35
  } satisfies PointAndClickVisibilityPayload);
87
36
  };
88
37
 
89
- onStateClear = () => this.emit(this.EVENTS.POINT_AND_CLICK.CLOSED, { isForce: true } satisfies PointAndClickVisibilityPayload);
90
-
91
- mapOptions = async ({ optionLine: { line = "", args = {} }, index }: NonNullable<PointAndClickEmitPayload["options"]>[number]) => {
92
- const [, , icon, x, y] = tokenizeExecLine(line).map(String);
93
- const result: PointAndClickOption = { index, coords: [x, y].map(Number), icon, ...args };
94
-
95
- await Promise.all(
96
- Object.keys(args).map(async (key) => {
97
- if (typeof args[key] !== "string" || !args[key].startsWith(this.CONST.SCENARIO.LINE_PREFIXES.MODULE)) return;
98
-
99
- const { line: execLine = "", module = "", keywords = [] } = splitLineKeywords(String(args[key]));
100
-
101
- result[key] = await this.emitOne(this.EVENTS.POINT_AND_CLICK.EXEC_GET, { line: execLine, module, keywords } satisfies PointAndClickExecGetPayload);
102
- }),
103
- );
104
-
105
- return result;
106
- };
38
+ onStateClear = () => this.emit(this.EVENTS.POINT_AND_CLICK.HIDE, { isForce: true } satisfies PointAndClickVisibilityPayload);
107
39
 
108
40
  getDefaultState = (): PointAndClickPluginModelState => ({ options: [], args: {}, isShow: false });
109
41
  }
@@ -32,7 +32,7 @@ export class PointAndClickScenarioModule extends ModuleCore<
32
32
  return this.emitNext();
33
33
  }
34
34
 
35
- this.emitLog({ action: this.CONST.POINT_AND_CLICK.EXEC_ACTIONS.REPEAT, label, from: curLine, to: targetIndex });
35
+ this.emitLog({ action: this.CONST.POINT_AND_CLICK.LOGS_ACTIONS.REPEAT, label, from: curLine, to: targetIndex });
36
36
  this.globalState.scenario.curLine = targetIndex;
37
37
 
38
38
  return this.emitNext();
@@ -0,0 +1,35 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+
3
+ import type { PointAndClickPluginConstants, PointAndClickPluginEvents, PointAndClickPluginParams, PointAndClickPluginSettings } from "../types.js";
4
+ import type { PointAndClickOptionLine } from "../utils/point-and-click.js";
5
+
6
+ export class PointAndClickSkip extends ModuleCore<
7
+ PointAndClickPluginEvents,
8
+ PointAndClickPluginConstants,
9
+ PointAndClickPluginSettings,
10
+ PointAndClickPluginParams
11
+ > {
12
+ name = "point_and_click.skip";
13
+
14
+ subscribe = () => {
15
+ this.on(this.EVENTS.POINT_AND_CLICK.SKIP, this.onSkip);
16
+ };
17
+
18
+ onSkip = async () => {
19
+ const { curLine = 0, label } = this.globalState.scenario;
20
+ const lines = (await this.emitOne(this.EVENTS.SCENARIO.LINES_GET, { label })) as PointAndClickOptionLine[];
21
+ const parentIndent = lines[curLine]?.indent ?? 0;
22
+
23
+ let indexShift = 1;
24
+ let curLineObj = lines[curLine + indexShift];
25
+
26
+ while (curLineObj && (curLineObj.indent ?? 0) > parentIndent) {
27
+ indexShift++;
28
+ curLineObj = lines[curLine + indexShift];
29
+ }
30
+
31
+ this.globalState.scenario.curLine = curLine + indexShift;
32
+
33
+ return this.emitNext();
34
+ };
35
+ }
@@ -0,0 +1,77 @@
1
+ import { beforeEach, describe, expect, it } from "vitest";
2
+
3
+ import { SUBSCRIBE_EVENTS as LOGS_EVENTS } from "@vnejs/contracts.core.logs";
4
+ import { spyEvent } from "@vnejs/test-utils";
5
+
6
+ import { PointAndClickLogs } from "../modules/logs.js";
7
+ import { CONSTANTS, createPointAndClickTestModule, registerPointAndClickPluginVne, SUBSCRIBE_EVENTS } from "./setup.js";
8
+
9
+ describe("PointAndClickLogs", () => {
10
+ beforeEach(() => {
11
+ registerPointAndClickPluginVne();
12
+ });
13
+
14
+ it("EMIT emits LOGS.EMIT with emit action", async () => {
15
+ const { observer } = createPointAndClickTestModule(PointAndClickLogs);
16
+ const logs = spyEvent(observer, LOGS_EVENTS.EMIT);
17
+ const options = [{ index: 0, optionLine: { line: "% point-and-click.option star 1 2", args: {} } }];
18
+
19
+ await observer.emit(SUBSCRIBE_EVENTS.EMIT, { options, args: { a: 1 } });
20
+
21
+ expect(logs).toHaveBeenCalledExactlyOnceWith({
22
+ module: "point_and_click.logs",
23
+ value: { action: CONSTANTS.LOGS_ACTIONS.EMIT, options, args: { a: 1 } },
24
+ });
25
+ });
26
+
27
+ it("OPTION emits LOGS.EMIT with option action and index", async () => {
28
+ const { observer } = createPointAndClickTestModule(PointAndClickLogs);
29
+ const logs = spyEvent(observer, LOGS_EVENTS.EMIT);
30
+
31
+ await observer.emit(SUBSCRIBE_EVENTS.OPTION, { index: 2 });
32
+
33
+ expect(logs).toHaveBeenCalledExactlyOnceWith({
34
+ module: "point_and_click.logs",
35
+ value: { action: CONSTANTS.LOGS_ACTIONS.OPTION, index: 2 },
36
+ });
37
+ });
38
+
39
+ it("SKIP emits LOGS.EMIT with skip action and scenario cursor", async () => {
40
+ const { observer, state } = createPointAndClickTestModule(PointAndClickLogs);
41
+ const logs = spyEvent(observer, LOGS_EVENTS.EMIT);
42
+
43
+ state.scenario.curLine = 3;
44
+ state.scenario.label = "lab";
45
+
46
+ await observer.emit(SUBSCRIBE_EVENTS.SKIP);
47
+
48
+ expect(logs).toHaveBeenCalledExactlyOnceWith({
49
+ module: "point_and_click.logs",
50
+ value: { action: CONSTANTS.LOGS_ACTIONS.SKIP, label: "lab", from: 3 },
51
+ });
52
+ });
53
+
54
+ it("SHOW emits LOGS.EMIT with show action", async () => {
55
+ const { observer } = createPointAndClickTestModule(PointAndClickLogs);
56
+ const logs = spyEvent(observer, LOGS_EVENTS.EMIT);
57
+
58
+ await observer.emit(SUBSCRIBE_EVENTS.SHOW);
59
+
60
+ expect(logs).toHaveBeenCalledExactlyOnceWith({
61
+ module: "point_and_click.logs",
62
+ value: { action: CONSTANTS.LOGS_ACTIONS.SHOW },
63
+ });
64
+ });
65
+
66
+ it("HIDE emits LOGS.EMIT with hide action", async () => {
67
+ const { observer } = createPointAndClickTestModule(PointAndClickLogs);
68
+ const logs = spyEvent(observer, LOGS_EVENTS.EMIT);
69
+
70
+ await observer.emit(SUBSCRIBE_EVENTS.HIDE);
71
+
72
+ expect(logs).toHaveBeenCalledExactlyOnceWith({
73
+ module: "point_and_click.logs",
74
+ value: { action: CONSTANTS.LOGS_ACTIONS.HIDE },
75
+ });
76
+ });
77
+ });
@@ -2,32 +2,46 @@ import { beforeEach, describe, expect, it } from "vitest";
2
2
 
3
3
  import { spyEvent } from "@vnejs/test-utils";
4
4
 
5
- import { PointAndClick } from "../modules/point_and_click.js";
6
- import { createPointAndClickTestModule, registerPointAndClickPluginVne, SCENARIO_EVENTS, SUBSCRIBE_EVENTS } from "./setup.js";
5
+ import { PointAndClickState } from "../modules/point_and_click.js";
6
+ import { createPointAndClickFlowModules, createPointAndClickTestModule, registerPointAndClickPluginVne, SCENARIO_EVENTS, SUBSCRIBE_EVENTS } from "./setup.js";
7
7
 
8
- describe("PointAndClick", () => {
8
+ describe("PointAndClickState", () => {
9
9
  beforeEach(() => {
10
10
  registerPointAndClickPluginVne();
11
11
  });
12
12
 
13
- it("EMIT stores options and emits OPENED", async () => {
14
- const { module, observer } = createPointAndClickTestModule(PointAndClick);
15
- const opened = spyEvent(observer, SUBSCRIBE_EVENTS.OPENED);
13
+ it("STATE_UPDATE merges partial point_and_click state", async () => {
14
+ const { module, observer } = createPointAndClickTestModule(PointAndClickState);
15
+
16
+ await observer.emit(SUBSCRIBE_EVENTS.STATE_UPDATE, { isShow: true });
17
+
18
+ expect((module as PointAndClickState).state.isShow).toBe(true);
19
+ });
20
+ });
21
+
22
+ describe("PointAndClick flow", () => {
23
+ beforeEach(() => {
24
+ registerPointAndClickPluginVne();
25
+ });
26
+
27
+ it("EMIT stores options and emits SHOW", async () => {
28
+ const { stateModule, observer } = createPointAndClickFlowModules();
29
+ const show = spyEvent(observer, SUBSCRIBE_EVENTS.SHOW);
16
30
  const skip = spyEvent(observer, SUBSCRIBE_EVENTS.SKIP);
17
31
 
18
32
  await observer.emit(SUBSCRIBE_EVENTS.EMIT, {
19
33
  options: [{ index: 0, optionLine: { line: "% point-and-click.option star 100 200", args: {} } }],
20
34
  });
21
35
 
22
- expect((module as PointAndClick).state.isShow).toBe(true);
23
- expect((module as PointAndClick).state.options[0]).toMatchObject({ index: 0, icon: "star", coords: [100, 200] });
24
- expect(opened).toHaveBeenCalledOnce();
36
+ expect(stateModule.state.isShow).toBe(true);
37
+ expect(stateModule.state.options[0]).toMatchObject({ index: 0, icon: "star", coords: [100, 200] });
38
+ expect(show).toHaveBeenCalledOnce();
25
39
  expect(skip).not.toHaveBeenCalled();
26
40
  });
27
41
 
28
42
  it("EMIT with all hided options emits SKIP and advances past the block", async () => {
29
- const { module, observer, state } = createPointAndClickTestModule(PointAndClick);
30
- const opened = spyEvent(observer, SUBSCRIBE_EVENTS.OPENED);
43
+ const { stateModule, observer, state } = createPointAndClickFlowModules();
44
+ const show = spyEvent(observer, SUBSCRIBE_EVENTS.SHOW);
31
45
  const skip = spyEvent(observer, SUBSCRIBE_EVENTS.SKIP);
32
46
  const next = spyEvent(observer, SCENARIO_EVENTS.NEXT);
33
47
  const lines = [
@@ -44,14 +58,14 @@ describe("PointAndClick", () => {
44
58
  });
45
59
 
46
60
  expect(skip).toHaveBeenCalledOnce();
47
- expect(opened).not.toHaveBeenCalled();
48
- expect((module as PointAndClick).state.isShow).toBe(false);
61
+ expect(show).not.toHaveBeenCalled();
62
+ expect(stateModule.state.isShow).toBe(false);
49
63
  expect(state.scenario.curLine).toBe(2);
50
64
  expect(next).toHaveBeenCalledOnce();
51
65
  });
52
66
 
53
67
  it("EMIT with empty options emits SKIP and advances past the block", async () => {
54
- const { observer, state } = createPointAndClickTestModule(PointAndClick);
68
+ const { observer, state } = createPointAndClickFlowModules();
55
69
  const skip = spyEvent(observer, SUBSCRIBE_EVENTS.SKIP);
56
70
  const next = spyEvent(observer, SCENARIO_EVENTS.NEXT);
57
71
  const lines = [
@@ -69,20 +83,20 @@ describe("PointAndClick", () => {
69
83
  expect(next).toHaveBeenCalledOnce();
70
84
  });
71
85
 
72
- it("OPTION emits CLOSED, updates curLine and resets state", async () => {
73
- const { module, observer, state } = createPointAndClickTestModule(PointAndClick);
74
- const closed = spyEvent(observer, SUBSCRIBE_EVENTS.CLOSED);
86
+ it("OPTION emits HIDE, updates curLine and resets state", async () => {
87
+ const { stateModule, observer, state } = createPointAndClickFlowModules();
88
+ const hide = spyEvent(observer, SUBSCRIBE_EVENTS.HIDE);
75
89
 
76
- (module as PointAndClick).state = {
90
+ stateModule.setState({
77
91
  options: [{ index: 3, icon: "star", coords: [0, 0] }],
78
92
  args: {},
79
93
  isShow: true,
80
- };
94
+ });
81
95
 
82
96
  await observer.emit(SUBSCRIBE_EVENTS.OPTION, { index: 0 });
83
97
 
84
- expect(closed).toHaveBeenCalledOnce();
98
+ expect(hide).toHaveBeenCalledOnce();
85
99
  expect(state.scenario.curLine).toBe(4);
86
- expect((module as PointAndClick).state.isShow).toBe(false);
100
+ expect(stateModule.state.isShow).toBe(false);
87
101
  });
88
102
  });
@@ -3,6 +3,11 @@ import { CONSTANTS, PARAMS, PLUGIN_NAME, SUBSCRIBE_EVENTS } from "@vnejs/contrac
3
3
  import { SourcesSet } from "@vnejs/sources-set";
4
4
  import { createTestModule as baseCreateTestModule, registerCoreVne, registerVnePlugin, stubSilentEvent } from "@vnejs/test-utils";
5
5
 
6
+ import { PointAndClickEmit } from "../modules/emit.js";
7
+ import { PointAndClickOption } from "../modules/option.js";
8
+ import { PointAndClickState } from "../modules/point_and_click.js";
9
+ import { PointAndClickSkip } from "../modules/skip.js";
10
+
6
11
  export const registerPointAndClickPluginVne = () => {
7
12
  registerCoreVne();
8
13
  registerVnePlugin(PLUGIN_NAME, { constants: CONSTANTS, events: SUBSCRIBE_EVENTS, params: PARAMS });
@@ -25,10 +30,31 @@ export const createPointAndClickTestModule = <T extends Parameters<typeof baseCr
25
30
  ...options,
26
31
  });
27
32
 
28
- stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.OPENED);
29
- stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.CLOSED);
33
+ stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.SHOW);
34
+ stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.HIDE);
30
35
 
31
36
  return result;
32
37
  };
33
38
 
39
+ export const createPointAndClickFlowModules = (options: Parameters<typeof baseCreateTestModule>[1] = {}) => {
40
+ const { module: stateModule, observer, state, shared } = createPointAndClickTestModule(PointAndClickState, options);
41
+
42
+ const attach = <T extends new () => InstanceType<T>>(ModuleClass: T) => {
43
+ const module = new ModuleClass();
44
+ module.inject({ observer, state, shared, media: {} });
45
+ module.subscribe();
46
+ return module;
47
+ };
48
+
49
+ return {
50
+ stateModule: stateModule as PointAndClickState,
51
+ emitModule: attach(PointAndClickEmit),
52
+ optionModule: attach(PointAndClickOption),
53
+ skipModule: attach(PointAndClickSkip),
54
+ observer,
55
+ state,
56
+ shared,
57
+ };
58
+ };
59
+
34
60
  export { CONSTANTS, SUBSCRIBE_EVENTS, PARAMS, PLUGIN_NAME, SCENARIO_EVENTS };
package/src/types.ts CHANGED
@@ -17,9 +17,7 @@ export type PointAndClickPluginEvents = ModuleCoreEvents &
17
17
  Record<VendorsPluginName, VendorsSubscribeEvents> &
18
18
  Record<LogsPluginName, LogsSubscribeEvents>;
19
19
 
20
- export type PointAndClickPluginConstants = ModuleCoreConstants &
21
- Record<PluginName, PointAndClickConstants> &
22
- Record<ScenarioPluginName, ScenarioConstants>;
20
+ export type PointAndClickPluginConstants = ModuleCoreConstants & Record<PluginName, PointAndClickConstants> & Record<ScenarioPluginName, ScenarioConstants>;
23
21
 
24
22
  export type PointAndClickPluginSettings = ModuleCoreSettings;
25
23