@flex-development/mlly 1.0.0-alpha.11 → 1.0.0-alpha.13

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 (95) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/README.md +1 -1
  3. package/dist/interfaces/options-get-format.d.mts +3 -13
  4. package/dist/interfaces/options-get-source.d.mts +3 -13
  5. package/dist/interfaces/options-parse-subpath.d.mts +18 -0
  6. package/dist/interfaces/parsed-subpath.d.mts +5 -1
  7. package/dist/internal/regex-invalid-segment.d.mts +14 -0
  8. package/dist/internal/regex-invalid-segment.mjs +11 -0
  9. package/dist/internal/regex-invalid-segment.mjs.map +6 -0
  10. package/dist/internal/resolver.mjs +6 -9
  11. package/dist/internal/resolver.mjs.map +1 -1
  12. package/dist/internal/validate-array-set.d.mts +22 -0
  13. package/dist/internal/validate-array-set.mjs +11 -0
  14. package/dist/internal/validate-array-set.mjs.map +6 -0
  15. package/dist/internal/validate-map.d.mts +23 -0
  16. package/dist/internal/validate-map.mjs +11 -0
  17. package/dist/internal/validate-map.mjs.map +6 -0
  18. package/dist/internal/validate-set.d.mts +4 -5
  19. package/dist/internal/validate-set.mjs.map +1 -1
  20. package/dist/utils/fill-modules.d.mts +1 -0
  21. package/dist/utils/fill-modules.mjs +7 -1
  22. package/dist/utils/fill-modules.mjs.map +1 -1
  23. package/dist/utils/find-requires.mjs +1 -1
  24. package/dist/utils/find-subpath.d.mts +2 -1
  25. package/dist/utils/find-subpath.mjs +2 -0
  26. package/dist/utils/find-subpath.mjs.map +1 -1
  27. package/dist/utils/get-format.d.mts +8 -1
  28. package/dist/utils/get-format.mjs +22 -11
  29. package/dist/utils/get-format.mjs.map +1 -1
  30. package/dist/utils/get-source.d.mts +7 -0
  31. package/dist/utils/get-source.mjs +13 -6
  32. package/dist/utils/get-source.mjs.map +1 -1
  33. package/dist/utils/is-absolute-specifier.d.mts +1 -0
  34. package/dist/utils/is-absolute-specifier.mjs +2 -0
  35. package/dist/utils/is-absolute-specifier.mjs.map +1 -1
  36. package/dist/utils/is-bare-specifier.d.mts +1 -0
  37. package/dist/utils/is-bare-specifier.mjs +2 -0
  38. package/dist/utils/is-bare-specifier.mjs.map +1 -1
  39. package/dist/utils/is-exports-sugar.mjs +1 -1
  40. package/dist/utils/is-exports-sugar.mjs.map +1 -1
  41. package/dist/utils/is-relative-specifier.mjs.map +1 -1
  42. package/dist/utils/parse-module-id.d.mts +1 -3
  43. package/dist/utils/parse-module-id.mjs +3 -0
  44. package/dist/utils/parse-module-id.mjs.map +1 -1
  45. package/dist/utils/parse-subpath.d.mts +1 -2
  46. package/dist/utils/parse-subpath.mjs +115 -5
  47. package/dist/utils/parse-subpath.mjs.map +1 -1
  48. package/dist/utils/read-package-json.mjs +7 -5
  49. package/dist/utils/read-package-json.mjs.map +1 -1
  50. package/dist/utils/resolve-alias.mjs +3 -2
  51. package/dist/utils/resolve-alias.mjs.map +1 -1
  52. package/dist/utils/resolve-module.mjs +16 -1
  53. package/dist/utils/resolve-module.mjs.map +1 -1
  54. package/dist/utils/to-bare-specifier.mjs +8 -10
  55. package/dist/utils/to-bare-specifier.mjs.map +1 -1
  56. package/dist/utils/to-relative-specifier.d.mts +2 -0
  57. package/dist/utils/to-relative-specifier.mjs +3 -0
  58. package/dist/utils/to-relative-specifier.mjs.map +1 -1
  59. package/dist/utils/to-url.d.mts +2 -3
  60. package/dist/utils/to-url.mjs.map +1 -1
  61. package/dist/utils/validate-assertions.mjs +2 -0
  62. package/dist/utils/validate-assertions.mjs.map +1 -1
  63. package/dist/utils/validate-exports.d.mts +2 -2
  64. package/dist/utils/validate-exports.mjs +2 -2
  65. package/dist/utils/validate-exports.mjs.map +1 -1
  66. package/package.json +34 -41
  67. package/src/interfaces/options-get-format.ts +2 -14
  68. package/src/interfaces/options-get-source.ts +2 -14
  69. package/src/interfaces/options-parse-subpath.ts +20 -0
  70. package/src/interfaces/parsed-subpath.ts +10 -1
  71. package/src/internal/regex-invalid-segment.ts +23 -0
  72. package/src/internal/resolver.ts +7 -22
  73. package/src/internal/validate-array-set.ts +32 -0
  74. package/src/internal/validate-map.ts +33 -0
  75. package/src/internal/validate-set.ts +4 -5
  76. package/src/utils/fill-modules.ts +10 -1
  77. package/src/utils/find-requires.ts +1 -1
  78. package/src/utils/find-subpath.ts +11 -2
  79. package/src/utils/get-format.ts +33 -12
  80. package/src/utils/get-source.ts +21 -6
  81. package/src/utils/is-absolute-specifier.ts +5 -0
  82. package/src/utils/is-bare-specifier.ts +5 -0
  83. package/src/utils/is-exports-sugar.ts +1 -1
  84. package/src/utils/is-relative-specifier.ts +1 -0
  85. package/src/utils/parse-module-id.ts +6 -3
  86. package/src/utils/parse-subpath.ts +154 -9
  87. package/src/utils/read-package-json.ts +8 -3
  88. package/src/utils/resolve-alias.ts +3 -2
  89. package/src/utils/resolve-module.ts +40 -11
  90. package/src/utils/to-bare-specifier.ts +10 -12
  91. package/src/utils/to-relative-specifier.ts +7 -0
  92. package/src/utils/to-url.ts +2 -3
  93. package/src/utils/validate-assertions.ts +2 -0
  94. package/src/utils/validate-exports.ts +5 -5
  95. package/changelog.config.ts +0 -404
