fork-version 1.4.13 → 1.4.48

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.
@@ -0,0 +1,798 @@
1
+ import { z } from 'zod';
2
+ import { resolve, parse } from 'path';
3
+ import JoyCon from 'joycon';
4
+ import { bundleRequire } from 'bundle-require';
5
+ import meow from 'meow';
6
+ import conventionalChangelogConfigSpec from 'conventional-changelog-config-spec';
7
+ import semver3 from 'semver';
8
+ import conventionalRecommendedBump from 'conventional-recommended-bump';
9
+ import gitSemverTags from 'git-semver-tags';
10
+ import { writeFileSync, lstatSync, readFileSync } from 'fs';
11
+ import conventionalChangelog from 'conventional-changelog';
12
+ import { execFile } from 'child_process';
13
+ import detectIndent from 'detect-indent';
14
+ import { detectNewline } from 'detect-newline';
15
+
16
+ // src/config/schema.ts
17
+ var ChangelogPresetConfigSchema = z.object({
18
+ /**
19
+ * An array of `type` objects representing the explicitly supported commit message types,
20
+ * and whether they should show up in generated `CHANGELOG`s.
21
+ */
22
+ types: z.array(
23
+ z.object({
24
+ type: z.string(),
25
+ section: z.string().optional(),
26
+ hidden: z.boolean().optional()
27
+ })
28
+ ),
29
+ /**
30
+ * A URL representing a specific commit at a hash.
31
+ * @default "{{host}}/{{owner}}/{{repository}}/commit/{{hash}}"
32
+ */
33
+ commitUrlFormat: z.string(),
34
+ /**
35
+ * A URL representing the comparison between two git SHAs.
36
+ * @default "{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}"
37
+ */
38
+ compareUrlFormat: z.string(),
39
+ /**
40
+ * A URL representing the issue format (allowing a different URL format to be swapped in
41
+ * for Gitlab, Bitbucket, etc).
42
+ * @default "{{host}}/{{owner}}/{{repository}}/issues/{{id}}"
43
+ */
44
+ issueUrlFormat: z.string(),
45
+ /**
46
+ * A URL representing the a user's profile URL on GitHub, Gitlab, etc. This URL is used
47
+ * for substituting @bcoe with https://github.com/bcoe in commit messages.
48
+ * @default "{{host}}/{{user}}"
49
+ */
50
+ userUrlFormat: z.string(),
51
+ /**
52
+ * A string to be used to format the auto-generated release commit message.
53
+ * @default "chore(release): {{currentTag}}"
54
+ */
55
+ releaseCommitMessageFormat: z.string(),
56
+ /**
57
+ * An array of prefixes used to detect references to issues
58
+ * @default ["#"]
59
+ */
60
+ issuePrefixes: z.array(z.string())
61
+ });
62
+ var ForkConfigSchema = z.object({
63
+ /**
64
+ * The path fork-version will run from.
65
+ * @default
66
+ * ```js
67
+ * process.cwd()
68
+ * ```
69
+ */
70
+ path: z.string(),
71
+ /**
72
+ * Name of the changelog file.
73
+ * @default "CHANGELOG.md"
74
+ */
75
+ changelog: z.string(),
76
+ /**
77
+ * The header to be used in the changelog.
78
+ * @default
79
+ * ```markdown
80
+ * # Changelog
81
+ *
82
+ * All notable changes to this project will be documented in this file. See [fork-version](https://github.com/eglavin/fork-version) for commit guidelines.
83
+ * ```
84
+ */
85
+ header: z.string(),
86
+ /**
87
+ * Files to be updated.
88
+ * @default
89
+ * ```js
90
+ * ["bower.json", "manifest.json", "npm-shrinkwrap.json", "package-lock.json", "package.json"]
91
+ * ```
92
+ */
93
+ files: z.array(z.string()),
94
+ /**
95
+ * Specify a prefix for the git tag fork-version will create.
96
+ *
97
+ * For instance if your version tag is prefixed by "version/" instead of "v" you have to specify
98
+ * `tagPrefix: "version/"`.
99
+ *
100
+ * `tagPrefix` can also be used for a monorepo environment where you might want to deploy
101
+ * multiple package from the same repository. In this case you can specify a prefix for
102
+ * each package:
103
+ *
104
+ * | Value | Tag Created |
105
+ * |:-------------------------|:------------------------------|
106
+ * | "" | `1.2.3` |
107
+ * | "version/" | `version/1.2.3` |
108
+ * | "@eglavin/fork-version-" | `@eglavin/fork-version-1.2.3` |
109
+ *
110
+ * @example "", "version/", "@eglavin/fork-version-"
111
+ * @default "v"
112
+ */
113
+ tagPrefix: z.string(),
114
+ /**
115
+ * Make a pre-release with optional label, if value is a string it will be used as the
116
+ * pre-release tag.
117
+ *
118
+ * | Value | Version |
119
+ * |:----------|:----------------|
120
+ * | true | "1.2.3-0" |
121
+ * | "alpha" | "1.2.3-alpha-0" |
122
+ * | "beta" | "1.2.3-beta-0" |
123
+ *
124
+ * @example true, "alpha", "beta", "rc"
125
+ * @default undefined
126
+ */
127
+ preReleaseTag: z.string().or(z.boolean()).optional(),
128
+ /**
129
+ * Commit all staged changes, not just files updated by fork-version.
130
+ * @default false
131
+ */
132
+ commitAll: z.boolean(),
133
+ /**
134
+ * If set we'll log debug information.
135
+ * @default false
136
+ */
137
+ debug: z.boolean(),
138
+ /**
139
+ * If true, no output will be written to disk or committed.
140
+ * @default false
141
+ */
142
+ dryRun: z.boolean(),
143
+ /**
144
+ * If true and we cant find a version in the list of `files`, we'll fallback
145
+ * and attempt to use the latest git tag to get the current version.
146
+ * @default true
147
+ */
148
+ gitTagFallback: z.boolean(),
149
+ /**
150
+ * If set, we'll gather information about the current version and exit.
151
+ * @default false
152
+ */
153
+ inspectVersion: z.boolean(),
154
+ /**
155
+ * Should we sign the git commit using GPG?
156
+ * @see {@link https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--Sltkeyidgt GPG Sign Commits}
157
+ * @default false
158
+ */
159
+ sign: z.boolean(),
160
+ /**
161
+ * If true, no output will be written to stdout.
162
+ * @default false
163
+ */
164
+ silent: z.boolean(),
165
+ /**
166
+ * If true, allow git to run git commit hooks.
167
+ * @default false
168
+ */
169
+ verify: z.boolean(),
170
+ /**
171
+ * If set, we'll use this version number instead of trying to find a version from the list of `files`.
172
+ * @example "1.0.0"
173
+ * @default undefined
174
+ */
175
+ currentVersion: z.string().optional(),
176
+ /**
177
+ * If set, we'll attempt to update the version number to this version, instead of incrementing
178
+ * using "conventional-commit".
179
+ * @example "2.0.0"
180
+ * @default undefined
181
+ */
182
+ nextVersion: z.string().optional(),
183
+ /**
184
+ * Override the default conventional-changelog preset configuration.
185
+ */
186
+ changelogPresetConfig: ChangelogPresetConfigSchema.partial()
187
+ });
188
+ function defineConfig(config) {
189
+ return config;
190
+ }
191
+
192
+ // src/config/defaults.ts
193
+ var DEFAULT_CONFIG = {
194
+ path: process.cwd(),
195
+ changelog: "CHANGELOG.md",
196
+ files: [
197
+ "package.json",
198
+ "package-lock.json",
199
+ "npm-shrinkwrap.json",
200
+ "manifest.json",
201
+ // Chrome extensions
202
+ "bower.json"
203
+ ],
204
+ header: `# Changelog
205
+
206
+ All notable changes to this project will be documented in this file. See [fork-version](https://github.com/eglavin/fork-version) for commit guidelines.
207
+ `,
208
+ tagPrefix: "v",
209
+ commitAll: false,
210
+ debug: false,
211
+ dryRun: false,
212
+ gitTagFallback: true,
213
+ inspectVersion: false,
214
+ sign: false,
215
+ silent: false,
216
+ verify: false,
217
+ changelogPresetConfig: {}
218
+ };
219
+ function getCliArguments() {
220
+ return meow(
221
+ `
222
+ Usage:
223
+ $ fork-version [options]
224
+
225
+ Options:
226
+ --path [Default: process.cwd()]
227
+ The path fork-version will run from.
228
+ --changelog [Default: "CHANGELOG.md"]
229
+ Name of the changelog file.
230
+ --header, -H
231
+ The header to be used in the changelog.
232
+ --files, --file, -F [Default: ["bower.json", "manifest.json", "npm-shrinkwrap.json", "package-lock.json", "package.json"]]
233
+ Files to be updated.
234
+ --tag-prefix [Default: "v"]
235
+ Specify a prefix for the git tag "fork-version" will create.
236
+ --pre-release-tag [Default: undefined]
237
+ Make a pre-release with optional label, If value is a string it
238
+ will be used as the pre-release tag.
239
+
240
+ --commit-all
241
+ Commit all staged changes, not just files updated by fork-version.
242
+ --debug
243
+ If true, we'll output debug information.
244
+ --dry-run
245
+ If true, no output will be written to disk or committed.
246
+ --git-tag-fallback [Default: true]
247
+ If true and we cant find a version in the given files, we'll fallback
248
+ and attempt to use the latest git tag for the current version.
249
+ --inspect-version
250
+ If set, we'll gather information about the current version and exit.
251
+ --sign
252
+ Should we sign the git commit using GPG?
253
+ --silent
254
+ If true, no output will be written to stdout.
255
+ --verify
256
+ If true, allow git to run git commit hooks.
257
+
258
+ --current-version
259
+ If set, we'll use this version number instead of trying to find a
260
+ version in a "file".
261
+ --next-version
262
+ If set, we'll attempt to update the version number to this version,
263
+ instead of incrementing using "conventional-commit".
264
+ `,
265
+ {
266
+ importMeta: import.meta,
267
+ flags: {
268
+ path: { type: "string", default: process.cwd() },
269
+ changelog: { type: "string" },
270
+ header: { type: "string", shortFlag: "H" },
271
+ files: { type: "string", isMultiple: true, aliases: ["file"], shortFlag: "F" },
272
+ tagPrefix: { type: "string" },
273
+ preReleaseTag: { type: "string" },
274
+ commitAll: { type: "boolean" },
275
+ debug: { type: "boolean" },
276
+ dryRun: { type: "boolean" },
277
+ gitTagFallback: { type: "boolean" },
278
+ inspectVersion: { type: "boolean" },
279
+ sign: { type: "boolean" },
280
+ silent: { type: "boolean" },
281
+ verify: { type: "boolean" },
282
+ currentVersion: { type: "string" },
283
+ nextVersion: { type: "string" }
284
+ }
285
+ }
286
+ );
287
+ }
288
+ function getChangelogPresetConfig(usersChangelogPresetConfig) {
289
+ const preset = {
290
+ name: "conventionalcommits"
291
+ };
292
+ if (typeof conventionalChangelogConfigSpec.properties === "object") {
293
+ Object.entries(conventionalChangelogConfigSpec.properties).forEach(([key, value]) => {
294
+ if ("default" in value && value.default !== void 0) {
295
+ preset[key] = value.default;
296
+ }
297
+ });
298
+ }
299
+ if (usersChangelogPresetConfig && typeof usersChangelogPresetConfig === "object") {
300
+ Object.entries(usersChangelogPresetConfig).forEach(([key, value]) => {
301
+ if (value !== void 0) {
302
+ preset[key] = value;
303
+ }
304
+ });
305
+ }
306
+ return ChangelogPresetConfigSchema.passthrough().parse(preset);
307
+ }
308
+
309
+ // src/config/user-config.ts
310
+ async function getUserConfig() {
311
+ const cliArguments = getCliArguments();
312
+ const cwd = cliArguments.flags.path ? resolve(cliArguments.flags.path) : process.cwd();
313
+ const joycon = new JoyCon();
314
+ const configFilePath = await joycon.resolve({
315
+ files: ["fork.config.ts", "fork.config.js", "fork.config.cjs", "fork.config.mjs"],
316
+ cwd,
317
+ stopDir: parse(cwd).root
318
+ });
319
+ if (!configFilePath) {
320
+ return {
321
+ ...DEFAULT_CONFIG,
322
+ ...cliArguments.flags,
323
+ path: cwd,
324
+ changelogPresetConfig: getChangelogPresetConfig()
325
+ };
326
+ }
327
+ const foundConfig = await bundleRequire({ filepath: configFilePath });
328
+ const parsedConfig = ForkConfigSchema.partial().safeParse(
329
+ foundConfig.mod.default || foundConfig.mod
330
+ );
331
+ if (!parsedConfig.success) {
332
+ throw parsedConfig.error;
333
+ }
334
+ const usersConfig = {
335
+ ...DEFAULT_CONFIG,
336
+ ...parsedConfig.data,
337
+ ...cliArguments.flags
338
+ };
339
+ const files = mergeFiles(parsedConfig.data?.files, cliArguments.flags?.files);
340
+ return {
341
+ ...usersConfig,
342
+ path: cwd,
343
+ files: files.length > 0 ? files : DEFAULT_CONFIG.files,
344
+ changelogPresetConfig: getChangelogPresetConfig(usersConfig?.changelogPresetConfig)
345
+ };
346
+ }
347
+ function mergeFiles(configFiles, cliFiles) {
348
+ return Array.from(
349
+ new Set(
350
+ [].concat(
351
+ Array.isArray(configFiles) ? configFiles : [],
352
+ Array.isArray(cliFiles) ? cliFiles : []
353
+ )
354
+ )
355
+ );
356
+ }
357
+ async function getLatestGitTagVersion(tagPrefix) {
358
+ const gitTags = await gitSemverTags({ tagPrefix });
359
+ if (!gitTags.length) {
360
+ return "1.0.0";
361
+ }
362
+ const cleanedTags = [];
363
+ for (const tag of gitTags) {
364
+ const cleanedTag = semver3.clean(tag.replace(new RegExp(`^${tagPrefix}`), ""));
365
+ if (cleanedTag) {
366
+ cleanedTags.push(cleanedTag);
367
+ }
368
+ }
369
+ return cleanedTags.sort(semver3.rcompare)[0];
370
+ }
371
+ function getPriority(type) {
372
+ return ["patch", "minor", "major"].indexOf(type ?? "");
373
+ }
374
+ function getVersionType(version) {
375
+ const parseVersion = semver3.parse(version);
376
+ if (parseVersion?.major) {
377
+ return "major";
378
+ } else if (parseVersion?.minor) {
379
+ return "minor";
380
+ } else if (parseVersion?.patch) {
381
+ return "patch";
382
+ }
383
+ return void 0;
384
+ }
385
+ function getReleaseType(releaseType, currentVersion, preReleaseTag) {
386
+ if (!preReleaseTag) {
387
+ return releaseType;
388
+ }
389
+ const currentVersionsIsPreRelease = Array.isArray(semver3.prerelease(currentVersion));
390
+ if (currentVersionsIsPreRelease) {
391
+ const currentReleaseType = getVersionType(currentVersion);
392
+ if (currentReleaseType === releaseType || getPriority(currentReleaseType) > getPriority(releaseType)) {
393
+ return "prerelease";
394
+ }
395
+ }
396
+ return `pre${releaseType}`;
397
+ }
398
+
399
+ // src/process/version.ts
400
+ async function getCurrentVersion(config, logger, fileManager) {
401
+ const files = [];
402
+ const versions = /* @__PURE__ */ new Set();
403
+ for (const file of config.files) {
404
+ const fileState = fileManager.read(file);
405
+ if (fileState) {
406
+ files.push(fileState);
407
+ if (config.currentVersion) {
408
+ continue;
409
+ }
410
+ versions.add(fileState.version);
411
+ }
412
+ }
413
+ if (config.currentVersion) {
414
+ versions.add(config.currentVersion);
415
+ }
416
+ if (versions.size === 0) {
417
+ if (config.gitTagFallback) {
418
+ const version = await getLatestGitTagVersion(config.tagPrefix);
419
+ if (version) {
420
+ return {
421
+ files: [],
422
+ version
423
+ };
424
+ }
425
+ }
426
+ throw new Error("Unable to find current version");
427
+ } else if (versions.size > 1) {
428
+ throw new Error("Found multiple versions");
429
+ }
430
+ const currentVersion = versions.entries().next().value[0];
431
+ if (config.inspectVersion) {
432
+ console.log(currentVersion);
433
+ process.exit(0);
434
+ }
435
+ logger.log(`Current version: ${currentVersion}`);
436
+ return {
437
+ files,
438
+ version: currentVersion
439
+ };
440
+ }
441
+ async function getNextVersion(config, logger, currentVersion) {
442
+ if (config.nextVersion && semver3.valid(config.nextVersion)) {
443
+ logger.log(`Next version: ${config.nextVersion}`);
444
+ return { version: config.nextVersion };
445
+ }
446
+ const isPreMajor = semver3.lt(currentVersion, "1.0.0");
447
+ let recommendedBump;
448
+ try {
449
+ recommendedBump = await conventionalRecommendedBump({
450
+ preset: {
451
+ name: "conventionalcommits",
452
+ ...config.changelogPresetConfig,
453
+ preMajor: isPreMajor
454
+ },
455
+ path: config.path,
456
+ tagPrefix: config.tagPrefix,
457
+ cwd: config.path
458
+ });
459
+ } catch (error) {
460
+ throw new Error(`[conventional-recommended-bump] Unable to determine next version`);
461
+ }
462
+ if (recommendedBump.releaseType) {
463
+ const releaseType = getReleaseType(
464
+ recommendedBump.releaseType,
465
+ currentVersion,
466
+ config.preReleaseTag
467
+ );
468
+ const state = {
469
+ ...recommendedBump,
470
+ preMajor: isPreMajor,
471
+ releaseType,
472
+ version: semver3.inc(
473
+ currentVersion,
474
+ releaseType,
475
+ typeof config.preReleaseTag === "string" ? config.preReleaseTag : void 0
476
+ ) ?? ""
477
+ };
478
+ logger.log(`Next version: ${state.version} (${state.releaseType})`);
479
+ return state;
480
+ }
481
+ throw new Error("Unable to find next version");
482
+ }
483
+ function fileExists(filePath) {
484
+ try {
485
+ return lstatSync(filePath).isFile();
486
+ } catch (e) {
487
+ return false;
488
+ }
489
+ }
490
+
491
+ // src/process/changelog.ts
492
+ var RELEASE_PATTERN = /(^#+ \[?[0-9]+\.[0-9]+\.[0-9]+|<a name=)/m;
493
+ function getOldReleaseContent(filePath, exists) {
494
+ if (exists) {
495
+ const fileContents = readFileSync(filePath, "utf-8");
496
+ const oldContentStart = fileContents.search(RELEASE_PATTERN);
497
+ if (oldContentStart !== -1) {
498
+ return fileContents.substring(oldContentStart);
499
+ }
500
+ }
501
+ return "";
502
+ }
503
+ function getNewReleaseContent(config, logger, nextVersion) {
504
+ return new Promise((onResolve) => {
505
+ let newContent = "";
506
+ conventionalChangelog(
507
+ {
508
+ preset: {
509
+ name: "conventionalcommits",
510
+ ...config.changelogPresetConfig
511
+ },
512
+ tagPrefix: config.tagPrefix,
513
+ warn: (...message) => logger.error("conventional-changelog: ", ...message),
514
+ cwd: config.path
515
+ },
516
+ {
517
+ version: nextVersion
518
+ },
519
+ {
520
+ merges: null,
521
+ path: config.path
522
+ }
523
+ ).on("error", (error) => {
524
+ logger.error("conventional-changelog: Unable to parse changes");
525
+ throw error;
526
+ }).on("data", (chunk) => {
527
+ newContent += chunk.toString();
528
+ }).on("end", () => {
529
+ onResolve(newContent);
530
+ });
531
+ });
532
+ }
533
+ async function updateChangelog(config, logger, nextVersion) {
534
+ if (config.header.search(RELEASE_PATTERN) !== -1) {
535
+ throw new Error("Header cannot contain release pattern");
536
+ }
537
+ const changelogPath = resolve(config.path, config.changelog);
538
+ if (!config.dryRun && !fileExists(changelogPath)) {
539
+ logger.log(`Creating Changelog file: ${changelogPath}`);
540
+ writeFileSync(changelogPath, "\n", "utf8");
541
+ }
542
+ const oldContent = getOldReleaseContent(changelogPath, fileExists(changelogPath));
543
+ const newContent = await getNewReleaseContent(config, logger, nextVersion);
544
+ logger.log(`Updating Changelog: ${changelogPath}`);
545
+ if (!config.dryRun && newContent) {
546
+ writeFileSync(
547
+ changelogPath,
548
+ `${config.header}
549
+ ${newContent}
550
+ ${oldContent}
551
+ `,
552
+ "utf8"
553
+ );
554
+ }
555
+ return {
556
+ changelogPath,
557
+ oldContent,
558
+ newContent
559
+ };
560
+ }
561
+ var Git = class {
562
+ constructor(config, logger) {
563
+ this.config = config;
564
+ this.logger = logger;
565
+ this.add = this.add.bind(this);
566
+ this.commit = this.commit.bind(this);
567
+ this.tag = this.tag.bind(this);
568
+ this.revParse = this.revParse.bind(this);
569
+ }
570
+ add(...args) {
571
+ return this.execGit("add", args.filter(Boolean));
572
+ }
573
+ commit(...args) {
574
+ return this.execGit("commit", args.filter(Boolean));
575
+ }
576
+ tag(...args) {
577
+ return this.execGit("tag", args.filter(Boolean));
578
+ }
579
+ revParse(...args) {
580
+ return this.execGit("rev-parse", args.filter(Boolean));
581
+ }
582
+ execGit(command, args) {
583
+ if (this.config.dryRun) {
584
+ return Promise.resolve("");
585
+ }
586
+ this.logger.debug(`Executing: git ${command} ${args.join(" ")}`);
587
+ return new Promise((onResolve, onReject) => {
588
+ execFile(
589
+ "git",
590
+ [command, ...args],
591
+ {
592
+ cwd: this.config.path
593
+ },
594
+ (error, stdout, stderr) => {
595
+ if (error) {
596
+ this.logger.error(`git ${command}:`);
597
+ onReject(error);
598
+ }
599
+ onResolve(stdout ? stdout : stderr);
600
+ }
601
+ );
602
+ });
603
+ }
604
+ };
605
+
606
+ // src/utils/format-commit-message.ts
607
+ function formatCommitMessage(message, version) {
608
+ if (!message) {
609
+ message = "chore(release): {{currentTag}}";
610
+ }
611
+ return message.replace(new RegExp("{{currentTag}}", "g"), version);
612
+ }
613
+
614
+ // src/process/commit.ts
615
+ async function commitChanges(config, logger, files, nextVersion) {
616
+ const git = new Git(config, logger);
617
+ logger.log("Committing changes");
618
+ const filesToCommit = [];
619
+ if (fileExists(resolve(config.path, config.changelog))) {
620
+ filesToCommit.push(resolve(config.path, config.changelog));
621
+ }
622
+ for (const file of files) {
623
+ filesToCommit.push(file.path);
624
+ }
625
+ if (filesToCommit.length === 0) {
626
+ return {
627
+ filesToCommit
628
+ };
629
+ }
630
+ const shouldVerify = config.verify ? void 0 : "--no-verify";
631
+ const shouldSign = config.sign ? "--gpg-sign" : void 0;
632
+ if (config.commitAll) {
633
+ return {
634
+ filesToCommit,
635
+ gitAddOutput: await git.add("--all"),
636
+ gitCommitOutput: await git.commit(
637
+ shouldVerify,
638
+ shouldSign,
639
+ "--message",
640
+ formatCommitMessage(config.changelogPresetConfig?.releaseCommitMessageFormat, nextVersion)
641
+ )
642
+ };
643
+ }
644
+ return {
645
+ filesToCommit,
646
+ gitAddOutput: await git.add(...filesToCommit),
647
+ gitCommitOutput: await git.commit(
648
+ shouldVerify,
649
+ shouldSign,
650
+ ...filesToCommit,
651
+ "--message",
652
+ formatCommitMessage(config.changelogPresetConfig?.releaseCommitMessageFormat, nextVersion)
653
+ )
654
+ };
655
+ }
656
+
657
+ // src/process/tag.ts
658
+ async function tagChanges(config, logger, nextVersion) {
659
+ const git = new Git(config, logger);
660
+ const tag = `${config.tagPrefix}${nextVersion}`;
661
+ logger.log(`Creating Tag: ${tag}`);
662
+ const gitTagOutput = await git.tag(
663
+ config.sign ? "--sign" : "--annotate",
664
+ tag,
665
+ "--message",
666
+ formatCommitMessage(config.changelogPresetConfig?.releaseCommitMessageFormat, nextVersion)
667
+ );
668
+ return {
669
+ gitTagOutput
670
+ };
671
+ }
672
+
673
+ // src/libs/stringify-package.ts
674
+ var DEFAULT_INDENT = 2;
675
+ var CRLF = "\r\n";
676
+ var LF = "\n";
677
+ function stringifyPackage(data, indent, newline) {
678
+ const stringified = JSON.stringify(data, null, indent ?? DEFAULT_INDENT);
679
+ if (newline === CRLF) {
680
+ return stringified.replace(new RegExp(LF, "g"), CRLF);
681
+ }
682
+ return stringified;
683
+ }
684
+
685
+ // src/strategies/json-package.ts
686
+ var JSONPackage = class {
687
+ constructor(config, logger) {
688
+ this.config = config;
689
+ this.logger = logger;
690
+ }
691
+ read(fileName) {
692
+ const filePath = resolve(this.config.path, fileName);
693
+ if (fileExists(filePath)) {
694
+ const fileContents = readFileSync(filePath, "utf8");
695
+ const parsedJson = JSON.parse(fileContents);
696
+ if (parsedJson.version) {
697
+ return {
698
+ name: fileName,
699
+ path: filePath,
700
+ version: parsedJson.version,
701
+ isPrivate: typeof parsedJson?.private === "boolean" ? parsedJson.private : true
702
+ };
703
+ }
704
+ this.logger.warn(`Unable to determine json package file: ${fileName}`);
705
+ }
706
+ }
707
+ write(filePath, newVersion) {
708
+ const fileContents = readFileSync(filePath, "utf8");
709
+ const parsedJson = JSON.parse(fileContents);
710
+ parsedJson.version = newVersion;
711
+ if (parsedJson.packages?.[""]) {
712
+ parsedJson.packages[""].version = newVersion;
713
+ }
714
+ writeFileSync(
715
+ filePath,
716
+ stringifyPackage(parsedJson, detectIndent(fileContents).amount, detectNewline(fileContents)),
717
+ "utf8"
718
+ );
719
+ }
720
+ };
721
+ var PlainText = class {
722
+ constructor(config, logger) {
723
+ this.config = config;
724
+ this.logger = logger;
725
+ }
726
+ read(fileName) {
727
+ const filePath = resolve(this.config.path, fileName);
728
+ if (fileExists(filePath)) {
729
+ const fileContents = readFileSync(filePath, "utf8");
730
+ return {
731
+ name: fileName,
732
+ path: filePath,
733
+ version: fileContents || ""
734
+ };
735
+ }
736
+ this.logger.warn(`Unable to determine plain text file: ${fileName}`);
737
+ }
738
+ write(filePath, newVersion) {
739
+ writeFileSync(filePath, newVersion, "utf8");
740
+ }
741
+ };
742
+
743
+ // src/strategies/file-manager.ts
744
+ var FileManager = class {
745
+ constructor(config, logger) {
746
+ this.config = config;
747
+ this.logger = logger;
748
+ this.JSONPackage = new JSONPackage(config, logger);
749
+ this.PlainText = new PlainText(config, logger);
750
+ }
751
+ JSONPackage;
752
+ PlainText;
753
+ /**
754
+ * Get the state from the given file name.
755
+ *
756
+ * @example
757
+ * ```ts
758
+ * fileManager.read("package.json");
759
+ * ```
760
+ *
761
+ * @returns
762
+ * ```json
763
+ * { "name": "package.json", "path": "/path/to/package.json", "version": "1.2.3", "isPrivate": true }
764
+ * ```
765
+ */
766
+ read(fileName) {
767
+ if (fileName.toLowerCase().endsWith(".json")) {
768
+ return this.JSONPackage.read(fileName);
769
+ } else if (fileName.toLowerCase().endsWith("version.txt")) {
770
+ return this.PlainText.read(fileName);
771
+ }
772
+ this.logger.error(`Unsupported file type: ${fileName}`);
773
+ }
774
+ /**
775
+ * Write the new version to the given file path.
776
+ *
777
+ * @example
778
+ * ```ts
779
+ * fileManager.write("/path/to/package.json", "1.2.3");
780
+ * ```
781
+ */
782
+ write(filePath, newVersion) {
783
+ if (this.config.dryRun) {
784
+ this.logger.log(`[Dry run]: Not updating ${filePath}`);
785
+ return;
786
+ }
787
+ if (filePath.toLowerCase().endsWith(".json")) {
788
+ return this.JSONPackage.write(filePath, newVersion);
789
+ } else if (filePath.toLowerCase().endsWith("version.txt")) {
790
+ return this.PlainText.write(filePath, newVersion);
791
+ }
792
+ this.logger.error(`Unsupported file type: ${filePath}`);
793
+ }
794
+ };
795
+
796
+ export { FileManager, ForkConfigSchema, Git, commitChanges, defineConfig, getCurrentVersion, getNextVersion, getUserConfig, tagChanges, updateChangelog };
797
+ //# sourceMappingURL=out.js.map
798
+ //# sourceMappingURL=chunk-S2VPLFG2.js.map