@putdotio/rokit 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -47,7 +47,13 @@ pnpm exec rokit screenshot artifacts/live/player.png
47
47
  App-specific scenario scripts can also import the generic helpers:
48
48
 
49
49
  ```ts
50
- import { assertSceneGraphNode, pressKey, querySceneGraph, type RokuContext } from "@putdotio/rokit";
50
+ import {
51
+ assertSceneGraphNode,
52
+ pressKey,
53
+ querySceneGraph,
54
+ readNamedNodeTranslation,
55
+ type RokuContext,
56
+ } from "@putdotio/rokit";
51
57
 
52
58
  const target = process.env.ROKIT_TARGET;
53
59
 
@@ -62,8 +68,9 @@ const context: RokuContext = {
62
68
  };
63
69
 
64
70
  await pressKey(context, "Info");
71
+ const xml = await querySceneGraph(context, { attempts: 3 });
65
72
  await assertSceneGraphNode(context, "videoPlayerScreen", { state: "visible" });
66
- await querySceneGraph(context, { attempts: 3 });
73
+ console.log(readNamedNodeTranslation(xml, "videoPlayerScreen"));
67
74
  ```
68
75
 
69
76
  ## Commands
@@ -130,6 +137,7 @@ tokens, and app-specific media identifiers do not belong in git.
130
137
  - remote keypresses
131
138
  - raw ECP queries
132
139
  - SceneGraph state queries and named-node assertions
140
+ - SceneGraph attribute, numeric geometry, bounds, and translation readers
133
141
  - screenshots
134
142
 
135
143
  App repositories should keep their own scenario commands for product behavior,
package/dist/index.d.mts CHANGED
@@ -2,6 +2,8 @@ import * as rokuDeploy from "roku-deploy";
2
2
 
3
3
  //#region src/scenegraph.d.ts
4
4
  type NodeState = "absent" | "hidden" | "visible";
