diff --git a/.build/bump_version.js b/.build/bump_version.js
new file mode 100644
index 00000000..b5b42e53
--- /dev/null
+++ b/.build/bump_version.js
@@ -0,0 +1,43 @@
+const { exec } = require("child_process");
+const { readFile, writeFile } = require("fs");
+const { join } = require("path");
+
+const args = process.argv.slice(2);
+const version = args[0];
+
+if (version == null || version === "") {
+ throw new Error("Version is required");
+}
+
+exec("pnpm m ls --json --depth=-1", (_, stdout) => {
+ const modules = JSON.parse(stdout).filter(
+ (module) => module.private !== true,
+ );
+
+ for (const module of modules) {
+ const filePath = join(module.path, "package.json");
+
+ readFile(filePath, "utf8", (err, data) => {
+ if (err) {
+ throw new Error(err);
+ }
+ // Parse JSON
+ const obj = JSON.parse(data);
+
+ // Change a property
+ obj.version = version;
+
+ // Convert object back to JSON
+ const json = JSON.stringify(obj, null, 2);
+
+ // Write JSON file
+ writeFile(filePath, json, "utf8", (err) => {
+ if (err) {
+ throw new Error(err);
+ } else {
+ console.log("File successfully updated.");
+ }
+ });
+ });
+ }
+});
diff --git a/.build/pre-release.sh b/.build/pre-release.sh
old mode 100644
new mode 100755
index 1f515ee3..780cd47c
--- a/.build/pre-release.sh
+++ b/.build/pre-release.sh
@@ -5,4 +5,4 @@ patchVersion=$(npm --no-git-tag version patch)
nextVersion=${patchVersion}-next."$(date +%Y%m%d%H%M%S)"
echo "${nextVersion:1}"
-npm version --no-git-tag -f "${nextVersion:1}"
\ No newline at end of file
+node ./bump_version.js "${nextVersion:1}"
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index dfe2c7b4..e9e0a19e 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -13,6 +13,8 @@ jobs:
sonar:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, 'skip ci')"
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
steps:
- name: Set up Git repository
uses: actions/checkout@v3
@@ -20,30 +22,28 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 18
+ registry-url: https://registry.npmjs.org/
+ token: ${{ secrets.NPM_TOKEN }}
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v3.0.0
- name: Install
- run: npm ci
+ run: |
+ pnpm whoami
+ pnpm i
- name: Compile
- run: npm run compile
- - name: Init window e2e test subpackage
- run: npm --prefix e2e/window-test ci
+ run: pnpm -r run compile
- name: Clean coverage report
- run: npm run coverage:clean
+ run: pnpm run coverage:clean
- name: Generate coverage report
uses: GabrielBB/xvfb-action@v1
env:
NODE_OPTIONS: "--max-old-space-size=8192"
with:
- run: npm run coverage -- --coverageDirectory=coverage/unit
- - name: Run Electron e2e test subpackage
- uses: GabrielBB/xvfb-action@v1
- with:
- run: npm --prefix e2e/electron-test cit
- - name: Merge coverage reports
- run: |
- npm run coverage:merge
- npm run coverage:merge-report
+ run: pnpm run coverage
- name: Send results to SonarCloud
- uses: SonarSource/sonarcloud-github-action@v2.0.2
+ uses: SonarSource/sonarcloud-github-action@v2.1.1
+ with:
+ projectBaseDir: core/nut.js
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
@@ -51,10 +51,12 @@ jobs:
test:
needs:
- sonar
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
strategy:
matrix:
- os: [windows-latest, macos-latest]
- node: [18]
+ os: [ windows-latest, macos-latest ]
+ node: [ 18 ]
runs-on: ${{matrix.os}}
steps:
- name: Set up Git repository
@@ -63,19 +65,16 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: ${{matrix.node}}
+ registry-url: https://registry.npmjs.org/
+ token: ${{ secrets.NPM_TOKEN }}
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v3.0.0
- name: Install
- run: npm ci
+ run: pnpm i
- name: Compile
- run: npm run compile
- - name: Init window e2e test subpackage
- run: npm --prefix e2e/window-test ci
+ run: pnpm run compile
- name: Generate coverage report
uses: GabrielBB/xvfb-action@v1
with:
run: |
- npx playwright install --with-deps
- npm test
- - name: Run Electron e2e test subpackage
- uses: GabrielBB/xvfb-action@v1
- with:
- run: npm --prefix e2e/electron-test cit
+ pnpm run coverage
diff --git a/.github/workflows/snapshot_release.yaml b/.github/workflows/snapshot_release.yaml
index 8d5588f5..867775b8 100644
--- a/.github/workflows/snapshot_release.yaml
+++ b/.github/workflows/snapshot_release.yaml
@@ -24,24 +24,21 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: ${{matrix.node}}
+ registry-url: https://registry.npmjs.org/
+ token: ${{ secrets.NPM_TOKEN }}
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v3.0.0
- name: Install
- run: npm ci
+ run: pnpm i
- name: Install @nut-tree/libnut@next
- run: npm i @nut-tree/libnut@next
+ run: |
+ pnpm --filter @nut-tree/libnut i @nut-tree/libnut-darwin@next @nut-tree/libnut-linux@next @nut-tree/libnut-win32@next
- name: Compile
- run: npm run compile
- - name: Init window e2e test subpackage
- run: npm --prefix e2e/window-test ci
+ run: pnpm run compile
- name: Run tests
uses: GabrielBB/xvfb-action@v1
with:
- run: |
- npx playwright install --with-deps
- npm test
- - name: Run Electron e2e test subpackage
- uses: GabrielBB/xvfb-action@v1
- with:
- run: npm --prefix e2e/electron-test cit
+ run: pnpm run coverage
deploy:
needs:
@@ -54,15 +51,19 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 18
- registry-url: "https://registry.npmjs.org"
+ registry-url: https://registry.npmjs.org/
+ token: ${{ secrets.NPM_TOKEN }}
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v3.0.0
- name: Install
- run: npm ci
+ run: pnpm i
- name: Install @nut-tree/libnut@next
- run: npm i @nut-tree/libnut@next
+ run: |
+ pnpm --filter @nut-tree/libnut i @nut-tree/libnut-darwin@next @nut-tree/libnut-linux@next @nut-tree/libnut-win32@next
- name: Create snapshot release
run: bash ./.build/pre-release.sh
- name: Publish snapshot release to npm
- run: npm run publish-next
+ run: pnpm run publish:next
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- uses: actions/setup-node@v3
diff --git a/.github/workflows/tagged_release.yaml b/.github/workflows/tagged_release.yaml
index 53c92732..99e71333 100644
--- a/.github/workflows/tagged_release.yaml
+++ b/.github/workflows/tagged_release.yaml
@@ -18,6 +18,10 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: ${{matrix.node}}
+ registry-url: https://registry.npmjs.org/
+ token: ${{ secrets.NPM_TOKEN }}
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v3.0.0
- name: Install
run: npm ci
- name: Compile
@@ -46,7 +50,10 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 18
- registry-url: "https://registry.npmjs.org"
+ registry-url: https://registry.npmjs.org/
+ token: ${{ secrets.NPM_TOKEN }}
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v3.0.0
- name: Install
run: npm ci
- name: Run typedoc
diff --git a/.husky/pre-commit b/.husky/pre-commit
deleted file mode 100755
index d24fdfc6..00000000
--- a/.husky/pre-commit
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env sh
-. "$(dirname -- "$0")/_/husky.sh"
-
-npx lint-staged
diff --git a/.nvmrc b/.nvmrc
deleted file mode 100644
index 50e4b92a..00000000
--- a/.nvmrc
+++ /dev/null
@@ -1 +0,0 @@
-v16.18.0
diff --git a/README.md b/README.md
index d7401d34..9e4723f6 100644
--- a/README.md
+++ b/README.md
@@ -50,10 +50,6 @@ Check out this demo video to get a first impression of what nut.js is capable of
Please consult the project website at [nutjs.dev](https://nutjs.dev/docs/tutorial-first_steps/prerequisites) for in-depth tutorials
-# Examples
-
-[nut-tree/trailmix](https://github.com/nut-tree/trailmix) contains a set of ready to use examples which demo the usage of nut.js.
-
# API Docs
nut.js provides [public API documentation](https://nut-tree.github.io/apidoc/) auto-generated by [TypeDoc](https://typedoc.org).
diff --git a/core/configs/package.json b/core/configs/package.json
new file mode 100644
index 00000000..2a877f91
--- /dev/null
+++ b/core/configs/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "@nut-tree/configs",
+ "private": true,
+ "version": "4.0.0",
+ "description": "Shared configs for nut.js",
+ "author": {
+ "name": "dry Software UG (haftungsbeschränkt)",
+ "email": "info@dry.software",
+ "url": "https://dry.software"
+ }
+}
diff --git a/tsconfig.json b/core/configs/tsconfig/base.json
similarity index 65%
rename from tsconfig.json
rename to core/configs/tsconfig/base.json
index 7cfd6840..d36da828 100644
--- a/tsconfig.json
+++ b/core/configs/tsconfig/base.json
@@ -2,19 +2,17 @@
"compilerOptions": {
"target": "ES2018",
"module": "commonjs",
- "lib": ["es6"],
- "outDir": "./dist",
+ "lib": [
+ "es6"
+ ],
"declaration": true,
- "declarationMap": true,
+ "declarationMap": false,
"sourceMap": true,
"strict": true,
"noImplicitAny": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
-
"esModuleInterop": true
- },
- "include": ["lib/**/*.ts", "index.ts"],
- "exclude": ["node_modules"]
+ }
}
diff --git a/core/nut.js/.gfx/nut.png b/core/nut.js/.gfx/nut.png
new file mode 100644
index 00000000..0cad75a5
Binary files /dev/null and b/core/nut.js/.gfx/nut.png differ
diff --git a/core/nut.js/.gfx/permissions.png b/core/nut.js/.gfx/permissions.png
new file mode 100644
index 00000000..d1dbdb0a
Binary files /dev/null and b/core/nut.js/.gfx/permissions.png differ
diff --git a/core/nut.js/.gfx/permissions_popup.png b/core/nut.js/.gfx/permissions_popup.png
new file mode 100644
index 00000000..3d9be887
Binary files /dev/null and b/core/nut.js/.gfx/permissions_popup.png differ
diff --git a/core/nut.js/.gfx/sponsors/mighty.svg b/core/nut.js/.gfx/sponsors/mighty.svg
new file mode 100644
index 00000000..24d470fd
--- /dev/null
+++ b/core/nut.js/.gfx/sponsors/mighty.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/core/nut.js/.gitignore b/core/nut.js/.gitignore
new file mode 100644
index 00000000..733cc87c
--- /dev/null
+++ b/core/nut.js/.gitignore
@@ -0,0 +1,144 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+
+# next.js build output
+.next
+
+# nuxt.js build output
+.nuxt
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless
+
+.vscode
+/dist/
+/lib/**/*.js
+/lib/**/*.js.map
+### macOS template
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+.idea/
+
+# CMake
+cmake-build-debug/
+cmake-build-release/
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Test data
+/lib/provider/opencv/__mocks__/output.jpg
+/asdf.jpg
+/foo_asdf_bar.jpg
+/asdf.png
+/asdf_bar.jpg
+/foo_asdf.jpg
+/.scratch/
+docs
+scratch.js
+debug.js
diff --git a/.npmignore b/core/nut.js/.npmignore
similarity index 100%
rename from .npmignore
rename to core/nut.js/.npmignore
diff --git a/.prettierignore b/core/nut.js/.prettierignore
similarity index 100%
rename from .prettierignore
rename to core/nut.js/.prettierignore
diff --git a/.prettierrc.json b/core/nut.js/.prettierrc.json
similarity index 100%
rename from .prettierrc.json
rename to core/nut.js/.prettierrc.json
diff --git a/CHANGELOG.md b/core/nut.js/CHANGELOG.md
similarity index 100%
rename from CHANGELOG.md
rename to core/nut.js/CHANGELOG.md
diff --git a/CODE_OF_CONDUCT.md b/core/nut.js/CODE_OF_CONDUCT.md
similarity index 100%
rename from CODE_OF_CONDUCT.md
rename to core/nut.js/CODE_OF_CONDUCT.md
diff --git a/LICENSE b/core/nut.js/LICENSE
similarity index 100%
rename from LICENSE
rename to core/nut.js/LICENSE
diff --git a/core/nut.js/README.md b/core/nut.js/README.md
new file mode 100644
index 00000000..b63a55e5
--- /dev/null
+++ b/core/nut.js/README.md
@@ -0,0 +1,3 @@
+# nut.js (Native UI Toolkit)
+
+This is the core package for nut.js, the one package that keeps all the other packages together. It provides the basic functionality to interact with the screen, the keyboard, and the mouse.
\ No newline at end of file
diff --git a/e2e/assets/calculator.png b/core/nut.js/assets/calculator.png
similarity index 100%
rename from e2e/assets/calculator.png
rename to core/nut.js/assets/calculator.png
diff --git a/e2e/assets/checkers.png b/core/nut.js/assets/checkers.png
similarity index 100%
rename from e2e/assets/checkers.png
rename to core/nut.js/assets/checkers.png
diff --git a/e2e/assets/close.png b/core/nut.js/assets/close.png
similarity index 100%
rename from e2e/assets/close.png
rename to core/nut.js/assets/close.png
diff --git a/e2e/assets/desktop.png b/core/nut.js/assets/desktop.png
similarity index 100%
rename from e2e/assets/desktop.png
rename to core/nut.js/assets/desktop.png
diff --git a/e2e/assets/dot.png b/core/nut.js/assets/dot.png
similarity index 100%
rename from e2e/assets/dot.png
rename to core/nut.js/assets/dot.png
diff --git a/e2e/assets/dots.png b/core/nut.js/assets/dots.png
similarity index 100%
rename from e2e/assets/dots.png
rename to core/nut.js/assets/dots.png
diff --git a/e2e/assets/equals.png b/core/nut.js/assets/equals.png
similarity index 100%
rename from e2e/assets/equals.png
rename to core/nut.js/assets/equals.png
diff --git a/e2e/assets/menu.png b/core/nut.js/assets/menu.png
similarity index 100%
rename from e2e/assets/menu.png
rename to core/nut.js/assets/menu.png
diff --git a/e2e/assets/mouse.png b/core/nut.js/assets/mouse.png
similarity index 100%
rename from e2e/assets/mouse.png
rename to core/nut.js/assets/mouse.png
diff --git a/e2e/assets/moved_trash.png b/core/nut.js/assets/moved_trash.png
similarity index 100%
rename from e2e/assets/moved_trash.png
rename to core/nut.js/assets/moved_trash.png
diff --git a/e2e/assets/one.png b/core/nut.js/assets/one.png
similarity index 100%
rename from e2e/assets/one.png
rename to core/nut.js/assets/one.png
diff --git a/e2e/assets/plus.png b/core/nut.js/assets/plus.png
similarity index 100%
rename from e2e/assets/plus.png
rename to core/nut.js/assets/plus.png
diff --git a/e2e/assets/result.png b/core/nut.js/assets/result.png
similarity index 100%
rename from e2e/assets/result.png
rename to core/nut.js/assets/result.png
diff --git a/e2e/assets/terminal.png b/core/nut.js/assets/terminal.png
similarity index 100%
rename from e2e/assets/terminal.png
rename to core/nut.js/assets/terminal.png
diff --git a/e2e/assets/trash.png b/core/nut.js/assets/trash.png
similarity index 100%
rename from e2e/assets/trash.png
rename to core/nut.js/assets/trash.png
diff --git a/e2e/assets/xfce-menu.png b/core/nut.js/assets/xfce-menu.png
similarity index 100%
rename from e2e/assets/xfce-menu.png
rename to core/nut.js/assets/xfce-menu.png
diff --git a/e2e/assets/zero.png b/core/nut.js/assets/zero.png
similarity index 100%
rename from e2e/assets/zero.png
rename to core/nut.js/assets/zero.png
diff --git a/index.ts b/core/nut.js/index.ts
similarity index 74%
rename from index.ts
rename to core/nut.js/index.ts
index e74a354b..91db9160 100644
--- a/index.ts
+++ b/core/nut.js/index.ts
@@ -8,13 +8,7 @@ import { LineHelper } from "./lib/util/linehelper.class";
import { createWindowApi } from "./lib/window.function";
import providerRegistry from "./lib/provider/provider-registry.class";
import { loadImageResource } from "./lib/imageResources.function";
-import {
- ColorQuery,
- LineQuery,
- WindowQuery,
- WordQuery,
-} from "./lib/query.class";
-import { RGBA } from "./lib/rgba.class";
+import { ColorQuery, LineQuery, RGBA, WindowQuery, WordQuery } from "@nut-tree/shared";
export {
AssertClass,
@@ -25,34 +19,24 @@ export {
MouseConfig,
ScreenClass,
ScreenConfig,
- providerRegistry,
+ providerRegistry
};
-export { MatchRequest } from "./lib/match-request.class";
-export { MatchResult } from "./lib/match-result.class";
-export * from "./lib/provider";
+export { MatchRequest } from "@nut-tree/shared";
+export { MatchResult } from "@nut-tree/shared";
+export * from "@nut-tree/provider-interfaces";
+export * from "@nut-tree/shared";
export { jestMatchers } from "./lib/expect/jest.matcher.function";
export { sleep } from "./lib/sleep.function";
-export { Image } from "./lib/image.class";
-export { RGBA } from "./lib/rgba.class";
-export { Key } from "./lib/key.enum";
-export { Button } from "./lib/button.enum";
export { centerOf, randomPointIn } from "./lib/location.function";
-export { OptionalSearchParameters } from "./lib/optionalsearchparameters.class";
export { EasingFunction, linear } from "./lib/mouse-movement.function";
-export { Point } from "./lib/point.class";
-export { Size } from "./lib/size.class";
-export { Region } from "./lib/region.class";
export { Window } from "./lib/window.class";
-export { FileType } from "./lib/file-type.enum";
-export { ColorMode } from "./lib/colormode.enum";
export {
useLogger,
useConsoleLogger,
- ConsoleLogLevel,
+ ConsoleLogLevel
} from "./lib/logging.function";
-export * from "./lib/query.class";
const lineHelper = new LineHelper();
@@ -64,7 +48,7 @@ const assert = new AssertClass(screen);
const { straightTo, up, down, left, right } = createMovementApi(
providerRegistry,
- lineHelper,
+ lineHelper
);
const { getWindows, getActiveWindow } = createWindowApi(providerRegistry);
@@ -75,7 +59,7 @@ const imageResource = (fileName: string) =>
loadImageResource(
providerRegistry,
screen.config.resourceDirectory,
- fileName,
+ fileName
);
const singleWord = (word: string): WordQuery => {
@@ -83,8 +67,8 @@ const singleWord = (word: string): WordQuery => {
type: "text",
id: `word-query-${word}`,
by: {
- word,
- },
+ word
+ }
};
};
const textLine = (line: string): LineQuery => {
@@ -92,8 +76,8 @@ const textLine = (line: string): LineQuery => {
type: "text",
id: `line-query-${line}`,
by: {
- line,
- },
+ line
+ }
};
};
@@ -102,8 +86,8 @@ const windowWithTitle = (title: string | RegExp): WindowQuery => {
type: "window",
id: `window-by-title-query-${title}`,
by: {
- title,
- },
+ title
+ }
};
};
@@ -112,8 +96,8 @@ const pixelWithColor = (color: RGBA): ColorQuery => {
type: "color",
id: `pixel-by-color-query-RGBA(${color.R},${color.G},${color.B},${color.A})`,
by: {
- color,
- },
+ color
+ }
};
};
@@ -138,5 +122,5 @@ export {
singleWord,
textLine,
windowWithTitle,
- pixelWithColor,
+ pixelWithColor
};
diff --git a/jest.config.js b/core/nut.js/jest.config.js
similarity index 100%
rename from jest.config.js
rename to core/nut.js/jest.config.js
diff --git a/lib/assert.class.spec.ts b/core/nut.js/lib/assert.class.spec.ts
similarity index 94%
rename from lib/assert.class.spec.ts
rename to core/nut.js/lib/assert.class.spec.ts
index 66f59e44..4eefebf1 100644
--- a/lib/assert.class.spec.ts
+++ b/core/nut.js/lib/assert.class.spec.ts
@@ -1,11 +1,10 @@
import { AssertClass } from "./assert.class";
-import { Region } from "./region.class";
+import { Region } from "@nut-tree/shared";
import { ScreenClass } from "./screen.class";
import providerRegistry from "./provider/provider-registry.class";
import { Image } from "../index";
import { mockPartial } from "sneer";
-jest.mock("jimp", () => {});
jest.mock("./screen.class");
const needleId = "needleId";
@@ -19,7 +18,7 @@ describe("Assert", () => {
const screenMock = new ScreenClass(providerRegistry);
const SUT = new AssertClass(screenMock);
const needle = mockPartial({
- id: needleId,
+ id: needleId
});
// WHEN
@@ -34,7 +33,7 @@ describe("Assert", () => {
const screenMock = new ScreenClass(providerRegistry);
const SUT = new AssertClass(screenMock);
const needle = mockPartial({
- id: needleId,
+ id: needleId
});
// WHEN
@@ -52,7 +51,7 @@ describe("Assert", () => {
const SUT = new AssertClass(screenMock);
const searchRegion = new Region(10, 10, 10, 10);
const needle = mockPartial({
- id: needleId,
+ id: needleId
});
// WHEN
@@ -71,7 +70,7 @@ describe("Assert", () => {
const screenMock = new ScreenClass(providerRegistry);
const SUT = new AssertClass(screenMock);
const needle = mockPartial({
- id: needleId,
+ id: needleId
});
// WHEN
@@ -88,7 +87,7 @@ describe("Assert", () => {
const screenMock = new ScreenClass(providerRegistry);
const SUT = new AssertClass(screenMock);
const needle = mockPartial({
- id: needleId,
+ id: needleId
});
// WHEN
diff --git a/lib/assert.class.ts b/core/nut.js/lib/assert.class.ts
similarity index 81%
rename from lib/assert.class.ts
rename to core/nut.js/lib/assert.class.ts
index 12fdf242..4db61fe1 100644
--- a/lib/assert.class.ts
+++ b/core/nut.js/lib/assert.class.ts
@@ -1,9 +1,9 @@
-import { Region } from "./region.class";
-import { FindInput, ScreenClass } from "./screen.class";
-import { OptionalSearchParameters } from "./optionalsearchparameters.class";
+import { FindInput, OptionalSearchParameters, Region } from "@nut-tree/shared";
+import { ScreenClass } from "./screen.class";
export class AssertClass {
- constructor(private screen: ScreenClass) {}
+ constructor(private screen: ScreenClass) {
+ }
public async isVisible(
searchInput: FindInput | Promise,
@@ -16,7 +16,7 @@ export class AssertClass {
try {
await this.screen.find(needle, {
searchRegion,
- confidence,
+ confidence
} as OptionalSearchParameters);
} catch (err) {
if (searchRegion !== undefined) {
@@ -40,7 +40,7 @@ export class AssertClass {
try {
await this.screen.find(needle, {
searchRegion,
- confidence,
+ confidence
} as OptionalSearchParameters);
} catch (err) {
return;
diff --git a/lib/clipboard.class.spec.ts b/core/nut.js/lib/clipboard.class.spec.ts
similarity index 86%
rename from lib/clipboard.class.spec.ts
rename to core/nut.js/lib/clipboard.class.spec.ts
index 2128ab3c..f768086a 100644
--- a/lib/clipboard.class.spec.ts
+++ b/core/nut.js/lib/clipboard.class.spec.ts
@@ -1,10 +1,7 @@
import { ClipboardClass } from "./clipboard.class";
-import { ProviderRegistry } from "./provider/provider-registry.class";
import { mockPartial } from "sneer";
-import { ClipboardProviderInterface } from "./provider";
import { NoopLogProvider } from "./provider/log/noop-log-provider.class";
-
-jest.mock("jimp", () => {});
+import { ClipboardProviderInterface, ProviderRegistry } from "@nut-tree/provider-interfaces";
beforeEach(() => {
jest.clearAllMocks();
@@ -19,7 +16,7 @@ describe("Clipboard class", () => {
const copyMock = jest.fn();
providerRegistryMock.getClipboard = jest.fn(() =>
mockPartial({
- copy: copyMock,
+ copy: copyMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -39,7 +36,7 @@ describe("Clipboard class", () => {
const pasteMock = jest.fn();
providerRegistryMock.getClipboard = jest.fn(() =>
mockPartial({
- paste: pasteMock,
+ paste: pasteMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
diff --git a/lib/clipboard.class.ts b/core/nut.js/lib/clipboard.class.ts
similarity index 86%
rename from lib/clipboard.class.ts
rename to core/nut.js/lib/clipboard.class.ts
index 394902a9..63ec8fc2 100644
--- a/lib/clipboard.class.ts
+++ b/core/nut.js/lib/clipboard.class.ts
@@ -1,14 +1,15 @@
/**
* {@link ClipboardClass} class gives access to a systems clipboard
*/
-import { ProviderRegistry } from "./provider/provider-registry.class";
+import { ProviderRegistry } from "@nut-tree/provider-interfaces";
export class ClipboardClass {
/**
* {@link ClipboardClass} class constructor
* @param providerRegistry
*/
- constructor(private providerRegistry: ProviderRegistry) {}
+ constructor(private providerRegistry: ProviderRegistry) {
+ }
/**
* {@link setContent} copies a given text to the system clipboard
diff --git a/core/nut.js/lib/constants.ts b/core/nut.js/lib/constants.ts
new file mode 100644
index 00000000..dc768c66
--- /dev/null
+++ b/core/nut.js/lib/constants.ts
@@ -0,0 +1,24 @@
+export const DISABLE_DEFAULT_PROVIDERS_ENV_VAR =
+ "NUT_JS_DISABLE_DEFAULT_PROVIDERS";
+export const DISABLE_DEFAULT_CLIPBOARD_PROVIDER_ENV_VAR =
+ "NUT_JS_DISABLE_DEFAULT_CLIPBOARD_PROVIDER";
+export const DISABLE_DEFAULT_KEYBOARD_PROVIDER_ENV_VAR =
+ "NUT_JS_DISABLE_DEFAULT_KEYBOARD_PROVIDER";
+export const DISABLE_DEFAULT_MOUSE_PROVIDER_ENV_VAR =
+ "NUT_JS_DISABLE_DEFAULT_MOUSE_PROVIDER";
+export const DISABLE_DEFAULT_SCREEN_PROVIDER_ENV_VAR =
+ "NUT_JS_DISABLE_DEFAULT_SCREEN_PROVIDER";
+export const DISABLE_DEFAULT_WINDOW_PROVIDER_ENV_VAR =
+ "NUT_JS_DISABLE_DEFAULT_WINDOW_PROVIDER";
+export const NPM_CONFIG_DISABLE_DEFAULT_PROVIDERS_ENV_VAR =
+ "npm_package_config_nut.js_disableDefaultProviders";
+export const NPM_CONFIG_DISABLE_DEFAULT_CLIPBOARD_PROVIDER_ENV_VAR =
+ "npm_package_config_nut.js_disableClipboardProvider";
+export const NPM_CONFIG_DISABLE_DEFAULT_KEYBOARD_PROVIDER_ENV_VAR =
+ "npm_package_config_nut.js_disableKeyboardProvider";
+export const NPM_CONFIG_DISABLE_DEFAULT_MOUSE_PROVIDER_ENV_VAR =
+ "npm_package_config_nut.js_disableMouseProvider";
+export const NPM_CONFIG_DISABLE_DEFAULT_SCREEN_PROVIDER_ENV_VAR =
+ "npm_package_config_nut.js_disableScreenProvider";
+export const NPM_CONFIG_DISABLE_DEFAULT_WINDOW_PROVIDER_ENV_VAR =
+ "npm_package_config_nut.js_disableWindowProvider";
diff --git a/lib/expect/jest.matcher.function.ts b/core/nut.js/lib/expect/jest.matcher.function.ts
similarity index 67%
rename from lib/expect/jest.matcher.function.ts
rename to core/nut.js/lib/expect/jest.matcher.function.ts
index 393ab63f..32e846f8 100644
--- a/lib/expect/jest.matcher.function.ts
+++ b/core/nut.js/lib/expect/jest.matcher.function.ts
@@ -1,12 +1,8 @@
-import { Point } from "../point.class";
-import { Region } from "../region.class";
+import { FindInput, OptionalSearchParameters, Point, Region, RGBA } from "@nut-tree/shared";
import { toBeAt } from "./matchers/toBeAt.function";
import { toBeIn } from "./matchers/toBeIn.function";
import { toShow } from "./matchers/toShow.function";
-import { FindInput } from "../screen.class";
-import { RGBA } from "../rgba.class";
import { toHaveColor } from "./matchers/toHaveColor.function";
-import { OptionalSearchParameters } from "../optionalsearchparameters.class";
declare global {
namespace jest {
@@ -16,7 +12,7 @@ declare global {
// @ts-ignore
toShow: (
needle: FindInput,
- parameters?: OptionalSearchParameters,
+ parameters?: OptionalSearchParameters
) => ReturnType;
toHaveColor: (color: RGBA) => ReturnType;
}
@@ -27,5 +23,5 @@ export const jestMatchers = {
toBeAt,
toBeIn,
toShow,
- toHaveColor,
+ toHaveColor
};
diff --git a/lib/expect/matchers/toBeAt.function.spec.ts b/core/nut.js/lib/expect/matchers/toBeAt.function.spec.ts
similarity index 93%
rename from lib/expect/matchers/toBeAt.function.spec.ts
rename to core/nut.js/lib/expect/matchers/toBeAt.function.spec.ts
index 7bcec6f4..7763a86c 100644
--- a/lib/expect/matchers/toBeAt.function.spec.ts
+++ b/core/nut.js/lib/expect/matchers/toBeAt.function.spec.ts
@@ -1,5 +1,5 @@
import { mouse } from "../../../index";
-import { Point } from "../../point.class";
+import { Point } from "@nut-tree/shared";
import { toBeAt } from "./toBeAt.function";
const targetPoint = new Point(100, 100);
diff --git a/lib/expect/matchers/toBeAt.function.ts b/core/nut.js/lib/expect/matchers/toBeAt.function.ts
similarity index 87%
rename from lib/expect/matchers/toBeAt.function.ts
rename to core/nut.js/lib/expect/matchers/toBeAt.function.ts
index e0bd7cd4..840f8b0d 100644
--- a/lib/expect/matchers/toBeAt.function.ts
+++ b/core/nut.js/lib/expect/matchers/toBeAt.function.ts
@@ -1,5 +1,5 @@
import { MouseClass } from "../../mouse.class";
-import { Point } from "../../point.class";
+import { Point } from "@nut-tree/shared";
export const toBeAt = async (received: MouseClass, position: Point) => {
const currentPosition = await received.getPosition();
@@ -11,12 +11,12 @@ export const toBeAt = async (received: MouseClass, position: Point) => {
return {
message: () =>
`Expected cursor to not be at position ${position.toString()}`,
- pass: true,
+ pass: true
};
}
return {
message: () =>
`Cursor should be at position ${position.toString()} but is at ${currentPosition.toString()}`,
- pass: false,
+ pass: false
};
};
diff --git a/lib/expect/matchers/toBeIn.function.spec.ts b/core/nut.js/lib/expect/matchers/toBeIn.function.spec.ts
similarity index 89%
rename from lib/expect/matchers/toBeIn.function.spec.ts
rename to core/nut.js/lib/expect/matchers/toBeIn.function.spec.ts
index ff26421c..1037f606 100644
--- a/lib/expect/matchers/toBeIn.function.spec.ts
+++ b/core/nut.js/lib/expect/matchers/toBeIn.function.spec.ts
@@ -1,6 +1,5 @@
import { mouse } from "../../../index";
-import { Point } from "../../point.class";
-import { Region } from "../../region.class";
+import { Point, Region } from "@nut-tree/shared";
import { toBeIn } from "./toBeIn.function";
const targetPoint = new Point(400, 400);
diff --git a/lib/expect/matchers/toBeIn.function.ts b/core/nut.js/lib/expect/matchers/toBeIn.function.ts
similarity index 89%
rename from lib/expect/matchers/toBeIn.function.ts
rename to core/nut.js/lib/expect/matchers/toBeIn.function.ts
index 372ec64e..bdb30c37 100644
--- a/lib/expect/matchers/toBeIn.function.ts
+++ b/core/nut.js/lib/expect/matchers/toBeIn.function.ts
@@ -1,5 +1,5 @@
import { MouseClass } from "../../mouse.class";
-import { Region } from "../../region.class";
+import { Region } from "@nut-tree/shared";
export const toBeIn = async (received: MouseClass, region: Region) => {
const currentPosition = await received.getPosition();
@@ -17,12 +17,12 @@ export const toBeIn = async (received: MouseClass, region: Region) => {
return {
message: () =>
`Expected cursor to be outside of region ${region.toString()}`,
- pass: true,
+ pass: true
};
}
return {
message: () =>
`Cursor should be within region ${region.toString()} but is at ${currentPosition.toString()}`,
- pass: false,
+ pass: false
};
};
diff --git a/lib/expect/matchers/toHaveColor.function.spec.ts b/core/nut.js/lib/expect/matchers/toHaveColor.function.spec.ts
similarity index 92%
rename from lib/expect/matchers/toHaveColor.function.spec.ts
rename to core/nut.js/lib/expect/matchers/toHaveColor.function.spec.ts
index 81797b9b..0ddfa9eb 100644
--- a/lib/expect/matchers/toHaveColor.function.spec.ts
+++ b/core/nut.js/lib/expect/matchers/toHaveColor.function.spec.ts
@@ -1,5 +1,5 @@
-import { RGBA, screen } from "../../../index";
-import { Point } from "../../point.class";
+import { screen } from "../../../index";
+import { Point, RGBA } from "@nut-tree/shared";
import { mockPartial } from "sneer";
import { toHaveColor } from "./toHaveColor.function";
@@ -40,7 +40,7 @@ describe(".toHaveColor", () => {
return new RGBA(0, 0, 0, 0);
});
expect.extend({
- toHaveColor,
+ toHaveColor
});
// WHEN
@@ -55,7 +55,7 @@ describe(".toHaveColor", () => {
return new RGBA(255, 0, 5, 0);
});
expect.extend({
- toHaveColor,
+ toHaveColor
});
// WHEN
diff --git a/lib/expect/matchers/toHaveColor.function.ts b/core/nut.js/lib/expect/matchers/toHaveColor.function.ts
similarity index 79%
rename from lib/expect/matchers/toHaveColor.function.ts
rename to core/nut.js/lib/expect/matchers/toHaveColor.function.ts
index 80808cc0..3c56cc32 100644
--- a/lib/expect/matchers/toHaveColor.function.ts
+++ b/core/nut.js/lib/expect/matchers/toHaveColor.function.ts
@@ -1,4 +1,5 @@
-import { Point, RGBA, screen } from "../../../index";
+import { screen } from "../../../index";
+import { Point, RGBA } from "@nut-tree/shared";
export const toHaveColor = async (received: Point, needle: RGBA) => {
const color = await screen.colorAt(received);
@@ -7,13 +8,13 @@ export const toHaveColor = async (received: Point, needle: RGBA) => {
return {
message: () =>
`Expected pixel ${received.toString()} not to to have color ${needle.toHex()}`,
- pass: true,
+ pass: true
};
} else {
return {
message: () =>
`Expected pixel ${received.toString()} to have color ${needle.toHex()} but is ${color.toHex()}`,
- pass: false,
+ pass: false
};
}
};
diff --git a/lib/expect/matchers/toShow.function.ts b/core/nut.js/lib/expect/matchers/toShow.function.ts
similarity index 73%
rename from lib/expect/matchers/toShow.function.ts
rename to core/nut.js/lib/expect/matchers/toShow.function.ts
index 00ae7706..d25cfc1a 100644
--- a/lib/expect/matchers/toShow.function.ts
+++ b/core/nut.js/lib/expect/matchers/toShow.function.ts
@@ -1,12 +1,11 @@
-import { FindInput, ScreenClass } from "../../screen.class";
-import { OptionalSearchParameters } from "../../optionalsearchparameters.class";
-import { isRegion, Region } from "../../region.class";
+import { ScreenClass } from "../../screen.class";
+import { FindInput, isRegion, OptionalSearchParameters, Region } from "@nut-tree/shared";
import { screen } from "../../../index";
export const toShow = async (
received: ScreenClass | Region,
needle: FindInput,
- parameters?: OptionalSearchParameters,
+ parameters?: OptionalSearchParameters
) => {
const identifier = (await needle).id;
if (isRegion(received)) {
@@ -19,12 +18,12 @@ export const toShow = async (
await screen.find(needle, parameters);
return {
message: () => `Expected screen to not show ${identifier}`,
- pass: true,
+ pass: true
};
} catch (err) {
return {
message: () => `Screen is not showing ${identifier}: ${err}`,
- pass: false,
+ pass: false
};
}
} else {
@@ -32,12 +31,12 @@ export const toShow = async (
await received.find(needle, parameters);
return {
message: () => `Expected screen to not show ${identifier}`,
- pass: true,
+ pass: true
};
} catch (err) {
return {
message: () => `Screen is not showing ${identifier}: ${err}`,
- pass: false,
+ pass: false
};
}
}
diff --git a/lib/generate-output-path.function.spec.ts b/core/nut.js/lib/generate-output-path.function.spec.ts
similarity index 95%
rename from lib/generate-output-path.function.spec.ts
rename to core/nut.js/lib/generate-output-path.function.spec.ts
index 0b4a51ef..35097e9c 100644
--- a/lib/generate-output-path.function.spec.ts
+++ b/core/nut.js/lib/generate-output-path.function.spec.ts
@@ -1,6 +1,6 @@
import { join } from "path";
import { cwd } from "process";
-import { FileType } from "./file-type.enum";
+import { FileType } from "@nut-tree/shared";
import { generateOutputPath } from "./generate-output-path.function";
describe("generate-output-path", () => {
@@ -56,7 +56,7 @@ describe("generate-output-path", () => {
// WHEN
const result = generateOutputPath(filename, {
postfix: post,
- prefix: pre,
+ prefix: pre
});
// THEN
@@ -72,7 +72,7 @@ describe("generate-output-path", () => {
// WHEN
const result = generateOutputPath(filename, {
- path: filepath,
+ path: filepath
});
// THEN
@@ -88,7 +88,7 @@ describe("generate-output-path", () => {
// WHEN
const result = generateOutputPath(filename, {
- path: filepath,
+ path: filepath
});
// THEN
@@ -103,7 +103,7 @@ describe("generate-output-path", () => {
// WHEN
const result = generateOutputPath(filename, {
- type: FileType.JPG,
+ type: FileType.JPG
});
// THEN
diff --git a/lib/generate-output-path.function.ts b/core/nut.js/lib/generate-output-path.function.ts
similarity index 94%
rename from lib/generate-output-path.function.ts
rename to core/nut.js/lib/generate-output-path.function.ts
index b39adfbd..a11dbea3 100644
--- a/lib/generate-output-path.function.ts
+++ b/core/nut.js/lib/generate-output-path.function.ts
@@ -1,6 +1,6 @@
import { join, parse } from "path";
import { cwd } from "process";
-import { FileType } from "./file-type.enum";
+import { FileType } from "@nut-tree/shared";
/**
* {@link generateOutputPath} is used to assemble full file path from a filename and various parameters
@@ -14,7 +14,7 @@ export const generateOutputPath = (
path?: string;
prefix?: string;
postfix?: string;
- },
+ }
) => {
const name = parse(filename).name;
const imageType = params?.type ? params.type : FileType.PNG;
diff --git a/lib/imageResources.function.spec.ts b/core/nut.js/lib/imageResources.function.spec.ts
similarity index 87%
rename from lib/imageResources.function.spec.ts
rename to core/nut.js/lib/imageResources.function.spec.ts
index 2c56f54c..b9705e61 100644
--- a/lib/imageResources.function.spec.ts
+++ b/core/nut.js/lib/imageResources.function.spec.ts
@@ -1,17 +1,16 @@
import { fetchFromUrl, loadImageResource } from "./imageResources.function";
import { mockPartial } from "sneer";
-import { ProviderRegistry } from "./provider/provider-registry.class";
-import { ImageReader } from "./provider";
+import { ImageReader, ProviderRegistry } from "@nut-tree/provider-interfaces";
import { join } from "path";
-import { ColorMode } from "./colormode.enum";
+import { ColorMode } from "@nut-tree/shared";
const loadMock = jest.fn();
const providerRegistryMock = mockPartial({
getImageReader(): ImageReader {
return mockPartial({
- load: loadMock,
+ load: loadMock
});
- },
+ }
});
describe("imageResources", () => {
@@ -28,7 +27,7 @@ describe("imageResources", () => {
);
// THEN
- expect(loadMock).toBeCalledWith(join(resourceDirectoryPath, imageFileName));
+ expect(loadMock).toHaveBeenCalledWith(join(resourceDirectoryPath, imageFileName));
});
});
@@ -65,7 +64,7 @@ describe("fetchFromUrl", () => {
"https://github.com/nut-tree/nut.js/raw/master/.gfx/nut.png";
const expectedDimensions = {
width: 502,
- height: 411,
+ height: 411
};
const expectedColorMode = ColorMode.RGB;
diff --git a/lib/imageResources.function.ts b/core/nut.js/lib/imageResources.function.ts
similarity index 89%
rename from lib/imageResources.function.ts
rename to core/nut.js/lib/imageResources.function.ts
index 7f7875cf..6830a25d 100644
--- a/lib/imageResources.function.ts
+++ b/core/nut.js/lib/imageResources.function.ts
@@ -1,9 +1,8 @@
import { join, normalize } from "path";
-import { ProviderRegistry } from "./provider/provider-registry.class";
import { URL } from "url";
-import { Image } from "./image.class";
+import { ColorMode, Image } from "@nut-tree/shared";
import Jimp from "jimp";
-import { ColorMode } from "./colormode.enum";
+import { ProviderRegistry } from "@nut-tree/provider-interfaces";
export function loadImageResource(
providerRegistry: ProviderRegistry,
diff --git a/lib/keyboard.class.spec.ts b/core/nut.js/lib/keyboard.class.spec.ts
similarity index 96%
rename from lib/keyboard.class.spec.ts
rename to core/nut.js/lib/keyboard.class.spec.ts
index e2cb5af5..cc33467d 100644
--- a/lib/keyboard.class.spec.ts
+++ b/core/nut.js/lib/keyboard.class.spec.ts
@@ -1,8 +1,7 @@
-import { Key } from "./key.enum";
+import { Key } from "@nut-tree/shared";
import { KeyboardClass } from "./keyboard.class";
-import { ProviderRegistry } from "./provider/provider-registry.class";
import { mockPartial } from "sneer";
-import { KeyboardProviderInterface, LogProviderInterface } from "./provider";
+import { KeyboardProviderInterface, LogProviderInterface, ProviderRegistry } from "@nut-tree/provider-interfaces";
import { NoopLogProvider } from "./provider/log/noop-log-provider.class";
jest.setTimeout(10000);
diff --git a/lib/keyboard.class.ts b/core/nut.js/lib/keyboard.class.ts
similarity index 96%
rename from lib/keyboard.class.ts
rename to core/nut.js/lib/keyboard.class.ts
index f4ba6080..c1aaab4c 100644
--- a/lib/keyboard.class.ts
+++ b/core/nut.js/lib/keyboard.class.ts
@@ -1,6 +1,6 @@
-import { Key } from "./key.enum";
+import { Key } from "@nut-tree/shared";
import { sleep } from "./sleep.function";
-import { ProviderRegistry } from "./provider/provider-registry.class";
+import { ProviderRegistry } from "@nut-tree/provider-interfaces";
type StringOrKey = string[] | Key[];
@@ -26,7 +26,7 @@ export class KeyboardClass {
* Config object for {@link KeyboardClass} class
*/
public config: KeyboardConfig = {
- autoDelayMs: 300,
+ autoDelayMs: 300
};
/**
diff --git a/lib/location.function.spec.ts b/core/nut.js/lib/location.function.spec.ts
similarity index 92%
rename from lib/location.function.spec.ts
rename to core/nut.js/lib/location.function.spec.ts
index 0697b817..1d73ef1c 100644
--- a/lib/location.function.spec.ts
+++ b/core/nut.js/lib/location.function.spec.ts
@@ -1,6 +1,5 @@
import { centerOf, randomPointIn } from "./location.function";
-import { Point } from "./point.class";
-import { Region } from "./region.class";
+import { Point, Region } from "@nut-tree/shared";
describe("Location", () => {
describe("centerOf", () => {
@@ -15,7 +14,7 @@ describe("Location", () => {
const testRegion = {
left: 0,
top: 0,
- width: 4,
+ width: 4
};
await expect(centerOf(testRegion as Region)).rejects.toThrowError(
@@ -38,7 +37,7 @@ describe("Location", () => {
const testRegion = {
left: 0,
top: 0,
- width: 4,
+ width: 4
};
await expect(randomPointIn(testRegion as Region)).rejects.toThrowError(
diff --git a/lib/location.function.ts b/core/nut.js/lib/location.function.ts
similarity index 93%
rename from lib/location.function.ts
rename to core/nut.js/lib/location.function.ts
index 623f0a80..a33a3d23 100644
--- a/lib/location.function.ts
+++ b/core/nut.js/lib/location.function.ts
@@ -1,5 +1,4 @@
-import { Point } from "./point.class";
-import { isRegion, Region } from "./region.class";
+import { isRegion, Point, Region } from "@nut-tree/shared";
/**
* {@link centerOf} returns the center {@link Point} for a given {@link Region}
diff --git a/lib/logging.function.ts b/core/nut.js/lib/logging.function.ts
similarity index 58%
rename from lib/logging.function.ts
rename to core/nut.js/lib/logging.function.ts
index 6807a01c..16bc5e3f 100644
--- a/lib/logging.function.ts
+++ b/core/nut.js/lib/logging.function.ts
@@ -1,5 +1,9 @@
-import { LogProviderInterface } from "./provider";
-import { ConsoleLogLevel, ConsoleLogProvider, ConsoleLogProviderConfig } from "./provider/log/console-log-provider.class";
+import { LogProviderInterface } from "@nut-tree/provider-interfaces";
+import {
+ ConsoleLogLevel,
+ ConsoleLogProvider,
+ ConsoleLogProviderConfig
+} from "./provider/log/console-log-provider.class";
import providerRegistry from "./provider/provider-registry.class";
export const useLogger = (logger: LogProviderInterface) => {
@@ -8,6 +12,6 @@ export const useLogger = (logger: LogProviderInterface) => {
export const useConsoleLogger = (config?: ConsoleLogProviderConfig) => {
providerRegistry.registerLogProvider(new ConsoleLogProvider(config));
-}
+};
-export { ConsoleLogLevel }
+export { ConsoleLogLevel };
diff --git a/lib/mouse-movement.function.spec.ts b/core/nut.js/lib/mouse-movement.function.spec.ts
similarity index 97%
rename from lib/mouse-movement.function.spec.ts
rename to core/nut.js/lib/mouse-movement.function.spec.ts
index 9e9fbabe..a6a51e9a 100644
--- a/lib/mouse-movement.function.spec.ts
+++ b/core/nut.js/lib/mouse-movement.function.spec.ts
@@ -35,7 +35,7 @@ describe("MovementType", () => {
);
// THEN
- expect(easingFunction).toBeCalledTimes(amountOfSteps);
+ expect(easingFunction).toHaveBeenCalledTimes(amountOfSteps);
});
});
diff --git a/lib/mouse-movement.function.ts b/core/nut.js/lib/mouse-movement.function.ts
similarity index 100%
rename from lib/mouse-movement.function.ts
rename to core/nut.js/lib/mouse-movement.function.ts
diff --git a/lib/mouse.class.spec.ts b/core/nut.js/lib/mouse.class.spec.ts
similarity index 84%
rename from lib/mouse.class.spec.ts
rename to core/nut.js/lib/mouse.class.spec.ts
index 7c7883bb..b4fafc11 100644
--- a/lib/mouse.class.spec.ts
+++ b/core/nut.js/lib/mouse.class.spec.ts
@@ -1,10 +1,8 @@
-import { Button } from "./button.enum";
+import { Button, Point } from "@nut-tree/shared";
import { MouseClass } from "./mouse.class";
-import { Point } from "./point.class";
import { LineHelper } from "./util/linehelper.class";
-import { ProviderRegistry } from "./provider/provider-registry.class";
import { mockPartial } from "sneer";
-import { MouseProviderInterface } from "./provider";
+import { MouseProviderInterface, ProviderRegistry } from "@nut-tree/provider-interfaces";
import { NoopLogProvider } from "./provider/log/noop-log-provider.class";
beforeEach(() => {
@@ -16,12 +14,12 @@ const linehelper = new LineHelper();
const providerRegistryMock = mockPartial({
getMouse(): MouseProviderInterface {
return mockPartial({
- setMouseDelay: jest.fn(),
+ setMouseDelay: jest.fn()
});
},
hasMouse(): boolean {
return true;
- },
+ }
});
describe("Mouse class", () => {
@@ -44,7 +42,7 @@ describe("Mouse class", () => {
providerRegistryMock.getMouse = jest.fn(() =>
mockPartial({
setMouseDelay: jest.fn(),
- scrollLeft: scrollMock,
+ scrollLeft: scrollMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -53,7 +51,7 @@ describe("Mouse class", () => {
const result = await SUT.scrollLeft(scrollAmount);
// THEN
- expect(scrollMock).toBeCalledWith(scrollAmount);
+ expect(scrollMock).toHaveBeenCalledWith(scrollAmount);
expect(result).toBe(SUT);
});
@@ -66,7 +64,7 @@ describe("Mouse class", () => {
providerRegistryMock.getMouse = jest.fn(() =>
mockPartial({
setMouseDelay: jest.fn(),
- scrollRight: scrollMock,
+ scrollRight: scrollMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -75,7 +73,7 @@ describe("Mouse class", () => {
const result = await SUT.scrollRight(scrollAmount);
// THEN
- expect(scrollMock).toBeCalledWith(scrollAmount);
+ expect(scrollMock).toHaveBeenCalledWith(scrollAmount);
expect(result).toBe(SUT);
});
@@ -88,7 +86,7 @@ describe("Mouse class", () => {
providerRegistryMock.getMouse = jest.fn(() =>
mockPartial({
setMouseDelay: jest.fn(),
- scrollDown: scrollMock,
+ scrollDown: scrollMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -97,7 +95,7 @@ describe("Mouse class", () => {
const result = await SUT.scrollDown(scrollAmount);
// THEN
- expect(scrollMock).toBeCalledWith(scrollAmount);
+ expect(scrollMock).toHaveBeenCalledWith(scrollAmount);
expect(result).toBe(SUT);
});
@@ -110,7 +108,7 @@ describe("Mouse class", () => {
providerRegistryMock.getMouse = jest.fn(() =>
mockPartial({
setMouseDelay: jest.fn(),
- scrollUp: scrollMock,
+ scrollUp: scrollMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -119,7 +117,7 @@ describe("Mouse class", () => {
const result = await SUT.scrollUp(scrollAmount);
// THEN
- expect(scrollMock).toBeCalledWith(scrollAmount);
+ expect(scrollMock).toHaveBeenCalledWith(scrollAmount);
expect(result).toBe(SUT);
});
@@ -132,7 +130,7 @@ describe("Mouse class", () => {
providerRegistryMock.getMouse = jest.fn(() =>
mockPartial({
setMouseDelay: jest.fn(),
- setMousePosition: setPositionMock,
+ setMousePosition: setPositionMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -141,7 +139,7 @@ describe("Mouse class", () => {
const result = await SUT.move(path);
// THEN
- expect(setPositionMock).toBeCalledTimes(path.length);
+ expect(setPositionMock).toHaveBeenCalledTimes(path.length);
expect(result).toBe(SUT);
});
@@ -154,7 +152,7 @@ describe("Mouse class", () => {
providerRegistryMock.getMouse = jest.fn(() =>
mockPartial({
setMouseDelay: jest.fn(),
- setMousePosition: setPositionMock,
+ setMousePosition: setPositionMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -163,8 +161,8 @@ describe("Mouse class", () => {
const result = await SUT.move(testPoint as unknown as Array);
// THEN
- expect(setPositionMock).toBeCalledTimes(1);
- expect(setPositionMock).toBeCalledWith(testPoint);
+ expect(setPositionMock).toHaveBeenCalledTimes(1);
+ expect(setPositionMock).toHaveBeenCalledWith(testPoint);
expect(result).toBe(SUT);
});
@@ -181,7 +179,7 @@ describe("Mouse class", () => {
setMouseDelay: jest.fn(),
setMousePosition: setPositionMock,
pressButton: pressButtonMock,
- releaseButton: releaseButtonMock,
+ releaseButton: releaseButtonMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -190,9 +188,9 @@ describe("Mouse class", () => {
const result = await SUT.drag(path);
// THEN
- expect(pressButtonMock).toBeCalledWith(Button.LEFT);
- expect(setPositionMock).toBeCalledTimes(path.length);
- expect(releaseButtonMock).toBeCalledWith(Button.LEFT);
+ expect(pressButtonMock).toHaveBeenCalledWith(Button.LEFT);
+ expect(setPositionMock).toHaveBeenCalledTimes(path.length);
+ expect(releaseButtonMock).toHaveBeenCalledWith(Button.LEFT);
expect(result).toBe(SUT);
});
@@ -200,7 +198,7 @@ describe("Mouse class", () => {
it.each([
[Button.LEFT, Button.LEFT],
[Button.MIDDLE, Button.MIDDLE],
- [Button.RIGHT, Button.RIGHT],
+ [Button.RIGHT, Button.RIGHT]
] as Array<[Button, Button]>)(
"should be pressed and released",
async (input: Button, expected: Button) => {
@@ -212,7 +210,7 @@ describe("Mouse class", () => {
mockPartial({
setMouseDelay: jest.fn(),
pressButton: pressButtonMock,
- releaseButton: releaseButtonMock,
+ releaseButton: releaseButtonMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -222,8 +220,8 @@ describe("Mouse class", () => {
const released = await SUT.releaseButton(input);
// THEN
- expect(pressButtonMock).toBeCalledWith(expected);
- expect(releaseButtonMock).toBeCalledWith(expected);
+ expect(pressButtonMock).toHaveBeenCalledWith(expected);
+ expect(releaseButtonMock).toHaveBeenCalledWith(expected);
expect(pressed).toBe(SUT);
expect(released).toBe(SUT);
}
@@ -240,7 +238,7 @@ describe("Mouse class", () => {
providerRegistryMock.getMouse = jest.fn(() =>
mockPartial({
setMouseDelay: jest.fn(),
- pressButton: mouseMock,
+ pressButton: mouseMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -264,7 +262,7 @@ describe("Mouse class", () => {
providerRegistryMock.getMouse = jest.fn(() =>
mockPartial({
setMouseDelay: jest.fn(),
- releaseButton: mouseMock,
+ releaseButton: mouseMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -285,7 +283,7 @@ describe("Mouse class", () => {
it.each([
[Button.LEFT, Button.LEFT],
[Button.MIDDLE, Button.MIDDLE],
- [Button.RIGHT, Button.RIGHT],
+ [Button.RIGHT, Button.RIGHT]
] as Array<[Button, Button]>)(
"should click the respective button on the provider",
async (input: Button, expected: Button) => {
@@ -295,7 +293,7 @@ describe("Mouse class", () => {
providerRegistryMock.getMouse = jest.fn(() =>
mockPartial({
setMouseDelay: jest.fn(),
- click: clickMock,
+ click: clickMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -304,7 +302,7 @@ describe("Mouse class", () => {
await SUT.click(input);
// THEN
- expect(clickMock).toBeCalledWith(expected);
+ expect(clickMock).toHaveBeenCalledWith(expected);
}
);
});
@@ -313,7 +311,7 @@ describe("Mouse class", () => {
it.each([
[Button.LEFT, Button.LEFT],
[Button.MIDDLE, Button.MIDDLE],
- [Button.RIGHT, Button.RIGHT],
+ [Button.RIGHT, Button.RIGHT]
] as Array<[Button, Button]>)(
"should click the respective button on the provider",
async (input: Button, expected: Button) => {
@@ -323,7 +321,7 @@ describe("Mouse class", () => {
providerRegistryMock.getMouse = jest.fn(() =>
mockPartial({
setMouseDelay: jest.fn(),
- doubleClick: clickMock,
+ doubleClick: clickMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -332,7 +330,7 @@ describe("Mouse class", () => {
await SUT.doubleClick(input);
// THEN
- expect(clickMock).toBeCalledWith(expected);
+ expect(clickMock).toHaveBeenCalledWith(expected);
}
);
});
@@ -347,7 +345,7 @@ describe("Mouse class", () => {
providerRegistryMock.getMouse = jest.fn(() =>
mockPartial({
setMouseDelay: jest.fn(),
- click: clickMock,
+ click: clickMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -356,8 +354,8 @@ describe("Mouse class", () => {
const result = await SUT.leftClick();
// THEN
- expect(clickSpy).toBeCalledWith(Button.LEFT);
- expect(clickMock).toBeCalledWith(Button.LEFT);
+ expect(clickSpy).toHaveBeenCalledWith(Button.LEFT);
+ expect(clickMock).toHaveBeenCalledWith(Button.LEFT);
expect(result).toBe(SUT);
});
});
@@ -372,7 +370,7 @@ describe("Mouse class", () => {
providerRegistryMock.getMouse = jest.fn(() =>
mockPartial({
setMouseDelay: jest.fn(),
- click: clickMock,
+ click: clickMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -381,8 +379,8 @@ describe("Mouse class", () => {
const result = await SUT.rightClick();
// THEN
- expect(clickSpy).toBeCalledWith(Button.RIGHT);
- expect(clickMock).toBeCalledWith(Button.RIGHT);
+ expect(clickSpy).toHaveBeenCalledWith(Button.RIGHT);
+ expect(clickMock).toHaveBeenCalledWith(Button.RIGHT);
expect(result).toBe(SUT);
});
});
diff --git a/lib/mouse.class.ts b/core/nut.js/lib/mouse.class.ts
similarity index 96%
rename from lib/mouse.class.ts
rename to core/nut.js/lib/mouse.class.ts
index b1396f8a..8c818656 100644
--- a/lib/mouse.class.ts
+++ b/core/nut.js/lib/mouse.class.ts
@@ -1,12 +1,7 @@
-import { Button } from "./button.enum";
-import { isPoint, Point } from "./point.class";
+import { Button, isPoint, Point } from "@nut-tree/shared";
import { busyWaitForNanoSeconds, sleep } from "./sleep.function";
-import {
- calculateMovementTimesteps,
- EasingFunction,
- linear,
-} from "./mouse-movement.function";
-import { ProviderRegistry } from "./provider/provider-registry.class";
+import { calculateMovementTimesteps, EasingFunction, linear } from "./mouse-movement.function";
+import { ProviderRegistry } from "@nut-tree/provider-interfaces";
/**
* Config object for {@link MouseClass} class
@@ -29,7 +24,7 @@ export interface MouseConfig {
export class MouseClass {
public config: MouseConfig = {
autoDelayMs: 100,
- mouseSpeed: 1000,
+ mouseSpeed: 1000
};
/**
diff --git a/lib/movement-api.interface.ts b/core/nut.js/lib/movement-api.interface.ts
similarity index 95%
rename from lib/movement-api.interface.ts
rename to core/nut.js/lib/movement-api.interface.ts
index 896372f9..8549dfb6 100644
--- a/lib/movement-api.interface.ts
+++ b/core/nut.js/lib/movement-api.interface.ts
@@ -1,4 +1,4 @@
-import { Point } from "./point.class";
+import { Point } from "@nut-tree/shared";
/**
* {@link MovementApi} provides helper functions to generate movement paths relative tot he current mouse position
@@ -9,21 +9,25 @@ export interface MovementApi {
* @param px Length of the movement path in pixels
*/
down(px: number): Promise;
+
/**
* {@link left} generates a leftward movement path
* @param px Length of the movement path in pixels
*/
left(px: number): Promise;
+
/**
* {@link right} generates a rightward movement path
* @param px Length of the movement path in pixels
*/
right(px: number): Promise;
+
/**
* {@link straightTo} generates a straight movement path to a given target {@link Point}
* @param target The target {@link Point} to move towards
*/
straightTo(target: Point | Promise): Promise;
+
/**
* {@link up} generates a upward movement path
* @param px Length of the movement path in pixels
diff --git a/lib/movement.function.spec.ts b/core/nut.js/lib/movement.function.spec.ts
similarity index 79%
rename from lib/movement.function.spec.ts
rename to core/nut.js/lib/movement.function.spec.ts
index 1e858e20..c24e3bd9 100644
--- a/lib/movement.function.spec.ts
+++ b/core/nut.js/lib/movement.function.spec.ts
@@ -1,15 +1,14 @@
import { createMovementApi } from "./movement.function";
import { mockPartial } from "sneer";
-import { ProviderRegistry } from "./provider/provider-registry.class";
-import { MouseProviderInterface } from "./provider";
-import { Point } from "./point.class";
+import { MouseProviderInterface, ProviderRegistry } from "@nut-tree/provider-interfaces";
+import { Point } from "@nut-tree/shared";
beforeEach(() => {
jest.clearAllMocks();
});
const lineHelperMock = {
- straightLine: jest.fn(),
+ straightLine: jest.fn()
};
const currentPosition = new Point(500, 500);
@@ -17,9 +16,9 @@ const currentPosition = new Point(500, 500);
const providerRegistryMock = mockPartial({
getMouse(): MouseProviderInterface {
return mockPartial({
- currentMousePosition: () => Promise.resolve(currentPosition),
+ currentMousePosition: () => Promise.resolve(currentPosition)
});
- },
+ }
});
describe("MovementApi", () => {
@@ -37,8 +36,8 @@ describe("MovementApi", () => {
await SUT.down(step);
// THEN
- expect(lineHelperMock.straightLine).toBeCalledTimes(1);
- expect(lineHelperMock.straightLine).toBeCalledWith(
+ expect(lineHelperMock.straightLine).toHaveBeenCalledTimes(1);
+ expect(lineHelperMock.straightLine).toHaveBeenCalledWith(
currentPosition,
targetPoint
);
@@ -57,8 +56,8 @@ describe("MovementApi", () => {
await SUT.up(step);
// THEN
- expect(lineHelperMock.straightLine).toBeCalledTimes(1);
- expect(lineHelperMock.straightLine).toBeCalledWith(
+ expect(lineHelperMock.straightLine).toHaveBeenCalledTimes(1);
+ expect(lineHelperMock.straightLine).toHaveBeenCalledWith(
currentPosition,
targetPoint
);
@@ -77,8 +76,8 @@ describe("MovementApi", () => {
await SUT.left(step);
// THEN
- expect(lineHelperMock.straightLine).toBeCalledTimes(1);
- expect(lineHelperMock.straightLine).toBeCalledWith(
+ expect(lineHelperMock.straightLine).toHaveBeenCalledTimes(1);
+ expect(lineHelperMock.straightLine).toHaveBeenCalledWith(
currentPosition,
targetPoint
);
@@ -97,8 +96,8 @@ describe("MovementApi", () => {
await SUT.right(step);
// THEN
- expect(lineHelperMock.straightLine).toBeCalledTimes(1);
- expect(lineHelperMock.straightLine).toBeCalledWith(
+ expect(lineHelperMock.straightLine).toHaveBeenCalledTimes(1);
+ expect(lineHelperMock.straightLine).toHaveBeenCalledWith(
currentPosition,
targetPoint
);
@@ -130,8 +129,8 @@ describe("MovementApi", () => {
await SUT.straightTo(targetPoint);
// THEN
- expect(lineHelperMock.straightLine).toBeCalledTimes(1);
- expect(lineHelperMock.straightLine).toBeCalledWith(
+ expect(lineHelperMock.straightLine).toHaveBeenCalledTimes(1);
+ expect(lineHelperMock.straightLine).toHaveBeenCalledWith(
currentPosition,
targetPoint
);
diff --git a/lib/movement.function.ts b/core/nut.js/lib/movement.function.ts
similarity index 92%
rename from lib/movement.function.ts
rename to core/nut.js/lib/movement.function.ts
index f5ae6652..cdc56bcb 100644
--- a/lib/movement.function.ts
+++ b/core/nut.js/lib/movement.function.ts
@@ -1,7 +1,7 @@
import { MovementApi } from "./movement-api.interface";
-import { isPoint, Point } from "./point.class";
+import { isPoint, Point } from "@nut-tree/shared";
import { LineHelper } from "./util/linehelper.class";
-import { ProviderRegistry } from "./provider/provider-registry.class";
+import { ProviderRegistry } from "@nut-tree/provider-interfaces";
export const createMovementApi = (
providerRegistry: ProviderRegistry,
@@ -35,6 +35,6 @@ export const createMovementApi = (
up: async (px: number): Promise => {
const pos = await providerRegistry.getMouse().currentMousePosition();
return lineHelper.straightLine(pos, new Point(pos.x, pos.y - px));
- },
+ }
};
};
diff --git a/lib/provider/color/color-finder.class.spec.ts b/core/nut.js/lib/provider/color/color-finder.class.spec.ts
similarity index 93%
rename from lib/provider/color/color-finder.class.spec.ts
rename to core/nut.js/lib/provider/color/color-finder.class.spec.ts
index dc4acb70..66179624 100644
--- a/lib/provider/color/color-finder.class.spec.ts
+++ b/core/nut.js/lib/provider/color/color-finder.class.spec.ts
@@ -14,7 +14,7 @@ describe("color finder", () => {
it("should resolve", async () => {
// GIVEN
const screenImage = await loadImage(
- join(__dirname, `../../../e2e/assets/dot.png`)
+ join(__dirname, `../../../assets/dot.png`)
);
const SUT = new ColorFinder();
const colorQuery: ColorQuery = {
@@ -40,7 +40,7 @@ describe("color finder", () => {
it("should resolve", async () => {
// GIVEN
const screenImage = await loadImage(
- join(__dirname, `../../../e2e/assets/dots.png`)
+ join(__dirname, `../../../assets/dots.png`)
);
const SUT = new ColorFinder();
const colorQuery: ColorQuery = {
diff --git a/lib/provider/color/color-finder.class.ts b/core/nut.js/lib/provider/color/color-finder.class.ts
similarity index 85%
rename from lib/provider/color/color-finder.class.ts
rename to core/nut.js/lib/provider/color/color-finder.class.ts
index 567df6d8..73041dfd 100644
--- a/lib/provider/color/color-finder.class.ts
+++ b/core/nut.js/lib/provider/color/color-finder.class.ts
@@ -1,9 +1,5 @@
-import { ColorFinderInterface } from "../color-finder.interface";
-import { MatchRequest } from "../../match-request.class";
-import { ColorQuery } from "../../query.class";
-import { MatchResult } from "../../match-result.class";
-import { imageToJimp } from "../io/imageToJimp.function";
-import { Point } from "../../point.class";
+import { ColorFinderInterface } from "@nut-tree/provider-interfaces";
+import { ColorQuery, imageToJimp, MatchRequest, MatchResult, Point } from "@nut-tree/shared";
export default class implements ColorFinderInterface {
async findMatch(
diff --git a/lib/provider/image/jimp-image-processor.class.spec.ts b/core/nut.js/lib/provider/image/jimp-image-processor.class.spec.ts
similarity index 94%
rename from lib/provider/image/jimp-image-processor.class.spec.ts
rename to core/nut.js/lib/provider/image/jimp-image-processor.class.spec.ts
index af6dfc96..329fd266 100644
--- a/lib/provider/image/jimp-image-processor.class.spec.ts
+++ b/core/nut.js/lib/provider/image/jimp-image-processor.class.spec.ts
@@ -1,5 +1,4 @@
-import { Image } from "../../image.class";
-import { Point } from "../../point.class";
+import { Image, Point } from "@nut-tree/shared";
import JimpImageProcessor from "./jimp-image-processor.class";
const imageWidth = 10;
diff --git a/lib/provider/image/jimp-image-processor.class.ts b/core/nut.js/lib/provider/image/jimp-image-processor.class.ts
similarity index 76%
rename from lib/provider/image/jimp-image-processor.class.ts
rename to core/nut.js/lib/provider/image/jimp-image-processor.class.ts
index cb8c6d75..1a1f9425 100644
--- a/lib/provider/image/jimp-image-processor.class.ts
+++ b/core/nut.js/lib/provider/image/jimp-image-processor.class.ts
@@ -1,9 +1,6 @@
import Jimp from "jimp";
-import { Image } from "../../image.class";
-import { Point } from "../../point.class";
-import { ImageProcessor } from "../image-processor.interface";
-import { imageToJimp } from "../io/imageToJimp.function";
-import { RGBA } from "../../rgba.class";
+import { Image, imageToJimp, Point, RGBA } from "@nut-tree/shared";
+import { ImageProcessor } from "@nut-tree/provider-interfaces";
export default class implements ImageProcessor {
async colorAt(
diff --git a/lib/provider/io/jimp-image-reader.class.spec.ts b/core/nut.js/lib/provider/io/jimp-image-reader.class.spec.ts
similarity index 92%
rename from lib/provider/io/jimp-image-reader.class.spec.ts
rename to core/nut.js/lib/provider/io/jimp-image-reader.class.spec.ts
index bd1267e7..f234e9b5 100644
--- a/lib/provider/io/jimp-image-reader.class.spec.ts
+++ b/core/nut.js/lib/provider/io/jimp-image-reader.class.spec.ts
@@ -34,8 +34,8 @@ describe("Jimp image reader", () => {
// THEN
expect(scanMock).toHaveBeenCalledTimes(1);
- expect(Jimp.read).toBeCalledTimes(1);
- expect(Jimp.read).toBeCalledWith(inputPath);
+ expect(Jimp.read).toHaveBeenCalledTimes(1);
+ expect(Jimp.read).toHaveBeenCalledWith(inputPath);
});
it("should reject on loading failures", async () => {
diff --git a/lib/provider/io/jimp-image-reader.class.ts b/core/nut.js/lib/provider/io/jimp-image-reader.class.ts
similarity index 82%
rename from lib/provider/io/jimp-image-reader.class.ts
rename to core/nut.js/lib/provider/io/jimp-image-reader.class.ts
index f680be2c..c29baac2 100644
--- a/lib/provider/io/jimp-image-reader.class.ts
+++ b/core/nut.js/lib/provider/io/jimp-image-reader.class.ts
@@ -1,7 +1,6 @@
import Jimp from "jimp";
-import { ImageReader } from "../image-reader.type";
-import { Image } from "../../image.class";
-import { ColorMode } from "../../colormode.enum";
+import { ImageReader } from "@nut-tree/provider-interfaces";
+import { ColorMode, Image } from "@nut-tree/shared";
export default class implements ImageReader {
load(parameters: string): Promise {
@@ -14,7 +13,7 @@ export default class implements ImageReader {
0,
jimpImage.bitmap.width,
jimpImage.bitmap.height,
- function (_, __, idx) {
+ function(_, __, idx) {
const red = this.bitmap.data[idx];
this.bitmap.data[idx] = this.bitmap.data[idx + 2];
this.bitmap.data[idx + 2] = red;
@@ -28,7 +27,7 @@ export default class implements ImageReader {
jimpImage.hasAlpha() ? 4 : 3,
parameters,
jimpImage.bitmap.data.length /
- (jimpImage.bitmap.width * jimpImage.bitmap.height),
+ (jimpImage.bitmap.width * jimpImage.bitmap.height),
jimpImage.bitmap.data.length / jimpImage.bitmap.height,
ColorMode.BGR
)
diff --git a/lib/provider/io/jimp-image-writer.class.spec.ts b/core/nut.js/lib/provider/io/jimp-image-writer.class.spec.ts
similarity index 94%
rename from lib/provider/io/jimp-image-writer.class.spec.ts
rename to core/nut.js/lib/provider/io/jimp-image-writer.class.spec.ts
index 1128fb67..a77caa93 100644
--- a/lib/provider/io/jimp-image-writer.class.spec.ts
+++ b/core/nut.js/lib/provider/io/jimp-image-writer.class.spec.ts
@@ -1,5 +1,5 @@
import ImageWriter from "./jimp-image-writer.class";
-import { Image } from "../../image.class";
+import { Image } from "@nut-tree/shared";
import Jimp from "jimp";
jest.mock("jimp", () => {
@@ -7,7 +7,7 @@ jest.mock("jimp", () => {
bitmap = {
width: 100,
height: 100,
- data: Buffer.from([]),
+ data: Buffer.from([])
};
hasAlpha = () => false;
static read = jest.fn(() => Promise.resolve(new JimpMock()));
@@ -15,7 +15,7 @@ jest.mock("jimp", () => {
return {
__esModule: true,
- default: JimpMock,
+ default: JimpMock
};
});
diff --git a/lib/provider/io/jimp-image-writer.class.ts b/core/nut.js/lib/provider/io/jimp-image-writer.class.ts
similarity index 72%
rename from lib/provider/io/jimp-image-writer.class.ts
rename to core/nut.js/lib/provider/io/jimp-image-writer.class.ts
index b80343f6..f8e0faeb 100644
--- a/lib/provider/io/jimp-image-writer.class.ts
+++ b/core/nut.js/lib/provider/io/jimp-image-writer.class.ts
@@ -1,5 +1,5 @@
-import { ImageWriter, ImageWriterParameters } from "../image-writer.type";
-import { imageToJimp } from "./imageToJimp.function";
+import { ImageWriter, ImageWriterParameters } from "@nut-tree/provider-interfaces";
+import { imageToJimp } from "@nut-tree/shared";
export default class implements ImageWriter {
store(parameters: ImageWriterParameters): Promise {
diff --git a/lib/provider/log/console-log-provider.class.spec.ts b/core/nut.js/lib/provider/log/console-log-provider.class.spec.ts
similarity index 90%
rename from lib/provider/log/console-log-provider.class.spec.ts
rename to core/nut.js/lib/provider/log/console-log-provider.class.spec.ts
index e02c227a..ee479e93 100644
--- a/lib/provider/log/console-log-provider.class.spec.ts
+++ b/core/nut.js/lib/provider/log/console-log-provider.class.spec.ts
@@ -67,7 +67,7 @@ describe("ConsoleLogProvider", () => {
// THEN
for (const mock of validMocks) {
- expect(mock).toBeCalledTimes(1);
+ expect(mock).toHaveBeenCalledTimes(1);
}
for (const mock of invalidMocks) {
expect(mock).not.toBeCalled();
@@ -95,11 +95,11 @@ describe("ConsoleLogProvider", () => {
SUT.error(new Error("test"), { data: "test" });
// THEN
- expect(mock).toBeCalledTimes(1);
+ expect(mock).toHaveBeenCalledTimes(1);
if (level != ConsoleLogLevel.ERROR) {
- expect(mock).toBeCalledWith(expect.any(String), expect.any(Object));
+ expect(mock).toHaveBeenCalledWith(expect.any(String), expect.any(Object));
} else {
- expect(mock).toBeCalledWith(expect.any(Error), expect.any(Object));
+ expect(mock).toHaveBeenCalledWith(expect.any(Error), expect.any(Object));
}
}
);
diff --git a/lib/provider/log/console-log-provider.class.ts b/core/nut.js/lib/provider/log/console-log-provider.class.ts
similarity index 96%
rename from lib/provider/log/console-log-provider.class.ts
rename to core/nut.js/lib/provider/log/console-log-provider.class.ts
index b7af9d56..157c1014 100644
--- a/lib/provider/log/console-log-provider.class.ts
+++ b/core/nut.js/lib/provider/log/console-log-provider.class.ts
@@ -1,4 +1,4 @@
-import { LogProviderInterface } from "../log-provider.interface";
+import { LogProviderInterface } from "@nut-tree/provider-interfaces";
export enum ConsoleLogLevel {
TRACE,
@@ -15,7 +15,7 @@ export interface ConsoleLogProviderConfig {
const defaultConfig: ConsoleLogProviderConfig = {
logLevel: ConsoleLogLevel.INFO,
- withTimeStamp: true,
+ withTimeStamp: true
};
export class ConsoleLogProvider implements LogProviderInterface {
diff --git a/core/nut.js/lib/provider/log/noop-log-provider.class.ts b/core/nut.js/lib/provider/log/noop-log-provider.class.ts
new file mode 100644
index 00000000..d70d0e97
--- /dev/null
+++ b/core/nut.js/lib/provider/log/noop-log-provider.class.ts
@@ -0,0 +1,18 @@
+import { LogProviderInterface } from "@nut-tree/provider-interfaces";
+
+export class NoopLogProvider implements LogProviderInterface {
+ public trace(_: string, __?: {}) {
+ }
+
+ public debug(_: string, __?: {}) {
+ }
+
+ public info(_: string, __?: {}) {
+ }
+
+ public warn(_: string, __?: {}) {
+ }
+
+ public error(_: Error, __?: {}) {
+ }
+}
diff --git a/lib/provider/log-provider.interface.ts b/core/nut.js/lib/provider/log/wrap-logger.function.ts
similarity index 52%
rename from lib/provider/log-provider.interface.ts
rename to core/nut.js/lib/provider/log/wrap-logger.function.ts
index 124672cf..7eaa2d57 100644
--- a/lib/provider/log-provider.interface.ts
+++ b/core/nut.js/lib/provider/log/wrap-logger.function.ts
@@ -1,21 +1,10 @@
-export type LogFunction = (message: string, data?: {}) => void;
-export type ErrorLogFunction = (error: Error, data?: {}) => void;
+import { LogProviderInterface } from "@nut-tree/provider-interfaces";
const logIdentifier = "[nut.js]";
-
-export interface LogProviderInterface {
- trace: LogFunction;
- debug: LogFunction;
- info: LogFunction;
- warn: LogFunction;
- error: ErrorLogFunction;
-}
-
-const nonErrorLevels = ['info', 'warn', 'debug', 'trace'];
-const errorLevels = ['error'];
-
-type NonErrorLogger = Omit;
-type ErrorLogger = Pick;
+const nonErrorLevels = ["info", "warn", "debug", "trace"];
+const errorLevels = ["error"];
+type NonErrorLogger = Omit;
+type ErrorLogger = Pick;
export function wrapLogger(originalLogger: LogProviderInterface): LogProviderInterface {
for (const level of nonErrorLevels) {
@@ -23,16 +12,15 @@ export function wrapLogger(originalLogger: LogProviderInterface): LogProviderInt
originalLogger[level as keyof NonErrorLogger] = (message: string, data?: {}) => {
const wrappedMessage = `${logIdentifier} - ${message}`;
originalMethod(wrappedMessage, data);
- }
+ };
}
for (const level of errorLevels) {
const originalMethod = originalLogger[level as keyof ErrorLogger];
originalLogger[level as keyof ErrorLogger] = (message: Error, data?: {}) => {
- const wrappedMessage = `${logIdentifier} - ${message}`;
- message.message = wrappedMessage;
+ message.message = `${logIdentifier} - ${message}`;
originalMethod(message, data);
- }
+ };
}
return originalLogger;
-}
+}
\ No newline at end of file
diff --git a/lib/provider/provider-registry.class.spec.ts b/core/nut.js/lib/provider/provider-registry.class.spec.ts
similarity index 89%
rename from lib/provider/provider-registry.class.spec.ts
rename to core/nut.js/lib/provider/provider-registry.class.spec.ts
index e48b54f2..6ec8fc0f 100644
--- a/lib/provider/provider-registry.class.spec.ts
+++ b/core/nut.js/lib/provider/provider-registry.class.spec.ts
@@ -1,12 +1,14 @@
import providerRegistry from "./provider-registry.class";
-import { MouseProviderInterface } from "./mouse-provider.interface";
-import { ImageProcessor } from "./image-processor.interface";
-import { ImageWriter } from "./image-writer.type";
-import { ImageReader } from "./image-reader.type";
-import { ClipboardProviderInterface } from "./clipboard-provider.interface";
-import { KeyboardProviderInterface } from "./keyboard-provider.interface";
-import { ScreenProviderInterface } from "./screen-provider.interface";
-import { WindowProviderInterface } from "./window-provider.interface";
+import {
+ ClipboardProviderInterface,
+ ImageProcessor,
+ ImageReader,
+ ImageWriter,
+ KeyboardProviderInterface,
+ MouseProviderInterface,
+ ScreenProviderInterface,
+ WindowProviderInterface
+} from "@nut-tree/provider-interfaces";
describe("DefaultProviderRegistry", () => {
describe("non-defaults", () => {
diff --git a/lib/provider/provider-registry.class.ts b/core/nut.js/lib/provider/provider-registry.class.ts
similarity index 74%
rename from lib/provider/provider-registry.class.ts
rename to core/nut.js/lib/provider/provider-registry.class.ts
index b168c136..78ee9ec4 100644
--- a/lib/provider/provider-registry.class.ts
+++ b/core/nut.js/lib/provider/provider-registry.class.ts
@@ -1,22 +1,24 @@
-import { ClipboardProviderInterface } from "./clipboard-provider.interface";
-import { ImageFinderInterface } from "./image-finder.interface";
-import { KeyboardProviderInterface } from "./keyboard-provider.interface";
-import { MouseProviderInterface } from "./mouse-provider.interface";
-import { ScreenProviderInterface } from "./screen-provider.interface";
-import { WindowProviderInterface } from "./window-provider.interface";
-
-import { ImageReader } from "./image-reader.type";
-import { ImageWriter } from "./image-writer.type";
-import { ImageProcessor } from "./image-processor.interface";
+import {
+ ClipboardProviderInterface,
+ ColorFinderInterface,
+ ImageFinderInterface,
+ ImageProcessor,
+ ImageReader,
+ ImageWriter,
+ KeyboardProviderInterface,
+ LogProviderInterface,
+ MouseProviderInterface,
+ ProviderRegistry,
+ ScreenProviderInterface,
+ TextFinderInterface,
+ WindowFinderInterface,
+ WindowProviderInterface
+} from "@nut-tree/provider-interfaces";
import ImageReaderImpl from "./io/jimp-image-reader.class";
import ImageWriterImpl from "./io/jimp-image-writer.class";
import ImageProcessorImpl from "./image/jimp-image-processor.class";
-import { LogProviderInterface, wrapLogger } from "./log-provider.interface";
import { NoopLogProvider } from "./log/noop-log-provider.class";
-import { TextFinderInterface } from "./text-finder.interface";
-import { WindowFinderInterface } from "./window-finder.interface";
-import { ColorFinderInterface } from "./color-finder.interface";
import ColorFinderImpl from "./color/color-finder.class";
import {
DISABLE_DEFAULT_CLIPBOARD_PROVIDER_ENV_VAR,
@@ -25,87 +27,14 @@ import {
DISABLE_DEFAULT_PROVIDERS_ENV_VAR,
DISABLE_DEFAULT_SCREEN_PROVIDER_ENV_VAR,
DISABLE_DEFAULT_WINDOW_PROVIDER_ENV_VAR,
+ NPM_CONFIG_DISABLE_DEFAULT_CLIPBOARD_PROVIDER_ENV_VAR,
+ NPM_CONFIG_DISABLE_DEFAULT_KEYBOARD_PROVIDER_ENV_VAR,
+ NPM_CONFIG_DISABLE_DEFAULT_MOUSE_PROVIDER_ENV_VAR,
+ NPM_CONFIG_DISABLE_DEFAULT_SCREEN_PROVIDER_ENV_VAR,
+ NPM_CONFIG_DISABLE_DEFAULT_WINDOW_PROVIDER_ENV_VAR
} from "../constants";
+import { wrapLogger } from "./log/wrap-logger.function";
-export interface ProviderRegistry {
- hasClipboard(): boolean;
-
- getClipboard(): ClipboardProviderInterface;
-
- registerClipboardProvider(value: ClipboardProviderInterface): void;
-
- hasKeyboard(): boolean;
-
- getKeyboard(): KeyboardProviderInterface;
-
- registerKeyboardProvider(value: KeyboardProviderInterface): void;
-
- hasMouse(): boolean;
-
- getMouse(): MouseProviderInterface;
-
- registerMouseProvider(value: MouseProviderInterface): void;
-
- hasScreen(): boolean;
-
- getScreen(): ScreenProviderInterface;
-
- registerScreenProvider(value: ScreenProviderInterface): void;
-
- hasWindow(): boolean;
-
- getWindow(): WindowProviderInterface;
-
- registerWindowProvider(value: WindowProviderInterface): void;
-
- hasImageFinder(): boolean;
-
- getImageFinder(): ImageFinderInterface;
-
- registerImageFinder(value: ImageFinderInterface): void;
-
- hasImageReader(): boolean;
-
- getImageReader(): ImageReader;
-
- registerImageReader(value: ImageReader): void;
-
- hasImageWriter(): boolean;
-
- getImageWriter(): ImageWriter;
-
- registerImageWriter(value: ImageWriter): void;
-
- hasImageProcessor(): boolean;
-
- getImageProcessor(): ImageProcessor;
-
- registerImageProcessor(value: ImageProcessor): void;
-
- hasLogProvider(): boolean;
-
- getLogProvider(): LogProviderInterface;
-
- registerLogProvider(value: LogProviderInterface): void;
-
- hasTextFinder(): boolean;
-
- getTextFinder(): TextFinderInterface;
-
- registerTextFinder(value: TextFinderInterface): void;
-
- hasWindowFinder(): boolean;
-
- getWindowFinder(): WindowFinderInterface;
-
- registerWindowFinder(value: WindowFinderInterface): void;
-
- hasColorFinder(): boolean;
-
- getColorFinder(): ColorFinderInterface;
-
- registerColorFinder(value: ColorFinderInterface): void;
-}
class DefaultProviderRegistry implements ProviderRegistry {
private _clipboard?: ClipboardProviderInterface;
@@ -366,23 +295,23 @@ providerRegistry.registerColorFinder(new ColorFinderImpl());
providerRegistry.registerLogProvider(new NoopLogProvider());
if (!process.env[DISABLE_DEFAULT_PROVIDERS_ENV_VAR]) {
- if (!process.env[DISABLE_DEFAULT_CLIPBOARD_PROVIDER_ENV_VAR]) {
+ if (!process.env[DISABLE_DEFAULT_CLIPBOARD_PROVIDER_ENV_VAR] && !process.env[NPM_CONFIG_DISABLE_DEFAULT_CLIPBOARD_PROVIDER_ENV_VAR]) {
const Clipboard = require("@nut-tree/default-clipboard-provider").default;
providerRegistry.registerClipboardProvider(new Clipboard());
}
- if (!process.env[DISABLE_DEFAULT_KEYBOARD_PROVIDER_ENV_VAR]) {
+ if (!process.env[DISABLE_DEFAULT_KEYBOARD_PROVIDER_ENV_VAR] && !process.env[NPM_CONFIG_DISABLE_DEFAULT_KEYBOARD_PROVIDER_ENV_VAR]) {
const { DefaultKeyboardAction } = require("@nut-tree/libnut");
providerRegistry.registerKeyboardProvider(new DefaultKeyboardAction());
}
- if (!process.env[DISABLE_DEFAULT_MOUSE_PROVIDER_ENV_VAR]) {
+ if (!process.env[DISABLE_DEFAULT_MOUSE_PROVIDER_ENV_VAR] && !process.env[NPM_CONFIG_DISABLE_DEFAULT_MOUSE_PROVIDER_ENV_VAR]) {
const { DefaultMouseAction } = require("@nut-tree/libnut");
providerRegistry.registerMouseProvider(new DefaultMouseAction());
}
- if (!process.env[DISABLE_DEFAULT_SCREEN_PROVIDER_ENV_VAR]) {
+ if (!process.env[DISABLE_DEFAULT_SCREEN_PROVIDER_ENV_VAR] && !process.env[NPM_CONFIG_DISABLE_DEFAULT_SCREEN_PROVIDER_ENV_VAR]) {
const { DefaultScreenAction } = require("@nut-tree/libnut");
providerRegistry.registerScreenProvider(new DefaultScreenAction());
}
- if (!process.env[DISABLE_DEFAULT_WINDOW_PROVIDER_ENV_VAR]) {
+ if (!process.env[DISABLE_DEFAULT_WINDOW_PROVIDER_ENV_VAR] && !process.env[NPM_CONFIG_DISABLE_DEFAULT_WINDOW_PROVIDER_ENV_VAR]) {
const { DefaultWindowAction } = require("@nut-tree/libnut");
providerRegistry.registerWindowProvider(new DefaultWindowAction());
}
diff --git a/core/nut.js/lib/screen-helpers.function.spec.ts b/core/nut.js/lib/screen-helpers.function.spec.ts
new file mode 100644
index 00000000..8c6347a5
--- /dev/null
+++ b/core/nut.js/lib/screen-helpers.function.spec.ts
@@ -0,0 +1,211 @@
+import { Image, Region, TextQuery } from "@nut-tree/shared";
+import {
+ createMatchRequest,
+ getMatchResult,
+ getMatchResults,
+ isImageMatchRequest,
+ isTextMatchRequest
+} from "./screen-helpers.function";
+import { mockPartial } from "sneer";
+import {
+ ImageFinderInterface,
+ LogProviderInterface,
+ ProviderRegistry,
+ TextFinderInterface
+} from "@nut-tree/provider-interfaces";
+import { NoopLogProvider } from "./provider/log/noop-log-provider.class";
+
+beforeEach(() => {
+ jest.clearAllMocks();
+});
+
+const imageFinderMock: ImageFinderInterface = {
+ findMatch: jest.fn(),
+ findMatches: jest.fn()
+};
+const textFinderMock: TextFinderInterface = {
+ findMatch: jest.fn(),
+ findMatches: jest.fn()
+};
+
+const providerRegistryMock = mockPartial({
+ getLogProvider(): LogProviderInterface {
+ return new NoopLogProvider();
+ },
+ getImageFinder(): ImageFinderInterface {
+ return imageFinderMock as unknown as ImageFinderInterface;
+ },
+ getTextFinder(): TextFinderInterface {
+ return textFinderMock as unknown as TextFinderInterface;
+ }
+});
+
+const screenImage = new Image(0, 0, Buffer.of(0), 3, "dummy", 0, 0);
+const dummyRegion = new Region(0, 0, 0, 0);
+
+describe("screen helpers", () => {
+ describe("MatchRequest", () => {
+ it("should create an image match request for images", () => {
+ // GIVEN
+ const needle = new Image(0, 0, Buffer.of(0), 3, "dummy", 0, 0);
+
+ // WHEN
+ const matchRequest = createMatchRequest(
+ providerRegistryMock,
+ needle,
+ dummyRegion,
+ 0,
+ screenImage
+ );
+
+ // THEN
+ expect(isImageMatchRequest(matchRequest)).toBeTruthy();
+ });
+
+ it.each([
+ {
+ id: "dummy",
+ type: "text",
+ by: {
+ word: "dummy-query"
+ }
+ },
+ {
+ id: "dummy",
+ type: "text",
+ by: {
+ line: "dummy-query"
+ }
+ }
+ ])(
+ "should create a text match request for text queries",
+ (needle: TextQuery) => {
+ // GIVEN
+
+ // WHEN
+ const matchRequest = createMatchRequest(
+ providerRegistryMock,
+ needle,
+ dummyRegion,
+ 0,
+ screenImage
+ );
+
+ // THEN
+ expect(isTextMatchRequest(matchRequest)).toBeTruthy();
+ }
+ );
+ });
+
+ const dummyImage = new Image(0, 0, Buffer.of(0), 3, "dummy-needle", 0, 0);
+
+ describe("matchResults", () => {
+ describe("getMatchResult", () => {
+ it("should call the correct finder implementation for a given image match request", async () => {
+ // GIVEN
+ const imageMatchRequest = createMatchRequest(
+ providerRegistryMock,
+ dummyImage,
+ dummyRegion,
+ 0,
+ screenImage
+ );
+
+ // WHEN
+ await getMatchResult(providerRegistryMock, imageMatchRequest);
+
+ // THEN
+ expect(imageFinderMock.findMatch).toHaveBeenCalledTimes(1);
+ });
+
+ it.each([
+ {
+ id: "dummy",
+ type: "text",
+ by: {
+ word: "dummy-query"
+ }
+ },
+ {
+ id: "dummy",
+ type: "text",
+ by: {
+ line: "dummy-query"
+ }
+ }
+ ])(
+ "should all the correct finder implementation for a given text query",
+ async (needle: TextQuery) => {
+ // GIVEN
+ const matchRequest = createMatchRequest(
+ providerRegistryMock,
+ needle,
+ dummyRegion,
+ 0,
+ screenImage
+ );
+
+ // WHEN
+ await getMatchResult(providerRegistryMock, matchRequest);
+
+ // THEN
+ expect(textFinderMock.findMatch).toHaveBeenCalledTimes(1);
+ }
+ );
+ });
+
+ describe("getMatchResults", () => {
+ it("should call the correct finder implementation for a given image match request", async () => {
+ // GIVEN
+ const imageMatchRequest = createMatchRequest(
+ providerRegistryMock,
+ dummyImage,
+ dummyRegion,
+ 0,
+ screenImage
+ );
+
+ // WHEN
+ await getMatchResults(providerRegistryMock, imageMatchRequest);
+
+ // THEN
+ expect(imageFinderMock.findMatches).toHaveBeenCalledTimes(1);
+ });
+
+ it.each([
+ {
+ id: "dummy",
+ type: "text",
+ by: {
+ word: "dummy-query"
+ }
+ },
+ {
+ id: "dummy",
+ type: "text",
+ by: {
+ line: "dummy-query"
+ }
+ }
+ ])(
+ "should all the correct finder implementation for a given text query",
+ async (needle: TextQuery) => {
+ // GIVEN
+ const matchRequest = createMatchRequest(
+ providerRegistryMock,
+ needle,
+ dummyRegion,
+ 0,
+ screenImage
+ );
+
+ // WHEN
+ await getMatchResults(providerRegistryMock, matchRequest);
+
+ // THEN
+ expect(textFinderMock.findMatches).toHaveBeenCalledTimes(1);
+ }
+ );
+ });
+ });
+});
\ No newline at end of file
diff --git a/core/nut.js/lib/screen-helpers.function.ts b/core/nut.js/lib/screen-helpers.function.ts
new file mode 100644
index 00000000..d20c9fa0
--- /dev/null
+++ b/core/nut.js/lib/screen-helpers.function.ts
@@ -0,0 +1,182 @@
+import {
+ ColorQuery,
+ Image,
+ isColorQuery,
+ isImage,
+ isLineQuery,
+ isTextQuery,
+ MatchRequest,
+ MatchResult,
+ OptionalSearchParameters,
+ Point,
+ PointResultFindInput,
+ Region,
+ RegionResultFindInput,
+ TextQuery
+} from "@nut-tree/shared";
+import { ProviderRegistry } from "@nut-tree/provider-interfaces";
+
+export function isRegionResultFindInput(
+ input: RegionResultFindInput | PointResultFindInput
+): input is RegionResultFindInput {
+ return isImage(input) || isTextQuery(input);
+}
+
+export function isPointResultFindInput(
+ input: RegionResultFindInput | PointResultFindInput
+): input is PointResultFindInput {
+ return isColorQuery(input);
+}
+
+export function isImageMatchRequest(
+ matchRequest: any
+): matchRequest is MatchRequest {
+ return isImage(matchRequest.needle);
+}
+
+export function isTextMatchRequest(
+ matchRequest: any
+): matchRequest is MatchRequest {
+ return isTextQuery(matchRequest.needle);
+}
+
+export function isColorMatchRequest(
+ matchRequest: any
+): matchRequest is MatchRequest {
+ return isColorQuery(matchRequest.needle);
+}
+
+export function createMatchRequest(
+ providerRegistry: ProviderRegistry,
+ needle: PointResultFindInput,
+ searchRegion: Region,
+ minMatch: number | undefined,
+ screenImage: Image,
+ params?: OptionalSearchParameters
+): MatchRequest;
+export function createMatchRequest(
+ providerRegistry: ProviderRegistry,
+ needle: RegionResultFindInput,
+ searchRegion: Region,
+ minMatch: number | undefined,
+ screenImage: Image,
+ params?: OptionalSearchParameters
+): MatchRequest;
+export function createMatchRequest(
+ providerRegistry: ProviderRegistry,
+ needle: RegionResultFindInput | PointResultFindInput,
+ searchRegion: Region,
+ minMatch: number | undefined,
+ screenImage: Image,
+ params?: OptionalSearchParameters
+):
+ | MatchRequest
+ | MatchRequest;
+export function createMatchRequest(
+ providerRegistry: ProviderRegistry,
+ needle: RegionResultFindInput | PointResultFindInput,
+ searchRegion: Region,
+ minMatch: number | undefined,
+ screenImage: Image,
+ params?: OptionalSearchParameters
+):
+ | MatchRequest
+ | MatchRequest {
+ if (isImage(needle)) {
+ providerRegistry
+ .getLogProvider()
+ .info(
+ `Searching for image ${
+ needle.id
+ } in region ${searchRegion.toString()}.${
+ minMatch != null ? ` Required confidence: ${minMatch}` : ""
+ }`
+ );
+
+ return new MatchRequest(
+ screenImage,
+ needle,
+ minMatch,
+ params?.providerData
+ );
+ } else if (isTextQuery(needle)) {
+ providerRegistry.getLogProvider().info(
+ `Searching for ${isLineQuery(needle) ? "line" : "word"} {
+ ${isLineQuery(needle) ? needle.by.line : needle.by.word}
+ } in region ${searchRegion.toString()}.${
+ minMatch != null
+ ? ` Required confidence: ${minMatch}`
+ : ""
+ }`
+ );
+
+ return new MatchRequest(
+ screenImage,
+ needle,
+ minMatch,
+ params?.providerData
+ );
+ } else if (isColorQuery(needle)) {
+ const color = needle.by.color;
+ providerRegistry
+ .getLogProvider()
+ .info(
+ `Searching for color RGBA(${color.R},${color.G},${color.B},${
+ color.A
+ }) in region ${searchRegion.toString()}.`
+ );
+
+ return new MatchRequest(screenImage, needle, 1, params?.providerData);
+ }
+ throw new Error(`Unknown input type: ${JSON.stringify(needle)}`);
+}
+
+export async function getMatchResults(
+ providerRegistry: ProviderRegistry,
+ matchRequest: MatchRequest
+): Promise[]>;
+export async function getMatchResults(
+ providerRegistry: ProviderRegistry,
+ matchRequest: MatchRequest
+): Promise[]>;
+export async function getMatchResults(
+ providerRegistry: ProviderRegistry,
+ matchRequest:
+ | MatchRequest
+ | MatchRequest
+): Promise[]> {
+ if (isImageMatchRequest(matchRequest)) {
+ return providerRegistry.getImageFinder().findMatches(matchRequest);
+ } else if (isTextMatchRequest(matchRequest)) {
+ return providerRegistry.getTextFinder().findMatches(matchRequest);
+ } else if (isColorMatchRequest(matchRequest)) {
+ return providerRegistry.getColorFinder().findMatches(matchRequest);
+ }
+ throw new Error(
+ `Unknown match request type: ${JSON.stringify(matchRequest.needle)}`
+ );
+}
+
+export async function getMatchResult(
+ providerRegistry: ProviderRegistry,
+ matchRequest: MatchRequest
+): Promise>;
+export async function getMatchResult(
+ providerRegistry: ProviderRegistry,
+ matchRequest: MatchRequest
+): Promise>;
+export async function getMatchResult(
+ providerRegistry: ProviderRegistry,
+ matchRequest:
+ | MatchRequest
+ | MatchRequest
+): Promise> {
+ if (isImageMatchRequest(matchRequest)) {
+ return providerRegistry.getImageFinder().findMatch(matchRequest);
+ } else if (isTextMatchRequest(matchRequest)) {
+ return providerRegistry.getTextFinder().findMatch(matchRequest);
+ } else if (isColorMatchRequest(matchRequest)) {
+ return providerRegistry.getColorFinder().findMatch(matchRequest);
+ }
+ throw new Error("Unknown match request type");
+}
diff --git a/lib/screen.class.spec.ts b/core/nut.js/lib/screen.class.spec.ts
similarity index 87%
rename from lib/screen.class.spec.ts
rename to core/nut.js/lib/screen.class.spec.ts
index 3405fa4c..630a96f6 100644
--- a/lib/screen.class.spec.ts
+++ b/core/nut.js/lib/screen.class.spec.ts
@@ -1,36 +1,38 @@
import { join } from "path";
import { cwd } from "process";
-import { Image } from "./image.class";
-import { MatchRequest } from "./match-request.class";
-import { MatchResult } from "./match-result.class";
-import { Region } from "./region.class";
+import {
+ ColorQuery,
+ Image,
+ MatchRequest,
+ MatchResult,
+ OptionalSearchParameters,
+ Point,
+ Region,
+ RGBA,
+ TextQuery,
+ WindowQuery
+} from "@nut-tree/shared";
import { ScreenClass } from "./screen.class";
import { mockPartial } from "sneer";
-import { ProviderRegistry } from "./provider/provider-registry.class";
import {
+ ColorFinderInterface,
ImageFinderInterface,
ImageWriter,
ImageWriterParameters,
LogProviderInterface,
+ ProviderRegistry,
ScreenProviderInterface,
-} from "./provider";
-import { OptionalSearchParameters } from "./optionalsearchparameters.class";
+ TextFinderInterface,
+ WindowFinderInterface
+} from "@nut-tree/provider-interfaces";
import { NoopLogProvider } from "./provider/log/noop-log-provider.class";
-import { ColorQuery, TextQuery, WindowQuery } from "./query.class";
-import { TextFinderInterface } from "./provider";
-import { WindowFinderInterface } from "./provider";
-import { RGBA } from "./rgba.class";
-import { ColorFinderInterface } from "./provider/color-finder.interface";
-import { Point } from "./point.class";
-
-jest.mock("jimp", () => {});
const searchRegion = new Region(0, 0, 1000, 1000);
const loggingMock = mockPartial({
debug: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
- error: jest.fn(),
+ error: jest.fn()
});
const providerRegistryMock = mockPartial({
@@ -48,8 +50,8 @@ const providerRegistryMock = mockPartial({
3,
"needle_image",
4,
- searchRegion.width * 4,
- ),
+ searchRegion.width * 4
+ )
);
},
screenSize(): Promise {
@@ -60,9 +62,9 @@ const providerRegistryMock = mockPartial({
},
screenHeight(): Promise {
return Promise.resolve(searchRegion.height);
- },
+ }
});
- },
+ }
});
beforeEach(() => {
@@ -110,15 +112,15 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
const needlePromise = Promise.resolve(needle);
const findMatchMock = jest.fn(() => Promise.resolve(matchResult));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -136,15 +138,15 @@ describe("Screen.", () => {
id: "window-query",
type: "window",
by: {
- title: "query",
- },
+ title: "query"
+ }
};
const findMatchMock = jest.fn(() => Promise.resolve(1234));
providerRegistryMock.getWindowFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -165,15 +167,15 @@ describe("Screen.", () => {
id: "color-query",
type: "color",
by: {
- color: new RGBA(255, 0, 255, 1),
- },
+ color: new RGBA(255, 0, 255, 1)
+ }
};
const findMatchMock = jest.fn(() => Promise.resolve(matchResult));
providerRegistryMock.getColorFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -189,16 +191,16 @@ describe("Screen.", () => {
id: "dummy",
type: "text",
by: {
- word: "dummy-query",
- },
+ word: "dummy-query"
+ }
},
{
id: "dummy",
type: "text",
by: {
- line: "dummy-query",
- },
- },
+ line: "dummy-query"
+ }
+ }
])(
"should choose the correct finder implementation for text queries",
async (needle: TextQuery) => {
@@ -210,8 +212,8 @@ describe("Screen.", () => {
const findMatchMock = jest.fn(() => Promise.resolve(matchResult));
providerRegistryMock.getTextFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -220,7 +222,7 @@ describe("Screen.", () => {
// THEN
expect(findMatchMock).toHaveBeenCalledTimes(1);
- },
+ }
);
});
@@ -233,7 +235,7 @@ describe("Screen.", () => {
// THEN
await expect(result).rejects.toThrowError(
- /find requires an Image, a text query, a color query or a window query.*/,
+ /find requires an Image, a text query, a color query or a window query.*/
);
});
@@ -248,15 +250,15 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
const needlePromise = Promise.resolve(needle);
const findMatchMock = jest.fn(() => Promise.resolve(matchResult));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -268,7 +270,7 @@ describe("Screen.", () => {
const matchRequest = new MatchRequest(
expect.any(Image),
needle,
- undefined,
+ undefined
);
expect(findMatchMock).toHaveBeenCalledWith(matchRequest);
});
@@ -279,8 +281,8 @@ describe("Screen.", () => {
const findMatchMock = jest.fn(() => Promise.resolve(matchResult));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -293,7 +295,7 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
SUT.on(needle, testCallback);
@@ -301,8 +303,8 @@ describe("Screen.", () => {
await SUT.find(needle);
// THEN
- expect(testCallback).toBeCalledTimes(1);
- expect(testCallback).toBeCalledWith(matchResult);
+ expect(testCallback).toHaveBeenCalledTimes(1);
+ expect(testCallback).toHaveBeenCalledWith(matchResult);
});
it("should call multiple registered hooks before resolve", async () => {
@@ -311,8 +313,8 @@ describe("Screen.", () => {
const findMatchMock = jest.fn(() => Promise.resolve(matchResult));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -326,7 +328,7 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
SUT.on(needle, testCallback);
SUT.on(needle, secondCallback);
@@ -336,8 +338,8 @@ describe("Screen.", () => {
// THEN
for (const callback of [testCallback, secondCallback]) {
- expect(callback).toBeCalledTimes(1);
- expect(callback).toBeCalledWith(matchResult);
+ expect(callback).toHaveBeenCalledTimes(1);
+ expect(callback).toHaveBeenCalledWith(matchResult);
}
});
@@ -349,8 +351,8 @@ describe("Screen.", () => {
const findMatchMock = jest.fn(() => Promise.reject(expectedReason));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -363,7 +365,7 @@ describe("Screen.", () => {
// THEN
await expect(resultRegion).rejects.toThrowError(
- `Searching for ${id} failed. Reason: '${expectedReason}'`,
+ `Searching for ${id} failed. Reason: '${expectedReason}'`
);
});
@@ -373,8 +375,8 @@ describe("Screen.", () => {
const findMatchMock = jest.fn(() => Promise.reject(rejectionReason));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -387,7 +389,7 @@ describe("Screen.", () => {
// THEN
await expect(resultRegion).rejects.toThrowError(
- `Searching for ${id} failed. Reason: '${rejectionReason}'`,
+ `Searching for ${id} failed. Reason: '${rejectionReason}'`
);
});
@@ -399,8 +401,8 @@ describe("Screen.", () => {
const findMatchMock = jest.fn(() => Promise.resolve(matchResult));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -413,7 +415,7 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
const parameters = new OptionalSearchParameters(undefined, minMatch);
@@ -425,7 +427,7 @@ describe("Screen.", () => {
const matchRequest = new MatchRequest(
expect.any(Image),
needle,
- minMatch,
+ minMatch
);
expect(findMatchMock).toHaveBeenCalledWith(matchRequest);
});
@@ -438,8 +440,8 @@ describe("Screen.", () => {
const findMatchMock = jest.fn(() => Promise.resolve(matchResult));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -452,13 +454,13 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
const parameters = new OptionalSearchParameters(customSearchRegion);
const expectedMatchRequest = new MatchRequest(
expect.any(Image),
needle,
- undefined,
+ undefined
);
// WHEN
@@ -476,8 +478,8 @@ describe("Screen.", () => {
const findMatchMock = jest.fn(() => Promise.resolve(matchResult));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -489,16 +491,16 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
const parameters = new OptionalSearchParameters(
customSearchRegion,
- minMatch,
+ minMatch
);
const expectedMatchRequest = new MatchRequest(
expect.any(Image),
needle,
- minMatch,
+ minMatch
);
// WHEN
@@ -518,14 +520,14 @@ describe("Screen.", () => {
limitedSearchRegion.left + resultRegion.left,
limitedSearchRegion.top + resultRegion.top,
resultRegion.width,
- resultRegion.height,
+ resultRegion.height
);
const findMatchMock = jest.fn(() => Promise.resolve(matchResult));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -534,8 +536,8 @@ describe("Screen.", () => {
const matchRegion = await SUT.find(
new Image(100, 100, Buffer.from([]), 3, "needle_image", 4, 100 * 4),
{
- searchRegion: limitedSearchRegion,
- },
+ searchRegion: limitedSearchRegion
+ }
);
// THEN
@@ -552,7 +554,7 @@ describe("Screen.", () => {
["with region bigger than screen on x axis", new Region(0, 0, 1100, 100)],
[
"with region bigger than screen on y axis",
- new Region(0, 0, 1000, 1100),
+ new Region(0, 0, 1000, 1100)
],
["with region of 1 px width", new Region(0, 0, 1, 1100)],
["with region of 1 px height", new Region(0, 0, 100, 1)],
@@ -560,14 +562,14 @@ describe("Screen.", () => {
["with region leaving screen on y axis", new Region(0, 500, 100, 600)],
[
"with NaN x coordinate",
- new Region("a" as unknown as number, 0, 100, 100),
+ new Region("a" as unknown as number, 0, 100, 100)
],
[
"with NaN y coordinate",
- new Region(0, "a" as unknown as number, 100, 600),
+ new Region(0, "a" as unknown as number, 100, 600)
],
["with NaN on width", new Region(0, 0, "a" as unknown as number, 100)],
- ["with NaN on height", new Region(0, 0, 100, "a" as unknown as number)],
+ ["with NaN on height", new Region(0, 0, 100, "a" as unknown as number)]
])("should reject search regions %s", async (_: string, region: Region) => {
// GIVEN
const id = "needle_image";
@@ -576,8 +578,8 @@ describe("Screen.", () => {
const findMatchMock = jest.fn(() => Promise.resolve(matchResult));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatch: findMatchMock,
- }),
+ findMatch: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -585,12 +587,12 @@ describe("Screen.", () => {
// WHEN
const findPromise = SUT.find(needle, {
- searchRegion: region,
+ searchRegion: region
});
// THEN
await expect(findPromise).rejects.toThrowError(
- `Searching for ${id} failed. Reason:`,
+ `Searching for ${id} failed. Reason:`
);
});
});
@@ -606,7 +608,7 @@ describe("Screen.", () => {
// THEN
await expect(result).rejects.toThrowError(
- /findAll requires an Image, a text query, a color query or a window query.*/,
+ /findAll requires an Image, a text query, a color query or a window query.*/
);
});
@@ -622,15 +624,15 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
const needlePromise = Promise.resolve(needle);
const findMatchMock = jest.fn(() => Promise.resolve([matchResult]));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatches: findMatchMock,
- }),
+ findMatches: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -648,15 +650,15 @@ describe("Screen.", () => {
id: "window-query",
type: "window",
by: {
- title: "query",
- },
+ title: "query"
+ }
};
const findMatchMock = jest.fn(() => Promise.resolve([1234]));
providerRegistryMock.getWindowFinder = jest.fn(() =>
mockPartial({
- findMatches: findMatchMock,
- }),
+ findMatches: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -677,15 +679,15 @@ describe("Screen.", () => {
id: "color-query",
type: "color",
by: {
- color: new RGBA(255, 0, 255, 1),
- },
+ color: new RGBA(255, 0, 255, 1)
+ }
};
const findMatchMock = jest.fn(() => Promise.resolve([matchResult]));
providerRegistryMock.getColorFinder = jest.fn(() =>
mockPartial({
- findMatches: findMatchMock,
- }),
+ findMatches: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -701,16 +703,16 @@ describe("Screen.", () => {
id: "dummy",
type: "text",
by: {
- word: "dummy-query",
- },
+ word: "dummy-query"
+ }
},
{
id: "dummy",
type: "text",
by: {
- line: "dummy-query",
- },
- },
+ line: "dummy-query"
+ }
+ }
])(
"should choose the correct finder implementation for text queries",
async (needle: TextQuery) => {
@@ -722,8 +724,8 @@ describe("Screen.", () => {
const findMatchMock = jest.fn(() => Promise.resolve([matchResult]));
providerRegistryMock.getTextFinder = jest.fn(() =>
mockPartial({
- findMatches: findMatchMock,
- }),
+ findMatches: findMatchMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -732,7 +734,7 @@ describe("Screen.", () => {
// THEN
expect(findMatchMock).toHaveBeenCalledTimes(1);
- },
+ }
);
});
it("should call registered hook before resolve", async () => {
@@ -742,8 +744,8 @@ describe("Screen.", () => {
const findMatchesMock = jest.fn(() => Promise.resolve(matchResults));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatches: findMatchesMock,
- }),
+ findMatches: findMatchesMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -756,7 +758,7 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
SUT.on(needle, testCallback);
@@ -764,8 +766,8 @@ describe("Screen.", () => {
await SUT.findAll(needle);
// THEN
- expect(testCallback).toBeCalledTimes(matchResults.length);
- expect(testCallback).toBeCalledWith(matchResult);
+ expect(testCallback).toHaveBeenCalledTimes(matchResults.length);
+ expect(testCallback).toHaveBeenCalledWith(matchResult);
});
it("should call multiple registered hooks before resolve", async () => {
@@ -775,8 +777,8 @@ describe("Screen.", () => {
const findMatchesMock = jest.fn(() => Promise.resolve(matchResults));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatches: findMatchesMock,
- }),
+ findMatches: findMatchesMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -790,7 +792,7 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
SUT.on(needle, testCallback);
SUT.on(needle, secondCallback);
@@ -800,8 +802,8 @@ describe("Screen.", () => {
// THEN
for (const callback of [testCallback, secondCallback]) {
- expect(callback).toBeCalledTimes(matchResults.length);
- expect(callback).toBeCalledWith(matchResult);
+ expect(callback).toHaveBeenCalledTimes(matchResults.length);
+ expect(callback).toHaveBeenCalledWith(matchResult);
}
});
@@ -811,8 +813,8 @@ describe("Screen.", () => {
const findMatchesMock = jest.fn(() => Promise.reject(rejectionReason));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatches: findMatchesMock,
- }),
+ findMatches: findMatchesMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -825,7 +827,7 @@ describe("Screen.", () => {
// THEN
await expect(resultRegion).rejects.toThrowError(
- `Searching for ${id} failed. Reason: '${rejectionReason}'`,
+ `Searching for ${id} failed. Reason: '${rejectionReason}'`
);
});
@@ -837,8 +839,8 @@ describe("Screen.", () => {
const findMatchesMock = jest.fn(() => Promise.resolve([matchResult]));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatches: findMatchesMock,
- }),
+ findMatches: findMatchesMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -851,7 +853,7 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
const parameters = new OptionalSearchParameters(undefined, minMatch);
@@ -863,7 +865,7 @@ describe("Screen.", () => {
const matchRequest = new MatchRequest(
expect.any(Image),
needle,
- minMatch,
+ minMatch
);
expect(findMatchesMock).toHaveBeenCalledWith(matchRequest);
});
@@ -876,8 +878,8 @@ describe("Screen.", () => {
const findMatchesMock = jest.fn(() => Promise.resolve([matchResult]));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatches: findMatchesMock,
- }),
+ findMatches: findMatchesMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -890,13 +892,13 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
const parameters = new OptionalSearchParameters(customSearchRegion);
const expectedMatchRequest = new MatchRequest(
expect.any(Image),
needle,
- undefined,
+ undefined
);
// WHEN
@@ -914,8 +916,8 @@ describe("Screen.", () => {
const findMatchesMock = jest.fn(() => Promise.resolve([matchResult]));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatches: findMatchesMock,
- }),
+ findMatches: findMatchesMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -927,16 +929,16 @@ describe("Screen.", () => {
3,
"needle_image",
4,
- 100 * 4,
+ 100 * 4
);
const parameters = new OptionalSearchParameters(
customSearchRegion,
- minMatch,
+ minMatch
);
const expectedMatchRequest = new MatchRequest(
expect.any(Image),
needle,
- minMatch,
+ minMatch
);
// WHEN
@@ -956,14 +958,14 @@ describe("Screen.", () => {
limitedSearchRegion.left + resultRegion.left,
limitedSearchRegion.top + resultRegion.top,
resultRegion.width,
- resultRegion.height,
+ resultRegion.height
);
const findMatchesMock = jest.fn(() => Promise.resolve([matchResult]));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatches: findMatchesMock,
- }),
+ findMatches: findMatchesMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -972,8 +974,8 @@ describe("Screen.", () => {
const [matchRegion] = await SUT.findAll(
new Image(100, 100, Buffer.from([]), 3, "needle_image", 4, 100 * 4),
{
- searchRegion: limitedSearchRegion,
- },
+ searchRegion: limitedSearchRegion
+ }
);
// THEN
@@ -990,7 +992,7 @@ describe("Screen.", () => {
["with region bigger than screen on x axis", new Region(0, 0, 1100, 100)],
[
"with region bigger than screen on y axis",
- new Region(0, 0, 1000, 1100),
+ new Region(0, 0, 1000, 1100)
],
["with region of 1 px width", new Region(0, 0, 1, 1100)],
["with region of 1 px height", new Region(0, 0, 100, 1)],
@@ -998,14 +1000,14 @@ describe("Screen.", () => {
["with region leaving screen on y axis", new Region(0, 500, 100, 600)],
[
"with NaN x coordinate",
- new Region("a" as unknown as number, 0, 100, 100),
+ new Region("a" as unknown as number, 0, 100, 100)
],
[
"with NaN y coordinate",
- new Region(0, "a" as unknown as number, 100, 600),
+ new Region(0, "a" as unknown as number, 100, 600)
],
["with NaN on width", new Region(0, 0, "a" as unknown as number, 100)],
- ["with NaN on height", new Region(0, 0, 100, "a" as unknown as number)],
+ ["with NaN on height", new Region(0, 0, 100, "a" as unknown as number)]
])("should reject search regions %s", async (_: string, region: Region) => {
// GIVEN
const id = "needle_image";
@@ -1014,8 +1016,8 @@ describe("Screen.", () => {
const findMatchesMock = jest.fn(() => Promise.resolve([matchResult]));
providerRegistryMock.getImageFinder = jest.fn(() =>
mockPartial({
- findMatches: findMatchesMock,
- }),
+ findMatches: findMatchesMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -1023,12 +1025,12 @@ describe("Screen.", () => {
// WHEN
const findPromise = SUT.findAll(needle, {
- searchRegion: region,
+ searchRegion: region
});
// THEN
await expect(findPromise).rejects.toThrowError(
- `Searching for ${id} failed. Reason:`,
+ `Searching for ${id} failed. Reason:`
);
});
});
@@ -1039,8 +1041,8 @@ describe("Screen.", () => {
const highlightMock = jest.fn((value: any) => Promise.resolve(value));
providerRegistryMock.getScreen = jest.fn(() =>
mockPartial({
- highlightScreenRegion: highlightMock,
- }),
+ highlightScreenRegion: highlightMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -1056,13 +1058,13 @@ describe("Screen.", () => {
// GIVEN
const highlightRegion = new Region(10, 20, 30, 40);
const highlightRegionPromise = new Promise((res) =>
- res(highlightRegion),
+ res(highlightRegion)
);
const highlightMock = jest.fn((value: any) => Promise.resolve(value));
providerRegistryMock.getScreen = jest.fn(() =>
mockPartial({
- highlightScreenRegion: highlightMock,
- }),
+ highlightScreenRegion: highlightMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -1085,19 +1087,19 @@ describe("Screen.", () => {
4,
"test",
4,
- 100 * 4,
+ 100 * 4
);
const grabScreenMock = jest.fn(() => Promise.resolve(screenshot));
const saveImageMock = jest.fn();
providerRegistryMock.getScreen = jest.fn(() =>
mockPartial({
- grabScreen: grabScreenMock,
- }),
+ grabScreen: grabScreenMock
+ })
);
providerRegistryMock.getImageWriter = jest.fn(() =>
mockPartial({
- store: saveImageMock,
- }),
+ store: saveImageMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -1106,7 +1108,7 @@ describe("Screen.", () => {
const expectedImagePath = join(cwd(), imageName);
const expectedData: ImageWriterParameters = {
image: screenshot,
- path: expectedImagePath,
+ path: expectedImagePath
};
// WHEN
@@ -1124,8 +1126,8 @@ describe("Screen.", () => {
const grabScreenMock = jest.fn(() => Promise.resolve(screenshot));
providerRegistryMock.getScreen = jest.fn(() =>
mockPartial({
- grabScreen: grabScreenMock,
- }),
+ grabScreen: grabScreenMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -1137,7 +1139,7 @@ describe("Screen.", () => {
// THEN
expect(result).rejects.toThrowError(
- /^capture requires an Image, but received/,
+ /^capture requires an Image, but received/
);
});
});
@@ -1152,25 +1154,25 @@ describe("Screen.", () => {
4,
"test",
4,
- 100 * 4,
+ 100 * 4
);
const regionToCapture = mockPartial({
top: 42,
left: 9,
height: 10,
- width: 3.14159265359,
+ width: 3.14159265359
});
const grabScreenMock = jest.fn(() => Promise.resolve(screenshot));
const saveImageMock = jest.fn();
providerRegistryMock.getScreen = jest.fn(() =>
mockPartial({
- grabScreenRegion: grabScreenMock,
- }),
+ grabScreenRegion: grabScreenMock
+ })
);
providerRegistryMock.getImageWriter = jest.fn(() =>
mockPartial({
- store: saveImageMock,
- }),
+ store: saveImageMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -1179,7 +1181,7 @@ describe("Screen.", () => {
const expectedImagePath = join(cwd(), imageName);
const expectedData: ImageWriterParameters = {
image: screenshot,
- path: expectedImagePath,
+ path: expectedImagePath
};
// WHEN
@@ -1198,13 +1200,13 @@ describe("Screen.", () => {
top: 42,
left: 9,
height: 10,
- width: 3.14159265359,
+ width: 3.14159265359
});
const grabScreenMock = jest.fn(() => Promise.resolve(screenshot));
providerRegistryMock.getScreen = jest.fn(() =>
mockPartial({
- grabScreenRegion: grabScreenMock,
- }),
+ grabScreenRegion: grabScreenMock
+ })
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -1216,7 +1218,7 @@ describe("Screen.", () => {
// THEN
expect(result).rejects.toThrowError(
- /^captureRegion requires an Image, but received/,
+ /^captureRegion requires an Image, but received/
);
});
});
diff --git a/lib/screen.class.ts b/core/nut.js/lib/screen.class.ts
similarity index 86%
rename from lib/screen.class.ts
rename to core/nut.js/lib/screen.class.ts
index 27a72e9c..64dc65e5 100644
--- a/lib/screen.class.ts
+++ b/core/nut.js/lib/screen.class.ts
@@ -1,32 +1,42 @@
import { cwd } from "process";
-import { FileType } from "./file-type.enum";
-import { generateOutputPath } from "./generate-output-path.function";
-import { createMatchRequest, MatchRequest } from "./match-request.class";
-import {
- getMatchResult,
- getMatchResults,
- MatchResult,
-} from "./match-result.class";
-import { isRegion, Region } from "./region.class";
-import { timeout } from "./util/timeout.function";
-import { Image, isImage } from "./image.class";
-import { ProviderRegistry } from "./provider/provider-registry.class";
-import { isPoint, Point } from "./point.class";
-import { OptionalSearchParameters } from "./optionalsearchparameters.class";
import {
ColorQuery,
+ FileType,
+ FindInput,
+ FindResult,
+ Image,
isColorQuery,
+ isImage,
+ isPoint,
+ isRegion,
isTextQuery,
isWindowQuery,
LineQuery,
- WindowQuery,
- WordQuery,
-} from "./query.class";
+ MatchRequest,
+ MatchResult,
+ OptionalSearchParameters,
+ Point,
+ PointResultFindInput,
+ Region,
+ RegionResultFindInput,
+ WindowResultFindInput,
+ WordQuery
+} from "@nut-tree/shared";
+import { generateOutputPath } from "./generate-output-path.function";
+import { timeout } from "./util/timeout.function";
import { Window } from "./window.class";
+import { ProviderRegistry } from "@nut-tree/provider-interfaces";
+import {
+ createMatchRequest,
+ getMatchResult,
+ getMatchResults,
+ isPointResultFindInput,
+ isRegionResultFindInput
+} from "./screen-helpers.function";
export type WindowCallback = (target: Window) => void | Promise;
export type MatchResultCallback = (
- target: MatchResult,
+ target: MatchResult
) => void | Promise;
export type FindHookCallback =
| WindowCallback
@@ -36,7 +46,7 @@ export type FindHookCallback =
function validateSearchRegion(
search: Region,
screen: Region,
- providerRegistry: ProviderRegistry,
+ providerRegistry: ProviderRegistry
) {
providerRegistry
.getLogProvider()
@@ -63,7 +73,7 @@ function validateSearchRegion(
}
if (search.width < 2 || search.height < 2) {
const e = new Error(
- `Search region is not large enough. Must be at least two pixels in both width and height.`,
+ `Search region is not large enough. Must be at least two pixels in both width and height.`
);
providerRegistry.getLogProvider().error(e, { region: search });
throw e;
@@ -73,7 +83,7 @@ function validateSearchRegion(
search.top + search.height > screen.height
) {
const e = new Error(
- `Search region extends beyond screen boundaries (${screen.width}x${screen.height})`,
+ `Search region extends beyond screen boundaries (${screen.width}x${screen.height})`
);
providerRegistry.getLogProvider().error(e, { region: search, screen });
throw e;
@@ -109,27 +119,6 @@ export interface ScreenConfig {
resourceDirectory: string;
}
-export type RegionResultFindInput = Image | WordQuery | LineQuery;
-export type PointResultFindInput = ColorQuery;
-export type WindowResultFindInput = WindowQuery;
-export type FindInput =
- | RegionResultFindInput
- | WindowResultFindInput
- | PointResultFindInput;
-export type FindResult = Region | Point | Window;
-
-function isRegionResultFindInput(
- input: RegionResultFindInput | PointResultFindInput,
-): input is RegionResultFindInput {
- return isImage(input) || isTextQuery(input);
-}
-
-function isPointResultFindInput(
- input: RegionResultFindInput | PointResultFindInput,
-): input is PointResultFindInput {
- return isColorQuery(input);
-}
-
/**
* {@link ScreenClass} class provides methods to access screen content of a systems main display
*/
@@ -139,7 +128,7 @@ export class ScreenClass {
autoHighlight: false,
highlightDurationMs: 500,
highlightOpacity: 0.25,
- resourceDirectory: cwd(),
+ resourceDirectory: cwd()
};
/**
@@ -152,8 +141,9 @@ export class ScreenClass {
private findHooks: Map = new Map<
FindInput,
FindHookCallback[]
- >(),
- ) {}
+ >()
+ ) {
+ }
/**
* {@link width} returns the main screen width
@@ -182,23 +172,23 @@ export class ScreenClass {
*/
public async find(
searchInput: RegionResultFindInput | Promise,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise;
public async find(
searchInput: PointResultFindInput | Promise,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise;
public async find(
searchInput: WindowResultFindInput | Promise,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise;
public async find(
searchInput: FindInput | Promise,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise;
public async find(
searchInput: FindInput | Promise,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise {
const needle = await searchInput;
this.providerRegistry.getLogProvider().info(`Searching for ${needle}`);
@@ -236,7 +226,7 @@ export class ScreenClass {
searchRegion,
minMatch,
screenImage,
- params,
+ params
);
if (isRegionResultFindInput(needle)) {
@@ -245,7 +235,7 @@ export class ScreenClass {
matchRequest as MatchRequest<
RegionResultFindInput,
PROVIDER_DATA_TYPE
- >,
+ >
);
this.providerRegistry
@@ -265,7 +255,7 @@ export class ScreenClass {
searchRegion.left + matchResult.location.left,
searchRegion.top + matchResult.location.top,
matchResult.location.width,
- matchResult.location.height,
+ matchResult.location.height
);
this.providerRegistry
@@ -286,7 +276,7 @@ export class ScreenClass {
matchRequest as MatchRequest<
PointResultFindInput,
PROVIDER_DATA_TYPE
- >,
+ >
);
this.providerRegistry
@@ -304,7 +294,7 @@ export class ScreenClass {
const resultPoint = new Point(
searchRegion.left + matchResult.location.x,
- searchRegion.top + matchResult.location.y,
+ searchRegion.top + matchResult.location.y
);
this.providerRegistry
@@ -315,11 +305,11 @@ export class ScreenClass {
}
}
throw new Error(
- `Search input is not supported. Please use a valid search input type.`,
+ `Search input is not supported. Please use a valid search input type.`
);
} catch (e) {
const error = new Error(
- `Searching for ${needle.id} failed. Reason: '${e}'`,
+ `Searching for ${needle.id} failed. Reason: '${e}'`
);
this.providerRegistry.getLogProvider().error(error);
throw error;
@@ -333,19 +323,19 @@ export class ScreenClass {
*/
public async findAll(
searchInput: RegionResultFindInput | Promise,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise;
public async findAll(
searchInput: PointResultFindInput | Promise,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise;
public async findAll(
searchInput: WindowResultFindInput | Promise,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise;
public async findAll(
searchInput: FindInput | Promise,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise {
const needle = await searchInput;
this.providerRegistry.getLogProvider().info(`Searching for ${needle}`);
@@ -359,13 +349,13 @@ export class ScreenClass {
.findMatches(needle);
const windows = matches.map(
(windowHandle: number) =>
- new Window(this.providerRegistry, windowHandle),
+ new Window(this.providerRegistry, windowHandle)
);
const possibleHooks = this.getHooksForInput(needle) || [];
this.providerRegistry
.getLogProvider()
.debug(
- `${possibleHooks.length} hooks triggered for ${windows.length} matches`,
+ `${possibleHooks.length} hooks triggered for ${windows.length} matches`
);
for (const hook of possibleHooks) {
for (const wnd of windows) {
@@ -385,7 +375,7 @@ export class ScreenClass {
searchRegion,
minMatch,
screenImage,
- params,
+ params
);
validateSearchRegion(searchRegion, screenSize, this.providerRegistry);
@@ -393,13 +383,13 @@ export class ScreenClass {
const matchResults = await getMatchResults(
this.providerRegistry,
- matchRequest,
+ matchRequest
);
const possibleHooks = this.getHooksForInput(needle) || [];
this.providerRegistry
.getLogProvider()
.debug(
- `${possibleHooks.length} hooks triggered for ${matchResults.length} matches`,
+ `${possibleHooks.length} hooks triggered for ${matchResults.length} matches`
);
for (const hook of possibleHooks) {
for (const matchResult of matchResults) {
@@ -412,7 +402,7 @@ export class ScreenClass {
searchRegion.left + matchResult.location.left,
searchRegion.top + matchResult.location.top,
matchResult.location.width,
- matchResult.location.height,
+ matchResult.location.height
);
this.providerRegistry
.getLogProvider()
@@ -445,7 +435,7 @@ export class ScreenClass {
searchRegion,
0,
screenImage,
- params,
+ params
);
validateSearchRegion(searchRegion, screenSize, this.providerRegistry);
@@ -453,13 +443,13 @@ export class ScreenClass {
const matchResults = await getMatchResults(
this.providerRegistry,
- matchRequest,
+ matchRequest
);
const possibleHooks = this.getHooksForInput(needle) || [];
this.providerRegistry
.getLogProvider()
.debug(
- `${possibleHooks.length} hooks triggered for ${matchResults.length} matches`,
+ `${possibleHooks.length} hooks triggered for ${matchResults.length} matches`
);
for (const hook of possibleHooks) {
for (const matchResult of matchResults) {
@@ -470,7 +460,7 @@ export class ScreenClass {
return matchResults.map((matchResult) => {
const resultPoint = new Point(
searchRegion.left + matchResult.location.x,
- searchRegion.top + matchResult.location.y,
+ searchRegion.top + matchResult.location.y
);
this.providerRegistry
.getLogProvider()
@@ -479,11 +469,11 @@ export class ScreenClass {
});
}
throw new Error(
- `Search input is not supported. Please use a valid search input type.`,
+ `Search input is not supported. Please use a valid search input type.`
);
} catch (e) {
const error = new Error(
- `Searching for ${needle.id} failed. Reason: '${e}'`,
+ `Searching for ${needle.id} failed. Reason: '${e}'`
);
this.providerRegistry.getLogProvider().error(error);
throw error;
@@ -495,14 +485,14 @@ export class ScreenClass {
* @param regionToHighlight The {@link Region} to highlight
*/
public async highlight(
- regionToHighlight: Region | Promise,
+ regionToHighlight: Region | Promise
): Promise {
const highlightRegion = await regionToHighlight;
if (!isRegion(highlightRegion)) {
const e = Error(
`highlight requires an Region, but received ${JSON.stringify(
- highlightRegion,
- )}`,
+ highlightRegion
+ )}`
);
this.providerRegistry.getLogProvider().error(e);
throw e;
@@ -512,14 +502,14 @@ export class ScreenClass {
.info(
`Highlighting ${highlightRegion.toString()} for ${
this.config.highlightDurationMs / 1000
- } with ${this.config.highlightOpacity * 100}% opacity`,
+ } with ${this.config.highlightOpacity * 100}% opacity`
);
await this.providerRegistry
.getScreen()
.highlightScreenRegion(
highlightRegion,
this.config.highlightDurationMs,
- this.config.highlightOpacity,
+ this.config.highlightOpacity
);
return highlightRegion;
}
@@ -535,25 +525,25 @@ export class ScreenClass {
searchInput: RegionResultFindInput | Promise,
timeoutMs?: number,
updateInterval?: number,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise;
public async waitFor(
searchInput: PointResultFindInput | Promise,
timeoutMs?: number,
updateInterval?: number,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise;
public async waitFor(
searchInput: WindowResultFindInput | Promise,
timeoutMs?: number,
updateInterval?: number,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise;
public async waitFor(
searchInput: FindInput | Promise,
timeoutMs?: number,
updateInterval?: number,
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
): Promise {
const needle = await searchInput;
@@ -567,7 +557,7 @@ export class ScreenClass {
.info(
`Waiting for ${needle.id} to appear on screen. Timeout: ${
timeoutValue / 1000
- } seconds, interval: ${updateIntervalValue} ms`,
+ } seconds, interval: ${updateIntervalValue} ms`
);
return timeout(
updateIntervalValue,
@@ -576,8 +566,8 @@ export class ScreenClass {
return this.find(needle, params);
},
{
- signal: params?.abort,
- },
+ signal: params?.abort
+ }
);
}
@@ -589,11 +579,11 @@ export class ScreenClass {
public on(searchInput: WindowResultFindInput, callback: WindowCallback): void;
public on(
searchInput: PointResultFindInput,
- callback: MatchResultCallback,
+ callback: MatchResultCallback
): void;
public on(
searchInput: RegionResultFindInput,
- callback: MatchResultCallback,
+ callback: MatchResultCallback
): void;
public on(searchInput: FindInput, callback: FindHookCallback): void {
this.validateSearchInput("on", searchInput);
@@ -605,7 +595,7 @@ export class ScreenClass {
.info(
`Registered callback for image ${searchInput.id}. There are currently ${
existingHooks.length + 1
- } hooks registered`,
+ } hooks registered`
);
}
@@ -622,14 +612,14 @@ export class ScreenClass {
fileFormat: FileType = FileType.PNG,
filePath: string = cwd(),
fileNamePrefix: string = "",
- fileNamePostfix: string = "",
+ fileNamePostfix: string = ""
): Promise {
const currentScreen = await this.providerRegistry.getScreen().grabScreen();
if (!isImage(currentScreen)) {
const e = new Error(
`capture requires an Image, but received ${JSON.stringify(
- currentScreen,
- )}`,
+ currentScreen
+ )}`
);
this.providerRegistry.getLogProvider().error(e);
throw e;
@@ -637,7 +627,7 @@ export class ScreenClass {
this.providerRegistry
.getLogProvider()
.info(
- `Capturing whole screen (0, 0, ${currentScreen.width}, ${currentScreen.height})`,
+ `Capturing whole screen (0, 0, ${currentScreen.width}, ${currentScreen.height})`
);
return this.saveImage(
currentScreen,
@@ -645,7 +635,7 @@ export class ScreenClass {
fileFormat,
filePath,
fileNamePrefix,
- fileNamePostfix,
+ fileNamePostfix
);
}
@@ -657,7 +647,7 @@ export class ScreenClass {
this.providerRegistry
.getLogProvider()
.info(
- `Grabbed whole screen (0, 0, ${currentScreen.width}, ${currentScreen.height})`,
+ `Grabbed whole screen (0, 0, ${currentScreen.width}, ${currentScreen.height})`
);
return currentScreen;
}
@@ -677,14 +667,14 @@ export class ScreenClass {
fileFormat: FileType = FileType.PNG,
filePath: string = cwd(),
fileNamePrefix: string = "",
- fileNamePostfix: string = "",
+ fileNamePostfix: string = ""
): Promise {
const targetRegion = await regionToCapture;
if (!isRegion(targetRegion)) {
const e = new Error(
`captureRegion requires an Region, but received ${JSON.stringify(
- targetRegion,
- )}`,
+ targetRegion
+ )}`
);
this.providerRegistry.getLogProvider().error(e);
throw e;
@@ -698,8 +688,8 @@ export class ScreenClass {
if (!isImage(regionImage)) {
const e = new Error(
`captureRegion requires an Image, but received ${JSON.stringify(
- regionImage,
- )}`,
+ regionImage
+ )}`
);
this.providerRegistry.getLogProvider().error(e);
throw e;
@@ -710,7 +700,7 @@ export class ScreenClass {
fileFormat,
filePath,
fileNamePrefix,
- fileNamePostfix,
+ fileNamePostfix
);
}
@@ -719,14 +709,14 @@ export class ScreenClass {
* @param regionToGrab The screen region to grab
*/
public async grabRegion(
- regionToGrab: Region | Promise,
+ regionToGrab: Region | Promise
): Promise {
const targetRegion = await regionToGrab;
if (!isRegion(targetRegion)) {
const e = new Error(
`grabRegion requires an Region, but received ${JSON.stringify(
- targetRegion,
- )}`,
+ targetRegion
+ )}`
);
this.providerRegistry.getLogProvider().error(e);
throw e;
@@ -749,14 +739,14 @@ export class ScreenClass {
const inputPoint = await point;
if (!isPoint(inputPoint)) {
const e = new Error(
- `colorAt requires a Point, but received ${JSON.stringify(inputPoint)}`,
+ `colorAt requires a Point, but received ${JSON.stringify(inputPoint)}`
);
this.providerRegistry.getLogProvider().error(e);
throw e;
}
const scaledPoint = new Point(
inputPoint.x * screenContent.pixelDensity.scaleX,
- inputPoint.y * screenContent.pixelDensity.scaleY,
+ inputPoint.y * screenContent.pixelDensity.scaleY
);
this.providerRegistry
.getLogProvider()
@@ -765,7 +755,7 @@ export class ScreenClass {
screenContent.pixelDensity.scaleX
}, ${
screenContent.pixelDensity.scaleY
- }) into ${scaledPoint.toString()}`,
+ }) into ${scaledPoint.toString()}`
);
const color = await this.providerRegistry
.getImageProcessor()
@@ -782,13 +772,13 @@ export class ScreenClass {
fileFormat: FileType,
filePath: string,
fileNamePrefix: string,
- fileNamePostfix: string,
+ fileNamePostfix: string
) {
const outputPath = generateOutputPath(fileName, {
path: filePath,
postfix: fileNamePostfix,
prefix: fileNamePrefix,
- type: fileFormat,
+ type: fileFormat
});
this.providerRegistry
.getLogProvider()
@@ -801,7 +791,7 @@ export class ScreenClass {
}
private async getFindParameters(
- params?: OptionalSearchParameters,
+ params?: OptionalSearchParameters
) {
const minMatch = params?.confidence;
const screenSize = await this.providerRegistry.getScreen().screenSize();
@@ -814,27 +804,27 @@ export class ScreenClass {
minMatch,
screenSize,
searchRegion,
- screenImage,
+ screenImage
};
this.providerRegistry
.getLogProvider()
.debug(`Running on-screen search with parameters`, {
minMatch,
screenSize,
- searchRegion,
+ searchRegion
});
return findParameters;
}
private getHooksForInput(input: WindowResultFindInput): WindowCallback[];
private getHooksForInput(
- input: RegionResultFindInput,
+ input: RegionResultFindInput
): MatchResultCallback[];
private getHooksForInput(
- input: PointResultFindInput,
+ input: PointResultFindInput
): MatchResultCallback[];
private getHooksForInput(
- input: FindInput,
+ input: FindInput
):
| MatchResultCallback[]
| MatchResultCallback[]
@@ -865,7 +855,7 @@ export class ScreenClass {
| LineQuery
| WindowResultFindInput
| PointResultFindInput
- | Promise,
+ | Promise
) {
if (
!isImage(needle) &&
@@ -875,8 +865,8 @@ export class ScreenClass {
) {
const e = Error(
`${functionName} requires an Image, a text query, a color query or a window query, but received ${JSON.stringify(
- needle,
- )}`,
+ needle
+ )}`
);
this.providerRegistry.getLogProvider().error(e, { needle });
throw e;
diff --git a/lib/screen.colorAt.spec.ts b/core/nut.js/lib/screen.colorAt.spec.ts
similarity index 85%
rename from lib/screen.colorAt.spec.ts
rename to core/nut.js/lib/screen.colorAt.spec.ts
index 65661595..fb139f5d 100644
--- a/lib/screen.colorAt.spec.ts
+++ b/core/nut.js/lib/screen.colorAt.spec.ts
@@ -1,17 +1,7 @@
-import {
- Image,
- loadImage,
- Point,
- Region,
- RGBA,
- ScreenClass,
- ScreenProviderInterface,
-} from "../index";
+import { Image, loadImage, Point, Region, RGBA, ScreenClass } from "../index";
import { mockPartial } from "sneer";
-import providerRegistry, {
- ProviderRegistry,
-} from "./provider/provider-registry.class";
-import { ImageProcessor } from "./provider/image-processor.interface";
+import providerRegistry from "./provider/provider-registry.class";
+import { ImageProcessor, ProviderRegistry, ScreenProviderInterface } from "@nut-tree/provider-interfaces";
import { NoopLogProvider } from "./provider/log/noop-log-provider.class";
const searchRegion = new Region(0, 0, 1000, 1000);
@@ -33,22 +23,22 @@ const providerRegistryMock = mockPartial({
},
screenSize(): Promise {
return Promise.resolve(searchRegion);
- },
+ }
});
},
getImageProcessor(): ImageProcessor {
return providerRegistry.getImageProcessor();
- },
+ }
});
describe("colorAt", () => {
it("should return the correct RGBA value for a given pixel", async () => {
// GIVEN
- const screenshot = loadImage(`${__dirname}/../e2e/assets/checkers.png`);
+ const screenshot = loadImage(`${__dirname}/../assets/checkers.png`);
const grabScreenMock = jest.fn(() => Promise.resolve(screenshot));
providerRegistryMock.getScreen = jest.fn(() =>
mockPartial({
- grabScreen: grabScreenMock,
+ grabScreen: grabScreenMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -69,14 +59,14 @@ describe("colorAt", () => {
it("should account for pixel density when retrieving pixel color", async () => {
// GIVEN
const screenshot = await loadImage(
- `${__dirname}/../e2e/assets/checkers.png`
+ `${__dirname}/../assets/checkers.png`
);
screenshot.pixelDensity.scaleX = 2.0;
screenshot.pixelDensity.scaleY = 2.0;
const grabScreenMock = jest.fn(() => Promise.resolve(screenshot));
providerRegistryMock.getScreen = jest.fn(() =>
mockPartial({
- grabScreen: grabScreenMock,
+ grabScreen: grabScreenMock
})
);
providerRegistryMock.getLogProvider = () => new NoopLogProvider();
@@ -101,7 +91,7 @@ describe("colorAt", () => {
);
providerRegistryMock.getScreen = jest.fn(() =>
mockPartial({
- grabScreen: grabScreenMock,
+ grabScreen: grabScreenMock
})
);
const SUT = new ScreenClass(providerRegistryMock);
diff --git a/lib/sleep.function.spec.ts b/core/nut.js/lib/sleep.function.spec.ts
similarity index 100%
rename from lib/sleep.function.spec.ts
rename to core/nut.js/lib/sleep.function.spec.ts
diff --git a/lib/sleep.function.ts b/core/nut.js/lib/sleep.function.ts
similarity index 100%
rename from lib/sleep.function.ts
rename to core/nut.js/lib/sleep.function.ts
diff --git a/lib/util/bresenham.class.spec.ts b/core/nut.js/lib/util/bresenham.class.spec.ts
similarity index 96%
rename from lib/util/bresenham.class.spec.ts
rename to core/nut.js/lib/util/bresenham.class.spec.ts
index a00154a4..2efe93a4 100644
--- a/lib/util/bresenham.class.spec.ts
+++ b/core/nut.js/lib/util/bresenham.class.spec.ts
@@ -1,4 +1,4 @@
-import { Point } from "../point.class";
+import { Point } from "@nut-tree/shared";
import { Bresenham } from "./bresenham.class";
describe("Bresenham", () => {
diff --git a/lib/util/bresenham.class.ts b/core/nut.js/lib/util/bresenham.class.ts
similarity index 97%
rename from lib/util/bresenham.class.ts
rename to core/nut.js/lib/util/bresenham.class.ts
index 82a66396..efd6c568 100644
--- a/lib/util/bresenham.class.ts
+++ b/core/nut.js/lib/util/bresenham.class.ts
@@ -1,4 +1,4 @@
-import { Point } from "../point.class";
+import { Point } from "@nut-tree/shared";
export class Bresenham {
public static compute(from: Point, to: Point): Point[] {
diff --git a/lib/util/linehelper.class.spec.ts b/core/nut.js/lib/util/linehelper.class.spec.ts
similarity index 96%
rename from lib/util/linehelper.class.spec.ts
rename to core/nut.js/lib/util/linehelper.class.spec.ts
index 691f03c5..fdd63efa 100644
--- a/lib/util/linehelper.class.spec.ts
+++ b/core/nut.js/lib/util/linehelper.class.spec.ts
@@ -1,4 +1,4 @@
-import { Point } from "../point.class";
+import { Point } from "@nut-tree/shared";
import { LineHelper } from "./linehelper.class";
describe("LineHelper", () => {
diff --git a/lib/util/linehelper.class.ts b/core/nut.js/lib/util/linehelper.class.ts
similarity index 82%
rename from lib/util/linehelper.class.ts
rename to core/nut.js/lib/util/linehelper.class.ts
index 2833f1c4..0407a4de 100644
--- a/lib/util/linehelper.class.ts
+++ b/core/nut.js/lib/util/linehelper.class.ts
@@ -1,4 +1,4 @@
-import { Point } from "../point.class";
+import { Point } from "@nut-tree/shared";
import { Bresenham } from "./bresenham.class";
diff --git a/lib/util/timeout.function.spec.ts b/core/nut.js/lib/util/timeout.function.spec.ts
similarity index 90%
rename from lib/util/timeout.function.spec.ts
rename to core/nut.js/lib/util/timeout.function.spec.ts
index 7fc5af96..1e6e0e0c 100644
--- a/lib/util/timeout.function.spec.ts
+++ b/core/nut.js/lib/util/timeout.function.spec.ts
@@ -1,5 +1,5 @@
import { timeout } from "./timeout.function";
-import AbortController from "node-abort-controller";
+import {AbortController} from "node-abort-controller";
import { sleep } from "../sleep.function";
describe("timeout", () => {
@@ -17,7 +17,7 @@ describe("timeout", () => {
await timeout(updateInterval, maxDuration, action);
} catch (e) {
expect(e).toBe(
- `Action timed out after ${maxDuration} ms. Last rejection reason was: false.`,
+ `Action timed out after ${maxDuration} ms. Last rejection reason was: false.`
);
}
const end = Date.now();
@@ -40,7 +40,7 @@ describe("timeout", () => {
await timeout(updateInterval, maxDuration, action);
} catch (e) {
expect(e).toEqual(
- `Action timed out after ${maxDuration} ms. Didn't receive a result within timeout.`,
+ `Action timed out after ${maxDuration} ms. Didn't receive a result within timeout.`
);
}
const end = Date.now();
@@ -64,7 +64,7 @@ describe("timeout", () => {
// THEN
expect(end - start).toBeLessThan(updateInterval);
- expect(action).toBeCalledTimes(1);
+ expect(action).toHaveBeenCalledTimes(1);
});
it("should resolve after updateInterval if action resolves != true", async () => {
@@ -82,7 +82,7 @@ describe("timeout", () => {
// THEN
expect(end - start).toBeLessThan(updateInterval);
- expect(action).toBeCalledTimes(1);
+ expect(action).toHaveBeenCalledTimes(1);
});
it("should retry until action succeeds", async () => {
@@ -94,7 +94,7 @@ describe("timeout", () => {
const action = jest.fn(() => {
const interval = Date.now() - start;
return new Promise((resolve, reject) =>
- interval > delay ? resolve(true) : reject(),
+ interval > delay ? resolve(true) : reject()
);
});
@@ -119,13 +119,13 @@ describe("timeout", () => {
await timeout(updateInterval, maxDuration, action);
} catch (e) {
expect(e).toEqual(
- `Action timed out after ${maxDuration} ms. Didn't receive a result within timeout.`,
+ `Action timed out after ${maxDuration} ms. Didn't receive a result within timeout.`
);
}
const end = Date.now();
// THEN
- expect(action).toBeCalledTimes(1);
+ expect(action).toHaveBeenCalledTimes(1);
expect(end - start).toBeLessThan(updateInterval);
});
@@ -144,9 +144,9 @@ describe("timeout", () => {
// THEN
await expect(SUT).rejects.toBe(
- `Action timed out after ${maxDuration} ms. Didn't receive a result within timeout.`,
+ `Action timed out after ${maxDuration} ms. Didn't receive a result within timeout.`
);
- expect(action).toBeCalledTimes(1);
+ expect(action).toHaveBeenCalledTimes(1);
});
it("should fail after timeout if no result is returned from long running action", async () => {
@@ -166,11 +166,11 @@ describe("timeout", () => {
// THEN
await expect(SUT).rejects.toBe(
- `Action timed out after ${maxDuration} ms. Didn't receive a result within timeout.`,
+ `Action timed out after ${maxDuration} ms. Didn't receive a result within timeout.`
);
- expect(action).toBeCalledTimes(1);
+ expect(action).toHaveBeenCalledTimes(1);
await sleep(500);
- expect(action).toBeCalledTimes(1);
+ expect(action).toHaveBeenCalledTimes(1);
});
it("should be externally abortable", async () => {
diff --git a/lib/util/timeout.function.ts b/core/nut.js/lib/util/timeout.function.ts
similarity index 100%
rename from lib/util/timeout.function.ts
rename to core/nut.js/lib/util/timeout.function.ts
diff --git a/lib/window-api.interface.ts b/core/nut.js/lib/window-api.interface.ts
similarity index 100%
rename from lib/window-api.interface.ts
rename to core/nut.js/lib/window-api.interface.ts
diff --git a/core/nut.js/lib/window-element.interface.ts b/core/nut.js/lib/window-element.interface.ts
new file mode 100644
index 00000000..67542600
--- /dev/null
+++ b/core/nut.js/lib/window-element.interface.ts
@@ -0,0 +1,14 @@
+import { Region } from "@nut-tree/shared";
+
+export interface WindowElement {
+ type?: string;
+ region?: Region;
+ title?: string;
+ value?: string;
+ isFocused?: boolean;
+ selectedText?: string;
+ isEnabled?: boolean;
+ role?: string;
+ subRole?: string;
+ children?: WindowElement[]
+}
\ No newline at end of file
diff --git a/lib/window.class.spec.ts b/core/nut.js/lib/window.class.spec.ts
similarity index 66%
rename from lib/window.class.spec.ts
rename to core/nut.js/lib/window.class.spec.ts
index f9121780..39c8f6d3 100644
--- a/lib/window.class.spec.ts
+++ b/core/nut.js/lib/window.class.spec.ts
@@ -1,9 +1,6 @@
import { Window } from "./window.class";
-import { ProviderRegistry } from "./provider/provider-registry.class";
+import { ProviderRegistry, WindowProviderInterface } from "@nut-tree/provider-interfaces";
import { mockPartial } from "sneer";
-import { WindowProviderInterface } from "./provider";
-
-jest.mock("jimp", () => {});
describe("Window class", () => {
it("should retrieve the window region via provider", async () => {
@@ -12,19 +9,19 @@ describe("Window class", () => {
const providerRegistryMock = mockPartial({
getWindow(): WindowProviderInterface {
return mockPartial({
- getWindowRegion: windowMock,
+ getWindowRegion: windowMock
});
- },
+ }
});
const mockWindowHandle = 123;
const SUT = new Window(providerRegistryMock, mockWindowHandle);
// WHEN
- await SUT.region;
+ await SUT.getRegion();
// THEN
- expect(windowMock).toBeCalledTimes(1);
- expect(windowMock).toBeCalledWith(mockWindowHandle);
+ expect(windowMock).toHaveBeenCalledTimes(1);
+ expect(windowMock).toHaveBeenCalledWith(mockWindowHandle);
});
it("should retrieve the window title via provider", async () => {
@@ -33,18 +30,18 @@ describe("Window class", () => {
const providerRegistryMock = mockPartial({
getWindow(): WindowProviderInterface {
return mockPartial({
- getWindowTitle: windowMock,
+ getWindowTitle: windowMock
});
- },
+ }
});
const mockWindowHandle = 123;
const SUT = new Window(providerRegistryMock, mockWindowHandle);
// WHEN
- await SUT.title;
+ await SUT.getTitle();
// THEN
- expect(windowMock).toBeCalledTimes(1);
- expect(windowMock).toBeCalledWith(mockWindowHandle);
+ expect(windowMock).toHaveBeenCalledTimes(1);
+ expect(windowMock).toHaveBeenCalledWith(mockWindowHandle);
});
});
diff --git a/lib/window.class.ts b/core/nut.js/lib/window.class.ts
similarity index 50%
rename from lib/window.class.ts
rename to core/nut.js/lib/window.class.ts
index c6fe6552..f52cd916 100644
--- a/lib/window.class.ts
+++ b/core/nut.js/lib/window.class.ts
@@ -1,35 +1,42 @@
-import { Region } from "./region.class";
-import { ProviderRegistry } from "./provider/provider-registry.class";
-import { Point } from "./point.class";
-import { Size } from "./size.class";
+import { Point, Region, Size, WindowInterface } from "@nut-tree/shared";
+import { ProviderRegistry } from "@nut-tree/provider-interfaces";
-export class Window {
+export class Window implements WindowInterface {
constructor(
private providerRegistry: ProviderRegistry,
- private windowHandle: number,
- ) {}
+ private windowHandle: number
+ ) {
+ }
get title(): Promise {
+ return this.getTitle();
+ }
+
+ async getTitle(): Promise {
return this.providerRegistry.getWindow().getWindowTitle(this.windowHandle);
}
get region(): Promise {
+ return this.getRegion();
+ }
+
+ async getRegion(): Promise {
return this.providerRegistry.getWindow().getWindowRegion(this.windowHandle);
}
async move(newOrigin: Point) {
- await this.providerRegistry
+ return this.providerRegistry
.getWindow()
.moveWindow(this.windowHandle, newOrigin);
}
async resize(newSize: Size) {
- await this.providerRegistry
+ return this.providerRegistry
.getWindow()
.resizeWindow(this.windowHandle, newSize);
}
async focus() {
- await this.providerRegistry.getWindow().focusWindow(this.windowHandle);
+ return this.providerRegistry.getWindow().focusWindow(this.windowHandle);
}
}
diff --git a/lib/window.function.spec.ts b/core/nut.js/lib/window.function.spec.ts
similarity index 100%
rename from lib/window.function.spec.ts
rename to core/nut.js/lib/window.function.spec.ts
diff --git a/lib/window.function.ts b/core/nut.js/lib/window.function.ts
similarity index 92%
rename from lib/window.function.ts
rename to core/nut.js/lib/window.function.ts
index 9a2d2453..e0d61203 100644
--- a/lib/window.function.ts
+++ b/core/nut.js/lib/window.function.ts
@@ -1,6 +1,6 @@
import { WindowApi } from "./window-api.interface";
import { Window } from "./window.class";
-import { ProviderRegistry } from "./provider/provider-registry.class";
+import { ProviderRegistry } from "@nut-tree/provider-interfaces";
export const createWindowApi = (
providerRegistry: ProviderRegistry
diff --git a/core/nut.js/package.json b/core/nut.js/package.json
new file mode 100644
index 00000000..2023639b
--- /dev/null
+++ b/core/nut.js/package.json
@@ -0,0 +1,76 @@
+{
+ "name": "@nut-tree/nut-js",
+ "version": "4.0.0",
+ "license": "Apache-2.0",
+ "main": "dist/index",
+ "typings": "dist/index",
+ "description": "Native system automation for node.js",
+ "author": {
+ "name": "dry Software UG (haftungsbeschränkt)",
+ "email": "info@dry.software",
+ "url": "https://dry.software"
+ },
+ "homepage": "https://nutjs.dev",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/nut-tree/nut.js.git"
+ },
+ "bugs": {
+ "url": "https://github.com/nut-tree/nut.js/issues"
+ },
+ "os": [
+ "linux",
+ "darwin",
+ "win32"
+ ],
+ "cpu": [
+ "x64",
+ "arm64"
+ ],
+ "keywords": [
+ "native",
+ "system",
+ "automation",
+ "testing",
+ "keyboard",
+ "mouse",
+ "process",
+ "memory",
+ "window",
+ "screen",
+ "monitor",
+ "display",
+ "timer",
+ "clock",
+ "clipboard"
+ ],
+ "scripts": {
+ "clean": "rimraf dist",
+ "compile": "pnpm run clean && tsc -p .",
+ "compile:dev": "pnpm run clean && tsc -p . --watch",
+ "test": "jest --runInBand",
+ "coverage": "jest --coverage --runInBand --logHeapUsage",
+ "coverage:clean": "rimraf coverage",
+ "publish:next": "pnpm publish --tag next",
+ "prepublishOnly": "pnpm run compile",
+ "versionBump": "bump --tag --push --all",
+ "typedoc": "typedoc --options ./typedoc.js --entryPointStrategy expand ./lib"
+ },
+ "dependencies": {
+ "@nut-tree/default-clipboard-provider": "workspace:*",
+ "@nut-tree/libnut": "workspace:*",
+ "@nut-tree/shared": "workspace:*",
+ "@nut-tree/provider-interfaces": "workspace:*",
+ "jimp": "0.22.10",
+ "node-abort-controller": "3.1.1"
+ },
+ "devDependencies": {
+ "@nut-tree/configs": "workspace:*",
+ "istanbul-merge": "2.0.0",
+ "nyc": "15.1.0",
+ "version-bump-prompt": "6.1.0"
+ },
+ "lint-staged": {
+ "**/*": "prettier --write --ignore-unknown"
+ }
+}
\ No newline at end of file
diff --git a/sonar-project.properties b/core/nut.js/sonar-project.properties
similarity index 63%
rename from sonar-project.properties
rename to core/nut.js/sonar-project.properties
index 1f120d9d..fd3915e8 100644
--- a/sonar-project.properties
+++ b/core/nut.js/sonar-project.properties
@@ -1,7 +1,7 @@
sonar.projectKey=nut-tree:nut.js
sonar.organization=nut-tree
sonar.sources=lib/,index.ts
-sonar.javascript.lcov.reportPaths=coverage/merged/lcov.info
-sonar.typescript.lcov.reportPaths=coverage/merged/lcov.info
+sonar.javascript.lcov.reportPaths=coverage/lcov.info
+sonar.typescript.lcov.reportPaths=coverage/lcov.info
sonar.javascript.exclusions=**/node_modules/**,**/*.spec.js
sonar.typescript.exclusions=**/node_modules/**,**/*.spec.ts
diff --git a/core/nut.js/tsconfig.json b/core/nut.js/tsconfig.json
new file mode 100644
index 00000000..74b93491
--- /dev/null
+++ b/core/nut.js/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "extends": "@nut-tree/configs/tsconfig/base.json",
+ "compilerOptions": {
+ "outDir": "./dist"
+ },
+ "include": [
+ "lib/**/*.ts",
+ "index.ts"
+ ],
+ "exclude": [
+ "**/*.spec.ts",
+ "node_modules"
+ ]
+}
\ No newline at end of file
diff --git a/tslint.json b/core/nut.js/tslint.json
similarity index 100%
rename from tslint.json
rename to core/nut.js/tslint.json
diff --git a/typedoc.js b/core/nut.js/typedoc.js
similarity index 100%
rename from typedoc.js
rename to core/nut.js/typedoc.js
diff --git a/core/provider-interfaces/.gitignore b/core/provider-interfaces/.gitignore
new file mode 100644
index 00000000..733cc87c
--- /dev/null
+++ b/core/provider-interfaces/.gitignore
@@ -0,0 +1,144 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+
+# next.js build output
+.next
+
+# nuxt.js build output
+.nuxt
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless
+
+.vscode
+/dist/
+/lib/**/*.js
+/lib/**/*.js.map
+### macOS template
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+.idea/
+
+# CMake
+cmake-build-debug/
+cmake-build-release/
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Test data
+/lib/provider/opencv/__mocks__/output.jpg
+/asdf.jpg
+/foo_asdf_bar.jpg
+/asdf.png
+/asdf_bar.jpg
+/foo_asdf.jpg
+/.scratch/
+docs
+scratch.js
+debug.js
diff --git a/core/provider-interfaces/.npmignore b/core/provider-interfaces/.npmignore
new file mode 100644
index 00000000..5874dd07
--- /dev/null
+++ b/core/provider-interfaces/.npmignore
@@ -0,0 +1,16 @@
+/lib
+/tsconfig.json
+/tslint.json
+/.travis.yml
+/appveyor.yml
+/.vscode
+/.idea
+/.github
+/.scratch/
+/docs/
+/e2e/
+/sonar-project.properties
+/typedoc.js
+/index.e2e.spec.ts
+/index.ts
+/jest.config.js
diff --git a/core/provider-interfaces/CHANGELOG.md b/core/provider-interfaces/CHANGELOG.md
new file mode 100644
index 00000000..dac609a2
--- /dev/null
+++ b/core/provider-interfaces/CHANGELOG.md
@@ -0,0 +1,7 @@
+# @nut-tree/default-clipboard-provider change log
+
+All notable changes to this project will be documented in this file.
+
+## 1.0.0
+
+- Initial release
diff --git a/core/provider-interfaces/index.ts b/core/provider-interfaces/index.ts
new file mode 100644
index 00000000..f41a696f
--- /dev/null
+++ b/core/provider-interfaces/index.ts
@@ -0,0 +1 @@
+export * from './lib';
diff --git a/lib/provider/clipboard-provider.interface.ts b/core/provider-interfaces/lib/clipboard-provider.interface.ts
similarity index 100%
rename from lib/provider/clipboard-provider.interface.ts
rename to core/provider-interfaces/lib/clipboard-provider.interface.ts
diff --git a/lib/provider/color-finder.interface.ts b/core/provider-interfaces/lib/color-finder.interface.ts
similarity index 83%
rename from lib/provider/color-finder.interface.ts
rename to core/provider-interfaces/lib/color-finder.interface.ts
index 43b810a0..9fda153a 100644
--- a/lib/provider/color-finder.interface.ts
+++ b/core/provider-interfaces/lib/color-finder.interface.ts
@@ -1,7 +1,4 @@
-import { ColorQuery } from "../query.class";
-import { MatchResult } from "../match-result.class";
-import { Point } from "../point.class";
-import { MatchRequest } from "../match-request.class";
+import { ColorQuery, MatchRequest, MatchResult, Point } from "@nut-tree/shared";
/**
* A WindowFinder should provide an abstraction layer to perform window searches
diff --git a/lib/provider/data-sink.interface.ts b/core/provider-interfaces/lib/data-sink.interface.ts
similarity index 100%
rename from lib/provider/data-sink.interface.ts
rename to core/provider-interfaces/lib/data-sink.interface.ts
diff --git a/lib/provider/data-source.interface.ts b/core/provider-interfaces/lib/data-source.interface.ts
similarity index 100%
rename from lib/provider/data-source.interface.ts
rename to core/provider-interfaces/lib/data-source.interface.ts
diff --git a/lib/provider/image-finder.interface.ts b/core/provider-interfaces/lib/image-finder.interface.ts
similarity index 85%
rename from lib/provider/image-finder.interface.ts
rename to core/provider-interfaces/lib/image-finder.interface.ts
index 7239ac83..d537e23b 100644
--- a/lib/provider/image-finder.interface.ts
+++ b/core/provider-interfaces/lib/image-finder.interface.ts
@@ -1,7 +1,4 @@
-import { MatchRequest } from "../match-request.class";
-import { MatchResult } from "../match-result.class";
-import { Image } from "../image.class";
-import { Region } from "../region.class";
+import { Image, MatchRequest, MatchResult, Region } from "@nut-tree/shared";
/**
* An ImageFinder should provide an abstraction layer to perform image matching
diff --git a/lib/provider/image-processor.interface.ts b/core/provider-interfaces/lib/image-processor.interface.ts
similarity index 81%
rename from lib/provider/image-processor.interface.ts
rename to core/provider-interfaces/lib/image-processor.interface.ts
index c77be27b..4872c7e5 100644
--- a/lib/provider/image-processor.interface.ts
+++ b/core/provider-interfaces/lib/image-processor.interface.ts
@@ -1,6 +1,4 @@
-import { Point } from "../point.class";
-import { RGBA } from "../rgba.class";
-import { Image } from "../image.class";
+import { Image, Point, RGBA } from "@nut-tree/shared";
/**
* An ImageProcessor should provide an abstraction layer to perform
diff --git a/lib/provider/image-reader.type.ts b/core/provider-interfaces/lib/image-reader.type.ts
similarity index 75%
rename from lib/provider/image-reader.type.ts
rename to core/provider-interfaces/lib/image-reader.type.ts
index 6733fc22..c45b9d2a 100644
--- a/lib/provider/image-reader.type.ts
+++ b/core/provider-interfaces/lib/image-reader.type.ts
@@ -1,4 +1,4 @@
import { DataSourceInterface } from "./data-source.interface";
-import { Image } from "../image.class";
+import { Image } from "@nut-tree/shared";
export type ImageReader = DataSourceInterface;
diff --git a/lib/provider/image-writer.type.ts b/core/provider-interfaces/lib/image-writer.type.ts
similarity index 83%
rename from lib/provider/image-writer.type.ts
rename to core/provider-interfaces/lib/image-writer.type.ts
index d8eceaf6..a0bf6735 100644
--- a/lib/provider/image-writer.type.ts
+++ b/core/provider-interfaces/lib/image-writer.type.ts
@@ -1,4 +1,4 @@
-import { Image } from "../image.class";
+import { Image } from "@nut-tree/shared";
import { DataSinkInterface } from "./data-sink.interface";
export interface ImageWriterParameters {
diff --git a/core/provider-interfaces/lib/index.ts b/core/provider-interfaces/lib/index.ts
new file mode 100644
index 00000000..d3e17989
--- /dev/null
+++ b/core/provider-interfaces/lib/index.ts
@@ -0,0 +1,16 @@
+export * from './clipboard-provider.interface';
+export * from './color-finder.interface';
+export * from './data-sink.interface';
+export * from './data-source.interface';
+export * from './image-finder.interface';
+export * from './image-processor.interface';
+export * from './image-reader.type';
+export * from './image-writer.type';
+export * from './keyboard-provider.interface';
+export * from './log-provider.interface';
+export * from './mouse-provider.interface';
+export * from './screen-provider.interface';
+export * from './text-finder.interface';
+export * from './window-finder.interface';
+export * from './window-provider.interface';
+export * from './provider-registry.interface';
\ No newline at end of file
diff --git a/lib/provider/keyboard-provider.interface.ts b/core/provider-interfaces/lib/keyboard-provider.interface.ts
similarity index 96%
rename from lib/provider/keyboard-provider.interface.ts
rename to core/provider-interfaces/lib/keyboard-provider.interface.ts
index ea4305b9..7291cda1 100644
--- a/lib/provider/keyboard-provider.interface.ts
+++ b/core/provider-interfaces/lib/keyboard-provider.interface.ts
@@ -1,4 +1,4 @@
-import { Key } from "../key.enum";
+import { Key } from "@nut-tree/shared";
/**
* A KeyboardActionProvider should provide access to a systems keyboard
diff --git a/core/provider-interfaces/lib/log-provider.interface.ts b/core/provider-interfaces/lib/log-provider.interface.ts
new file mode 100644
index 00000000..099d0a6a
--- /dev/null
+++ b/core/provider-interfaces/lib/log-provider.interface.ts
@@ -0,0 +1,11 @@
+export type LogFunction = (message: string, data?: {}) => void;
+export type ErrorLogFunction = (error: Error, data?: {}) => void;
+
+export interface LogProviderInterface {
+ trace: LogFunction;
+ debug: LogFunction;
+ info: LogFunction;
+ warn: LogFunction;
+ error: ErrorLogFunction;
+}
+
diff --git a/lib/provider/mouse-provider.interface.ts b/core/provider-interfaces/lib/mouse-provider.interface.ts
similarity index 96%
rename from lib/provider/mouse-provider.interface.ts
rename to core/provider-interfaces/lib/mouse-provider.interface.ts
index f38b0de0..f4e495db 100644
--- a/lib/provider/mouse-provider.interface.ts
+++ b/core/provider-interfaces/lib/mouse-provider.interface.ts
@@ -1,5 +1,4 @@
-import { Button } from "../button.enum";
-import { Point } from "../point.class";
+import { Button, Point } from "@nut-tree/shared";
/**
* A MouseActionProvider should provide access to a systems mouse input
diff --git a/core/provider-interfaces/lib/provider-registry.interface.ts b/core/provider-interfaces/lib/provider-registry.interface.ts
new file mode 100644
index 00000000..0a88571e
--- /dev/null
+++ b/core/provider-interfaces/lib/provider-registry.interface.ts
@@ -0,0 +1,95 @@
+import {
+ ClipboardProviderInterface,
+ ColorFinderInterface,
+ ImageFinderInterface,
+ ImageProcessor,
+ ImageReader,
+ ImageWriter,
+ KeyboardProviderInterface,
+ LogProviderInterface,
+ MouseProviderInterface,
+ ScreenProviderInterface,
+ TextFinderInterface,
+ WindowFinderInterface,
+ WindowProviderInterface
+} from ".";
+
+export interface ProviderRegistry {
+ hasClipboard(): boolean;
+
+ getClipboard(): ClipboardProviderInterface;
+
+ registerClipboardProvider(value: ClipboardProviderInterface): void;
+
+ hasKeyboard(): boolean;
+
+ getKeyboard(): KeyboardProviderInterface;
+
+ registerKeyboardProvider(value: KeyboardProviderInterface): void;
+
+ hasMouse(): boolean;
+
+ getMouse(): MouseProviderInterface;
+
+ registerMouseProvider(value: MouseProviderInterface): void;
+
+ hasScreen(): boolean;
+
+ getScreen(): ScreenProviderInterface;
+
+ registerScreenProvider(value: ScreenProviderInterface): void;
+
+ hasWindow(): boolean;
+
+ getWindow(): WindowProviderInterface;
+
+ registerWindowProvider(value: WindowProviderInterface): void;
+
+ hasImageFinder(): boolean;
+
+ getImageFinder(): ImageFinderInterface;
+
+ registerImageFinder(value: ImageFinderInterface): void;
+
+ hasImageReader(): boolean;
+
+ getImageReader(): ImageReader;
+
+ registerImageReader(value: ImageReader): void;
+
+ hasImageWriter(): boolean;
+
+ getImageWriter(): ImageWriter;
+
+ registerImageWriter(value: ImageWriter): void;
+
+ hasImageProcessor(): boolean;
+
+ getImageProcessor(): ImageProcessor;
+
+ registerImageProcessor(value: ImageProcessor): void;
+
+ hasLogProvider(): boolean;
+
+ getLogProvider(): LogProviderInterface;
+
+ registerLogProvider(value: LogProviderInterface): void;
+
+ hasTextFinder(): boolean;
+
+ getTextFinder(): TextFinderInterface;
+
+ registerTextFinder(value: TextFinderInterface): void;
+
+ hasWindowFinder(): boolean;
+
+ getWindowFinder(): WindowFinderInterface;
+
+ registerWindowFinder(value: WindowFinderInterface): void;
+
+ hasColorFinder(): boolean;
+
+ getColorFinder(): ColorFinderInterface;
+
+ registerColorFinder(value: ColorFinderInterface): void;
+}
\ No newline at end of file
diff --git a/lib/provider/screen-provider.interface.ts b/core/provider-interfaces/lib/screen-provider.interface.ts
similarity index 94%
rename from lib/provider/screen-provider.interface.ts
rename to core/provider-interfaces/lib/screen-provider.interface.ts
index 766307fd..b2de5a3d 100644
--- a/lib/provider/screen-provider.interface.ts
+++ b/core/provider-interfaces/lib/screen-provider.interface.ts
@@ -1,5 +1,4 @@
-import { Image } from "../image.class";
-import { Region } from "../region.class";
+import { Image, Region } from "@nut-tree/shared";
/**
* A ScreenActionProvider should provide access to a system's main screen
diff --git a/lib/provider/text-finder.interface.ts b/core/provider-interfaces/lib/text-finder.interface.ts
similarity index 85%
rename from lib/provider/text-finder.interface.ts
rename to core/provider-interfaces/lib/text-finder.interface.ts
index d5a215a8..a80f6c0b 100644
--- a/lib/provider/text-finder.interface.ts
+++ b/core/provider-interfaces/lib/text-finder.interface.ts
@@ -1,7 +1,4 @@
-import { MatchRequest } from "../match-request.class";
-import { MatchResult } from "../match-result.class";
-import { TextQuery } from "../query.class";
-import { Region } from "../region.class";
+import { MatchRequest, MatchResult, Region, TextQuery } from "@nut-tree/shared";
/**
* A TextFinder should provide an abstraction layer to perform text searches
diff --git a/lib/provider/window-finder.interface.ts b/core/provider-interfaces/lib/window-finder.interface.ts
similarity index 94%
rename from lib/provider/window-finder.interface.ts
rename to core/provider-interfaces/lib/window-finder.interface.ts
index cb74ec98..ccda3dd1 100644
--- a/lib/provider/window-finder.interface.ts
+++ b/core/provider-interfaces/lib/window-finder.interface.ts
@@ -1,4 +1,4 @@
-import { WindowQuery } from "../query.class";
+import { WindowQuery } from "@nut-tree/shared";
/**
* A WindowFinder should provide an abstraction layer to perform window searches
diff --git a/lib/provider/window-provider.interface.ts b/core/provider-interfaces/lib/window-provider.interface.ts
similarity index 93%
rename from lib/provider/window-provider.interface.ts
rename to core/provider-interfaces/lib/window-provider.interface.ts
index 54c09715..288a59a1 100644
--- a/lib/provider/window-provider.interface.ts
+++ b/core/provider-interfaces/lib/window-provider.interface.ts
@@ -1,6 +1,4 @@
-import { Region } from "../region.class";
-import { Point } from "../point.class";
-import { Size } from "../size.class";
+import { Point, Region, Size } from "@nut-tree/shared";
/**
* A WindowActionProvider should provide access to a system's window system
diff --git a/core/provider-interfaces/package.json b/core/provider-interfaces/package.json
new file mode 100644
index 00000000..6916b5af
--- /dev/null
+++ b/core/provider-interfaces/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "@nut-tree/provider-interfaces",
+ "version": "4.0.0",
+ "description": "Public provider interfaces for @nut-tree/nut-js",
+ "main": "dist/index",
+ "typings": "dist/index",
+ "scripts": {
+ "clean": "rimraf dist",
+ "compile": "pnpm run clean && tsc -p .",
+ "publish:next": "pnpm publish --tag next",
+ "prepublishOnly": "pnpm run compile"
+ },
+ "keywords": [
+ "nut-js",
+ "provider"
+ ],
+ "author": {
+ "name": "dry Software UG (haftungsbeschränkt)",
+ "email": "info@dry.software",
+ "url": "https://dry.software"
+ },
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@nut-tree/shared": "workspace:*"
+ },
+ "devDependencies": {
+ "@nut-tree/configs": "workspace:*"
+ }
+}
\ No newline at end of file
diff --git a/core/provider-interfaces/tsconfig.json b/core/provider-interfaces/tsconfig.json
new file mode 100644
index 00000000..74b93491
--- /dev/null
+++ b/core/provider-interfaces/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "extends": "@nut-tree/configs/tsconfig/base.json",
+ "compilerOptions": {
+ "outDir": "./dist"
+ },
+ "include": [
+ "lib/**/*.ts",
+ "index.ts"
+ ],
+ "exclude": [
+ "**/*.spec.ts",
+ "node_modules"
+ ]
+}
\ No newline at end of file
diff --git a/core/shared/.gitignore b/core/shared/.gitignore
new file mode 100644
index 00000000..733cc87c
--- /dev/null
+++ b/core/shared/.gitignore
@@ -0,0 +1,144 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+
+# next.js build output
+.next
+
+# nuxt.js build output
+.nuxt
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless
+
+.vscode
+/dist/
+/lib/**/*.js
+/lib/**/*.js.map
+### macOS template
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+.idea/
+
+# CMake
+cmake-build-debug/
+cmake-build-release/
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Test data
+/lib/provider/opencv/__mocks__/output.jpg
+/asdf.jpg
+/foo_asdf_bar.jpg
+/asdf.png
+/asdf_bar.jpg
+/foo_asdf.jpg
+/.scratch/
+docs
+scratch.js
+debug.js
diff --git a/core/shared/.npmignore b/core/shared/.npmignore
new file mode 100644
index 00000000..5874dd07
--- /dev/null
+++ b/core/shared/.npmignore
@@ -0,0 +1,16 @@
+/lib
+/tsconfig.json
+/tslint.json
+/.travis.yml
+/appveyor.yml
+/.vscode
+/.idea
+/.github
+/.scratch/
+/docs/
+/e2e/
+/sonar-project.properties
+/typedoc.js
+/index.e2e.spec.ts
+/index.ts
+/jest.config.js
diff --git a/core/shared/CHANGELOG.md b/core/shared/CHANGELOG.md
new file mode 100644
index 00000000..dac609a2
--- /dev/null
+++ b/core/shared/CHANGELOG.md
@@ -0,0 +1,7 @@
+# @nut-tree/default-clipboard-provider change log
+
+All notable changes to this project will be documented in this file.
+
+## 1.0.0
+
+- Initial release
diff --git a/core/shared/index.ts b/core/shared/index.ts
new file mode 100644
index 00000000..f41a696f
--- /dev/null
+++ b/core/shared/index.ts
@@ -0,0 +1 @@
+export * from './lib';
diff --git a/core/shared/jest.config.js b/core/shared/jest.config.js
new file mode 100644
index 00000000..22c81f1a
--- /dev/null
+++ b/core/shared/jest.config.js
@@ -0,0 +1,21 @@
+module.exports = {
+ collectCoverageFrom: [
+ "index.ts",
+ "**/*.ts",
+ "!**/*.spec.ts",
+ "!/node_modules/",
+ ],
+ transform: {},
+ preset: "ts-jest",
+ testEnvironment: "node",
+ testMatch: process.env.E2E_TEST
+ ? [
+ "**/__tests__/(e2e)/**/*.[jt]s?(x)",
+ "**/?(*.)(e2e.)+(spec|test).[jt]s?(x)",
+ ]
+ : [
+ "**/__tests__/!(e2e)/**/*.[jt]s?(x)",
+ "**/!(*.e2e.*)+(spec|test).[jt]s?(x)",
+ ],
+ testPathIgnorePatterns: ["/node_modules/", "/dist/"],
+};
diff --git a/lib/button.enum.ts b/core/shared/lib/enums/button.enum.ts
similarity index 100%
rename from lib/button.enum.ts
rename to core/shared/lib/enums/button.enum.ts
diff --git a/lib/colormode.enum.ts b/core/shared/lib/enums/colormode.enum.ts
similarity index 100%
rename from lib/colormode.enum.ts
rename to core/shared/lib/enums/colormode.enum.ts
diff --git a/lib/file-type.enum.ts b/core/shared/lib/enums/file-type.enum.ts
similarity index 100%
rename from lib/file-type.enum.ts
rename to core/shared/lib/enums/file-type.enum.ts
diff --git a/lib/key.enum.ts b/core/shared/lib/enums/key.enum.ts
similarity index 100%
rename from lib/key.enum.ts
rename to core/shared/lib/enums/key.enum.ts
diff --git a/lib/provider/io/__mocks__/calculator.png b/core/shared/lib/functions/__mocks__/calculator.png
similarity index 100%
rename from lib/provider/io/__mocks__/calculator.png
rename to core/shared/lib/functions/__mocks__/calculator.png
diff --git a/lib/provider/io/imageToJimp.function.spec.ts b/core/shared/lib/functions/imageToJimp.function.spec.ts
similarity index 89%
rename from lib/provider/io/imageToJimp.function.spec.ts
rename to core/shared/lib/functions/imageToJimp.function.spec.ts
index 741e0926..a5d30906 100644
--- a/lib/provider/io/imageToJimp.function.spec.ts
+++ b/core/shared/lib/functions/imageToJimp.function.spec.ts
@@ -1,13 +1,13 @@
-import { Image } from "../../image.class";
import { imageToJimp } from "./imageToJimp.function";
import Jimp from "jimp";
+import { Image } from "../objects/image.class";
jest.mock("jimp", () => {
class JimpMock {
bitmap = {
width: 100,
height: 100,
- data: Buffer.from([]),
+ data: Buffer.from([])
};
hasAlpha = () => false;
static read = jest.fn(() => Promise.resolve(new JimpMock()));
@@ -15,7 +15,7 @@ jest.mock("jimp", () => {
return {
__esModule: true,
- default: JimpMock,
+ default: JimpMock
};
});
diff --git a/lib/provider/io/imageToJimp.function.ts b/core/shared/lib/functions/imageToJimp.function.ts
similarity index 78%
rename from lib/provider/io/imageToJimp.function.ts
rename to core/shared/lib/functions/imageToJimp.function.ts
index a1253290..30a6a5b7 100644
--- a/lib/provider/io/imageToJimp.function.ts
+++ b/core/shared/lib/functions/imageToJimp.function.ts
@@ -1,12 +1,12 @@
import Jimp from "jimp";
-import { Image } from "../../image.class";
-import { ColorMode } from "../../colormode.enum";
+import { ColorMode } from "../enums/colormode.enum";
+import { Image } from "../objects/image.class";
export function imageToJimp(image: Image): Jimp {
const jimpImage = new Jimp({
data: image.data,
width: image.width,
- height: image.height,
+ height: image.height
});
if (image.colorMode === ColorMode.BGR) {
// Image treats data in BGR format, so we have to switch red and blue color channels
@@ -15,7 +15,7 @@ export function imageToJimp(image: Image): Jimp {
0,
jimpImage.bitmap.width,
jimpImage.bitmap.height,
- function (_, __, idx) {
+ function(_, __, idx) {
const red = this.bitmap.data[idx];
this.bitmap.data[idx] = this.bitmap.data[idx + 2];
this.bitmap.data[idx + 2] = red;
diff --git a/core/shared/lib/index.ts b/core/shared/lib/index.ts
new file mode 100644
index 00000000..7c4f7b5c
--- /dev/null
+++ b/core/shared/lib/index.ts
@@ -0,0 +1,17 @@
+export * from "./enums/button.enum";
+export * from "./enums/colormode.enum";
+export * from "./enums/file-type.enum";
+export * from "./enums/key.enum";
+export * from "./objects/image.class";
+export * from "./objects/match-request.class";
+export * from "./objects/match-result.class";
+export * from "./objects/optionalsearchparameters.class";
+export * from "./objects/point.class";
+export * from "./objects/query.class";
+export * from "./objects/region.class";
+export * from "./objects/rgba.class";
+export * from "./objects/scaled-match-result.class";
+export * from "./objects/size.class";
+export * from "./objects/window.interface";
+export * from "./types";
+export * from "./functions/imageToJimp.function";
\ No newline at end of file
diff --git a/lib/image.class.spec.ts b/core/shared/lib/objects/image.class.spec.ts
similarity index 92%
rename from lib/image.class.spec.ts
rename to core/shared/lib/objects/image.class.spec.ts
index 72593340..5aabd4be 100644
--- a/lib/image.class.spec.ts
+++ b/core/shared/lib/objects/image.class.spec.ts
@@ -1,8 +1,8 @@
import { Image, isImage } from "./image.class";
-import { imageToJimp } from "./provider/io/imageToJimp.function";
-import { ColorMode } from "./colormode.enum";
+import { imageToJimp } from "../functions/imageToJimp.function";
+import { ColorMode } from "../enums/colormode.enum";
-jest.mock("./provider/io/imageToJimp.function", () => {
+jest.mock("../functions/imageToJimp.function", () => {
return {
imageToJimp: jest.fn(),
};
@@ -60,7 +60,7 @@ describe("Image class", () => {
// THEN
expect(convertedImage).toBe(bgrImage);
- expect(imageToJimp).not.toBeCalledTimes(1);
+ expect(imageToJimp).not.toHaveBeenCalledTimes(1);
});
it("should not try to convert an image to RGB if it already has the correct color mode", async () => {
@@ -81,7 +81,7 @@ describe("Image class", () => {
// THEN
expect(convertedImage).toBe(rgbImage);
- expect(imageToJimp).not.toBeCalledTimes(1);
+ expect(imageToJimp).not.toHaveBeenCalledTimes(1);
});
});
diff --git a/lib/image.class.ts b/core/shared/lib/objects/image.class.ts
similarity index 96%
rename from lib/image.class.ts
rename to core/shared/lib/objects/image.class.ts
index 3e77a013..467b5643 100644
--- a/lib/image.class.ts
+++ b/core/shared/lib/objects/image.class.ts
@@ -1,5 +1,5 @@
-import { imageToJimp } from "./provider/io/imageToJimp.function";
-import { ColorMode } from "./colormode.enum";
+import { imageToJimp } from "../functions/imageToJimp.function";
+import { ColorMode } from "../enums/colormode.enum";
/**
* The {@link Image} class represents generic image data
diff --git a/core/shared/lib/objects/match-request.class.ts b/core/shared/lib/objects/match-request.class.ts
new file mode 100644
index 00000000..655ed584
--- /dev/null
+++ b/core/shared/lib/objects/match-request.class.ts
@@ -0,0 +1,12 @@
+import { Image } from "./image.class";
+
+export class MatchRequest {
+ public constructor(
+ public readonly haystack: Image,
+ public readonly needle: NEEDLE_TYPE,
+ public readonly confidence: number | undefined,
+ public readonly providerData?: PROVIDER_DATA_TYPE
+ ) {
+ }
+}
+
diff --git a/core/shared/lib/objects/match-result.class.ts b/core/shared/lib/objects/match-result.class.ts
new file mode 100644
index 00000000..0523650f
--- /dev/null
+++ b/core/shared/lib/objects/match-result.class.ts
@@ -0,0 +1,9 @@
+export class MatchResult {
+ constructor(
+ public readonly confidence: number,
+ public readonly location: LOCATION_TYPE,
+ public readonly error?: Error
+ ) {
+ }
+}
+
diff --git a/lib/optionalsearchparameters.class.ts b/core/shared/lib/objects/optionalsearchparameters.class.ts
similarity index 98%
rename from lib/optionalsearchparameters.class.ts
rename to core/shared/lib/objects/optionalsearchparameters.class.ts
index e09e9727..b5e38301 100644
--- a/lib/optionalsearchparameters.class.ts
+++ b/core/shared/lib/objects/optionalsearchparameters.class.ts
@@ -17,5 +17,6 @@ export class OptionalSearchParameters {
public confidence?: number,
public abort?: AbortSignal,
public providerData?: PROVIDER_DATA_TYPE
- ) {}
+ ) {
+ }
}
diff --git a/lib/point.class.spec.ts b/core/shared/lib/objects/point.class.spec.ts
similarity index 100%
rename from lib/point.class.spec.ts
rename to core/shared/lib/objects/point.class.spec.ts
diff --git a/lib/point.class.ts b/core/shared/lib/objects/point.class.ts
similarity index 100%
rename from lib/point.class.ts
rename to core/shared/lib/objects/point.class.ts
diff --git a/lib/query.class.spec.ts b/core/shared/lib/objects/query.class.spec.ts
similarity index 77%
rename from lib/query.class.spec.ts
rename to core/shared/lib/objects/query.class.spec.ts
index 54e1835b..4214f7c0 100644
--- a/lib/query.class.spec.ts
+++ b/core/shared/lib/objects/query.class.spec.ts
@@ -1,11 +1,4 @@
-import {
- ColorQuery,
- isColorQuery,
- isTextQuery,
- isWindowQuery,
- TextQuery,
- WindowQuery,
-} from "./query.class";
+import { ColorQuery, isColorQuery, isTextQuery, isWindowQuery, TextQuery, WindowQuery } from "./query.class";
import { Image, isImage } from "./image.class";
import { RGBA } from "./rgba.class";
@@ -18,31 +11,31 @@ describe("query types", () => {
id: "dummy",
type: "text",
by: {
- word: "dummy-query",
- },
+ word: "dummy-query"
+ }
},
- true,
+ true
],
[
{
id: "dummy",
type: "text",
by: {
- line: "dummy-query",
- },
+ line: "dummy-query"
+ }
},
- true,
+ true
],
[
{
id: "dummy",
type: "foo",
by: {
- line: "dummy-query",
- },
+ line: "dummy-query"
+ }
} as unknown as TextQuery,
- false,
- ],
+ false
+ ]
])(
"should correctly identify text queries",
(query: TextQuery, expected: boolean) => {
@@ -62,21 +55,21 @@ describe("query types", () => {
id: "dummy",
type: "color",
by: {
- color: new RGBA(0, 0, 0, 0),
- },
+ color: new RGBA(0, 0, 0, 0)
+ }
},
- true,
+ true
],
[
{
id: "dummy",
type: "foo",
by: {
- line: "dummy-query",
- },
+ line: "dummy-query"
+ }
} as unknown as ColorQuery,
- false,
- ],
+ false
+ ]
])(
"should correctly identify text queries",
(query: ColorQuery, expected: boolean) => {
@@ -96,21 +89,21 @@ describe("query types", () => {
id: "dummy",
type: "window",
by: {
- title: "dummy-query",
- },
+ title: "dummy-query"
+ }
},
- true,
+ true
],
[
{
id: "dummy",
type: "foo",
by: {
- title: "dummy-query",
- },
+ title: "dummy-query"
+ }
} as unknown as WindowQuery,
- false,
- ],
+ false
+ ]
])(
"should correctly identify window queries",
(query: WindowQuery, expected: boolean) => {
@@ -131,11 +124,11 @@ describe("query types", () => {
id: "dummy",
type: "foo",
by: {
- title: "dummy-query",
- },
+ title: "dummy-query"
+ }
} as unknown as Image,
- false,
- ],
+ false
+ ]
])(
"should correctly identify image queries",
(query: Image, expected: boolean) => {
diff --git a/lib/query.class.ts b/core/shared/lib/objects/query.class.ts
similarity index 86%
rename from lib/query.class.ts
rename to core/shared/lib/objects/query.class.ts
index d7375fc6..57b4442e 100644
--- a/lib/query.class.ts
+++ b/core/shared/lib/objects/query.class.ts
@@ -2,33 +2,33 @@ import { RGBA } from "./rgba.class";
type Query =
| {
- id: string;
- type: "text";
- by: {
- line: string;
- };
- }
+ id: string;
+ type: "text";
+ by: {
+ line: string;
+ };
+}
| {
- id: string;
- type: "text";
- by: {
- word: string;
- };
- }
+ id: string;
+ type: "text";
+ by: {
+ word: string;
+ };
+}
| {
- id: string;
- type: "window";
- by: {
- title: string | RegExp;
- };
- }
+ id: string;
+ type: "window";
+ by: {
+ title: string | RegExp;
+ };
+}
| {
- id: string;
- type: "color";
- by: {
- color: RGBA;
- };
- };
+ id: string;
+ type: "color";
+ by: {
+ color: RGBA;
+ };
+};
export type TextQuery = Extract;
diff --git a/lib/region.class.spec.ts b/core/shared/lib/objects/region.class.spec.ts
similarity index 100%
rename from lib/region.class.spec.ts
rename to core/shared/lib/objects/region.class.spec.ts
diff --git a/lib/region.class.ts b/core/shared/lib/objects/region.class.ts
similarity index 100%
rename from lib/region.class.ts
rename to core/shared/lib/objects/region.class.ts
diff --git a/lib/rgba.class.ts b/core/shared/lib/objects/rgba.class.ts
similarity index 100%
rename from lib/rgba.class.ts
rename to core/shared/lib/objects/rgba.class.ts
diff --git a/lib/scaled-match-result.class.ts b/core/shared/lib/objects/scaled-match-result.class.ts
similarity index 100%
rename from lib/scaled-match-result.class.ts
rename to core/shared/lib/objects/scaled-match-result.class.ts
diff --git a/lib/size.class.spec.ts b/core/shared/lib/objects/size.class.spec.ts
similarity index 100%
rename from lib/size.class.spec.ts
rename to core/shared/lib/objects/size.class.spec.ts
diff --git a/lib/size.class.ts b/core/shared/lib/objects/size.class.ts
similarity index 100%
rename from lib/size.class.ts
rename to core/shared/lib/objects/size.class.ts
diff --git a/core/shared/lib/objects/window.interface.ts b/core/shared/lib/objects/window.interface.ts
new file mode 100644
index 00000000..fd6160e4
--- /dev/null
+++ b/core/shared/lib/objects/window.interface.ts
@@ -0,0 +1,15 @@
+import { Region } from "./region.class";
+import { Point } from "./point.class";
+import { Size } from "./size.class";
+
+export interface WindowInterface {
+ getTitle(): Promise;
+
+ getRegion(): Promise;
+
+ move(newOrigin: Point): Promise;
+
+ resize(newSize: Size): Promise;
+
+ focus(): Promise