@@ -6,6 +6,10 @@
6
6
  import type { ResolveModuleOptions } from '#src/interfaces'
7
7
  import isFunction from '#src/internal/is-function'
8
8
  import Resolver from '#src/internal/resolver'
9
+ import validateArraySet from '#src/internal/validate-array-set'
10
+ import validateBoolean from '#src/internal/validate-boolean'
11
+ import validateString from '#src/internal/validate-string'
12
+ import validateURLString from '#src/internal/validate-url-string'
9
13
  import { ErrorCode, type NodeError } from '@flex-development/errnode'
10
14
  import { isBuiltin } from '@flex-development/is-builtin'
11
15
  import pathe from '@flex-development/pathe'
@@ -57,6 +61,16 @@ const resolveModule = async (
57
61
  preserveSymlinks = false
58
62
  } = options
59
63
 
64
+ // ensure specifier is a string
65
+ validateString(specifier, 'specifier')
66
+
67
+ // ensure option schemas
68
+ validateString(condition, 'options.condition')
69
+ validateArraySet(conditions, 'options.conditions')
70
+ validateArraySet(extensions, 'options.extensions')
71
+ validateURLString(parent, 'options.parent')
72
+ validateBoolean(preserveSymlinks, 'options.preserveSymlinks')
73
+
60
74
  /**
61
75
  * Module resolver.
62
76
  *
@@ -65,21 +79,35 @@ const resolveModule = async (
65
79
  const resolver: Resolver = new Resolver()
66
80
 
67
81
  /**
68
- * Module ids to try resolving.
82
+ * Boolean indicating only module id should be tried for resolution.
69
83
  *
70
- * @const {string[]} tries
84
+ * @const {boolean} onetry
71
85
  */