5
+ type SceneGraphBounds = readonly [x: number, y: number, width: number, height: number];
6
+ type SceneGraphPoint = readonly [x: number, y: number];
5
7
  type NodeExpectation = {
6
8
  readonly state: NodeState;
7
9
  readonly text?: string;
@@ -11,10 +13,14 @@ type NodeExpectation = {
11
13
  };
12
14
  declare const readNamedNodeAttributes: (xml: string, nodeName: string) => string | undefined;
13
15
  declare const readNamedNodeAttribute: (xml: string, nodeName: string, attributeName: string) => string | undefined;
16
+ declare const readNamedNodeNumber: (xml: string, nodeName: string, attributeName: string) => number | undefined;
17
+ declare const readNamedNodeBounds: (xml: string, nodeName: string) => SceneGraphBounds | undefined;
18
+ declare const readNamedNodeTranslation: (xml: string, nodeName: string) => SceneGraphPoint | undefined;
14
19
  declare const isNamedNodeVisible: (xml: string, nodeName: string) => boolean;
15
20
  declare const assertNamedNode: (xml: string, nodeName: string, expectation: NodeExpectation) => void;
16
21
  declare const assertNamedNodeState: (xml: string, nodeName: string, state: NodeState) => void;
17
22
  declare const assertNamedNodeText: (xml: string, nodeName: string, expectedText: string) => void;
23
+ declare const parseSceneGraphNumberList: (value: string) => number[];
18
24
  //#endregion
19
25
  //#region src/xml.d.ts
20
26
  type ActiveApp = {
@@ -64,4 +70,4 @@ declare const takeScreenshot: (context: RokuContext & {
64
70
  }, outputPath: string) => Promise<string>;
65
71
  declare const validateRemoteKey: (key: string) => void;
66
72
  //#endregion
67
- export { type ActiveApp, type DeviceSummary, type NodeExpectation, type NodeState, type RemoteKey, type RetryOptions, type RokuContext, assertNamedNode, assertNamedNodeState, assertNamedNodeText, assertSceneGraphNode, checkDevice, getDeviceInfo, installPackage, isNamedNodeVisible, launchApp, pressKey, queryActiveApp, queryEcp, querySceneGraph, readActiveApp, readNamedNodeAttribute, readNamedNodeAttributes, readXmlAttribute, readXmlTag, takeScreenshot, validateRemoteKey, waitForActiveApp, waitForSceneGraphNode };
73
+ export { type ActiveApp, type DeviceSummary, type NodeExpectation, type NodeState, type RemoteKey, type RetryOptions, type RokuContext, type SceneGraphBounds, type SceneGraphPoint, assertNamedNode, assertNamedNodeState, assertNamedNodeText, assertSceneGraphNode, checkDevice, getDeviceInfo, installPackage, isNamedNodeVisible, launchApp, parseSceneGraphNumberList, pressKey, queryActiveApp, queryEcp, querySceneGraph, readActiveApp, readNamedNodeAttribute, readNamedNodeAttributes, readNamedNodeBounds, readNamedNodeNumber, readNamedNodeTranslation, readXmlAttribute, readXmlTag, takeScreenshot, validateRemoteKey, waitForActiveApp, waitForSceneGraphNode };
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { S as readXmlTag, _ as isNamedNodeVisible, a as launchApp, b as readActiveApp, c as queryEcp, d as validateRemoteKey, f as waitForActiveApp, g as assertNamedNodeText, h as assertNamedNodeState, i as installPackage, l as querySceneGraph, m as assertNamedNode, n as checkDevice, o as pressKey, p as waitForSceneGraphNode, r as getDeviceInfo, s as queryActiveApp, t as assertSceneGraphNode, u as takeScreenshot, v as readNamedNodeAttribute, x as readXmlAttribute, y as readNamedNodeAttributes } from "./roku-DxlYPbY1.mjs";
2
- export { assertNamedNode, assertNamedNodeState, assertNamedNodeText, assertSceneGraphNode, checkDevice, getDeviceInfo, installPackage, isNamedNodeVisible, launchApp, pressKey, queryActiveApp, queryEcp, querySceneGraph, readActiveApp, readNamedNodeAttribute, readNamedNodeAttributes, readXmlAttribute, readXmlTag, takeScreenshot, validateRemoteKey, waitForActiveApp, waitForSceneGraphNode };
1
+ import { C as readNamedNodeTranslation, E as readXmlTag, S as readNamedNodeNumber, T as readXmlAttribute, _ as isNamedNodeVisible, a as launchApp, b as readNamedNodeAttributes, c as queryEcp, d as validateRemoteKey, f as waitForActiveApp, g as assertNamedNodeText, h as assertNamedNodeState, i as installPackage, l as querySceneGraph, m as assertNamedNode, n as checkDevice, o as pressKey, p as waitForSceneGraphNode, r as getDeviceInfo, s as queryActiveApp, t as assertSceneGraphNode, u as takeScreenshot, v as parseSceneGraphNumberList, w as readActiveApp, x as readNamedNodeBounds, y as readNamedNodeAttribute } from "./roku-7hiM97p0.mjs";
2
+ export { assertNamedNode, assertNamedNodeState, assertNamedNodeText, assertSceneGraphNode, checkDevice, getDeviceInfo, installPackage, isNamedNodeVisible, launchApp, parseSceneGraphNumberList, pressKey, queryActiveApp, queryEcp, querySceneGraph, readActiveApp, readNamedNodeAttribute, readNamedNodeAttributes, readNamedNodeBounds, readNamedNodeNumber, readNamedNodeTranslation, readXmlAttribute, readXmlTag, takeScreenshot, validateRemoteKey, waitForActiveApp, waitForSceneGraphNode };
package/dist/rokit.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as launchApp, c as queryEcp, f as waitForActiveApp, i as installPackage, l as querySceneGraph, n as checkDevice, o as pressKey, p as waitForSceneGraphNode, r as getDeviceInfo, s as queryActiveApp, t as assertSceneGraphNode, u as takeScreenshot } from "./roku-DxlYPbY1.mjs";
2
+ import { a as launchApp, c as queryEcp, f as waitForActiveApp, i as installPackage, l as querySceneGraph, n as checkDevice, o as pressKey, p as waitForSceneGraphNode, r as getDeviceInfo, s as queryActiveApp, t as assertSceneGraphNode, u as takeScreenshot } from "./roku-7hiM97p0.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { dirname, join } from "node:path";
5
5
  import { existsSync, mkdirSync } from "node:fs";
@@ -28,6 +28,36 @@ const readNamedNodeAttribute = (xml, nodeName, attributeName) => {
28
28
  if (!attributes) return;
29
29
  return readXmlAttribute(attributes, attributeName);
30
30
  };
31
+ const readNamedNodeNumber = (xml, nodeName, attributeName) => {
32
+ const value = readNamedNodeAttribute(xml, nodeName, attributeName);
33
+ if (value !== void 0) {
34
+ const parsed = Number(value);
35
+ return Number.isFinite(parsed) ? parsed : void 0;
36
+ }
37
+ if (attributeName !== "width" && attributeName !== "height") return;
38
+ const bounds = readNamedNodeBounds(xml, nodeName);
39
+ if (!bounds) return;
40
+ return attributeName === "width" ? bounds[2] : bounds[3];
41
+ };
42
+ const readNamedNodeBounds = (xml, nodeName) => {
43
+ const bounds = readNamedNodeAttribute(xml, nodeName, "bounds");
44
+ if (!bounds) return;
45
+ const parts = parseSceneGraphNumberList(bounds);
46
+ if (parts.length < 4) return;
47
+ return [
48
+ parts[0],
49
+ parts[1],
50
+ parts[2],
51
+ parts[3]
52
+ ];
53
+ };
54
+ const readNamedNodeTranslation = (xml, nodeName) => {
55
+ const translation = readNamedNodeAttribute(xml, nodeName, "translation");
56
+ if (!translation) return;
57
+ const parts = parseSceneGraphNumberList(translation);
58
+ if (parts.length < 2) return;
59
+ return [parts[0], parts[1]];
60
+ };
31
61
  const isNamedNodeVisible = (xml, nodeName) => {
32
62
  const attributes = readNamedNodeAttributes(xml, nodeName);
33
63
  return attributes !== void 0 && !attributes.includes("visible=\"false\"");
@@ -59,6 +89,7 @@ const assertNamedNodeAttribute = (xml, nodeName, attributeName, expectedValue) =
59
89
  if (value !== expectedValue) throw new Error(`expected "${nodeName}" ${attributeName} "${expectedValue}", got "${value ?? "missing"}"`);
60
90
  };
61
91
  const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
92
+ const parseSceneGraphNumberList = (value) => value.replace(/[[\]{}]/g, "").split(",").map((part) => Number(part.trim())).filter((part) => Number.isFinite(part));
62
93
  //#endregion
63
94
  //#region src/roku.ts
64
95
  const ecpPort = 8060;
@@ -227,4 +258,4 @@ const sleep = (ms) => new Promise((resolve) => {
227
258
  });
228
259
  const formatErrorMessage = (error) => error instanceof Error ? error.message : String(error);
229
260
  //#endregion
230
- export { readXmlTag as S, isNamedNodeVisible as _, launchApp as a, readActiveApp as b, queryEcp as c, validateRemoteKey as d, waitForActiveApp as f, assertNamedNodeText as g, assertNamedNodeState as h, installPackage as i, querySceneGraph as l, assertNamedNode as m, checkDevice as n, pressKey as o, waitForSceneGraphNode as p, getDeviceInfo as r, queryActiveApp as s, assertSceneGraphNode as t, takeScreenshot as u, readNamedNodeAttribute as v, readXmlAttribute as x, readNamedNodeAttributes as y };
261
+ export { readNamedNodeTranslation as C, readXmlTag as E, readNamedNodeNumber as S, readXmlAttribute as T, isNamedNodeVisible as _, launchApp as a, readNamedNodeAttributes as b, queryEcp as c, validateRemoteKey as d, waitForActiveApp as f, assertNamedNodeText as g, assertNamedNodeState as h, installPackage as i, querySceneGraph as l, assertNamedNode as m, checkDevice as n, pressKey as o, waitForSceneGraphNode as p, getDeviceInfo as r, queryActiveApp as s, assertSceneGraphNode as t, takeScreenshot as u, parseSceneGraphNumberList as v, readActiveApp as w, readNamedNodeBounds as x, readNamedNodeAttribute as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putdotio/rokit",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "A tiny CLI companion for Roku device harness work.",
5
5
  "keywords": [
6
6
  "cli",