ag-toolkit 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/git.js +1 -1
- package/dist/lib/arg-parser.d.ts +9 -5
- package/dist/lib/arg-parser.js +14 -0
- package/dist/tests/arg-parser.test.d.ts +1 -0
- package/dist/tests/arg-parser.test.js +404 -0
- package/dist/tests/config.test.d.ts +1 -0
- package/dist/tests/config.test.js +234 -0
- package/dist/tests/format.test.d.ts +1 -0
- package/dist/tests/format.test.js +76 -0
- package/dist/tests/isDeepEqual.test.d.ts +1 -0
- package/dist/tests/isDeepEqual.test.js +203 -0
- package/dist/tests/isValidBranchName.test.d.ts +1 -0
- package/dist/tests/isValidBranchName.test.js +89 -0
- package/dist/tests/match.test.d.ts +1 -0
- package/dist/tests/match.test.js +86 -0
- package/dist/tests/package.test.d.ts +1 -0
- package/dist/tests/package.test.js +77 -0
- package/dist/tests/sanitizeString.test.d.ts +1 -0
- package/dist/tests/sanitizeString.test.js +48 -0
- package/package.json +9 -8
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { matchPattern } from "../lib/match.js";
|
|
3
|
+
describe("matchPattern", () => {
|
|
4
|
+
describe("exact string matching", () => {
|
|
5
|
+
test("should match identical strings", () => {
|
|
6
|
+
expect(matchPattern("hello", "hello")).toBe(true);
|
|
7
|
+
expect(matchPattern("test123", "test123")).toBe(true);
|
|
8
|
+
});
|
|
9
|
+
test("should not match different strings", () => {
|
|
10
|
+
expect(matchPattern("hello", "world")).toBe(false);
|
|
11
|
+
expect(matchPattern("test", "test123")).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
test("should be case-sensitive for exact matches", () => {
|
|
14
|
+
expect(matchPattern("Hello", "hello")).toBe(false);
|
|
15
|
+
expect(matchPattern("TEST", "test")).toBe(false);
|
|
16
|
+
});
|
|
17
|
+
test("should handle empty strings", () => {
|
|
18
|
+
expect(matchPattern("", "")).toBe(true);
|
|
19
|
+
expect(matchPattern("test", "")).toBe(false);
|
|
20
|
+
expect(matchPattern("", "test")).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe("regex pattern matching", () => {
|
|
24
|
+
test("should match regex patterns with delimiters", () => {
|
|
25
|
+
expect(matchPattern("hello", "/hello/")).toBe(true);
|
|
26
|
+
expect(matchPattern("test123", "/test\\d+/")).toBe(true);
|
|
27
|
+
expect(matchPattern("abc", "/[a-z]+/")).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
test("should not match when regex pattern doesn't match", () => {
|
|
30
|
+
expect(matchPattern("hello", "/world/")).toBe(false);
|
|
31
|
+
expect(matchPattern("abc", "/\\d+/")).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
test("should support regex flags", () => {
|
|
34
|
+
expect(matchPattern("Hello", "/hello/i")).toBe(true);
|
|
35
|
+
expect(matchPattern("TEST", "/test/i")).toBe(true);
|
|
36
|
+
expect(matchPattern("Hello", "/hello/")).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
test("should support global flag", () => {
|
|
39
|
+
expect(matchPattern("test test", "/test/g")).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
test("should support multiline flag", () => {
|
|
42
|
+
expect(matchPattern("line1\nline2", "/^line2/m")).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
test("should handle complex regex patterns", () => {
|
|
45
|
+
expect(matchPattern("email@example.com", "/^[\\w.-]+@[\\w.-]+\\.\\w+$/")).toBe(true);
|
|
46
|
+
expect(matchPattern("2024-01-01", "/^\\d{4}-\\d{2}-\\d{2}$/")).toBe(true);
|
|
47
|
+
expect(matchPattern("invalid-date", "/^\\d{4}-\\d{2}-\\d{2}$/")).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
test("should handle patterns with special characters", () => {
|
|
50
|
+
expect(matchPattern("(test)", "/\\(test\\)/")).toBe(true);
|
|
51
|
+
expect(matchPattern("[abc]", "/\\[abc\\]/")).toBe(true);
|
|
52
|
+
expect(matchPattern("a.b", "/a\\.b/")).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
test("should return false for invalid regex patterns", () => {
|
|
55
|
+
expect(matchPattern("test", "/(/")).toBe(false);
|
|
56
|
+
expect(matchPattern("test", "/[/")).toBe(false);
|
|
57
|
+
expect(matchPattern("test", "/*/")).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
test("should handle patterns with multiple slashes", () => {
|
|
60
|
+
expect(matchPattern("path/to/file", "/path\\/to\\/file/")).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
describe("edge cases", () => {
|
|
64
|
+
test("should treat patterns without proper delimiters as exact strings", () => {
|
|
65
|
+
expect(matchPattern("/test", "/test")).toBe(true);
|
|
66
|
+
expect(matchPattern("test/", "test/")).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
test("should handle patterns that look like regex but aren't properly formatted", () => {
|
|
69
|
+
expect(matchPattern("/test", "/test")).toBe(true);
|
|
70
|
+
expect(matchPattern("test/", "test/")).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
test("should handle empty regex pattern", () => {
|
|
73
|
+
expect(matchPattern("test", "//")).toBe(true);
|
|
74
|
+
expect(matchPattern("", "//")).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
test("should handle patterns with only opening slash", () => {
|
|
77
|
+
expect(matchPattern("/hello", "/hello")).toBe(true);
|
|
78
|
+
expect(matchPattern("hello", "/hello")).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
test("should handle anchored patterns", () => {
|
|
81
|
+
expect(matchPattern("hello world", "/^hello/")).toBe(true);
|
|
82
|
+
expect(matchPattern("hello world", "/world$/")).toBe(true);
|
|
83
|
+
expect(matchPattern("hello world", "/^world/")).toBe(false);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { loadPackageJson } from "../lib/package.js";
|
|
6
|
+
describe("loadPackageJson", () => {
|
|
7
|
+
let testDir;
|
|
8
|
+
let testScriptPath;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
testDir = join(tmpdir(), `package-test-${Date.now()}`);
|
|
11
|
+
const scriptDir = join(testDir, "lib");
|
|
12
|
+
Bun.spawnSync(["mkdir", "-p", scriptDir]);
|
|
13
|
+
testScriptPath = join(scriptDir, "test-script.js");
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
Bun.spawnSync(["rm", "-rf", testDir]);
|
|
17
|
+
});
|
|
18
|
+
test("should load and parse package.json", () => {
|
|
19
|
+
const packageJson = {
|
|
20
|
+
name: "test-package",
|
|
21
|
+
version: "1.0.0",
|
|
22
|
+
description: "Test package",
|
|
23
|
+
};
|
|
24
|
+
writeFileSync(join(testDir, "package.json"), JSON.stringify(packageJson));
|
|
25
|
+
writeFileSync(testScriptPath, "");
|
|
26
|
+
const scriptUrl = `file://${testScriptPath}`;
|
|
27
|
+
const result = loadPackageJson(scriptUrl);
|
|
28
|
+
expect(result.name).toBe("test-package");
|
|
29
|
+
expect(result.version).toBe("1.0.0");
|
|
30
|
+
// biome-ignore lint/complexity/useLiteralKeys: ignore
|
|
31
|
+
expect(result["description"]).toBe("Test package");
|
|
32
|
+
});
|
|
33
|
+
test("should handle package.json with additional properties", () => {
|
|
34
|
+
const packageJson = {
|
|
35
|
+
name: "test-package",
|
|
36
|
+
version: "2.0.0",
|
|
37
|
+
author: "Test Author",
|
|
38
|
+
license: "MIT",
|
|
39
|
+
dependencies: {
|
|
40
|
+
"some-package": "^1.0.0",
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
writeFileSync(join(testDir, "package.json"), JSON.stringify(packageJson));
|
|
44
|
+
writeFileSync(testScriptPath, "");
|
|
45
|
+
const scriptUrl = `file://${testScriptPath}`;
|
|
46
|
+
const result = loadPackageJson(scriptUrl);
|
|
47
|
+
expect(result.name).toBe("test-package");
|
|
48
|
+
expect(result.version).toBe("2.0.0");
|
|
49
|
+
// biome-ignore lint/complexity/useLiteralKeys: ignore
|
|
50
|
+
expect(result["author"]).toBe("Test Author");
|
|
51
|
+
// biome-ignore lint/complexity/useLiteralKeys: ignore
|
|
52
|
+
expect(result["license"]).toBe("MIT");
|
|
53
|
+
});
|
|
54
|
+
test("should throw error when package.json doesn't exist", () => {
|
|
55
|
+
writeFileSync(testScriptPath, "");
|
|
56
|
+
const scriptUrl = `file://${testScriptPath}`;
|
|
57
|
+
expect(() => loadPackageJson(scriptUrl)).toThrow();
|
|
58
|
+
});
|
|
59
|
+
test("should throw error for invalid JSON in package.json", () => {
|
|
60
|
+
writeFileSync(join(testDir, "package.json"), "{ invalid json }");
|
|
61
|
+
writeFileSync(testScriptPath, "");
|
|
62
|
+
const scriptUrl = `file://${testScriptPath}`;
|
|
63
|
+
expect(() => loadPackageJson(scriptUrl)).toThrow();
|
|
64
|
+
});
|
|
65
|
+
test("should handle package.json with minimal required fields", () => {
|
|
66
|
+
const packageJson = {
|
|
67
|
+
name: "minimal-package",
|
|
68
|
+
version: "0.0.1",
|
|
69
|
+
};
|
|
70
|
+
writeFileSync(join(testDir, "package.json"), JSON.stringify(packageJson));
|
|
71
|
+
writeFileSync(testScriptPath, "");
|
|
72
|
+
const scriptUrl = `file://${testScriptPath}`;
|
|
73
|
+
const result = loadPackageJson(scriptUrl);
|
|
74
|
+
expect(result.name).toBe("minimal-package");
|
|
75
|
+
expect(result.version).toBe("0.0.1");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { sanitizeString } from "../lib/sanitizeString.js";
|
|
3
|
+
describe("sanitizeString", () => {
|
|
4
|
+
test("should return unchanged string for printable ASCII characters", () => {
|
|
5
|
+
expect(sanitizeString("Hello World")).toBe("Hello World");
|
|
6
|
+
expect(sanitizeString("ABC123")).toBe("ABC123");
|
|
7
|
+
expect(sanitizeString("!@#$%^&*()")).toBe("!@#$%^&*()");
|
|
8
|
+
});
|
|
9
|
+
test("should preserve newlines", () => {
|
|
10
|
+
expect(sanitizeString("line1\nline2")).toBe("line1\nline2");
|
|
11
|
+
expect(sanitizeString("first\nsecond\nthird")).toBe("first\nsecond\nthird");
|
|
12
|
+
});
|
|
13
|
+
test("should preserve carriage returns", () => {
|
|
14
|
+
expect(sanitizeString("line1\rline2")).toBe("line1\rline2");
|
|
15
|
+
});
|
|
16
|
+
test("should preserve tabs", () => {
|
|
17
|
+
expect(sanitizeString("column1\tcolumn2")).toBe("column1\tcolumn2");
|
|
18
|
+
expect(sanitizeString("\tindented")).toBe("\tindented");
|
|
19
|
+
});
|
|
20
|
+
test("should remove non-printable characters", () => {
|
|
21
|
+
expect(sanitizeString("test\x00string")).toBe("teststring");
|
|
22
|
+
expect(sanitizeString("hello\x01world")).toBe("helloworld");
|
|
23
|
+
expect(sanitizeString("test\x1Bstring")).toBe("teststring");
|
|
24
|
+
});
|
|
25
|
+
test("should remove ANSI escape codes", () => {
|
|
26
|
+
expect(sanitizeString("\x1b[31mRed Text\x1b[0m")).toBe("[31mRed Text[0m");
|
|
27
|
+
expect(sanitizeString("\x1b[1;32mGreen\x1b[0m")).toBe("[1;32mGreen[0m");
|
|
28
|
+
});
|
|
29
|
+
test("should handle empty strings", () => {
|
|
30
|
+
expect(sanitizeString("")).toBe("");
|
|
31
|
+
});
|
|
32
|
+
test("should handle strings with only non-printable characters", () => {
|
|
33
|
+
expect(sanitizeString("\x00\x01\x02")).toBe("");
|
|
34
|
+
});
|
|
35
|
+
test("should handle mixed printable and non-printable characters", () => {
|
|
36
|
+
expect(sanitizeString("Hello\x00World\x01!")).toBe("HelloWorld!");
|
|
37
|
+
});
|
|
38
|
+
test("should preserve spaces", () => {
|
|
39
|
+
expect(sanitizeString(" spaces ")).toBe(" spaces ");
|
|
40
|
+
});
|
|
41
|
+
test("should handle unicode characters outside printable ASCII", () => {
|
|
42
|
+
expect(sanitizeString("Hello 世界")).toBe("Hello ");
|
|
43
|
+
expect(sanitizeString("Emoji 😀 test")).toBe("Emoji test");
|
|
44
|
+
});
|
|
45
|
+
test("should handle strings with newlines, tabs, and carriage returns mixed", () => {
|
|
46
|
+
expect(sanitizeString("line1\nline2\tcolumn\rend")).toBe("line1\nline2\tcolumn\rend");
|
|
47
|
+
});
|
|
48
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ag-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Shared library for agbd and agrb",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -20,9 +20,10 @@
|
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "tsc",
|
|
22
22
|
"dev": "tsc --watch",
|
|
23
|
-
"test": "
|
|
23
|
+
"test": "bun test",
|
|
24
|
+
"test:watch": "bun test --watch",
|
|
24
25
|
"lint": "biome check . --write",
|
|
25
|
-
"ci": "biome ci .",
|
|
26
|
+
"ci": "biome ci . && bun test",
|
|
26
27
|
"prepublishOnly": "npm run build"
|
|
27
28
|
},
|
|
28
29
|
"files": [
|
|
@@ -35,18 +36,18 @@
|
|
|
35
36
|
"ink": "6.3.1",
|
|
36
37
|
"ink-select-input": "6.2.0",
|
|
37
38
|
"ink-spinner": "5.0.0",
|
|
38
|
-
"react": "19.
|
|
39
|
+
"react": "19.2.0",
|
|
39
40
|
"simple-git": "3.28.0",
|
|
40
41
|
"valibot": "1.1.0"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
|
-
"@biomejs/biome": "2.2.
|
|
44
|
+
"@biomejs/biome": "2.2.5",
|
|
44
45
|
"@sindresorhus/tsconfig": "8.0.1",
|
|
45
|
-
"@types/bun": "1.2.
|
|
46
|
-
"@types/react": "19.
|
|
46
|
+
"@types/bun": "1.2.23",
|
|
47
|
+
"@types/react": "19.2.0",
|
|
47
48
|
"chalk": "5.6.2",
|
|
48
49
|
"ink-testing-library": "4.0.0",
|
|
49
50
|
"ts-node": "10.9.2",
|
|
50
|
-
"typescript": "5.9.
|
|
51
|
+
"typescript": "5.9.3"
|
|
51
52
|
}
|
|
52
53
|
}
|