@notask/unity-cli-tools 1.1.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.claude/settings.local.json +7 -0
  2. package/CHANGELOG.md +164 -146
  3. package/LICENSE +23 -23
  4. package/README.md +809 -347
  5. package/dist/cjs/errors/Result.js +76 -0
  6. package/dist/cjs/errors/UnityError.js +77 -0
  7. package/dist/cjs/errors/index.js +18 -0
  8. package/dist/cjs/events/hubEventEmitter.js +16 -16
  9. package/dist/cjs/events/hubEventParser.js +97 -27
  10. package/dist/cjs/events/patterns/implementations/bracketModulePattern.js +57 -0
  11. package/dist/cjs/events/patterns/implementations/errorPattern.js +99 -0
  12. package/dist/cjs/events/patterns/implementations/fallbackPattern.js +63 -0
  13. package/dist/cjs/events/patterns/implementations/index.js +9 -0
  14. package/dist/cjs/events/patterns/index.js +23 -0
  15. package/dist/cjs/events/patterns/patternRegistry.js +69 -0
  16. package/dist/cjs/events/patterns/statusNormalizer.js +280 -0
  17. package/dist/cjs/events/patterns/types.js +2 -0
  18. package/dist/cjs/index.js +7 -6
  19. package/dist/cjs/unityEditor.js +162 -194
  20. package/dist/cjs/unityHub.js +82 -78
  21. package/dist/cjs/utils/commandExecutor.js +8 -9
  22. package/dist/esm/errors/Result.d.ts +21 -0
  23. package/dist/esm/errors/Result.js +63 -0
  24. package/dist/esm/errors/UnityError.d.ts +36 -0
  25. package/dist/esm/errors/UnityError.js +64 -0
  26. package/dist/esm/errors/index.d.ts +2 -0
  27. package/dist/esm/errors/index.js +2 -0
  28. package/dist/esm/events/hubEventEmitter.d.ts +1 -1
  29. package/dist/esm/events/hubEventParser.d.ts +17 -3
  30. package/dist/esm/events/hubEventParser.js +97 -27
  31. package/dist/esm/events/patterns/implementations/bracketModulePattern.d.ts +11 -0
  32. package/dist/esm/events/patterns/implementations/bracketModulePattern.js +53 -0
  33. package/dist/esm/events/patterns/implementations/errorPattern.d.ts +22 -0
  34. package/dist/esm/events/patterns/implementations/errorPattern.js +95 -0
  35. package/dist/esm/events/patterns/implementations/fallbackPattern.d.ts +13 -0
  36. package/dist/esm/events/patterns/implementations/fallbackPattern.js +59 -0
  37. package/dist/esm/events/patterns/implementations/index.d.ts +3 -0
  38. package/dist/esm/events/patterns/implementations/index.js +3 -0
  39. package/dist/esm/events/patterns/index.d.ts +4 -0
  40. package/dist/esm/events/patterns/index.js +4 -0
  41. package/dist/esm/events/patterns/patternRegistry.d.ts +14 -0
  42. package/dist/esm/events/patterns/patternRegistry.js +65 -0
  43. package/dist/esm/events/patterns/statusNormalizer.d.ts +15 -0
  44. package/dist/esm/events/patterns/statusNormalizer.js +276 -0
  45. package/dist/esm/events/patterns/types.d.ts +30 -0
  46. package/dist/esm/events/patterns/types.js +1 -0
  47. package/dist/esm/index.d.ts +5 -4
  48. package/dist/esm/index.js +1 -0
  49. package/dist/esm/unityEditor.d.ts +11 -13
  50. package/dist/esm/unityEditor.js +175 -207
  51. package/dist/esm/unityHub.d.ts +12 -11
  52. package/dist/esm/unityHub.js +80 -76
  53. package/dist/esm/utils/commandExecutor.d.ts +4 -3
  54. package/dist/esm/utils/commandExecutor.js +8 -9
  55. package/package.json +70 -70
  56. package/sandbox/index.js +51 -0
  57. package/sandbox/node_modules/.package-lock.json +10495 -0
  58. package/sandbox/package.json +13 -0