72
- const tries: string[] =
86
+ const onetry: boolean =
73
87
  isBuiltin(specifier) ||
74
88
  (/^\S+:/.test(specifier) && !specifier.startsWith('file:'))
75
- ? []
76
- : [...extensions]
77
- .flatMap(ext => [
78
- specifier + (ext = pathe.formatExt(ext)),
79
- specifier.startsWith('#') ? specifier + '/index' : '',
80
- specifier + '/index' + ext
81
- ])
82
- .filter(id => id.length > 0)
89
+
90
+ /**
91
+ * Module ids to try resolving.
92
+ *
93
+ * @const {string[]} tries
94
+ */
95
+ const tries: string[] = onetry
96
+ ? []
97
+ : [...extensions]
98
+ .flatMap(ext => [
99
+ specifier + (ext = pathe.formatExt(ext)),
100
+ specifier.startsWith('#') ? specifier + '/index' : '',
101
+ specifier + '/index' + ext
102
+ ])
103
+ .filter(id => id.length > 0)
104
+
105
+ // try @types resolution
106
+ if (!onetry) {
107
+ specifier.startsWith('@types')
108
+ ? tries.unshift(specifier + '/index.d.ts')
109
+ : tries.unshift('@types/' + specifier + '/index.d.ts')
110
+ }
83
111
 
84
112
  // ensure attempt to resolve original specifier is first
85
113
  tries.unshift(specifier)
