Skip to content

Commit 82c73e3

Browse files
committed
docs: Update CHANGELOG.md with granular error classes entry
refactor: Define and use granular error classes - Updated `CHANGELOG.md` to include the entry for defining granular error classes. - Defined `FileNotFoundError` and `InvalidManifestError` in `errors.ts`. - Modified `FileHandler` to throw `FileNotFoundError` when a file is not found. - Modified `ManifestParser` to throw `InvalidManifestError` for invalid JSON or regex matches. - Updated `index.ts` to catch and handle these new specific error types.
1 parent 8e2f90b commit 82c73e3

6 files changed

Lines changed: 132 additions & 26 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ All notable changes for each version of the Ambient Music extension.
88

99
- refactor: Moved `UpdaterRegistry` to `src/registry` for better organization and updated all relevant imports.
1010
- refactor: Applied Dependency Inversion Principle (DIP) by passing `FileHandler` as a dependency to `ManifestParser`, and `ManifestParser` as a dependency to updaters. This improves testability and flexibility.
11+
- refactor: Defined more granular error classes (`FileNotFoundError`, `InvalidManifestError`) within `errors.ts` to enable more precise error handling and user feedback.
12+
- refactor: Updated `FileHandler` and `ManifestParser` to throw these specific errors, and `index.ts` to catch and handle them.
1113

1214
## v0.7.1 2025 08 24
1315

dist/index.js

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28402,7 +28402,7 @@ exports.GIT_TAG = core.getInput('git_tag') === 'true';
2840228402
"use strict";
2840328403

2840428404
Object.defineProperty(exports, "__esModule", ({ value: true }));
28405-
exports.VersionBumpError = exports.PlatformDetectionError = void 0;
28405+
exports.InvalidManifestError = exports.FileNotFoundError = exports.VersionBumpError = exports.PlatformDetectionError = void 0;
2840628406
class PlatformDetectionError extends Error {
2840728407
constructor(message) {
2840828408
super(message);
@@ -28417,6 +28417,20 @@ class VersionBumpError extends Error {
2841728417
}
2841828418
}
2841928419
exports.VersionBumpError = VersionBumpError;
28420+
class FileNotFoundError extends Error {
28421+
constructor(message) {
28422+
super(message);
28423+
this.name = 'FileNotFoundError';
28424+
}
28425+
}
28426+
exports.FileNotFoundError = FileNotFoundError;
28427+
class InvalidManifestError extends Error {
28428+
constructor(message) {
28429+
super(message);
28430+
this.name = 'InvalidManifestError';
28431+
}
28432+
}
28433+
exports.InvalidManifestError = InvalidManifestError;
2842028434

2842128435

2842228436
/***/ }),
@@ -28498,6 +28512,12 @@ async function run() {
2849828512
else if (error instanceof errors_1.VersionBumpError) {
2849928513
core.setFailed(`Version bump failed: ${error.message}`);
2850028514
}
28515+
else if (error instanceof errors_1.FileNotFoundError) {
28516+
core.setFailed(`File not found: ${error.message}`);
28517+
}
28518+
else if (error instanceof errors_1.InvalidManifestError) {
28519+
core.setFailed(`Invalid manifest: ${error.message}`);
28520+
}
2850128521
else if (error instanceof Error) {
2850228522
core.setFailed(error.message);
2850328523
}
@@ -29065,15 +29085,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
2906529085
Object.defineProperty(exports, "__esModule", ({ value: true }));
2906629086
exports.FileHandler = void 0;
2906729087
const fs_1 = __importDefault(__nccwpck_require__(9896));
29088+
const errors_1 = __nccwpck_require__(4830);
2906829089
class FileHandler {
2906929090
constructor() { }
2907029091
fileExists(filePath) {
2907129092
return fs_1.default.existsSync(filePath);
2907229093
}
2907329094
readFile(filePath) {
29095+
if (!this.fileExists(filePath)) {
29096+
throw new errors_1.FileNotFoundError(`File not found: ${filePath}`);
29097+
}
2907429098
return fs_1.default.readFileSync(filePath, 'utf8');
2907529099
}
2907629100
writeFile(filePath, content) {
29101+
// For writeFile, we don't necessarily need to check fileExists first
29102+
// as fs.writeFileSync will create the file if it doesn't exist.
29103+
// However, if we want to ensure the directory exists, that's a different concern.
2907729104
fs_1.default.writeFileSync(filePath, content);
2907829105
}
2907929106
}
@@ -29110,12 +29137,13 @@ __exportStar(__nccwpck_require__(2521), exports);
2911029137
/***/ }),
2911129138