@@ -9,7 +9,8 @@ const path_1 = __importDefault(require("path"));
9
9
  const unity_js_1 = require("./types/unity.js");
10
10
  const commandExecutor_js_1 = require("./utils/commandExecutor.js");
11
11
  const unity_changeset_1 = require("unity-changeset");
12
- const hubEventEmitter_ts_1 = require("./events/hubEventEmitter.js");
12
+ const hubEventEmitter_js_1 = require("./events/hubEventEmitter.js");
13
+ const index_js_1 = require("./errors/index.js");
13
14
  class UnityHub {
14
15
  static CONFIG_PATHS = {
15
16
  win32: {
@@ -56,122 +57,124 @@ class UnityHub {
56
57
  const isAvailable = await UnityHub.isUnityHubAvailable();
57
58
  if (!isAvailable) {
58
59
  console.error("Unity Hub is not available.");
59
- return {
60
- success: false,
61
- stdout: "",
62
- stderr: "Unity Hub is not available.",
63
- exitCode: -1,
64
- };
65
- }
66
- try {
67
- const hubArgs = [this.platform !== "linux" ? "--" : "", "--headless", ...args].filter(Boolean);
68
- console.debug(`Executing Unity Hub command: ${this.hubPath} ${hubArgs.join(" ")}`);
69
- return await (0, commandExecutor_js_1.executeCommand)(this.hubPath, hubArgs, options);
70
- }
71
- catch (error) {
72
- console.error("Error executing Unity Hub command:", error);
73
- return {
74
- success: false,
75
- stdout: "",
76
- stderr: String(error),
77
- exitCode: -1,
78
- };
60
+ return (0, index_js_1.err)(new index_js_1.UnityHubNotFoundError("Unity Hub is not available", { hubPath: this.hubPath }));
79
61
  }
62
+ const hubArgs = [this.platform !== "linux" ? "--" : "", "--headless", ...args].filter(Boolean);
63
+ console.debug(`Executing Unity Hub command: ${this.hubPath} ${hubArgs.join(" ")}`);
64
+ return await (0, commandExecutor_js_1.executeCommand)(this.hubPath, hubArgs, options);
80
65
  }
81
66
  static async getInstallPath() {
82
- const { stdout, stderr } = await this.execUnityHubCommand(["install-path", "-g"], {
67
+ const result = await this.execUnityHubCommand(["install-path", "-g"], {
83
68
  reject: false,
84
69
  });
85
- if (stderr) {
86
- throw new Error(`Error getting install path: ${stderr}`);
70
+ if (!result.success) {
71
+ return result;
72
+ }
73
+ if (result.value.stderr) {
74
+ return (0, index_js_1.err)(new index_js_1.UnityCommandError(`Error getting install path: ${result.value.stderr}`, result.value.stdout, result.value.stderr, result.value.exitCode));
87
75
  }
88
- return stdout;
76
+ return (0, index_js_1.ok)(result.value.stdout.trim());
89
77
  }
90
78
  static async setInstallPath(path) {
91
- const { stdout, stderr } = await this.execUnityHubCommand(["install-path", "-s", path], {
79
+ const result = await this.execUnityHubCommand(["install-path", "-s", path], {
92
80
  reject: false,
93
81
  });
94
- if (stderr) {
95
- throw new Error(`Error setting install path: ${stderr}`);
82
+ if (!result.success) {
83
+ return result;
84
+ }
85
+ if (result.value.stderr) {
86
+ return (0, index_js_1.err)(new index_js_1.UnityCommandError(`Error setting install path: ${result.value.stderr}`, result.value.stdout, result.value.stderr, result.value.exitCode));
96
87
  }
97
- console.debug(`Install path set to: ${stdout}`);
88
+ console.debug(`Install path set to: ${result.value.stdout}`);
89
+ return (0, index_js_1.ok)(undefined);
98
90
  }
99
91
  static async getUnityInstallations(filter = "i") {
100
92
  if (!["i", "a", "r"].includes(filter)) {
101
- throw new Error(`Invalid filter "${filter}". Use "i" for installed, "a" for all, or "r" for available releases.`);
93
+ return (0, index_js_1.err)(new index_js_1.InvalidArgumentError(`Invalid filter "${filter}". Use "i" for installed, "a" for all, or "r" for available releases.`, { filter, validFilters: ["i", "a", "r"] }));
102
94
  }
103
- const { stdout, stderr } = await this.execUnityHubCommand(["editors", `-${filter}`], {
95
+ const result = await this.execUnityHubCommand(["editors", `-${filter}`], {
104
96
  reject: false,
105
97
  });
98
+ if (!result.success) {
99
+ return result;
100
+ }
101
+ const { stdout, stderr } = result.value;
106
102
  const isSuccess = stdout.includes(", installed at");
107
- if (stderr)
108
- throw new Error(`Get installations command warning/error: ${stderr}`);
109
- if (!isSuccess)
110
- throw new Error(`Consider install a Unity version using Unity Hub.`);
103
+ if (stderr) {
104
+ return (0, index_js_1.err)(new index_js_1.UnityCommandError(`Get installations command warning/error: ${stderr}`, stdout, stderr, result.value.exitCode));
105
+ }
106
+ if (!isSuccess) {
107
+ return (0, index_js_1.err)(new index_js_1.UnityInstallationError("No Unity installations found. Consider installing a Unity version using Unity Hub.", {
108
+ filter,
109
+ }));
110
+ }
111
111
  const lines = stdout.split(/\r\n|\n/);
112
112
  const installations = {};
113
113
  lines.forEach((line) => {
114
114
  const [version, unityPath] = line.split(", installed at").map((entry) => entry.trim());
115
- installations[version] = unityPath;
115
+ if (version && unityPath) {
116
+ installations[version] = unityPath;
117
+ }
116
118
  });
117
- if (Object.keys(installations).length <= 0)
118
- throw new Error("No unity installations found.");
119
- return installations;
119
+ if (Object.keys(installations).length <= 0) {
120
+ return (0, index_js_1.err)(new index_js_1.UnityInstallationError("No Unity installations found.", { filter }));
121
+ }
122
+ return (0, index_js_1.ok)(installations);
120
123
  }
121
124
  static async addModule(editorVersion, modules, childModules = true) {
122
- try {
123
- console.debug(`Adding module ${modules} to Unity ${editorVersion}`);
124
- const args = ["install-modules", "-v", editorVersion];
125
- if (modules.length > 0) {
126
- args.push(...["--module", modules.join(" ")]);
127
- if (childModules) {
128
- args.push("--child-modules");
129
- }
130
- }
131
- else {
132
- throw new Error("No module IDs provided.");
133
- }
134
- const installerEmitter = new hubEventEmitter_ts_1.UnityHubInstallerEvent();
135
- this.execUnityHubCommand(args, {
136
- reject: false,
137
- onStdout: (data) => installerEmitter.Progress(data),
138
- }).catch((error) => {
139
- console.error(`Error adding module ${modules} to Unity ${editorVersion}:`, error);
140
- });
141
- return installerEmitter;
125
+ if (modules.length === 0) {
126
+ return (0, index_js_1.err)(new index_js_1.InvalidArgumentError("No module IDs provided.", { editorVersion, modules }));
142
127
  }
143
- catch (error) {
144
- console.error(`Error adding module ${modules} to Unity ${editorVersion}:`, error);
145
- throw error;
128
+ console.debug(`Adding module ${modules} to Unity ${editorVersion}`);
129
+ const args = ["install-modules", "-v", editorVersion, "--module", modules.join(" ")];
130
+ if (childModules) {
131
+ args.push("--child-modules");
146
132
  }
133
+ const installerEmitter = new hubEventEmitter_js_1.UnityHubInstallerEvent();
134
+ this.execUnityHubCommand(args, {
135
+ reject: false,
136
+ onStdout: (data) => installerEmitter.Progress(data),
137
+ })
138
+ .then((result) => {
139
+ if (!result.success) {
140
+ console.error(`Error adding module ${modules} to Unity ${editorVersion}:`, result.error);
141
+ }
142
+ })
143
+ .catch((error) => {
144
+ console.error(`Error adding module ${modules} to Unity ${editorVersion}:`, error);
145
+ });
146
+ return (0, index_js_1.ok)(installerEmitter);
147
147
  }
148
148
  static async addEditor(version, modules = [], architecture) {
149
149
  try {
150
150
  const data = await (0, unity_changeset_1.getUnityChangeset)(version);
151
- const args = ["install", "-v", version];
152
- args.push("--changeset", data.changeset);
151
+ const args = ["install", "-v", version, "--changeset", data.changeset];
153
152
  if (modules.length > 0) {
154
- args.push("--module");
155
- args.push(modules.join(" "));
153
+ args.push("--module", modules.join(" "));
156
154
  }
157
155
  if (!architecture) {
158
156
  const arch = os_1.default.arch() || process.arch;
159
- const defaultArchitecture = arch === "arm64" || arch === "arm" ? unity_js_1.EditorArchitecture.arm64 : unity_js_1.EditorArchitecture.x86_64;
160
- architecture = defaultArchitecture;
157
+ architecture = arch === "arm64" || arch === "arm" ? unity_js_1.EditorArchitecture.arm64 : unity_js_1.EditorArchitecture.x86_64;
161
158
  }
162
159
  args.push("--architecture", architecture);
163
- const installerEmitter = new hubEventEmitter_ts_1.UnityHubInstallerEvent();
160
+ const installerEmitter = new hubEventEmitter_js_1.UnityHubInstallerEvent();
164
161
  this.execUnityHubCommand(args, {
165
162
  reject: false,
166
163
  onStdout: (data) => installerEmitter.Progress(data),
167
- }).catch((error) => {
164
+ })
165
+ .then((result) => {
166
+ if (!result.success) {
167
+ console.error(`Error installing Unity ${version}:`, result.error);
168
+ }
169
+ })
170
+ .catch((error) => {
168
171
  console.error(`Error installing Unity ${version}:`, error);
169
172
  });
170
- return installerEmitter;
173
+ return (0, index_js_1.ok)(installerEmitter);
171
174
  }
172
175
  catch (error) {
173
176
  console.error(error);
174
- throw error;
177
+ return (0, index_js_1.err)(new index_js_1.UnityInstallationError(`Failed to install Unity ${version}: ${String(error)}`, { version, modules, architecture }));
175
178
  }
176
179
  }
177
180
  static async getProjects() {
@@ -179,19 +182,20 @@ class UnityHub {
179
182
  const projectsPath = this.getProjectsPath();
180
183
  if (!projectsPath || !fs_extra_1.default.existsSync(projectsPath)) {
181
184
  console.debug(`Projects file not found at: ${projectsPath}`);
182
- return [];
185
+ return (0, index_js_1.err)(new index_js_1.UnityProjectError(`Projects file not found at: ${projectsPath}`, { projectsPath }));
183
186
  }
184
187
  const projectsData = await fs_extra_1.default.readJson(projectsPath);
185
188
  const projects = Object.values(projectsData.data);
186
- return projects.map((project) => ({
189
+ const mappedProjects = projects.map((project) => ({
187
190
  name: project.title,
188
191
  path: project.path,
189
192
  version: project.version,
190
193
  }));
194
+ return (0, index_js_1.ok)(mappedProjects);
191
195
  }
192
196
  catch (error) {
193
197
  console.error("Error getting recent projects:", error);
194
- return [];
198
+ return (0, index_js_1.err)(new index_js_1.UnityProjectError(`Failed to get projects: ${String(error)}`));
195
199
  }
196
200
  }
197
201
  static async getDefaultProjectsDirectory() {
@@ -199,14 +203,14 @@ class UnityHub {
199
203
  const projectDirPath = this.getProjectDirPath();
200
204
  if (!projectDirPath || !fs_extra_1.default.existsSync(projectDirPath)) {
201
205
  console.debug(`Project directory file not found at: ${projectDirPath}`);
202
- return null;
206
+ return (0, index_js_1.ok)(null);
203
207
  }
204
208
  const projectDirData = await fs_extra_1.default.readJson(projectDirPath);
205
- return projectDirData.directoryPath ?? null;
209
+ return (0, index_js_1.ok)(projectDirData.directoryPath ?? null);
206
210
  }
207
211
  catch (error) {
208
212
  console.error("Error getting default project directory:", error);
209
- return null;
213
+ return (0, index_js_1.err)(new index_js_1.UnityProjectError(`Failed to get default project directory: ${String(error)}`));
210
214
  }
211
215
  }
212
216
  }
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.executeCommand = executeCommand;
4
4
  const execa_1 = require("execa");
5
+ const index_js_1 = require("../errors/index.js");
6
+ const index_js_2 = require("../errors/index.js");
5
7
  async function executeCommand(executable, args, options = {}) {
6
8
  try {
7
9
  const streamOutput = options.onStdout || options.onStderr;
@@ -40,19 +42,16 @@ async function executeCommand(executable, args, options = {}) {
40
42
  }
41
43
  }
42
44
  const { stdout, stderr, exitCode } = await subprocess;
43
- return {
44
- success: true,
45
+ return (0, index_js_1.ok)({
45
46
  stdout,
46
47
  stderr,
47
48
  exitCode,
48
- };
49
+ });
49
50
  }
50
51
  catch (error) {
51
- return {
52
- success: false,
53
- stdout: error.stdout ?? "",
54
- stderr: error.stderr ?? String(error),
55
- exitCode: error.exitCode,
56
- };
52
+ const stdout = error.stdout ?? "";
53
+ const stderr = error.stderr ?? String(error);
54
+ const exitCode = error.exitCode;
55
+ return (0, index_js_1.err)(new index_js_2.UnityCommandError(`Command execution failed: ${executable} ${args.join(" ")}`, stdout, stderr, exitCode, { executable, args }));
57
56
  }
58
57
  }
@@ -0,0 +1,21 @@
1
+ import { UnityError } from "./UnityError.js";
2
+ export interface Success<T> {
3
+ readonly success: true;
4
+ readonly value: T;
5
+ }
6
+ export interface Failure<E extends UnityError> {
7
+ readonly success: false;
8
+ readonly error: E;
9
+ }
10
+ export type Result<T, E extends UnityError = UnityError> = Success<T> | Failure<E>;
11
+ export declare function ok<T>(value: T): Success<T>;
12
+ export declare function err<E extends UnityError>(error: E): Failure<E>;
13
+ export declare function isOk<T, E extends UnityError>(result: Result<T, E>): result is Success<T>;
14
+ export declare function isErr<T, E extends UnityError>(result: Result<T, E>): result is Failure<E>;
15
+ export declare function unwrap<T, E extends UnityError>(result: Result<T, E>): T;
16
+ export declare function unwrapOr<T, E extends UnityError>(result: Result<T, E>, defaultValue: T): T;
17
+ export declare function map<T, U, E extends UnityError>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;
18
+ export declare function mapErr<T, E extends UnityError, F extends UnityError>(result: Result<T, E>, fn: (error: E) => F): Result<T, F>;
19
+ export declare function andThen<T, U, E extends UnityError>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
20
+ export declare function firstOk<T, E extends UnityError>(results: Result<T, E>[]): Result<T, E>;
21
+ export declare function combine<T, E extends UnityError>(results: Result<T, E>[]): Result<T[], E>;
@@ -0,0 +1,63 @@
1
+ export function ok(value) {
2
+ return { success: true, value };
3
+ }
4
+ export function err(error) {
5
+ return { success: false, error };
6
+ }
7
+ export function isOk(result) {
8
+ return result.success === true;
9
+ }
10
+ export function isErr(result) {
11
+ return result.success === false;
12
+ }
13
+ export function unwrap(result) {
14
+ if (isOk(result)) {
15
+ return result.value;
16
+ }
17
+ throw result.error;
18
+ }
19
+ export function unwrapOr(result, defaultValue) {
20
+ if (isOk(result)) {
21
+ return result.value;
22
+ }
23
+ return defaultValue;
24
+ }
25
+ export function map(result, fn) {
26
+ if (isOk(result)) {
27
+ return ok(fn(result.value));
28
+ }
29
+ return result;
30
+ }
31
+ export function mapErr(result, fn) {
32
+ if (isErr(result)) {
33
+ return err(fn(result.error));
34
+ }
35
+ return result;
36
+ }
37
+ export function andThen(result, fn) {
38
+ if (isOk(result)) {
39
+ return fn(result.value);
40
+ }
41
+ return result;
42
+ }
43
+ export function firstOk(results) {
44
+ if (results.length === 0) {
45
+ throw new Error("Cannot call firstOk on empty array");
46
+ }
47
+ for (const result of results) {
48
+ if (isOk(result)) {
49
+ return result;
50
+ }
51
+ }
52
+ return results[results.length - 1];
53
+ }
54
+ export function combine(results) {
55
+ const values = [];
56
+ for (const result of results) {
57
+ if (isErr(result)) {
58
+ return result;
59
+ }
60
+ values.push(result.value);
61
+ }
62
+ return ok(values);
63
+ }
@@ -0,0 +1,36 @@
1
+ export declare abstract class UnityError extends Error {
2
+ readonly code: string;
3
+ readonly context?: Record<string, unknown>;
4
+ constructor(message: string, code: string, context?: Record<string, unknown>);
5
+ }
6
+ export declare class UnityHubNotFoundError extends UnityError {
7
+ constructor(message?: string, context?: Record<string, unknown>);
8
+ }
9
+ export declare class UnityEditorNotFoundError extends UnityError {
10
+ constructor(version: string, path?: string);
11
+ }
12
+ export declare class UnityCommandError extends UnityError {
13
+ readonly stdout: string;
14
+ readonly stderr: string;
15
+ readonly exitCode?: number;
16
+ constructor(message: string, stdout?: string, stderr?: string, exitCode?: number, context?: Record<string, unknown>);
17
+ }
18
+ export declare class UnityInstallationError extends UnityError {
19
+ constructor(message: string, context?: Record<string, unknown>);
20
+ }
21
+ export declare class UnityProjectError extends UnityError {
22
+ constructor(message: string, context?: Record<string, unknown>);
23
+ }
24
+ export declare class UnityLicenseError extends UnityError {
25
+ constructor(message: string, context?: Record<string, unknown>);
26
+ }
27
+ export declare class UnityPackageError extends UnityError {
28
+ constructor(message: string, context?: Record<string, unknown>);
29
+ }
30
+ export declare class UnityTestError extends UnityError {
31
+ readonly testOutput: string;
32
+ constructor(message: string, testOutput?: string, context?: Record<string, unknown>);
33
+ }
34
+ export declare class InvalidArgumentError extends UnityError {
35
+ constructor(message: string, context?: Record<string, unknown>);
36
+ }
@@ -0,0 +1,64 @@
1
+ export class UnityError extends Error {
2
+ code;
3
+ context;
4
+ constructor(message, code, context) {
5
+ super(message);
6
+ this.name = this.constructor.name;
7
+ this.code = code;
8
+ this.context = context;
9
+ Error.captureStackTrace(this, this.constructor);
10
+ }
11
+ }
12
+ export class UnityHubNotFoundError extends UnityError {
13
+ constructor(message = "Unity Hub is not available", context) {
14
+ super(message, "UNITY_HUB_NOT_FOUND", context);
15
+ }
16
+ }
17
+ export class UnityEditorNotFoundError extends UnityError {
18
+ constructor(version, path) {
19
+ super(`Unity Editor version ${version} not found${path ? ` at path: ${path}` : ""}`, "UNITY_EDITOR_NOT_FOUND", { version, path });
20
+ }
21
+ }
22
+ export class UnityCommandError extends UnityError {
23
+ stdout;
24
+ stderr;
25
+ exitCode;
26
+ constructor(message, stdout = "", stderr = "", exitCode, context) {
27
+ super(message, "UNITY_COMMAND_ERROR", context);
28
+ this.stdout = stdout;
29
+ this.stderr = stderr;
30
+ this.exitCode = exitCode;
31
+ }
32
+ }
33
+ export class UnityInstallationError extends UnityError {
34
+ constructor(message, context) {
35
+ super(message, "UNITY_INSTALLATION_ERROR", context);
36
+ }
37
+ }
38
+ export class UnityProjectError extends UnityError {
39
+ constructor(message, context) {
40
+ super(message, "UNITY_PROJECT_ERROR", context);
41
+ }
42
+ }
43
+ export class UnityLicenseError extends UnityError {
44
+ constructor(message, context) {
45
+ super(message, "UNITY_LICENSE_ERROR", context);
46
+ }
47
+ }
48
+ export class UnityPackageError extends UnityError {
49
+ constructor(message, context) {
50
+ super(message, "UNITY_PACKAGE_ERROR", context);
51
+ }
52
+ }
53
+ export class UnityTestError extends UnityError {
54
+ testOutput;
55
+ constructor(message, testOutput = "", context) {
56
+ super(message, "UNITY_TEST_ERROR", context);
57
+ this.testOutput = testOutput;
58
+ }
59
+ }
60
+ export class InvalidArgumentError extends UnityError {
61
+ constructor(message, context) {
62
+ super(message, "INVALID_ARGUMENT", context);
63
+ }
64
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./Result.js";
2
+ export * from "./UnityError.js";
@@ -0,0 +1,2 @@
1
+ export * from "./Result.js";
2
+ export * from "./UnityError.js";
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from "events";
2
- import { InstallerEventType, InstallerEvent } from "../types/unity.ts";
2
+ import { InstallerEventType, InstallerEvent } from "../types/unity.js";
3
3
  export interface InstallerEmitter extends EventEmitter {
4
4
  on(event: InstallerEventType.Progress, listener: (info: InstallerEvent[]) => void): this;
5
5
  on(event: InstallerEventType.Error, listener: (error: Error) => void): this;
@@ -1,6 +1,20 @@
1
- import { InstallerEvent } from "../types/unity.ts";
1
+ import { InstallerEvent } from "../types/unity.js";
2
+ import { ParserConfig, ParseResult, Pattern } from "./patterns/index.js";
2
3
  export declare class UnityHubEventParser {
3
- private static errorPatterns;
4
+ private static patternRegistry;
5
+ private static statusNormalizer;
6
+ private static config;
7
+ private static initialize;
4
8
  static parseUnityHubEvent(event: string): InstallerEvent[];
5
- private static checkForErrors;
9
+ static parseWithDetails(event: string): ParseResult;
10
+ static setLocale(locale: string): void;
11
+ static getLocale(): string;
12
+ static registerCustomPattern(pattern: Pattern): void;
13
+ static addStatusNormalization(statusText: string, status: any, locale?: string): void;
14
+ static getUnknownStatuses(): string[];
15
+ static clearUnknownStatuses(): void;
16
+ static configure(config: Partial<ParserConfig>): void;
17
+ static getConfig(): Readonly<ParserConfig>;
18
+ static reset(): void;
19
+ static getPatternNames(): string[];
6
20
  }
@@ -1,40 +1,110 @@
1
- import { InstallerStatus } from "../types/unity.js";
1
+ import { PatternRegistry, StatusNormalizer, BracketModulePattern, ErrorPattern, FallbackPattern, } from "./patterns/index.js";
2
2
  export class UnityHubEventParser {
3
- static errorPatterns = [/Error:.*/];
3
+ static patternRegistry;
4
+ static statusNormalizer;
5
+ static config = {
6
+ locale: "en",
7
+ logUnknownStatuses: true,
8
+ minConfidence: 30,
9
+ useFallbackPatterns: true,
10
+ };
11
+ static initialize() {
12
+ if (this.patternRegistry) {
13
+ return;
14
+ }
15
+ this.statusNormalizer = new StatusNormalizer();
16
+ this.patternRegistry = new PatternRegistry();
17
+ this.patternRegistry.register(new ErrorPattern(this.config.locale));
18
+ this.patternRegistry.register(new BracketModulePattern(this.statusNormalizer, this.config.locale));
19
+ if (this.config.useFallbackPatterns) {
20
+ this.patternRegistry.register(new FallbackPattern(this.statusNormalizer, this.config.locale));
21
+ }
22
+ }
4
23
  static parseUnityHubEvent(event) {
24
+ this.initialize();
25
+ const result = this.parseWithDetails(event);
26
+ return result.events;
27
+ }
28
+ static parseWithDetails(event) {
29
+ this.initialize();
5
30
  const events = [];
6
- const lines = event.split("\n");
31
+ const unparsedLines = [];
32
+ const lines = event.split(/\r?\n/);
7
33
  for (const line of lines) {
8
- const errorLine = this.checkForErrors(line);
9
- if (errorLine) {
10
- events.push(errorLine);
34
+ const trimmedLine = line.trim();
35
+ if (!trimmedLine) {
11
36
  continue;
12
37
  }
13
- }
14
- const pattern = /^\[(?<module>[^\]]+)\]\s+(?<status>.+?)(?:(?:\s+(?<progress>\d+(?:\.\d+)?))%)?\.*$/;
15
- for (const line of lines) {
16
- const match = line.match(pattern);
17
- if (match?.groups) {
18
- const { module, status, progress } = match.groups;
38
+ const match = this.patternRegistry.match(trimmedLine, this.config.locale, this.config.minConfidence);
39
+ if (match) {
19
40
  events.push({
20
- module: module.trim(),
21
- status: status.replace(/\.\.\.$/, "").trim(),
22
- progress: progress ? parseFloat(progress) : status !== InstallerStatus.Downloading ? null : 0,
41
+ module: match.module,
42
+ status: match.status,
43
+ progress: match.progress,
44
+ error: match.error,
23
45
  });
24
46
  }
25
- }
26
- return events;
27
- }
28
- static checkForErrors(line) {
29
- for (const pattern of this.errorPatterns) {
30
- if (pattern.test(line)) {
31
- return {
32
- module: "UnityHub",
33
- status: InstallerStatus.Error,
34
- error: line.trim(),
35
- };
47
+ else {
48
+ unparsedLines.push(trimmedLine);
49
+ if (this.config.logUnknownStatuses) {
50
+ console.debug(`UnityHubEventParser: Could not parse line: "${trimmedLine}"`);
51
+ }
36
52
  }
37
53
  }
38
- return null;
54
+ return {
55
+ events,
56
+ unknownStatuses: this.statusNormalizer.getUnknownStatuses(),
57
+ unparsedLines,
58
+ };
59
+ }
60
+ static setLocale(locale) {
61
+ this.config.locale = locale;
62
+ if (this.patternRegistry) {
63
+ this.patternRegistry.clear();
64
+ this.initialize();
65
+ }
66
+ }
67
+ static getLocale() {
68
+ return this.config.locale;
69
+ }
70
+ static registerCustomPattern(pattern) {
71
+ this.initialize();
72
+ this.patternRegistry.register(pattern);
73
+ }
74
+ static addStatusNormalization(statusText, status, locale) {
75
+ this.initialize();
76
+ this.statusNormalizer.addNormalization({ text: statusText, status, locale });
77
+ }
78
+ static getUnknownStatuses() {
79
+ this.initialize();
80
+ return this.statusNormalizer.getUnknownStatuses();
81
+ }
82
+ static clearUnknownStatuses() {
83
+ this.initialize();
84
+ this.statusNormalizer.clearUnknownStatuses();
85
+ }
86
+ static configure(config) {
87
+ this.config = { ...this.config, ...config };
88
+ if (config.locale && this.patternRegistry) {
89
+ this.patternRegistry.clear();
90
+ this.initialize();
91
+ }
92
+ }
93
+ static getConfig() {
94
+ return { ...this.config };
95
+ }
96
+ static reset() {
97
+ this.patternRegistry = undefined;
98
+ this.statusNormalizer = undefined;
99
+ this.config = {
100
+ locale: "en",
101
+ logUnknownStatuses: true,
102
+ minConfidence: 30,
103
+ useFallbackPatterns: true,
104
+ };
105
+ }
106
+ static getPatternNames() {
107
+ this.initialize();
108
+ return this.patternRegistry.getPatternNames();
39
109
  }
40
110
  }
@@ -0,0 +1,11 @@
1
+ import { Pattern, PatternMatch } from "../types.js";
2
+ import { StatusNormalizer } from "../statusNormalizer.js";
3
+ export declare class BracketModulePattern implements Pattern {
4
+ readonly name = "BracketModulePattern";
5
+ readonly priority = 80;
6
+ readonly locale?: string;
7
+ private statusNormalizer;
8
+ private pattern;
9
+ constructor(statusNormalizer: StatusNormalizer, locale?: string);
10
+ match(line: string, locale?: string): PatternMatch | null;
11
+ }