new-branch 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +0 -0
- package/dist/pattern/transforms/camel.js +25 -0
- package/dist/pattern/transforms/camel.test.js +13 -0
- package/dist/pattern/transforms/helpers/words.js +64 -0
- package/dist/pattern/transforms/helpers/words.test.js +35 -0
- package/dist/pattern/transforms/kebab.js +19 -0
- package/dist/pattern/transforms/kebab.test.js +13 -0
- package/dist/pattern/transforms/snake.js +19 -0
- package/dist/pattern/transforms/snake.test.js +13 -0
- package/dist/pattern/transforms/title.js +19 -0
- package/dist/pattern/transforms/title.test.js +13 -0
- package/dist/pattern/transforms/words.js +27 -0
- package/dist/pattern/transforms/words.test.js +16 -0
- package/dist/runtime/resolveMissingValues.js +27 -4
- package/dist/runtime/resolveMissingValues.test.js +64 -0
- package/package.json +4 -2
package/dist/cli.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { splitWords, upperFirst } from "./helpers/words.js";
|
|
2
|
+
/**
|
|
3
|
+
* Transform: camel
|
|
4
|
+
*
|
|
5
|
+
* Converts an input string into camelCase. Uses `splitWords` to extract word
|
|
6
|
+
* boundaries and lower-cases the words before joining. The first word is kept
|
|
7
|
+
* in lower-case; subsequent words are capitalized using `upperFirst`.
|
|
8
|
+
*
|
|
9
|
+
* Examples:
|
|
10
|
+
* - "My Task" -> "myTask"
|
|
11
|
+
* - "HTTP Server" -> "httpServer"
|
|
12
|
+
*/
|
|
13
|
+
export const camel = {
|
|
14
|
+
name: "camel",
|
|
15
|
+
fn: (value) => {
|
|
16
|
+
const words = splitWords(value).map((w) => w.toLowerCase());
|
|
17
|
+
if (!words.length)
|
|
18
|
+
return "";
|
|
19
|
+
return words[0] + words.slice(1).map(upperFirst).join("");
|
|
20
|
+
},
|
|
21
|
+
doc: {
|
|
22
|
+
summary: "Converts value to camelCase.",
|
|
23
|
+
usage: ["{title:camel}"],
|
|
24
|
+
},
|
|
25
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { camel } from "./camel.js";
|
|
3
|
+
describe("camel transform", () => {
|
|
4
|
+
it("converts spaced text to camelCase", () => {
|
|
5
|
+
expect(camel.fn("My Task", [])).toBe("myTask");
|
|
6
|
+
});
|
|
7
|
+
it("handles punctuation and multiple separators", () => {
|
|
8
|
+
expect(camel.fn("hello-world_test", [])).toBe("helloWorldTest");
|
|
9
|
+
});
|
|
10
|
+
it("returns empty string for empty input", () => {
|
|
11
|
+
expect(camel.fn("", [])).toBe("");
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splits an input string into word-like segments.
|
|
3
|
+
*
|
|
4
|
+
* The function attempts to be Unicode-aware and supports the following
|
|
5
|
+
* heuristics for identifying boundaries:
|
|
6
|
+
* - Splits on any run of non-letter/number characters (spaces, punctuation).
|
|
7
|
+
* - Inserts boundaries for camelCase (e.g. `myTask` -> `my Task`).
|
|
8
|
+
* - Inserts a boundary between an ALL-CAPS acronym and a following
|
|
9
|
+
* capitalized word (e.g. `HTTPServer` -> `HTTP Server`).
|
|
10
|
+
*
|
|
11
|
+
* Returned words are trimmed and empty segments are discarded.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* splitWords("myTask") // => ["my", "Task"]
|
|
15
|
+
* splitWords("HTTPServer") // => ["HTTP", "Server"]
|
|
16
|
+
* splitWords("Título grande") // => ["Título", "grande"]
|
|
17
|
+
*
|
|
18
|
+
* @param input - The string to split into words.
|
|
19
|
+
* @returns An array of word segments (possibly empty).
|
|
20
|
+
*/
|
|
21
|
+
export function splitWords(input) {
|
|
22
|
+
const cleaned = input.trim();
|
|
23
|
+
if (!cleaned)
|
|
24
|
+
return [];
|
|
25
|
+
const withBoundaries = cleaned
|
|
26
|
+
// camelCase boundary: myTask -> my Task
|
|
27
|
+
.replace(/(\p{Ll}|\p{N})(\p{Lu})/gu, "$1 $2")
|
|
28
|
+
// ALLCAPS followed by lowercase: HTTPServer -> HTTP Server
|
|
29
|
+
.replace(/(\p{Lu})(\p{Lu}\p{Ll})/gu, "$1 $2");
|
|
30
|
+
return withBoundaries
|
|
31
|
+
.split(/[^\p{L}\p{N}]+/u)
|
|
32
|
+
.map((w) => w.trim())
|
|
33
|
+
.filter(Boolean);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Upper-cases the first character of the provided string.
|
|
37
|
+
*
|
|
38
|
+
* Does not modify the remainder of the string.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* upperFirst("hello") // => "Hello"
|
|
42
|
+
* upperFirst("") // => ""
|
|
43
|
+
*
|
|
44
|
+
* @param s - Input string.
|
|
45
|
+
* @returns String with the first character upper-cased (if present).
|
|
46
|
+
*/
|
|
47
|
+
export function upperFirst(s) {
|
|
48
|
+
return s.length ? s[0].toUpperCase() + s.slice(1) : s;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Lower-cases the first character of the provided string.
|
|
52
|
+
*
|
|
53
|
+
* Does not modify the remainder of the string.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* lowerFirst("Hello") // => "hello"
|
|
57
|
+
* lowerFirst("") // => ""
|
|
58
|
+
*
|
|
59
|
+
* @param s - Input string.
|
|
60
|
+
* @returns String with the first character lower-cased (if present).
|
|
61
|
+
*/
|
|
62
|
+
export function lowerFirst(s) {
|
|
63
|
+
return s.length ? s[0].toLowerCase() + s.slice(1) : s;
|
|
64
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { splitWords, upperFirst, lowerFirst } from "./words.js";
|
|
3
|
+
describe("splitWords", () => {
|
|
4
|
+
it("returns empty array for empty or whitespace-only input", () => {
|
|
5
|
+
expect(splitWords("")).toEqual([]);
|
|
6
|
+
expect(splitWords(" ")).toEqual([]);
|
|
7
|
+
});
|
|
8
|
+
it("splits on separators and trims words", () => {
|
|
9
|
+
expect(splitWords("hello world-test")).toEqual(["hello", "world", "test"]);
|
|
10
|
+
expect(splitWords(" leading and trailing ")).toEqual(["leading", "and", "trailing"]);
|
|
11
|
+
});
|
|
12
|
+
it("handles camelCase boundaries", () => {
|
|
13
|
+
expect(splitWords("myTask")).toEqual(["my", "Task"]);
|
|
14
|
+
expect(splitWords("version2Beta")).toEqual(["version2", "Beta"]);
|
|
15
|
+
});
|
|
16
|
+
it("handles ALLCAPS followed by capitalized word", () => {
|
|
17
|
+
expect(splitWords("HTTPServer")).toEqual(["HTTP", "Server"]);
|
|
18
|
+
expect(splitWords("XMLHttpRequest")).toEqual(["XML", "Http", "Request"]);
|
|
19
|
+
});
|
|
20
|
+
it("keeps Unicode letters and accents", () => {
|
|
21
|
+
expect(splitWords("Título grande")).toEqual(["Título", "grande"]);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe("upperFirst / lowerFirst", () => {
|
|
25
|
+
it("upperFirst capitalizes only the first character", () => {
|
|
26
|
+
expect(upperFirst("hello")).toBe("Hello");
|
|
27
|
+
expect(upperFirst("")).toBe("");
|
|
28
|
+
expect(upperFirst("éclair")).toBe("Éclair");
|
|
29
|
+
});
|
|
30
|
+
it("lowerFirst lowercases only the first character", () => {
|
|
31
|
+
expect(lowerFirst("Hello")).toBe("hello");
|
|
32
|
+
expect(lowerFirst("")).toBe("");
|
|
33
|
+
expect(lowerFirst("Éclair")).toBe("éclair");
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { splitWords } from "./helpers/words.js";
|
|
2
|
+
/**
|
|
3
|
+
* Transform: kebab
|
|
4
|
+
*
|
|
5
|
+
* Converts an input string into kebab-case (lowercased words joined with
|
|
6
|
+
* hyphens). Uses `splitWords` to determine word boundaries.
|
|
7
|
+
*
|
|
8
|
+
* Example: "My Task" -> "my-task"
|
|
9
|
+
*/
|
|
10
|
+
export const kebab = {
|
|
11
|
+
name: "kebab",
|
|
12
|
+
fn: (value) => splitWords(value)
|
|
13
|
+
.map((w) => w.toLowerCase())
|
|
14
|
+
.join("-"),
|
|
15
|
+
doc: {
|
|
16
|
+
summary: "Converts value to kebab-case.",
|
|
17
|
+
usage: ["{title:kebab}"],
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { kebab } from "./kebab.js";
|
|
3
|
+
describe("kebab transform", () => {
|
|
4
|
+
it("converts spaced text to kebab-case", () => {
|
|
5
|
+
expect(kebab.fn("My Task", [])).toBe("my-task");
|
|
6
|
+
});
|
|
7
|
+
it("handles camelCase and punctuation", () => {
|
|
8
|
+
expect(kebab.fn("myTaskHTTP Server", [])).toBe("my-task-http-server");
|
|
9
|
+
});
|
|
10
|
+
it("returns empty string for empty input", () => {
|
|
11
|
+
expect(kebab.fn("", [])).toBe("");
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { splitWords } from "./helpers/words.js";
|
|
2
|
+
/**
|
|
3
|
+
* Transform: snake
|
|
4
|
+
*
|
|
5
|
+
* Converts an input string into snake_case (lowercased words joined with
|
|
6
|
+
* underscores). Uses `splitWords` to determine boundaries.
|
|
7
|
+
*
|
|
8
|
+
* Example: "My Task" -> "my_task"
|
|
9
|
+
*/
|
|
10
|
+
export const snake = {
|
|
11
|
+
name: "snake",
|
|
12
|
+
fn: (value) => splitWords(value)
|
|
13
|
+
.map((w) => w.toLowerCase())
|
|
14
|
+
.join("_"),
|
|
15
|
+
doc: {
|
|
16
|
+
summary: "Converts value to snake_case.",
|
|
17
|
+
usage: ["{title:snake}"],
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { snake } from "./snake.js";
|
|
3
|
+
describe("snake transform", () => {
|
|
4
|
+
it("converts spaced text to snake_case", () => {
|
|
5
|
+
expect(snake.fn("My Task", [])).toBe("my_task");
|
|
6
|
+
});
|
|
7
|
+
it("handles camelCase and punctuation", () => {
|
|
8
|
+
expect(snake.fn("myTaskHTTP Server", [])).toBe("my_task_http_server");
|
|
9
|
+
});
|
|
10
|
+
it("returns empty string for empty input", () => {
|
|
11
|
+
expect(snake.fn("", [])).toBe("");
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { splitWords, upperFirst } from "./helpers/words.js";
|
|
2
|
+
/**
|
|
3
|
+
* Transform: title
|
|
4
|
+
*
|
|
5
|
+
* Converts an input string into Title Case where each word's first
|
|
6
|
+
* character is upper-cased and the remainder lower-cased. Uses `splitWords`.
|
|
7
|
+
*
|
|
8
|
+
* Example: "hello WORLD" -> "Hello World"
|
|
9
|
+
*/
|
|
10
|
+
export const title = {
|
|
11
|
+
name: "title",
|
|
12
|
+
fn: (value) => splitWords(value)
|
|
13
|
+
.map((w) => upperFirst(w.toLowerCase()))
|
|
14
|
+
.join(" "),
|
|
15
|
+
doc: {
|
|
16
|
+
summary: "Converts value to Title Case.",
|
|
17
|
+
usage: ["{title:title}"],
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { title } from "./title.js";
|
|
3
|
+
describe("title transform", () => {
|
|
4
|
+
it("converts text to Title Case", () => {
|
|
5
|
+
expect(title.fn("hello WORLD", [])).toBe("Hello World");
|
|
6
|
+
});
|
|
7
|
+
it("handles punctuation and multiple separators", () => {
|
|
8
|
+
expect(title.fn("my-task_HTTP server", [])).toBe("My Task Http Server");
|
|
9
|
+
});
|
|
10
|
+
it("returns empty string for empty input", () => {
|
|
11
|
+
expect(title.fn("", [])).toBe("");
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { splitWords } from "./helpers/words.js";
|
|
2
|
+
/**
|
|
3
|
+
* Transform: words
|
|
4
|
+
*
|
|
5
|
+
* Limits the input to at most `n` words. The transform expects a single
|
|
6
|
+
* numeric argument that indicates the maximum number of words to keep. The
|
|
7
|
+
* returned value is the first `n` words joined by a single space.
|
|
8
|
+
*
|
|
9
|
+
* Examples:
|
|
10
|
+
* - `{title:words:2}` applied to "My big title" -> "My big"
|
|
11
|
+
*
|
|
12
|
+
* @throws If the provided argument is missing or not a non-negative number.
|
|
13
|
+
*/
|
|
14
|
+
export const words = {
|
|
15
|
+
name: "words",
|
|
16
|
+
fn: (value, [n]) => {
|
|
17
|
+
const count = Number(n);
|
|
18
|
+
if (!Number.isFinite(count) || count < 0) {
|
|
19
|
+
throw new Error(`words expects a non-negative number, got "${n ?? ""}"`);
|
|
20
|
+
}
|
|
21
|
+
return splitWords(value).slice(0, count).join(" ");
|
|
22
|
+
},
|
|
23
|
+
doc: {
|
|
24
|
+
summary: "Limits value to a maximum number of words.",
|
|
25
|
+
usage: ["{title:words:3}"],
|
|
26
|
+
},
|
|
27
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { words } from "./words.js";
|
|
3
|
+
describe("words transform", () => {
|
|
4
|
+
it("limits the number of words when a positive number is provided", () => {
|
|
5
|
+
expect(words.fn("one two three four", ["2"]).trim()).toBe("one two");
|
|
6
|
+
expect(words.fn("hello world", ["5"]).trim()).toBe("hello world");
|
|
7
|
+
});
|
|
8
|
+
it("returns empty string when 0 is provided", () => {
|
|
9
|
+
expect(words.fn("some text here", ["0"]).trim()).toBe("");
|
|
10
|
+
});
|
|
11
|
+
it("throws when argument is missing or invalid", () => {
|
|
12
|
+
expect(() => words.fn("a b c", [])).toThrow();
|
|
13
|
+
expect(() => words.fn("a b c", ["-1"])).toThrow();
|
|
14
|
+
expect(() => words.fn("a b c", ["not-a-number"])).toThrow();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
import { input, select } from "@inquirer/prompts";
|
|
2
2
|
import { TYPE_CHOICES } from "../runtime/enums.js";
|
|
3
3
|
/**
|
|
4
|
-
* Resolves missing variable values required by
|
|
4
|
+
* Resolves missing variable values required by a parsed pattern.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The function inspects `parsed.variablesUsed` and ensures each required
|
|
7
|
+
* variable has a non-empty value in the returned object. If a variable is
|
|
8
|
+
* missing or contains only whitespace and `opts.prompt` is `true`, the
|
|
9
|
+
* function will prompt the user for the value. The special variable name
|
|
10
|
+
* `type` is resolved with a select prompt pre-populated with
|
|
11
|
+
* {@link TYPE_CHOICES}.
|
|
12
|
+
*
|
|
13
|
+
* Behavior summary:
|
|
14
|
+
* - Any variable present in `parsed.variablesUsed` is considered required.
|
|
15
|
+
* - If a value exists and is non-empty (after trimming) it is preserved.
|
|
16
|
+
* - If a value is missing or blank and `opts.prompt` is `false`, an error is
|
|
17
|
+
* thrown listing the missing variable.
|
|
18
|
+
* - If `opts.prompt` is `true`, the function will:
|
|
19
|
+
* - use a select prompt for the variable named `type` (choices from
|
|
20
|
+
* {@link TYPE_CHOICES});
|
|
21
|
+
* - use a text input prompt for any other variable.
|
|
22
|
+
*
|
|
23
|
+
* @param parsed - Parsed pattern containing `variablesUsed`.
|
|
24
|
+
* @param initialValues - Existing values that may satisfy requirements.
|
|
25
|
+
* @param opts - Options controlling prompting behavior.
|
|
26
|
+
* @returns A promise resolving to a `RenderValues` object containing all
|
|
27
|
+
* required variables (original values preserved when present).
|
|
28
|
+
* @throws When a required variable is missing and `opts.prompt` is false.
|
|
29
|
+
* @example
|
|
30
|
+
* const parsed = parsePattern('{type}/{title}');
|
|
31
|
+
* await resolveMissingValues(parsed, { title: 'Hello' }, { prompt: true });
|
|
9
32
|
*/
|
|
10
33
|
export async function resolveMissingValues(parsed, initialValues, opts) {
|
|
11
34
|
const requiredVars = parsed.variablesUsed;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { resolveMissingValues } from "./resolveMissingValues.js";
|
|
3
|
+
import { parsePattern } from "../pattern/parsePattern.js";
|
|
4
|
+
// Mock prompts module so tests can control interactive behavior
|
|
5
|
+
vi.mock("@inquirer/prompts", () => {
|
|
6
|
+
return {
|
|
7
|
+
input: vi.fn(),
|
|
8
|
+
select: vi.fn(),
|
|
9
|
+
};
|
|
10
|
+
});
|
|
11
|
+
// Provide a lightweight mock for the runtime enums so module resolution
|
|
12
|
+
// does not fail in the test environment (we only need the shape used
|
|
13
|
+
// by the code under test).
|
|
14
|
+
vi.mock("@/runtime/enums.js", () => ({
|
|
15
|
+
TYPE_CHOICES: [
|
|
16
|
+
{ name: "Feature", value: "feat" },
|
|
17
|
+
{ name: "Fix", value: "fix" },
|
|
18
|
+
],
|
|
19
|
+
}));
|
|
20
|
+
import { input, select } from "@inquirer/prompts";
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
// resetAllMocks clears implementations and mock queues (e.g. mockResolvedValueOnce)
|
|
23
|
+
// which prevents cross-test leakage of one-off mock return values.
|
|
24
|
+
vi.resetAllMocks();
|
|
25
|
+
});
|
|
26
|
+
describe("resolveMissingValues", () => {
|
|
27
|
+
it("returns values unchanged when all required vars are present", async () => {
|
|
28
|
+
const parsed = parsePattern("{type}/{title}-{id}");
|
|
29
|
+
const initial = { type: "feat", title: "My Task", id: "123" };
|
|
30
|
+
const out = await resolveMissingValues(parsed, initial, { prompt: true });
|
|
31
|
+
expect(out).toEqual(initial);
|
|
32
|
+
expect(input).not.toHaveBeenCalled();
|
|
33
|
+
expect(select).not.toHaveBeenCalled();
|
|
34
|
+
});
|
|
35
|
+
it("prompts for a missing non-type variable using input", async () => {
|
|
36
|
+
const parsed = parsePattern("{type}/{title}");
|
|
37
|
+
// input should be used for `title`
|
|
38
|
+
input.mockResolvedValueOnce("Provided Title");
|
|
39
|
+
// Type is present so select should not be called
|
|
40
|
+
const out = await resolveMissingValues(parsed, { type: "fix" }, { prompt: true });
|
|
41
|
+
expect(input).toHaveBeenCalled();
|
|
42
|
+
expect(select).not.toHaveBeenCalled();
|
|
43
|
+
expect(out.title).toBe("Provided Title");
|
|
44
|
+
});
|
|
45
|
+
it("uses select for the `type` variable", async () => {
|
|
46
|
+
const parsed = parsePattern("{type}/{title}");
|
|
47
|
+
select.mockResolvedValueOnce("feat");
|
|
48
|
+
input.mockResolvedValueOnce("Some title");
|
|
49
|
+
const out = await resolveMissingValues(parsed, { title: "Some title" }, { prompt: true });
|
|
50
|
+
expect(select).toHaveBeenCalled();
|
|
51
|
+
expect(out.type).toBe("feat");
|
|
52
|
+
});
|
|
53
|
+
it("throws when prompt is false and a required variable is missing", async () => {
|
|
54
|
+
const parsed = parsePattern("{id}");
|
|
55
|
+
await expect(resolveMissingValues(parsed, {}, { prompt: false })).rejects.toThrow(/Missing required value/i);
|
|
56
|
+
});
|
|
57
|
+
it("treats whitespace-only values as missing and prompts", async () => {
|
|
58
|
+
const parsed = parsePattern("{title}");
|
|
59
|
+
input.mockResolvedValueOnce("Trimmed");
|
|
60
|
+
const out = await resolveMissingValues(parsed, { title: " " }, { prompt: true });
|
|
61
|
+
expect(input).toHaveBeenCalled();
|
|
62
|
+
expect(out.title).toBe("Trimmed");
|
|
63
|
+
});
|
|
64
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "new-branch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Generate and create standardized git branch names from a pattern.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"git",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"prepack": "pnpm build && pnpm test:run",
|
|
21
21
|
"test": "vitest --dir src --exclude **/dist/**",
|
|
22
22
|
"test:run": "vitest run --dir src --exclude **/dist/**",
|
|
23
|
+
"test:coverage": "vitest run --coverage --dir src --exclude **/dist/**",
|
|
23
24
|
"format": "prettier . --write",
|
|
24
25
|
"format:check": "prettier . --check",
|
|
25
26
|
"lint": "eslint src --ext .ts"
|
|
@@ -41,13 +42,14 @@
|
|
|
41
42
|
"url": "https://github.com/teles/new-branch/issues"
|
|
42
43
|
},
|
|
43
44
|
"new-branch": {
|
|
44
|
-
"pattern": "{type}/{title}-{id}"
|
|
45
|
+
"pattern": "{type}/{title:lower}-{id}"
|
|
45
46
|
},
|
|
46
47
|
"homepage": "https://github.com/teles/new-branch#readme",
|
|
47
48
|
"packageManager": "pnpm@10.22.0",
|
|
48
49
|
"devDependencies": {
|
|
49
50
|
"@eslint/js": "10.0.1",
|
|
50
51
|
"@types/node": "25.2.3",
|
|
52
|
+
"@vitest/coverage-v8": "4.0.18",
|
|
51
53
|
"eslint": "10.0.0",
|
|
52
54
|
"prettier": "3.8.1",
|
|
53
55
|
"tsc-alias": "1.8.16",
|