2911229139
/***/ 2521:
29113-
/***/ ((__unused_webpack_module, exports) => {
29140+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
2911429141

2911529142
"use strict";
2911629143

2911729144
Object.defineProperty(exports, "__esModule", ({ value: true }));
2911829145
exports.ManifestParser = void 0;
29146+
const errors_1 = __nccwpck_require__(4830);
2911929147
class ManifestParser {
2912029148
constructor(fileHandler) {
2912129149
this.fileHandler = fileHandler;
@@ -29131,46 +29159,63 @@ class ManifestParser {
2913129159
getVersion(manifestPath, type, options) {
2913229160
const content = this.fileHandler.readFile(manifestPath);
2913329161
if (type === 'json') {
29134-
const data = JSON.parse(content);
29162+
let data;
29163+
try {
29164+
data = JSON.parse(content);
29165+
}
29166+
catch (e) {
29167+
throw new errors_1.InvalidManifestError(`Invalid JSON in ${manifestPath}: ${e instanceof Error ? e.message : String(e)}`);
29168+
}
2913529169
let version = data;
2913629170
if (options.jsonPath) {
2913729171
for (const key of options.jsonPath) {
29138-
if (version && typeof version === 'object' && key in version) {
29172+
if (typeof version === 'object' && version !== null && key in version) {
2913929173
version = version[key];
2914029174
}
2914129175
else {
29142-
return null; // Path not found
29176+
throw new errors_1.InvalidManifestError(`JSON path '${options.jsonPath.join('.')}' not found in ${manifestPath}`);
2914329177
}
2914429178
}
2914529179
}
2914629180
return typeof version === 'string' ? version : null;
2914729181
}
2914829182
else if (type === 'regex' && options.regex) {
2914929183
const match = content.match(options.regex);
29150-
return match ? match[1] : null;
29184+
if (!match) {
29185+
throw new errors_1.InvalidManifestError(`Regex '${options.regex.source}' did not find a match in ${manifestPath}`);
29186+
}
29187+
return match[1];
2915129188
}
2915229189
return null;
2915329190
}
2915429191
updateVersion(manifestPath, newVersion, type, options) {
2915529192
let content = this.fileHandler.readFile(manifestPath);
2915629193
if (type === 'json') {
29157-
const data = JSON.parse(content);
29194+
let data;
29195+
try {
29196+
data = JSON.parse(content);
29197+
}
29198+
catch (e) {
29199+
throw new errors_1.InvalidManifestError(`Invalid JSON in ${manifestPath}: ${e instanceof Error ? e.message : String(e)}`);
29200+
}
2915829201
let target = data;
2915929202
if (options.jsonPath && options.jsonPath.length > 0) {
2916029203
for (let i = 0; i < options.jsonPath.length - 1; i++) {
2916129204
const key = options.jsonPath[i];
29162-
if (target && typeof target === 'object' && key in target) {
29205+
if (typeof target === 'object' && target !== null && key in target) {
2916329206
target = target[key];
2916429207
}
2916529208
else {
29166-
// Path not found, or not an object, cannot update
29167-
return;
29209+
throw new errors_1.InvalidManifestError(`JSON path '${options.jsonPath.slice(0, i + 1).join('.')}' not found for update in ${manifestPath}`);
2916829210
}
2916929211
}
2917029212
const lastKey = options.jsonPath[options.jsonPath.length - 1];
29171-
if (target && typeof target === 'object' && lastKey in target) {
29213+
if (typeof target === 'object' && target !== null && lastKey in target) {
2917229214
target[lastKey] = newVersion;
2917329215
}
29216+
else {
29217+
throw new errors_1.InvalidManifestError(`JSON path '${options.jsonPath.join('.')}' not found for update in ${manifestPath}`);
29218+
}
2917429219
}
2917529220
else {
2917629221
// If no jsonPath, assume the root is the version (e.g., a simple string file)

src/errors.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,17 @@ export class VersionBumpError extends Error {
1111
this.name = 'VersionBumpError';
1212
}
1313
}
14+
15+
export class FileNotFoundError extends Error {
16+
constructor(message: string) {
17+
super(message);
18+
this.name = 'FileNotFoundError';
19+
}
20+
}
21+
22+
export class InvalidManifestError extends Error {
23+
constructor(message: string) {
24+
super(message);
25+
this.name = 'InvalidManifestError';
26+
}
27+
}

src/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ import {
88
RustUpdater,
99
} from './updaters';
1010
import { UpdaterRegistry } from './registry';
11-
import { PlatformDetectionError, VersionBumpError } from './errors';
11+
import {
12+
PlatformDetectionError,
13+
VersionBumpError,
14+
FileNotFoundError,
15+
InvalidManifestError,
16+
} from './errors';
1217
import { RELEASE_TYPE, TARGET_PLATFORM, GIT_TAG } from './config';
1318
import * as core from '@actions/core';
1419

@@ -46,6 +51,10 @@ async function run() {
4651
core.setFailed(`Platform detection failed: ${error.message}`);
4752
} else if (error instanceof VersionBumpError) {
4853
core.setFailed(`Version bump failed: ${error.message}`);
54+
} else if (error instanceof FileNotFoundError) {
55+
core.setFailed(`File not found: ${error.message}`);
56+
} else if (error instanceof InvalidManifestError) {
57+
core.setFailed(`Invalid manifest: ${error.message}`);
4958
} else if (error instanceof Error) {
5059
core.setFailed(error.message);
5160
} else {

src/utils/fileHandler.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import fs from 'fs';
2+
import { FileNotFoundError } from '../errors';
23

34
export class FileHandler {
45
constructor() {}
@@ -8,10 +9,16 @@ export class FileHandler {
89
}
910

1011
readFile(filePath: string): string {
12+
if (!this.fileExists(filePath)) {
13+
throw new FileNotFoundError(`File not found: ${filePath}`);
14+
}
1115
return fs.readFileSync(filePath, 'utf8');
1216
}
1317

1418
writeFile(filePath: string, content: string): void {
19+
// For writeFile, we don't necessarily need to check fileExists first
20+
// as fs.writeFileSync will create the file if it doesn't exist.
21+
// However, if we want to ensure the directory exists, that's a different concern.
1522
fs.writeFileSync(filePath, content);
1623
}
1724
}

src/utils/manifestParser.ts

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { FileHandler } from './fileHandler';
2+
import { InvalidManifestError } from '../errors';
23

34
export class ManifestParser {
45
private fileHandler: FileHandler;
@@ -24,21 +25,36 @@ export class ManifestParser {
2425
const content = this.fileHandler.readFile(manifestPath);
2526

2627
if (type === 'json') {
27-
const data = JSON.parse(content);
28-
let version = data;
28+
let data: unknown;
29+
try {
30+
data = JSON.parse(content);
31+
} catch (e: unknown) {
32+
throw new InvalidManifestError(
33+
`Invalid JSON in ${manifestPath}: ${e instanceof Error ? e.message : String(e)}`,
34+
);
35+
}
36+
37+
let version: unknown = data;
2938
if (options.jsonPath) {
3039
for (const key of options.jsonPath) {
31-
if (version && typeof version === 'object' && key in version) {
32-
version = version[key];
40+
if (typeof version === 'object' && version !== null && key in version) {
41+
version = (version as Record<string, unknown>)[key];
3342
} else {
34-
return null; // Path not found
43+
throw new InvalidManifestError(
44+
`JSON path '${options.jsonPath.join('.')}' not found in ${manifestPath}`,
45+
);
3546
}
3647
}
3748
}
3849
return typeof version === 'string' ? version : null;
3950
} else if (type === 'regex' && options.regex) {
4051
const match = content.match(options.regex);
41-
return match ? match[1] : null;
52+
if (!match) {
53+
throw new InvalidManifestError(
54+
`Regex '${options.regex.source}' did not find a match in ${manifestPath}`,
55+
);
56+
}
57+
return match[1];
4258
}
4359
return null;
4460
}
@@ -52,21 +68,34 @@ export class ManifestParser {
5268
let content = this.fileHandler.readFile(manifestPath);
5369

5470
if (type === 'json') {
55-
const data = JSON.parse(content);
56-
let target = data;
71+
let data: unknown;
72+
try {
73+
data = JSON.parse(content);
74+
} catch (e: unknown) {
75+
throw new InvalidManifestError(
76+
`Invalid JSON in ${manifestPath}: ${e instanceof Error ? e.message : String(e)}`,
77+
);
78+
}
79+
80+
let target: unknown = data;
5781
if (options.jsonPath && options.jsonPath.length > 0) {
5882
for (let i = 0; i < options.jsonPath.length - 1; i++) {
5983
const key = options.jsonPath[i];
60-
if (target && typeof target === 'object' && key in target) {
61-
target = target[key];
84+
if (typeof target === 'object' && target !== null && key in target) {
85+
target = (target as Record<string, unknown>)[key];
6286
} else {
63-
// Path not found, or not an object, cannot update
64-
return;
87+
throw new InvalidManifestError(
88+
`JSON path '${options.jsonPath.slice(0, i + 1).join('.')}' not found for update in ${manifestPath}`,
89+
);
6590
}
6691
}
6792
const lastKey = options.jsonPath[options.jsonPath.length - 1];
68-
if (target && typeof target === 'object' && lastKey in target) {
69-
target[lastKey] = newVersion;
93+
if (typeof target === 'object' && target !== null && lastKey in target) {
94+
(target as Record<string, unknown>)[lastKey] = newVersion;
95+
} else {
96+
throw new InvalidManifestError(
97+
`JSON path '${options.jsonPath.join('.')}' not found for update in ${manifestPath}`,
98+
);
7099
}
71100
} else {
72101
// If no jsonPath, assume the root is the version (e.g., a simple string file)

0 commit comments

Comments
 (0)