@j-ulrich/release-it-regex-bumper 3.0.1 → 4.1.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020-2021 Jochen Ulrich
3
+ Copyright (c) 2020-2022 Jochen Ulrich
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  > Regular expression based version read/write plugin for release-it
4
4
 
5
- ![CI](https://github.com/j-ulrich/release-it-regex-bumper/workflows/CI/badge.svg)
6
- [![Test Coverage](https://app.codacy.com/project/badge/Coverage/bf3c6e8740a9472b9acd7dac231adf4e)](https://www.codacy.com/manual/j-ulrich/release-it-regex-bumper?utm_source=github.com&utm_medium=referral&utm_content=j-ulrich/release-it-regex-bumper&utm_campaign=Badge_Coverage)
7
- [![Code Quality](https://app.codacy.com/project/badge/Grade/bf3c6e8740a9472b9acd7dac231adf4e)](https://www.codacy.com/manual/j-ulrich/release-it-regex-bumper?utm_source=github.com&utm_medium=referral&utm_content=j-ulrich/release-it-regex-bumper&utm_campaign=Badge_Grade)
5
+ [![CI](https://github.com/j-ulrich/release-it-regex-bumper/actions/workflows/CI.yml/badge.svg)](https://github.com/j-ulrich/release-it-regex-bumper/actions/workflows/CI.yml)
6
+ [![Test Coverage](https://app.codacy.com/project/badge/Coverage/bf3c6e8740a9472b9acd7dac231adf4e)](https://www.codacy.com/gh/j-ulrich/release-it-regex-bumper/dashboard?utm_source=github.com&utm_medium=referral&utm_content=j-ulrich/release-it-regex-bumper&utm_campaign=Badge_Coverage)
7
+ [![Code Quality](https://app.codacy.com/project/badge/Grade/bf3c6e8740a9472b9acd7dac231adf4e)](https://www.codacy.com/gh/j-ulrich/release-it-regex-bumper/dashboard?utm_source=github.com&utm_medium=referral&utm_content=j-ulrich/release-it-regex-bumper&utm_campaign=Badge_Grade)
8
8
 
9
9
  This [release-it](https://github.com/release-it/release-it) plugin reads and/or writes versions
10
10
  using regular expressions.
@@ -18,6 +18,10 @@ below for details.
18
18
 
19
19
  # Installation #
20
20
 
21
+ > ⚠️ **Note:**
22
+ > Version 4 and later of release-it-regex-bumper require version 15 or later of release-it.
23
+ > When you are using release-it version 14.x or earlier, then use release-it-regex-bumper version 3.x or earlier.
24
+
21
25
  ```
22
26
  npm install --save-dev @j-ulrich/release-it-regex-bumper
23
27
  ```
@@ -48,7 +52,7 @@ For example:
48
52
  }
49
53
  ```
50
54
 
51
- For a more complex example, see [.release-it.json](.release-it.json).
55
+ For a more complex example, see [here](https://gitlab.com/julrich/MockNetworkAccessManager/-/blob/main/.release-it.json).
52
56
 
53
57
 
54
58
  ## Regular Expressions ##
@@ -421,9 +425,18 @@ encodings are the ones supported by Node's `fs` module.
421
425
 
422
426
  If this option is not defined or set to `null`, the default value is used.
423
427
 
428
+ ## Tips ##
429
+
430
+ ### Disable Output via Command-Line Parameter ###
431
+ To completely disable changing any files by the plugin, you can use the command-line parameter `--no-plugins.@j-ulrich/release-it-regex-bumper.out`.
432
+ For example:
433
+ ```
434
+ npx release-it --no-plugins.@j-ulrich/release-it-regex-bumper.out
435
+ ```
436
+
424
437
 
425
438
  # License #
426
439
 
427
- Copyright (c) 2020-2021 Jochen Ulrich
440
+ Copyright (c) 2020-2022 Jochen Ulrich
428
441
 
429
442
  Licensed under [MIT license](LICENSE).
package/index.js CHANGED
@@ -1,28 +1,24 @@
1
- const fs = require( 'fs' );
2
- const assert = require( 'assert' ).strict;
3
- const util = require( 'util' );
4
- const glob = require( 'fast-glob' );
5
- const chalk = require( 'chalk' );
6
- const _ = {
7
- isEmpty: require( 'lodash/isEmpty' ),
8
- isNil: require( 'lodash/isNil' ),
9
- isNull: require( 'lodash/isNull' ),
10
- isString: require( 'lodash/isString' ),
11
- isFunction: require( 'lodash/isFunction' ),
12
- castArray: require( 'lodash/castArray' )
13
- };
14
- const XRegExp = require( 'xregexp' );
15
- const semver = require( 'semver' );
16
- const { Plugin } = require( 'release-it' );
17
- const dateFormat = require( 'date-fns/format' );
18
- const dateFormatIso = require( 'date-fns/formatISO' );
19
- const diff = optionalRequire( 'diff' );
20
-
21
-
22
- const readFile = util.promisify( fs.readFile );
23
- const writeFile = util.promisify( fs.writeFile );
24
-
25
- const semanticVersionRegex = XRegExp( /(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(?:\+[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*)?/ );
1
+
2
+ import { readFile as fsReadFile, writeFile as fsWriteFile } from 'fs';
3
+ import { strict as assert } from 'assert';
4
+ import { promisify } from 'util';
5
+ import glob from 'fast-glob';
6
+ import chalk from 'chalk';
7
+ import _ from 'lodash';
8
+ import XRegExp from 'xregexp';
9
+ import semver from 'semver';
10
+ import { Plugin } from 'release-it';
11
+ import dateFormat from 'date-fns/format/index.js';
12
+ import dateFormatIso from 'date-fns/formatISO/index.js';
13
+
14
+
15
+ const readFile = promisify( fsReadFile );
16
+ const writeFile = promisify( fsWriteFile );
17
+
18
+ const semanticVersionRegex = XRegExp(
19
+ // eslint-disable-next-line security/detect-unsafe-regex
20
+ /(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(?:\+[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*)?/
21
+ );
26
22
  const placeholderRegex = XRegExp( '\\{\\{(?<placeholder>(?:[a-z][a-z0-9_]*|\\{))(?::(?<format>.*))?\\}\\}', 'ig' );
27
23
 
28
24
  const prereleasePrefix = '-';
@@ -35,38 +31,51 @@ const defaultReplace = '{{version}}';
35
31
 
36
32
 
37
33
 
38
- class RegExBumper extends Plugin {
34
+ export default class RegExBumper extends Plugin {
39
35
 
40
- constructor(...args) {
41
- super(...args);
42
- this.setContext({executionTime: new Date()});
36
+ constructor( ...args ) {
37
+ super( ...args );
38
+ this.setContext( { executionTime: new Date() } );
43
39
  }
44
40
 
45
41
  async getLatestVersion() {
46
42
 
47
43
  const { in: inOptions, search: globalSearchOptions, encoding: globalEncoding } = this.options;
48
44
  if ( _.isNil( inOptions ) ) {
49
- return;
45
+ return undefined;
50
46
  }
51
47
 
52
48
  const context = Object.assign( {}, this.getContext(), this.config.contextOptions );
53
49
 
54
- const { searchRegex: globalSearchRegex, flags: globalSearchFlags, versionCaptureGroup: globalVersionCaptureGroup } = parseSearchOptions.call( this, globalSearchOptions );
55
- const { file, encoding, searchRegex, flags: searchFlags, versionCaptureGroup } = parseInOptions.call( this, inOptions );
50
+ const {
51
+ searchRegex: globalSearchRegex,
52
+ flags: globalSearchFlags,
53
+ versionCaptureGroup: globalVersionCaptureGroup,
54
+ } = parseSearchOptions( globalSearchOptions );
55
+ const { file, encoding, searchRegex, flags: searchFlags, versionCaptureGroup } = parseInOptions( inOptions );
56
56
 
57
57
  const effectiveEncoding = firstNotNil( encoding, globalEncoding, defaultEncoding );
58
58
  const fileContent = await readFile( file, { encoding: effectiveEncoding } );
59
- const effectiveSearchRegex = mergeSearchRegExes( [searchRegex, globalSearchRegex, defaultSearchRegex], [searchFlags, globalSearchFlags] );
59
+ const effectiveSearchRegex = mergeSearchRegExes(
60
+ [ searchRegex, globalSearchRegex, defaultSearchRegex ],
61
+ [ searchFlags, globalSearchFlags ]
62
+ );
60
63
  const replacedSearchRegex = prepareSearch( effectiveSearchRegex, context );
61
- const version = await extractVersion.call( this, fileContent, replacedSearchRegex,
62
- firstNotNil( versionCaptureGroup, globalVersionCaptureGroup, defaultVersionCaptureGroup ) );
64
+ const version = await extractVersion(
65
+ fileContent,
66
+ replacedSearchRegex,
67
+ firstNotNil( versionCaptureGroup, globalVersionCaptureGroup, defaultVersionCaptureGroup )
68
+ );
63
69
  return version;
64
70
  }
65
71
 
66
-
67
72
  async bump( version ) {
68
-
69
- const { out: outOptions, search: globalSearchOptions, replace: globalReplace, encoding: globalEncoding } = this.options;
73
+ const {
74
+ out: outOptions,
75
+ search: globalSearchOptions,
76
+ replace: globalReplace,
77
+ encoding: globalEncoding,
78
+ } = this.options;
70
79
  const { isDryRun } = this.config;
71
80
  if ( _.isNil( outOptions ) ) {
72
81
  return;
@@ -76,15 +85,21 @@ class RegExBumper extends Plugin {
76
85
  context.version = version;
77
86
  }
78
87
 
79
- const { searchRegex: globalSearchRegex, flags: globalSearchFlags } = parseSearchOptions.call( this, globalSearchOptions );
88
+ const { searchRegex: globalSearchRegex, flags: globalSearchFlags } = parseSearchOptions.call(
89
+ this,
90
+ globalSearchOptions
91
+ );
80
92
  const expandedOutOptions = await expandOutOptionFiles.call( this, parseOutOptions.call( this, outOptions ) );
81
93
 
82
- for ( const outOptions of expandedOutOptions ) {
83
-
84
- const { files, encoding, searchRegex, flags: searchFlags, replace } = outOptions;
94
+ /* eslint-disable no-await-in-loop */
95
+ for ( const outOption of expandedOutOptions ) {
96
+ const { files, encoding, searchRegex, flags: searchFlags, replace } = outOption;
85
97
 
86
98
  const effectiveEncoding = firstNotNil( encoding, globalEncoding, defaultEncoding );
87
- const effectiveSearchRegex = mergeSearchRegExes( [searchRegex, globalSearchRegex, defaultSearchRegex], [searchFlags, globalSearchFlags] );
99
+ const effectiveSearchRegex = mergeSearchRegExes(
100
+ [ searchRegex, globalSearchRegex, defaultSearchRegex ],
101
+ [ searchFlags, globalSearchFlags ]
102
+ );
88
103
  const effectiveReplacement = firstNotNil( replace, globalReplace, defaultReplace );
89
104
 
90
105
  const replacedSearchRegex = prepareSearch( effectiveSearchRegex, context );
@@ -96,26 +111,105 @@ class RegExBumper extends Plugin {
96
111
  const fileContent = await readFile( file, { encoding: effectiveEncoding } );
97
112
 
98
113
  if ( isDryRun ) {
99
- loadDiff.call( this );
114
+ await this.loadDiff();
100
115
  if ( this.diff ) {
101
- const processedFileContent = replaceVersion.call( this, fileContent, replacedSearchRegex, effectiveReplacement, context );
102
- await diffAndReport.call( this, fileContent, processedFileContent, file );
116
+ const processedFileContent = replaceVersion( fileContent, replacedSearchRegex,
117
+ effectiveReplacement, context );
118
+ await this.diffAndReport( fileContent, processedFileContent, file );
103
119
  continue;
104
120
  }
105
- await searchAndReport.call( this, fileContent, replacedSearchRegex, file );
121
+ await this.searchAndReport( fileContent, replacedSearchRegex, file );
106
122
  continue;
107
123
  }
108
124
 
109
- const processedFileContent = replaceVersion.call( this, fileContent, replacedSearchRegex, effectiveReplacement, context );
125
+ const processedFileContent = replaceVersion(
126
+ fileContent,
127
+ replacedSearchRegex,
128
+ effectiveReplacement,
129
+ context
130
+ );
110
131
 
111
- if ( processedFileContent == fileContent ) {
112
- warnNoFileChange.call( this, file );
132
+ if ( processedFileContent === fileContent ) {
133
+ this.warnNoFileChange( file );
113
134
  }
114
135
  else {
115
136
  await writeFile( file, processedFileContent, effectiveEncoding );
116
137
  }
117
138
  }
118
139
  }
140
+ /* eslint-enable no-await-in-loop */
141
+ }
142
+
143
+ async loadDiff() {
144
+ if ( this.diff ) {
145
+ return;
146
+ }
147
+ try {
148
+ const diff = await import( 'diff' );
149
+ if ( !diff || !diff.structuredPatch ) {
150
+ throw new Error( 'diff module no available' );
151
+ }
152
+ this.diff = diff;
153
+ }
154
+ catch ( e ) {
155
+ this.log.info( 'Optional "diff" package not available' );
156
+ this.log.verbose( 'Exception was:', e );
157
+ }
158
+ }
159
+
160
+ diffAndReport( oldContent, newContent, filePath ) {
161
+ const { isDryRun } = this.config;
162
+ const diffResult = this.diff.structuredPatch( filePath, filePath, oldContent, newContent, undefined, undefined,
163
+ {
164
+ context: 0,
165
+ }
166
+ );
167
+
168
+ if ( _.isEmpty( diffResult.hunks ) ) {
169
+ this.warnNoFileChange( filePath );
170
+ }
171
+ diffResult.hunks.forEach( ( hunk ) => {
172
+ this.log.exec(
173
+ `Replacing at line ${hunk.oldStart}:\n` +
174
+ hunk.lines
175
+ .map( ( line ) => {
176
+ const lineText = '\t' + line;
177
+ if ( line.startsWith( '-' ) ) {
178
+ return chalk.red( lineText );
179
+ }
180
+ if ( line.startsWith( '+' ) ) {
181
+ return chalk.green( lineText );
182
+ }
183
+ return lineText;
184
+ } )
185
+ .join( '\n' ),
186
+ { isDryRun }
187
+ );
188
+ } );
189
+ }
190
+
191
+ searchAndReport( content, searchRegex, filePath ) {
192
+ const { isDryRun } = this.config;
193
+ let foundMatch = false;
194
+ const lineCounter = new LineCounter( content );
195
+ XRegExp.forEach( content, searchRegex, ( match ) => {
196
+ const matchText = match[0];
197
+ const matchIndex = searchRegex.lastIndex - matchText.length;
198
+ this.log.exec(
199
+ `Replacing match at line ${lineCounter.lineOfIndex( matchIndex )}, ` +
200
+ `column ${lineCounter.columnOfIndex( matchIndex )}:\n\t` +
201
+ matchText,
202
+ { isDryRun }
203
+ );
204
+ foundMatch = true;
205
+ } );
206
+ if ( !foundMatch ) {
207
+ this.warnNoFileChange( filePath );
208
+ }
209
+ }
210
+
211
+ warnNoFileChange( filePath ) {
212
+ this.log.warn( `File "${filePath}" did not change!` );
119
213
  }
120
214
 
121
215
  }
@@ -146,7 +240,7 @@ function parseSearchOptions( options ) {
146
240
  return { searchRegex, versionCaptureGroup };
147
241
  }
148
242
  const { pattern, flags, versionCaptureGroup } = options;
149
- const searchRegex = _.isNil(pattern) ? pattern : XRegExp( pattern, _.isNull( flags ) ? undefined : flags );
243
+ const searchRegex = _.isNil( pattern ) ? pattern : XRegExp( pattern, _.isNull( flags ) ? undefined : flags );
150
244
  return { searchRegex, flags, versionCaptureGroup };
151
245
  }
152
246
 
@@ -156,22 +250,27 @@ function extractVersion( content, versionRegex, versionCaptureGroup ) {
156
250
  throw new Error( 'Could not extract version from file' );
157
251
  }
158
252
  if ( !_.isNil( versionCaptureGroup ) ) {
159
- if( hasOwnProperty( match, versionCaptureGroup ) ) {
253
+ if ( typeof versionCaptureGroup === 'number' && hasOwnProperty( match, versionCaptureGroup ) ) {
160
254
  // object injection mitigated by checking hasOwnProperty()
161
255
  // eslint-disable-next-line security/detect-object-injection
162
- return match[ versionCaptureGroup ];
256
+ return match[versionCaptureGroup];
257
+ }
258
+ if ( match.groups && hasOwnProperty( match.groups, versionCaptureGroup ) ) {
259
+ // object injection mitigated by checking hasOwnProperty()
260
+ // eslint-disable-next-line security/detect-object-injection
261
+ return match.groups[versionCaptureGroup];
163
262
  }
164
263
  }
165
264
  else {
166
- if ( hasOwnProperty( match, 'version' ) ) {
167
- return match[ 'version' ];
265
+ if ( match.groups && hasOwnProperty( match.groups, 'version' ) ) {
266
+ return match.groups.version;
168
267
  }
169
268
  if ( hasOwnProperty( match, 1 ) ) {
170
- return match[ 1 ];
269
+ return match[1];
171
270
  }
172
271
  }
173
272
 
174
- return match[ 0 ];
273
+ return match[0];
175
274
  }
176
275
 
177
276
  function hasOwnProperty( obj, prop ) {
@@ -179,20 +278,20 @@ function hasOwnProperty( obj, prop ) {
179
278
  }
180
279
 
181
280
  function parseOutOptions( options ) {
182
- return _.castArray( options ).map( options => {
183
- if ( _.isString( options ) ) {
281
+ return _.castArray( options ).map( ( option ) => {
282
+ if ( _.isString( option ) ) {
184
283
  return {
185
- files: [ options ],
284
+ files: [ option ],
186
285
  encoding: null,
187
286
  searchRegex: null,
188
287
  replace: null,
189
288
  };
190
289
  }
191
- const { encoding, replace } = options;
192
- const { searchRegex, flags } = parseSearchOptions( options.search );
193
- const files = options.files ? _.castArray( options.files ) : [];
194
- if( options.file ) {
195
- files.unshift( options.file );
290
+ const { encoding, replace } = option;
291
+ const { searchRegex, flags } = parseSearchOptions( option.search );
292
+ const files = option.files ? _.castArray( option.files ) : [];
293
+ if ( option.file ) {
294
+ files.unshift( option.file );
196
295
  }
197
296
  return { files, encoding, searchRegex, flags, replace };
198
297
  } );
@@ -215,55 +314,6 @@ async function expandOutOptionFiles( options ) {
215
314
  return options;
216
315
  }
217
316
 
218
- function loadDiff() {
219
- if ( !diff || diff instanceof Error ) {
220
- this.log.info( 'Optional "diff" package not available' );
221
- this.log.verbose( 'Exception was:', diff );
222
- }
223
- this.diff = diff;
224
- }
225
-
226
- function diffAndReport( oldContent, newContent, filePath ) {
227
- const { isDryRun } = this.config;
228
- const diffResult = this.diff.structuredPatch( filePath, filePath, oldContent, newContent, undefined, undefined, { context: 0 } );
229
-
230
- if ( _.isEmpty( diffResult.hunks ) ) {
231
- warnNoFileChange.call( this, filePath );
232
- }
233
- diffResult.hunks.forEach( hunk => {
234
- this.log.exec( `Replacing at line ${hunk.oldStart}:\n` + hunk.lines.map( line => {
235
- const lineText = '\t' + line;
236
- if ( line.startsWith( '-' ) ) {
237
- return chalk.red( lineText );
238
- }
239
- if ( line.startsWith( '+' ) ) {
240
- return chalk.green( lineText );
241
- }
242
- return lineText;
243
- } ).join( '\n' ), { isDryRun } );
244
- } );
245
-
246
- }
247
-
248
- function searchAndReport( content, searchRegex, filePath ) {
249
- const { isDryRun } = this.config;
250
- let foundMatch = false;
251
- const lineCounter = new LineCounter( content );
252
- XRegExp.forEach( content, searchRegex, ( match ) => {
253
- const matchText = match[ 0 ];
254
- const matchIndex = searchRegex.lastIndex - matchText.length;
255
- this.log.exec( `Replacing match at line ${lineCounter.lineOfIndex( matchIndex )}, column ${lineCounter.columnOfIndex( matchIndex )}:\n\t` + matchText, { isDryRun } );
256
- foundMatch = true;
257
- } );
258
- if ( !foundMatch ) {
259
- warnNoFileChange.call( this, filePath );
260
- }
261
- }
262
-
263
- function warnNoFileChange( filePath ) {
264
- this.log.warn( `File "${filePath}" did not change!` );
265
- }
266
-
267
317
  function mergeSearchRegExes( regExCandidates, flagCandidates ) {
268
318
  const searchRegEx = firstNotNil( ...regExCandidates );
269
319
  const flags = firstNotNil( ...flagCandidates );
@@ -273,36 +323,39 @@ function mergeSearchRegExes( regExCandidates, flagCandidates ) {
273
323
  function prepareSearch( searchRegEx, context ) {
274
324
  const pattern = searchRegEx.xregexp.source;
275
325
  const placeholderMap = {
276
- 'now': ( format ) => {
277
- if( _.isNil( format ) ) {
326
+ now: ( format ) => {
327
+ if ( _.isNil( format ) ) {
278
328
  throw new Error( "Missing required parameter 'format' for placeholder {{now}}" );
279
329
  }
280
330
  return XRegExp.escape( dateFormat( context.executionTime, format ) );
281
331
  },
282
- 'semver': `${semanticVersionRegex.xregexp.source || semanticVersionRegex.source}`
332
+ semver: `${semanticVersionRegex.xregexp.source || semanticVersionRegex.source}`,
283
333
  };
284
334
  const parsedVer = semver.parse( context.latestVersion );
285
- if( parsedVer ) {
335
+ if ( parsedVer ) {
286
336
  Object.assign( placeholderMap, {
287
- 'version': XRegExp.escape( parsedVer.raw ),
288
- 'major': parsedVer.major,
289
- 'minor': parsedVer.minor,
290
- 'patch': parsedVer.patch,
291
- 'prerelease': XRegExp.escape( parsedVer.prerelease.join( '.' ) ),
292
- 'prefixedPrerelease': parsedVer.prerelease.length > 0 ? XRegExp.escape( prereleasePrefix + parsedVer.prerelease.join( '.' ) ) : '',
293
- 'build': XRegExp.escape( parsedVer.build.join( '.' ) ),
294
- 'prefixedBuild': parsedVer.build.length > 0 ? XRegExp.escape( buildPrefix + parsedVer.build.join( '.' ) ) : '',
295
- 'versionWithoutBuild': XRegExp.escape( parsedVer.version ),
296
- 'versionWithoutPrerelease': XRegExp.escape( `${parsedVer.major}.${parsedVer.minor}.${parsedVer.patch}` ),
297
-
337
+ version: XRegExp.escape( parsedVer.raw ),
338
+ major: parsedVer.major,
339
+ minor: parsedVer.minor,
340
+ patch: parsedVer.patch,
341
+ prerelease: XRegExp.escape( parsedVer.prerelease.join( '.' ) ),
342
+ prefixedPrerelease:
343
+ parsedVer.prerelease.length > 0
344
+ ? XRegExp.escape( prereleasePrefix + parsedVer.prerelease.join( '.' ) )
345
+ : '',
346
+ build: XRegExp.escape( parsedVer.build.join( '.' ) ),
347
+ prefixedBuild:
348
+ parsedVer.build.length > 0 ? XRegExp.escape( buildPrefix + parsedVer.build.join( '.' ) ) : '',
349
+ versionWithoutBuild: XRegExp.escape( parsedVer.version ),
350
+ versionWithoutPrerelease: XRegExp.escape( `${parsedVer.major}.${parsedVer.minor}.${parsedVer.patch}` ),
298
351
  } );
299
352
  }
300
353
  if ( context.latestTag ) {
301
- Object.assign( placeholderMap, { 'tag': XRegExp.escape( context.latestTag ) } );
354
+ Object.assign( placeholderMap, { tag: XRegExp.escape( context.latestTag ) } );
302
355
  }
303
356
 
304
357
  if ( context.version ) {
305
- Object.assign( placeholderMap, { 'newVersion': XRegExp.escape( context.version ) } );
358
+ Object.assign( placeholderMap, { newVersion: XRegExp.escape( context.version ) } );
306
359
  }
307
360
 
308
361
  wrapSearchPatternPlaceholders( placeholderMap );
@@ -311,11 +364,11 @@ function prepareSearch( searchRegEx, context ) {
311
364
  }
312
365
 
313
366
  function wrapSearchPatternPlaceholders( placeholderMap ) {
314
- for( const placeholder of Object.keys( placeholderMap ) ) {
367
+ for ( const placeholder of Object.keys( placeholderMap ) ) {
315
368
  // object injection mitigated for placeholderMap since placeholder is from Object.keys( placeholderMap )
316
369
  // eslint-disable-next-line security/detect-object-injection
317
370
  const replacement = placeholderMap[ placeholder ];
318
- if( _.isFunction( replacement ) ) {
371
+ if ( _.isFunction( replacement ) ) {
319
372
  // eslint-disable-next-line security/detect-object-injection
320
373
  placeholderMap[ placeholder ] = ( ...args ) => {
321
374
  return wrapInRegexGroup( replacement( ...args ) );
@@ -332,7 +385,7 @@ function wrapInRegexGroup( pattern ) {
332
385
  }
333
386
 
334
387
  function replaceVersion( content, searchRegex, replace, context ) {
335
- const processedReplace = prepareReplacement.call( this, replace, context );
388
+ const processedReplace = prepareReplacement( replace, context );
336
389
  const processedContent = XRegExp.replace( content, searchRegex, processedReplace );
337
390
  return processedContent;
338
391
  }
@@ -340,24 +393,25 @@ function replaceVersion( content, searchRegex, replace, context ) {
340
393
  function prepareReplacement( replace, context ) {
341
394
  const parsedVer = semver.parse( context.version );
342
395
  const placeholderMap = {
343
- 'version': parsedVer.raw,
344
- 'major': parsedVer.major,
345
- 'minor': parsedVer.minor,
346
- 'patch': parsedVer.patch,
347
- 'prerelease': parsedVer.prerelease.join( '.' ),
348
- 'prefixedPrerelease': parsedVer.prerelease.length > 0 ? prereleasePrefix + parsedVer.prerelease.join( '.' ) : '',
349
- 'build': parsedVer.build.join( '.' ),
350
- 'prefixedBuild': parsedVer.build.length > 0 ? buildPrefix + parsedVer.build.join( '.' ) : '',
351
- 'versionWithoutBuild': parsedVer.version,
352
- 'versionWithoutPrerelease': `${parsedVer.major}.${parsedVer.minor}.${parsedVer.patch}`,
353
- 'latestVersion': context.latestVersion || '',
354
- 'latestTag': context.latestTag || '',
355
- 'now': ( format ) => {
356
- if( _.isNil( format ) ) {
396
+ version: parsedVer.raw,
397
+ major: parsedVer.major,
398
+ minor: parsedVer.minor,
399
+ patch: parsedVer.patch,
400
+ prerelease: parsedVer.prerelease.join( '.' ),
401
+ prefixedPrerelease:
402
+ parsedVer.prerelease.length > 0 ? prereleasePrefix + parsedVer.prerelease.join( '.' ) : '',
403
+ build: parsedVer.build.join( '.' ),
404
+ prefixedBuild: parsedVer.build.length > 0 ? buildPrefix + parsedVer.build.join( '.' ) : '',
405
+ versionWithoutBuild: parsedVer.version,
406
+ versionWithoutPrerelease: `${parsedVer.major}.${parsedVer.minor}.${parsedVer.patch}`,
407
+ latestVersion: context.latestVersion || '',
408
+ latestTag: context.latestTag || '',
409
+ now: ( format ) => {
410
+ if ( _.isNil( format ) ) {
357
411
  return dateFormatIso( context.executionTime );
358
412
  }
359
413
  return dateFormat( context.executionTime, format );
360
- }
414
+ },
361
415
  };
362
416
  return replacePlaceholders( replace, placeholderMap );
363
417
  }
@@ -381,34 +435,22 @@ function replacePlaceholders( template, placeholderMap ) {
381
435
  } );
382
436
  }
383
437
 
384
-
385
- function optionalRequire( packageName ) {
386
- try {
387
- // eslint-disable-next-line security/detect-non-literal-require
388
- return require( packageName );
389
- }
390
- /* c8 ignore next 4 */
391
- /* rewiremock can't simulate the absence of a package so we can't test this case */
392
- catch ( ex ) {
393
- return ex;
394
- }
395
- }
396
-
397
438
  function firstNotNil( ...args ) {
398
- return args.find( ele => !_.isNil( ele ) );
439
+ return args.find( ( ele ) => !_.isNil( ele ) );
399
440
  }
400
441
 
401
442
  class LineCounter {
402
443
  constructor( text ) {
403
444
  let index = 0;
404
- this.lineEndIndex = text.split( '\n' ).map( line => {
445
+ this.lineEndIndex = text.split( '\n' ).map( ( line ) => {
405
446
  index += line.length + 1;
406
447
  return index;
407
448
  } );
408
449
  }
409
450
 
410
451
  lineOfIndex( index ) {
411
- const arrayIndex = this.lineEndIndex.findIndex( lineEndIndex => ( index <= lineEndIndex ) );
452
+ // eslint-disable-next-line no-extra-parens
453
+ const arrayIndex = this.lineEndIndex.findIndex( ( lineEndIndex ) => index <= lineEndIndex );
412
454
  assert( arrayIndex >= 0 );
413
455
  return arrayIndex + 1;
414
456
  }
@@ -425,4 +467,3 @@ class LineCounter {
425
467
  }
426
468
  }
427
469
 
428
- module.exports = RegExBumper;
package/package.json CHANGED
@@ -1,11 +1,15 @@
1
1
  {
2
2
  "name": "@j-ulrich/release-it-regex-bumper",
3
- "version": "3.0.1",
3
+ "version": "4.1.0",
4
4
  "description": "Regular expression based version read/write plugin for release-it",
5
5
  "main": "index.js",
6
+ "type": "module",
7
+ "files": [
8
+ "index.js"
9
+ ],
6
10
  "scripts": {
7
- "test": "npx bron test.js",
8
- "test+coverage": "npx c8 npx bron test.js",
11
+ "test": "node --experimental-loader=testdouble ./node_modules/ava/entrypoints/cli.mjs --serial",
12
+ "test+coverage": "npx c8 node --experimental-loader=testdouble ./node_modules/ava/entrypoints/cli.mjs --serial",
9
13
  "lint": "npx eslint .",
10
14
  "release": "npx release-it"
11
15
  },
@@ -35,30 +39,32 @@
35
39
  "name": "Jochen Ulrich"
36
40
  },
37
41
  "dependencies": {
38
- "chalk": "^4.0.0",
42
+ "chalk": "^5.0.0",
39
43
  "date-fns": "^2.8.0",
40
44
  "fast-glob": "^3.2.0",
41
45
  "lodash": "^4.17.20",
42
46
  "semver": "^7.3.0",
43
- "xregexp": "^4.3.0"
47
+ "xregexp": "^5.0.0"
44
48
  },
45
49
  "peerDependencies": {
46
- "release-it": "11 - 15"
50
+ "release-it": "15"
47
51
  },
48
52
  "optionalDependencies": {
49
- "diff": "^3.0.0 || ^4.0.0"
53
+ "diff": "3 - 5"
50
54
  },
51
55
  "devDependencies": {
52
- "bron": "^1.1.0",
56
+ "@j-ulrich/eslint-config": "^1.0.0",
57
+ "@release-it/keep-a-changelog": "^3.0.0",
58
+ "ava": "^4.0.1",
53
59
  "c8": "^7.3.0",
54
- "eslint": "^8.0.1",
60
+ "eslint": "^8.6.0",
55
61
  "eslint-plugin-security": "^1.4.0",
56
- "mock-fs": "^5.1.1",
57
- "release-it": "^14.0.0",
58
- "rewiremock": "^3.14.3",
59
- "sinon": "^9.0.3"
62
+ "release-it": "^15.0.0",
63
+ "sinon": "^13.0.2",
64
+ "temp": "^0.9.4",
65
+ "testdouble": "^3.16.4"
60
66
  },
61
67
  "engines": {
62
- "node": ">=10.12.0"
68
+ "node": ">=14.9"
63
69
  }
64
70
  }