versionary 0.20.1 → 0.21.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.
@@ -8,6 +8,7 @@ const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const toml_1 = __importDefault(require("@iarna/toml"));
10
10
  const yaml_1 = __importDefault(require("yaml"));
11
+ const WILDCARD = Symbol("wildcard");
11
12
  function isRecord(value) {
12
13
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
13
14
  }
@@ -20,6 +21,11 @@ function parseFieldPath(fieldPath) {
20
21
  while (index < fieldPath.length) {
21
22
  const current = fieldPath[index];
22
23
  if (current === ".") {
24
+ if (fieldPath[index + 1] === "*") {
25
+ tokens.push(WILDCARD);
26
+ index += 2;
27
+ continue;
28
+ }
23
29
  const keyMatch = fieldPath.slice(index + 1).match(/^[A-Za-z0-9_-]+/u);
24
30
  if (!keyMatch) {
25
31
  throw new Error(`Invalid field-path "${fieldPath}" near index ${index}.`);
@@ -30,6 +36,11 @@ function parseFieldPath(fieldPath) {
30
36
  }
31
37
  if (current === "[") {
32
38
  const rest = fieldPath.slice(index + 1);
39
+ if (rest.startsWith("*]")) {
40
+ tokens.push(WILDCARD);
41
+ index += 3;
42
+ continue;
43
+ }
33
44
  const numberMatch = rest.match(/^(\d+)\]/u);
34
45
  if (numberMatch) {
35
46
  tokens.push(Number(numberMatch[1]));
@@ -55,49 +66,86 @@ function parseFieldPath(fieldPath) {
55
66
  }
56
67
  return tokens;
57
68
  }
58
- function setVersionAtJsonPath(document, fieldPath, version) {
59
- const tokens = parseFieldPath(fieldPath);
60
- let cursor = document;
61
- for (let index = 0; index < tokens.length - 1; index += 1) {
62
- const token = tokens[index];
63
- if (token === undefined) {
69
+ function assignLeaf(container, key, fieldPath, version) {
70
+ if (typeof key === "number") {
71
+ if (!Array.isArray(container) || key >= container.length) {
64
72
  throw new Error(`field-path "${fieldPath}" does not resolve to an existing field.`);
65
73
  }
66
- if (typeof token === "number") {
67
- if (!Array.isArray(cursor) || token >= cursor.length) {
68
- throw new Error(`field-path "${fieldPath}" does not resolve to an existing field.`);
69
- }
70
- cursor = cursor[token];
71
- continue;
72
- }
73
- if (!isRecord(cursor) || !(token in cursor)) {
74
- throw new Error(`field-path "${fieldPath}" does not resolve to an existing field.`);
75
- }
76
- cursor = cursor[token];
77
- }
78
- const leaf = tokens.at(-1);
79
- if (leaf === undefined) {
80
- throw new Error(`field-path "${fieldPath}" does not resolve to an existing field.`);
81
- }
82
- if (typeof leaf === "number") {
83
- if (!Array.isArray(cursor) || leaf >= cursor.length) {
84
- throw new Error(`field-path "${fieldPath}" does not resolve to an existing field.`);
85
- }
86
- const current = cursor[leaf];
74
+ const current = container[key];
87
75
  if (typeof current !== "string" && typeof current !== "number") {
88
76
  throw new Error(`field-path "${fieldPath}" must point to a string or number field for version updates.`);
89
77
  }
90
- cursor[leaf] = version;
78
+ container[key] = version;
91
79
  return;
92
80
  }
93
- if (!isRecord(cursor) || !(leaf in cursor)) {
81
+ if (!isRecord(container) || !(key in container)) {
94
82
  throw new Error(`field-path "${fieldPath}" does not resolve to an existing field.`);
95
83
  }
96
- const current = cursor[leaf];
84
+ const current = container[key];
97
85
  if (typeof current !== "string" && typeof current !== "number") {
98
86
  throw new Error(`field-path "${fieldPath}" must point to a string or number field for version updates.`);
99
87
  }
100
- cursor[leaf] = version;
88
+ container[key] = version;
89
+ }
90
+ function applyTokens(cursor, tokens, position, fieldPath, version) {
91
+ const token = tokens[position];
92
+ const isLeaf = position === tokens.length - 1;
93
+ if (token === WILDCARD) {
94
+ let matched = false;
95
+ if (isRecord(cursor)) {
96
+ for (const key of Object.keys(cursor)) {
97
+ if (isLeaf) {
98
+ assignLeaf(cursor, key, fieldPath, version);
99
+ matched = true;
100
+ }
101
+ else if (applyTokens(cursor[key], tokens, position + 1, fieldPath, version)) {
102
+ matched = true;
103
+ }
104
+ }
105
+ return matched;
106
+ }
107
+ if (Array.isArray(cursor)) {
108
+ for (let i = 0; i < cursor.length; i += 1) {
109
+ if (isLeaf) {
110
+ assignLeaf(cursor, i, fieldPath, version);
111
+ matched = true;
112
+ }
113
+ else if (applyTokens(cursor[i], tokens, position + 1, fieldPath, version)) {
114
+ matched = true;
115
+ }
116
+ }
117
+ return matched;
118
+ }
119
+ throw new Error(`field-path "${fieldPath}" wildcard segment does not target an object or array.`);
120
+ }
121
+ if (typeof token === "number") {
122
+ if (!Array.isArray(cursor) || token >= cursor.length) {
123
+ throw new Error(`field-path "${fieldPath}" does not resolve to an existing field.`);
124
+ }
125
+ if (isLeaf) {
126
+ assignLeaf(cursor, token, fieldPath, version);
127
+ return true;
128
+ }
129
+ return applyTokens(cursor[token], tokens, position + 1, fieldPath, version);
130
+ }
131
+ if (typeof token === "string") {
132
+ if (!isRecord(cursor) || !(token in cursor)) {
133
+ throw new Error(`field-path "${fieldPath}" does not resolve to an existing field.`);
134
+ }
135
+ if (isLeaf) {
136
+ assignLeaf(cursor, token, fieldPath, version);
137
+ return true;
138
+ }
139
+ return applyTokens(cursor[token], tokens, position + 1, fieldPath, version);
140
+ }
141
+ throw new Error(`field-path "${fieldPath}" does not resolve to an existing field.`);
142
+ }
143
+ function setVersionAtJsonPath(document, fieldPath, version) {
144
+ const tokens = parseFieldPath(fieldPath);
145
+ const matched = applyTokens(document, tokens, 0, fieldPath, version);
146
+ if (!matched) {
147
+ throw new Error(`field-path "${fieldPath}" did not match any fields.`);
148
+ }
101
149
  }
102
150
  function resolveFieldPath(rule) {
103
151
  const fieldPath = rule["field-path"] ?? rule.jsonpath;
@@ -232,6 +280,9 @@ function findMatchingBrace(content, openBraceIndex, endExclusive) {
232
280
  }
233
281
  function resolveNixPathTokens(fieldPath) {
234
282
  const tokens = parseFieldPath(fieldPath);
283
+ if (tokens.some((token) => token === WILDCARD)) {
284
+ throw new Error(`Nix artifact rules do not support wildcard segments in field-path "${fieldPath}".`);
285
+ }
235
286
  if (tokens.some((token) => typeof token === "number")) {
236
287
  throw new Error(`Nix artifact rules do not support array index segments in field-path "${fieldPath}".`);
237
288
  }
@@ -76,6 +76,7 @@ function groupCommitLines(commits, repoUrl) {
76
76
  const breaking = [];
77
77
  const features = [];
78
78
  const fixes = [];
79
+ const performance = [];
79
80
  const reverts = [];
80
81
  const effectiveCommits = (0, commits_js_1.applyRevertSuppression)(commits);
81
82
  const getRevertedSubject = (commit) => {
@@ -129,13 +130,15 @@ function groupCommitLines(commits, repoUrl) {
129
130
  features.push(line);
130
131
  continue;
131
132
  }
132
- if (commitType === "fix" ||
133
- commitType === "perf" ||
134
- (!isBreaking && type === "patch")) {
133
+ if (commitType === "perf") {
134
+ performance.push(line);
135
+ continue;
136
+ }
137
+ if (commitType === "fix" || (!isBreaking && type === "patch")) {
135
138
  fixes.push(line);
136
139
  }
137
140
  }
138
- return { breaking, features, fixes, reverts };
141
+ return { breaking, features, fixes, performance, reverts };
139
142
  }
140
143
  function renderSimpleReleaseNotes(input, options = {}) {
141
144
  const repoUrl = (0, repo_url_js_1.resolveRepositoryWebBaseUrl)(input.cwd ?? process.cwd());
@@ -154,6 +157,9 @@ function renderSimpleReleaseNotes(input, options = {}) {
154
157
  if (grouped.fixes.length > 0) {
155
158
  sections.push("### Bug Fixes", ...grouped.fixes, "");
156
159
  }
160
+ if (grouped.performance.length > 0) {
161
+ sections.push("### Performance Improvements", ...grouped.performance, "");
162
+ }
157
163
  if (grouped.reverts.length > 0) {
158
164
  sections.push("### Reverts", ...grouped.reverts, "");
159
165
  }
@@ -239,6 +245,9 @@ function renderPackageChangelogSection(input) {
239
245
  if (grouped.fixes.length > 0) {
240
246
  sections.push("### Bug Fixes", ...grouped.fixes, "");
241
247
  }
248
+ if (grouped.performance.length > 0) {
249
+ sections.push("### Performance Improvements", ...grouped.performance, "");
250
+ }
242
251
  if (grouped.reverts.length > 0) {
243
252
  sections.push("### Reverts", ...grouped.reverts, "");
244
253
  }
@@ -276,6 +285,9 @@ function renderRNewsReleaseNotes(input) {
276
285
  if (grouped.fixes.length > 0) {
277
286
  sections.push("## Bug fixes", "", ...grouped.fixes, "");
278
287
  }
288
+ if (grouped.performance.length > 0) {
289
+ sections.push("## Performance improvements", "", ...grouped.performance, "");
290
+ }
279
291
  if (grouped.reverts.length > 0) {
280
292
  sections.push("## Reverts", "", ...grouped.reverts, "");
281
293
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "versionary",
3
- "version": "0.20.1",
3
+ "version": "0.21.0",
4
4
  "description": "Automatic release framework based on conventional commits and semantic versioning",
5
5
  "keywords": [
6
6
  "releasing",