@j-ulrich/release-it-regex-bumper 5.4.0 → 5.5.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 (3) hide show
  1. package/README.md +35 -8
  2. package/index.js +44 -23
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -73,7 +73,7 @@ example, the pattern `\d+` needs to be written as `"\\d+"` inside JSON.
73
73
 
74
74
  ### `in` ###
75
75
 
76
- **Type:** `string|object`
76
+ **Type:** `string | object`
77
77
  **Default:** `null`
78
78
 
79
79
  The `in` option defines where and how to read the current version. If this option is defined and not
@@ -102,7 +102,7 @@ If this option is `null` or not defined, the [global `encoding`](#encoding) opti
102
102
 
103
103
  ### `in.search` ###
104
104
 
105
- **Type:** `string|object`
105
+ **Type:** `string | object`
106
106
  **Default:** `null`
107
107
 
108
108
  Defines the regular expression to find the version inside the `in.file`.
@@ -147,7 +147,7 @@ If this option is `null` or not defined, the [global `search.flags`](#searchflag
147
147
 
148
148
  ### `in.search.versionCaptureGroup` ###
149
149
 
150
- **Type:** `integer|string`
150
+ **Type:** `integer | string`
151
151
  **Default:** `null`
152
152
 
153
153
  Defines the capture group from the `in.search.pattern` which matches the version. If the
@@ -165,7 +165,7 @@ capturing group with index 1 is used if it exists. Else the whole match is used.
165
165
 
166
166
  ### `out` ###
167
167
 
168
- **Type:** `string|object|array<string|object>`
168
+ **Type:** `string | object | array<string | object>`
169
169
  **Default:** `null`
170
170
 
171
171
  The `out` option defines where and how to write the new version. If defined and not `null`, the
@@ -208,7 +208,7 @@ If both, this option and `out.files` are given, both are processed.
208
208
 
209
209
  ### `out.files` ###
210
210
 
211
- **Type:** `string|array<string>`
211
+ **Type:** `string | array<string>`
212
212
  **Default:** `null` but either this option or `out.file` (or both) must contain a value
213
213
  **Since:** 1.1.0
214
214
 
@@ -241,7 +241,7 @@ If this option is `null` or not defined, the [global `encoding`](#encoding) opti
241
241
 
242
242
  ### `out.search` ###
243
243
 
244
- **Type:** `string|object`
244
+ **Type:** `string | object`
245
245
  **Default:** `null`
246
246
 
247
247
  Defines the regular expression to find the text which is replaced with the new version inside
@@ -357,9 +357,27 @@ The template string also supports a set of placeholders:
357
357
  The placeholders are replaced before the template string is used in the search and replace and thus
358
358
  before the capturing group references are replaced.
359
359
 
360
+ ### `out.strict` ###
361
+
362
+ **Type:** `boolean | "off" | "warn" | "errorIfNoMatch" | "errorIfNoChange"`
363
+ **Default:** `null`
364
+
365
+ Defines the behavior if an output file was not changed by this output configuration or if the search pattern did not match in an output file.
366
+
367
+ If this option is `true` or `"warn", a warning is logged if the search pattern was not found in an output file or if a file was not changed by this output configuration.
368
+
369
+ If this options is `"errorIfNoMatch"`, an `Error` is thrown and the release is aborted if there was no match of the search pattern in an output file. If there was a match but the file did not change, a warning is logged.
370
+
371
+ If this options is `"errorIfNoChange"`, an `Error` is thrown and the release is aborted if either an output file was not changed by this output configuration or there was no match of the search pattern in an output file.
372
+
373
+ If this option is `false` or `"off"`, no warning is logged if the search pattern did not match or the file did not change.
374
+
375
+ If this option is `null` or not defined, the [global `strict`](#strict) is used.
376
+
377
+
360
378
  ### `search` ###
361
379
 
362
- **Type:** `string|object`
380
+ **Type:** `string | object`
363
381
  **Default:** An object with the default values as described below.
364
382
 
365
383
  Defines the default regular expression to be used when no `in.search` or `out.search` is given.
@@ -396,7 +414,7 @@ The default flags for the search pattern which are used when `in.search.flags` o
396
414
 
397
415
  ### `search.versionCaptureGroup` ###
398
416
 
399
- **Type:** `integer|string`
417
+ **Type:** `integer | string`
400
418
  **Default:** `null`
401
419
 
402
420
  Defines the default capture group which is used when `in.search.versionCaptureGroup` is `null` or
@@ -425,6 +443,15 @@ encodings are the ones supported by Node's `fs` module.
425
443
 
426
444
  If this option is not defined or set to `null`, the default value is used.
427
445
 
446
+ ### `strict` ###
447
+
448
+ **Type:** `boolean | "off" | "warn" | "errorIfNoMatch" | "errorIfNoChange"`
449
+ **Default:** `true`
450
+
451
+ The default strict mode used when `out.strict` is `null` or not defined.
452
+
453
+ If this option is not defined or set to `null`, the default value is used.
454
+
428
455
  ## Tips ##
429
456
 
430
457
  ### Disable Output via Command-Line Parameter ###
package/index.js CHANGED
@@ -23,11 +23,18 @@ const placeholderRegex = XRegExp( '\\{\\{(?<placeholder>(?:[a-z][a-z0-9_]*|\\{))
23
23
  const prereleasePrefix = '-';
24
24
  const buildPrefix = '+';
25
25
 
26
+ const StrictMode = {
27
+ Off: 'off',
28
+ Warn: 'warn',
29
+ ErrorIfNoMatch: 'errorIfNoMatch',
30
+ ErrorIfNoChange: 'errorIfNoChange',
31
+ };
32
+
26
33
  const defaultEncoding = 'utf-8';
27
34
  const defaultSearchRegex = XRegExp( '{{semver}}' );
28
35
  const defaultVersionCaptureGroup = null;
29
36
  const defaultReplace = '{{version}}';
30
-
37
+ const defaultStrictMode = true;
31
38
 
32
39
 
33
40
  export default class RegExBumper extends Plugin {
@@ -74,6 +81,7 @@ export default class RegExBumper extends Plugin {
74
81
  search: globalSearchOptions,
75
82
  replace: globalReplace,
76
83
  encoding: globalEncoding,
84
+ strict: globalStrict,
77
85
  } = this.options;
78
86
  const { isDryRun } = this.config;
79
87
  if ( _.isNil( outOptions ) ) {
@@ -92,7 +100,7 @@ export default class RegExBumper extends Plugin {
92
100
 
93
101
  /* eslint-disable no-await-in-loop */
94
102
  for ( const outOption of expandedOutOptions ) {
95
- const { files, encoding, searchRegex, flags: searchFlags, replace } = outOption;
103
+ const { files, encoding, searchRegex, flags: searchFlags, replace, strict } = outOption;
96
104
 
97
105
  const effectiveEncoding = firstNotNil( encoding, globalEncoding, defaultEncoding );
98
106
  const effectiveSearchRegex = mergeSearchRegExes(
@@ -100,6 +108,7 @@ export default class RegExBumper extends Plugin {
100
108
  [ searchFlags, globalSearchFlags ]
101
109
  );
102
110
  const effectiveReplacement = firstNotNil( replace, globalReplace, defaultReplace );
111
+ const effectiveStrictMode = firstNotNil( strict, globalStrict, defaultStrictMode );
103
112
 
104
113
  const replacedSearchRegex = prepareSearch( effectiveSearchRegex, context );
105
114
 
@@ -111,13 +120,15 @@ export default class RegExBumper extends Plugin {
111
120
 
112
121
  if ( isDryRun ) {
113
122
  await this.loadDiff();
123
+ const processedFileContent = replaceVersion( fileContent, replacedSearchRegex,
124
+ effectiveReplacement, context );
125
+ this.evaluateFileChanges( fileContent, processedFileContent,
126
+ replacedSearchRegex, effectiveStrictMode, file );
114
127
  if ( this.diff ) {
115
- const processedFileContent = replaceVersion( fileContent, replacedSearchRegex,
116
- effectiveReplacement, context );
117
- await this.diffAndReport( fileContent, processedFileContent, file );
128
+ await this.diffAndReport( fileContent, processedFileContent, effectiveStrictMode, file );
118
129
  continue;
119
130
  }
120
- await this.searchAndReport( fileContent, replacedSearchRegex, file );
131
+ await this.searchAndReport( fileContent, replacedSearchRegex );
121
132
  continue;
122
133
  }
123
134
 
@@ -128,10 +139,8 @@ export default class RegExBumper extends Plugin {
128
139
  context
129
140
  );
130
141
 
131
- if ( processedFileContent === fileContent ) {
132
- this.warnNoFileChange( file );
133
- }
134
- else {
142
+ if ( this.evaluateFileChanges( fileContent, processedFileContent,
143
+ replacedSearchRegex, effectiveStrictMode, file ) ) {
135
144
  await writeFile( file, processedFileContent, effectiveEncoding );
136
145
  }
137
146
  }
@@ -164,9 +173,6 @@ export default class RegExBumper extends Plugin {
164
173
  }
165
174
  );
166
175
 
167
- if ( _.isEmpty( diffResult.hunks ) ) {
168
- this.warnNoFileChange( filePath );
169
- }
170
176
  diffResult.hunks.forEach( ( hunk ) => {
171
177
  this.log.exec(
172
178
  `Replacing at line ${hunk.oldStart}:\n` +
@@ -187,9 +193,8 @@ export default class RegExBumper extends Plugin {
187
193
  } );
188
194
  }
189
195
 
190
- searchAndReport( content, searchRegex, filePath ) {
196
+ searchAndReport( content, searchRegex ) {
191
197
  const { isDryRun } = this.config;
192
- let foundMatch = false;
193
198
  const lineCounter = new LineCounter( content );
194
199
  XRegExp.forEach( content, searchRegex, ( match ) => {
195
200
  const matchText = match[0];
@@ -200,15 +205,31 @@ export default class RegExBumper extends Plugin {
200
205
  matchText,
201
206
  { isDryRun }
202
207
  );
203
- foundMatch = true;
204
208
  } );
205
- if ( !foundMatch ) {
206
- this.warnNoFileChange( filePath );
207
- }
208
209
  }
209
210
 
210
- warnNoFileChange( filePath ) {
211
- this.log.warn( `File "${filePath}" did not change!` );
211
+ evaluateFileChanges( originalFileContent, processedFileContent, searchRegex, strictMode, filePath ) {
212
+ const fileChanged = originalFileContent !== processedFileContent;
213
+ if ( fileChanged ) {
214
+ return fileChanged;
215
+ }
216
+ if ( strictMode && strictMode !== StrictMode.Off ) {
217
+ const match = XRegExp.match( originalFileContent, searchRegex, 'one' );
218
+ if ( match === null ) {
219
+ const message = `No matches found in file "${filePath}"!`;
220
+ if ( strictMode === StrictMode.ErrorIfNoMatch || strictMode === StrictMode.ErrorIfNoChange ) {
221
+ throw new Error( message );
222
+ }
223
+ this.log.warn( message );
224
+ return fileChanged;
225
+ }
226
+ const message = `File "${filePath}" did not change!`;
227
+ if ( strictMode === StrictMode.ErrorIfNoChange ) {
228
+ throw new Error( message );
229
+ }
230
+ this.log.warn( message );
231
+ }
232
+ return fileChanged;
212
233
  }
213
234
 
214
235
  }
@@ -286,13 +307,13 @@ function parseOutOptions( options ) {
286
307
  replace: null,
287
308
  };
288
309
  }
289
- const { encoding, replace } = option;
310
+ const { encoding, replace, strict } = option;
290
311
  const { searchRegex, flags } = parseSearchOptions( option.search );
291
312
  const files = option.files ? _.castArray( option.files ) : [];
292
313
  if ( option.file ) {
293
314
  files.unshift( option.file );
294
315
  }
295
- return { files, encoding, searchRegex, flags, replace };
316
+ return { files, encoding, searchRegex, flags, replace, strict };
296
317
  } );
297
318
  }
298
319
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@j-ulrich/release-it-regex-bumper",
3
- "version": "5.4.0",
3
+ "version": "5.5.0",
4
4
  "description": "Regular expression based version read/write plugin for release-it",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -60,7 +60,7 @@
60
60
  "c8": "^11.0.0",
61
61
  "eslint": "^8.6.0",
62
62
  "eslint-plugin-security": "^1.4.0",
63
- "release-it": "^19.2.4",
63
+ "release-it": "^20.0.0",
64
64
  "sinon": "^21.0.3",
65
65
  "temp": "^0.9.4",
66
66
  "testdouble": "^3.20.2"