@@ -93,6 +121,7 @@ const resolveModule = async (
93
121
  * @const {Set<ErrorCode>} ignore
94
122
  */
95
123
  const ignore: Set<ErrorCode> = new Set<ErrorCode>([
124
+ ErrorCode.ERR_INVALID_MODULE_SPECIFIER,
96
125
  ErrorCode.ERR_MODULE_NOT_FOUND,
97
126
  ErrorCode.ERR_PACKAGE_PATH_NOT_EXPORTED,
98
127
  ErrorCode.ERR_UNSUPPORTED_DIR_IMPORT
@@ -5,6 +5,7 @@
5
5
 
6
6
  import type { PackageScope, ParsedModuleId } from '#src/interfaces'
7
7
  import regexp from '#src/internal/escape-reg-exp'
8
+ import validateSet from '#src/internal/validate-set'
8
9
  import validateURLString from '#src/internal/validate-url-string'
9
10
  import type { ModuleId } from '#src/types'
10
11
  import {
@@ -71,6 +72,7 @@ const toBareSpecifier = (
71
72
  ): string => {
72
73
  validateURLString(specifier, 'specifier')
73
74
  validateURLString(parent, 'parent')
75
+ validateSet(conditions, 'conditions')
74
76
 
75
77
  // ensure specifier is a string
76
78
  if (specifier instanceof URL) specifier = specifier.href
@@ -102,26 +104,22 @@ const toBareSpecifier = (
102
104
  *
103
105
  * @const {Nullable<PackageScope>} scope
104
106
  */
105
- const scope: Nullable<PackageScope> = lookupPackageScope(
106
- url,
107
- pathToFileURL('.')
108
- )
107
+ const scope: Nullable<PackageScope> =
108
+ lookupPackageScope(url, pathToFileURL('.')) ??
109
+ lookupPackageScope(specifier, pathToFileURL('.'))
109
110
 
110
111
  // throw if package scope was not found
111
112
  if (!scope) {
112
113
  throw new ERR_OPERATION_FAILED(`Package scope for '${specifier}' not found`)
113
114
  }
114
115
 
115
- // get directory containing package.json file and package.json object
116
- const { dir: pkgdir, pkgjson } = scope
117
-
118
116
  // get package exports and name
119
- const { exports, main, name = '', types } = pkgjson
117
+ const { exports, main, name = '', types } = scope.pkgjson
120
118
 
121
119
  // convert specifier to bare specifier
122
120
  specifier = url.pathname.includes(name)
123
121
  ? name + url.pathname.replace(new RegExp(`.*?${regexp(name)}`), '')
124
- : name + specifier.replace(fileURLToPath(pkgdir.replace(/\/$/, '')), '')
122
+ : name + specifier.replace(fileURLToPath(scope.dir.replace(/\/$/, '')), '')
125
123
 
126
124
  /**
127
125
  * Parsed module specifier.
@@ -145,7 +143,7 @@ const toBareSpecifier = (
145
143
 
146
144
  // check if specifier contains valid subpath export
147
145
  try {
148
- parseSubpath(specifier, exports, { dir: pkgdir, parent })
146
+ parseSubpath(specifier, exports, { dir: scope.dir, parent })
149
147
  } catch (e: unknown) {
150
148
  // try finding defined subpath if specifier is invalid package path
151
149
  if ((e as NodeError).code === ErrorCode.ERR_PACKAGE_PATH_NOT_EXPORTED) {
@@ -164,14 +162,14 @@ const toBareSpecifier = (
164
162
  */
165
163
  let subpath: Nullable<string> = findSubpath(target, exports, {
166
164
  conditions,
167
- dir: pkgdir,
165
+ dir: scope.dir,
168
166
  parent
169
167
  })
170
168
 
171
169
  // throw if target was not matched to a subpath
172
170
  if (subpath === null) {
173
171
  throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
174
- fileURLToPath(pkgdir),
172
+ fileURLToPath(scope.dir),
175
173
  id.path,
176
174
  fileURLToPath(parent)
177
175
  )
@@ -3,7 +3,9 @@
3
3
  * @module mlly/utils/toRelativeSpecifier
4
4
  */
5
5
 
6
+ import validateURLString from '#src/internal/validate-url-string'
6
7
  import type { ModuleId } from '#src/types'
8
+ import type { NodeError } from '@flex-development/errnode'
7
9
  import pathe from '@flex-development/pathe'
8
10
  import { URL, fileURLToPath } from 'node:url'
9
11
 
@@ -21,8 +23,13 @@ import { URL, fileURLToPath } from 'node:url'
21
23
  * @param {ModuleId} specifier - Module specifier to convert
22
24
  * @param {ModuleId} parent - Parent module URL or path to resolve from
23
25
  * @return {string} `specifier` as relative specifier
26
+ * @throws {NodeError<TypeError>} If either `specifier` or `parent` is not a
27
+ * string or an instance of {@linkcode URL}
24
28
  */
25
29
  const toRelativeSpecifier = (specifier: ModuleId, parent: ModuleId): string => {
30
+ validateURLString(specifier, 'specifier')
31
+ validateURLString(parent, 'parent')
32
+
26
33
  // convert file url objects to file url strings
27
34
  if (parent instanceof URL) parent = parent.href
28
35
  if (specifier instanceof URL) specifier = specifier.href
@@ -17,10 +17,9 @@ import { URL, pathToFileURL } from 'node:url'
17
17
  *
18
18
  * @param {ModuleId} id - Module id to evaluate
19
19
  * @param {ModuleId?} [base=pathToFileURL('./')] - Base URL to resolve against
20
- * if `id` is not absolute
21
- * @return {URL} `id` as instance of `URL`
20
+ * @return {URL} `id` as instance of {@linkcode URL}
22
21
  * @throws {NodeError<TypeError>} If either `id` or `base` is not a string or an
23
- * instance of `URL`
22
+ * instance of {@linkcode URL}
24
23
  */
25
24
  const toURL = (id: ModuleId, base: ModuleId = pathToFileURL('./')): URL => {
26
25
  validateURLString(id, 'id')
@@ -7,6 +7,7 @@ import type { Format } from '#src/enums'
7
7
  import { AssertType } from '#src/enums'
8
8
  import type { ImportAssertions } from '#src/interfaces'
9
9
  import FORMAT_TYPE_MAP from '#src/internal/format-type-map'
10
+ import validateObject from '#src/internal/validate-object'
10
11
  import validateString from '#src/internal/validate-string'
11
12
  import validateURLString from '#src/internal/validate-url-string'
12
13
  import type { ModuleId } from '#src/types'
@@ -39,6 +40,7 @@ const validateAssertions = (
39
40
  ): true => {
40
41
  validateURLString(url, 'url')
41
42
  validateString(format, 'format')
43
+ validateObject(assertions, 'assertions')
42
44
 
43
45
  // ensure url is a string
44
46
  if (url instanceof URL) url = url.href
@@ -26,8 +26,8 @@ import { URL, fileURLToPath } from 'node:url'
26
26
  * @param {ModuleId} pkg - URL of relevant `package.json` file
27
27
  * @param {ModuleId} parent - URL of module to resolve from
28
28
  * @return {true} `true` if `exports` configuration and schema are valid
29
- * @throws {NodeError<Error | TypeError>} If either `pkg` or `parent` is not an
30
- * instance of {@linkcode URL} or a string, or if `exports` configuration or
29
+ * @throws {NodeError<Error | TypeError>} If either `pkg` or `parent` is not a
30
+ * string or an instance of {@linkcode URL}, or if `exports` configuration or
31
31
  * schema is invalid
32
32
  */
33
33
  const validateExports = (
@@ -35,6 +35,9 @@ const validateExports = (
35
35
  pkg: ModuleId,
36
36
  parent: ModuleId
37
37
  ): true => {
38
+ validateURLString(pkg, 'pkg')
39
+ validateURLString(parent, 'parent')
40
+
38
41
  switch (true) {
39
42
  case Array.isArray(exports):
40
43
  for (const item of exports as unknown[]) {
@@ -70,9 +73,6 @@ const validateExports = (
70
73
  default:
71
74
  exports = exports as Record<string, Exports>
72
75
 
73
- validateURLString(pkg, 'pkg')
74
- validateURLString(parent, 'parent')
75
-
76
76
  /**
77
77
  * Keys defined in {@linkcode exports}.
78
78
  *
@@ -1,404 +0,0 @@
1
- /**
2
- * @file Changelog Configuration
3
- * @module config/changelog
4
- * @see https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-conventionalcommits
5
- * @see https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-core
6
- * @see https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-writer
7
- * @see https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-commits-parser
8
- * @see https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/git-raw-commits
9
- */
10
-
11
- import pathe from '@flex-development/pathe'
12
- import { CompareResult, isNIL } from '@flex-development/tutils'
13
- import addStream from 'add-stream'
14
- import conventionalChangelog from 'conventional-changelog'
15
- import type { Options } from 'conventional-changelog-core'
16
- import type {
17
- CommitGroup,
18
- GeneratedContext
19
- } from 'conventional-changelog-writer'
20
- import type { Commit, ICommit } from 'conventional-commits-parser'
21
- import dateformat from 'dateformat'
22
- import type mri from 'mri'
23
- import {
24
- createReadStream,
25
- createWriteStream,
26
- readFileSync,
27
- type ReadStream,
28
- type WriteStream
29
- } from 'node:fs'
30
- import type { Readable } from 'node:stream'
31
- import sade from 'sade'
32
- import semver from 'semver'
33
- import tempfile from 'tempfile'
34
- import pkg from './package.json' assert { type: 'json' }
35
-
36
- /**
37
- * CLI flags.
38
- */
39
- interface Flags {
40
- /**
41
- * Output unreleased changelog.
42
- *
43
- * To the set the current version, pass a string value.
44
- *
45
- * @example
46
- * '1.0.0-alpha.7'
47
- * @example
48
- * true
49
- *
50
- * @default true
51
- */
52
- 'output-unreleased'?: boolean | string
53
-
54
- /**
55
- * Number of releases to be generated.
56
- *
57
- * If `0`, the changelog will be regenerated and the output file will be
58
- * overwritten.
59
- *
60
- * @default 1
61
- */
62
- 'release-count'?: number
63
-
64
- /**
65
- * Output content to {@linkcode infile}.
66
- *
67
- * @default false
68
- */
69
- 'same-file'?: boolean
70
-
71
- /**
72
- * Enable verbose output.
73
- *
74
- * @default false
75
- */
76
- debug?: boolean
77
-
78
- /**
79
- * Read CHANGELOG from this file.
80
- */
81
- infile?: string
82
-
83
- /**
84
- * Write content to this file.
85
- *
86
- * **Note**: Requires {@linkcode write} to be `true`.
87
- */
88
- outfile?: string
89
-
90
- /**
91
- * Write content to file instead of {@linkcode process.stdout}.
92
- *
93
- * @default false
94
- */
95
- write?: boolean
96
- }
97
-
98
- sade('changelog', true)
99
- .option('-d, --debug', 'Enable verbose output', false)
100
- .option('-i, --infile', 'Read CHANGELOG from this file')
101
- .option('-o, --outfile', 'Write content to this file (requires --write)')
102
- .option('-r, --release-count', 'Number of releases to be generated', 1)
103
- .option('-s, --same-file', 'Output content to infile', false)
104
- .option('-u, --output-unreleased', 'Output unreleased changelog')
105
- .option('-w, --write', 'Write content to file', false)
106
- .action((flags: mri.Argv<Flags>): void => {
107
- const {
108
- 'release-count': releaseCount = 1,
109
- debug = false,
110
- write = false
111
- } = flags
112
- let {
113
- 'output-unreleased': outputUnreleased = true,
114
- infile,
115
- 'same-file': samefile,
116
- outfile
117
- } = flags
118
-
119
- // convert possible 'false' or 'true' to boolean value
120
- if (outputUnreleased === 'false' || outputUnreleased === 'true') {
121
- outputUnreleased = JSON.parse(outputUnreleased)
122
- }
123
-
124
- /**
125
- * Regex used to extract a release version from a string containing
126
- * Git tags.
127
- *
128
- * @const {RegExp} vgx
129
- */
130
- const vgx: RegExp = pkg.tagPrefix
131
- ? new RegExp(`tag:\\s*[=]?${pkg.tagPrefix}(.+?)[,)]`, 'gi')
132
- : /tag:\s*[=v]?(.+?)[),]/gi
133
-
134
- /**
135
- * Changelog content stream.
136
- *
137
- * @const {Readable} changelog
138
- */
139
- const changelog: Readable = conventionalChangelog(
140
- {
141
- append: false,
142
- debug: debug ? console.debug.bind(console) : undefined,
143
- outputUnreleased:
144
- typeof outputUnreleased === 'boolean'
145
- ? outputUnreleased
146
- : typeof outputUnreleased === 'string'
147
- ? !!outputUnreleased.trim()
148
- : false,
149
- pkg: { path: pathe.resolve('package.json') },
150
- // @ts-expect-error ts(2322)
151
- preset: {
152
- header: '',
153
- name: 'conventionalcommits',
154
- releaseCommitMessageFormat: 'release: {{currentTag}}',
155
- types: [
156
- { section: ':package: Build', type: 'build' },
157
- { section: ':house_with_garden: Housekeeping', type: 'chore' },
158
- { section: ':robot: Continuous Integration', type: 'ci' },
159
- { section: ':pencil: Documentation', type: 'docs' },
160
- { section: ':sparkles: Features', type: 'feat' },
161
- { section: ':bug: Fixes', type: 'fix' },
162
- { section: ':fire: Performance Improvements', type: 'perf' },
163
- { section: ':zap: Refactors', type: 'refactor' },
164
- { section: ':rewind: Reverts', type: 'revert' },
165
- { hidden: true, type: 'style' },
166
- { section: ':white_check_mark: Testing', type: 'test' },
167
- { hidden: true, type: 'wip' }
168
- ]
169
- },
170
- releaseCount,
171
- skipUnstable: false,
172
- tagPrefix: pkg.tagPrefix,
173
- /**
174
- * Raw commit transformer.
175
- *
176
- * @see https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-core#transform-1
177
- * @see https://github.com/conventional-changelog/conventional-changelog/issues/415
178
- *
179
- * @param {Commit} commit - Commit object
180
- * @param {Options.Transform.Callback} apply - Commit handler
181
- * @return {void} Nothing when complete
182
- */
183
- transform(commit: Commit, apply: Options.Transform.Callback): void {
184
- return void apply(null, {
185
- ...commit,
186
- committerDate: dateformat(
187
- commit.committerDate!,
188
- 'yyyy-mm-dd',
189
- true
190
- ),
191
- mentions: commit.mentions.filter(m => m !== 'flexdevelopment'),
192
- // @ts-expect-error ts(2322)
193
- raw: commit,
194
- references: commit.references.filter(ref => ref.action !== null),
195
- shortHash: commit.hash!.slice(0, 7),
196
- version: commit.gitTags ? vgx.exec(commit.gitTags)?.[1] : undefined
197
- })
198
- }
199
- },
200
- {},
201
- {},
202
- {
203
- issuePrefixesCaseSensitive: true
204
- },
205
- {
206
- /**
207
- * Sorts commit groups in descending order by group title.
208
- *
209
- * GitHub emojis in titles will be ignored.
210
- *
211
- * @see https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-writer#commitgroupssort
212
- *
213
- * @param {CommitGroup} a - Commit group object
214
- * @param {CommitGroup} b - Commit group object to compare to `a`
215
- * @return {number} Compare result
216
- */
217
- commitGroupsSort(a: CommitGroup, b: CommitGroup): number {
218
- if (a.title === false) return CompareResult.GREATER_THAN
219
- if (b.title === false) return CompareResult.LESS_THAN
220
-
221
- /**
222
- * Regex used to extract commit group titles without GitHub emojis.
223
- *
224
- * @const {RegExp} tgx - Regex used to extract commit group title
225
- */
226
- const tgx: RegExp = /([A-Z])\w+/
227
-
228
- return tgx.exec(a.title)![0]!.localeCompare(tgx.exec(b.title)![0]!)
229
- },
230
- /**
231
- * Sorts commits in descending order by commit header and date.
232
- *
233
- * @see https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-writer#commitssort
234
- *
235
- * @param {ICommit} a - Commit object
236
- * @param {ICommit} b - Commit object to compare to `b`
237
- * @return {number} Compare result
238
- */
239
- commitsSort(a: ICommit, b: ICommit): number {
240
- /**
241
- * Compare result for {@linkcode b.committerDate} and
242
- * {@linkcode a.committerDate}.
243
- *
244
- * @const {number} by_date
245
- */
246
- const by_date: number =
247
- new Date(b.committerDate).getTime() -
248
- new Date(a.committerDate).getTime()
249
-
250
- return a.header && b.header
251
- ? a.header.localeCompare(b.header) || by_date
252
- : by_date
253
- },
254
- /**
255
- * Modifies `context` before the changelog is generated.
256
- *
257
- * This includes:
258
- *
259
- * - Setting the current and previous release tags
260
- * - Setting the release date
261
- * - Determining patch release state
262
- * - Determining if compare links should be generated
263
- *
264
- * @see https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-core#finalizecontext
265
- * @see https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-writer#finalizecontext
266
- *
267
- * @param {GeneratedContext} context - Generated changelog context
268
- * @param {Options} options - `conventional-changelog-core` options
269
- * @param {ICommit[]} commits - Commits for release
270
- * @param {ICommit | undefined} key - Release commit
271
- * @return {GeneratedContext} Final changelog context
272
- */
273
- finalizeContext(
274
- context: GeneratedContext,
275
- options: Options,
276
- commits: ICommit[],
277
- key: ICommit | undefined
278
- ): GeneratedContext {
279
- const { gitSemverTags = [], isPatch, linkCompare, version } = context
280
- let { currentTag, previousTag } = context
281
-
282
- /**
283
- * First commit in release.
284
- *
285
- * @const {ICommit | undefined} first_commit
286
- */
287
- const first_commit: ICommit | undefined = commits.at(0)
288
-
289
- /**
290
- * Last commit in release.
291
- *
292
- * @const {ICommit | undefined} last_commit
293
- */
294
- const last_commit: ICommit | undefined = commits.at(-1)
295
-
296
- // set current and previous tags
297
- if (key && (!currentTag || !previousTag)) {
298
- currentTag = key.version ?? undefined
299
-
300
- // try setting previous tag based on current tag
301
- if (gitSemverTags.includes(currentTag ?? '')) {
302
- const { version } = key
303
- previousTag = gitSemverTags[gitSemverTags.indexOf(version!) + 1]
304
- if (!previousTag) previousTag = last_commit?.hash ?? undefined
305
- }
306
- } else {
307
- currentTag = /^unreleased$/i.test(version ?? '')
308
- ? currentTag ??
309
- (typeof outputUnreleased === 'string' && outputUnreleased
310
- ? outputUnreleased
311
- : first_commit?.hash ?? undefined)
312
- : !currentTag && version
313
- ? pkg.tagPrefix + version
314
- : currentTag ?? version
315
- previousTag = previousTag ?? gitSemverTags[0]
316
- }
317
-
318
- // set release date
319
- context.date =
320
- key?.committerDate ?? dateformat(new Date(), 'yyyy-mm-dd', true)
321
-
322
- // determine patch release state
323
- if (version && semver.valid(version)) {
324
- context.isPatch = isPatch ?? semver.patch(version) !== 0
325
- }
326
-
327
- // @ts-expect-error ts(2322)
328
- return {
329
- ...context,
330
- currentTag,
331
- linkCompare: isNIL(linkCompare) && !!currentTag && !!previousTag,
332
- previousTag,
333
- repoUrl: pkg.repository.slice(0, -4)
334
- }
335
- },
336
- headerPartial: readFileSync('templates/changelog/header.hbs', 'utf8'),
337
- ignoreReverted: false
338
- }
339
- ).on('error', err => console.error(err.stack))
340
-
341
- // override samefile if infile and outfile are the same file
342
- if (infile && infile === outfile) samefile = true
343
-
344
- // reset outfile if changelog should be output to infile
345
- if (samefile) outfile = infile = infile ?? 'CHANGELOG.md'
346
-
347
- /**
348
- * Creates a file writer.
349
- *
350
- * If writing to file is disabled, {@linkcode process.stdout} will be used
351
- * to write content to the terminal.
352
- *
353
- * Otherwise, {@linkcode createWriteStream} will be used to create a stream
354
- * for {@linkcode outfile}.
355
- *
356
- * @see {@linkcode NodeJS.WriteStream}
357
- * @see {@linkcode WriteStream}
358
- * @see {@linkcode createWriteStream}
359
- *
360
- * @return {WriteStream | (NodeJS.WriteStream & { fd: 1 })} File writer
361
- */
362
- const writer = (): WriteStream | (NodeJS.WriteStream & { fd: 1 }) => {
363
- return write && outfile ? createWriteStream(outfile) : process.stdout
364
- }
365
-
366
- // write changelog to infile, outfile, or stdout
367
- switch (true) {
368
- case infile && releaseCount !== 0:
369
- /**
370
- * Changelog file stream.
371
- *
372
- * @const {ReadStream} rs
373
- */
374
- const rs: ReadStream = createReadStream(infile!).on('error', () => {
375
- if (debug) console.error('infile does not exist.')
376
- if (samefile) changelog.pipe(writer())
377
- })
378
-
379
- // write changelog to infile or stdout
380
- if (samefile) {
381
- /**
382
- * Absolute path to random temporary file.
383
- *
384
- * @const {string} tmp
385
- */
386
- const tmp: string = tempfile()
387
-
388
- changelog
389
- .pipe(addStream(rs))
390
- .pipe(createWriteStream(tmp))
391
- .on('finish', () => createReadStream(tmp).pipe(writer()))
392
- } else {
393
- changelog.pipe(addStream(rs)).pipe(writer())
394
- }
395
-
396
- break
397
- default:
398
- changelog.pipe(writer())
399
- break
400
- }
401
-
402
- return void 0
403
- })
404
- .parse(process.argv)