@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.
- package/CHANGELOG.md +101 -0
- package/README.md +1 -1
- package/dist/interfaces/options-get-format.d.mts +3 -13
- package/dist/interfaces/options-get-source.d.mts +3 -13
- package/dist/interfaces/options-parse-subpath.d.mts +18 -0
- package/dist/interfaces/parsed-subpath.d.mts +5 -1
- package/dist/internal/regex-invalid-segment.d.mts +14 -0
- package/dist/internal/regex-invalid-segment.mjs +11 -0
- package/dist/internal/regex-invalid-segment.mjs.map +6 -0
- package/dist/internal/resolver.mjs +6 -9
- package/dist/internal/resolver.mjs.map +1 -1
- package/dist/internal/validate-array-set.d.mts +22 -0
- package/dist/internal/validate-array-set.mjs +11 -0
- package/dist/internal/validate-array-set.mjs.map +6 -0
- package/dist/internal/validate-map.d.mts +23 -0
- package/dist/internal/validate-map.mjs +11 -0
- package/dist/internal/validate-map.mjs.map +6 -0
- package/dist/internal/validate-set.d.mts +4 -5
- package/dist/internal/validate-set.mjs.map +1 -1
- package/dist/utils/fill-modules.d.mts +1 -0
- package/dist/utils/fill-modules.mjs +7 -1
- package/dist/utils/fill-modules.mjs.map +1 -1
- package/dist/utils/find-requires.mjs +1 -1
- package/dist/utils/find-subpath.d.mts +2 -1
- package/dist/utils/find-subpath.mjs +2 -0
- package/dist/utils/find-subpath.mjs.map +1 -1
- package/dist/utils/get-format.d.mts +8 -1
- package/dist/utils/get-format.mjs +22 -11
- package/dist/utils/get-format.mjs.map +1 -1
- package/dist/utils/get-source.d.mts +7 -0
- package/dist/utils/get-source.mjs +13 -6
- package/dist/utils/get-source.mjs.map +1 -1
- package/dist/utils/is-absolute-specifier.d.mts +1 -0
- package/dist/utils/is-absolute-specifier.mjs +2 -0
- package/dist/utils/is-absolute-specifier.mjs.map +1 -1
- package/dist/utils/is-bare-specifier.d.mts +1 -0
- package/dist/utils/is-bare-specifier.mjs +2 -0
- package/dist/utils/is-bare-specifier.mjs.map +1 -1
- package/dist/utils/is-exports-sugar.mjs +1 -1
- package/dist/utils/is-exports-sugar.mjs.map +1 -1
- package/dist/utils/is-relative-specifier.mjs.map +1 -1
- package/dist/utils/parse-module-id.d.mts +1 -3
- package/dist/utils/parse-module-id.mjs +3 -0
- package/dist/utils/parse-module-id.mjs.map +1 -1
- package/dist/utils/parse-subpath.d.mts +1 -2
- package/dist/utils/parse-subpath.mjs +115 -5
- package/dist/utils/parse-subpath.mjs.map +1 -1
- package/dist/utils/read-package-json.mjs +7 -5
- package/dist/utils/read-package-json.mjs.map +1 -1
- package/dist/utils/resolve-alias.mjs +3 -2
- package/dist/utils/resolve-alias.mjs.map +1 -1
- package/dist/utils/resolve-module.mjs +16 -1
- package/dist/utils/resolve-module.mjs.map +1 -1
- package/dist/utils/to-bare-specifier.mjs +8 -10
- package/dist/utils/to-bare-specifier.mjs.map +1 -1
- package/dist/utils/to-relative-specifier.d.mts +2 -0
- package/dist/utils/to-relative-specifier.mjs +3 -0
- package/dist/utils/to-relative-specifier.mjs.map +1 -1
- package/dist/utils/to-url.d.mts +2 -3
- package/dist/utils/to-url.mjs.map +1 -1
- package/dist/utils/validate-assertions.mjs +2 -0
- package/dist/utils/validate-assertions.mjs.map +1 -1
- package/dist/utils/validate-exports.d.mts +2 -2
- package/dist/utils/validate-exports.mjs +2 -2
- package/dist/utils/validate-exports.mjs.map +1 -1
- package/package.json +34 -41
- package/src/interfaces/options-get-format.ts +2 -14
- package/src/interfaces/options-get-source.ts +2 -14
- package/src/interfaces/options-parse-subpath.ts +20 -0
- package/src/interfaces/parsed-subpath.ts +10 -1
- package/src/internal/regex-invalid-segment.ts +23 -0
- package/src/internal/resolver.ts +7 -22
- package/src/internal/validate-array-set.ts +32 -0
- package/src/internal/validate-map.ts +33 -0
- package/src/internal/validate-set.ts +4 -5
- package/src/utils/fill-modules.ts +10 -1
- package/src/utils/find-requires.ts +1 -1
- package/src/utils/find-subpath.ts +11 -2
- package/src/utils/get-format.ts +33 -12
- package/src/utils/get-source.ts +21 -6
- package/src/utils/is-absolute-specifier.ts +5 -0
- package/src/utils/is-bare-specifier.ts +5 -0
- package/src/utils/is-exports-sugar.ts +1 -1
- package/src/utils/is-relative-specifier.ts +1 -0
- package/src/utils/parse-module-id.ts +6 -3
- package/src/utils/parse-subpath.ts +154 -9
- package/src/utils/read-package-json.ts +8 -3
- package/src/utils/resolve-alias.ts +3 -2
- package/src/utils/resolve-module.ts +40 -11
- package/src/utils/to-bare-specifier.ts +10 -12
- package/src/utils/to-relative-specifier.ts +7 -0
- package/src/utils/to-url.ts +2 -3
- package/src/utils/validate-assertions.ts +2 -0
- package/src/utils/validate-exports.ts +5 -5
- 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
|
-
*
|
|
82
|
+
* Boolean indicating only module id should be tried for resolution.
|
|
69
83
|
*
|
|
70
|
-
* @const {
|
|
84
|
+
* @const {boolean} onetry
|
|
71
85
|
*/
|
|
72
|
-
const
|
|
86
|
+
const onetry: boolean =
|
|
73
87
|
isBuiltin(specifier) ||
|
|
74
88
|
(/^\S+:/.test(specifier) && !specifier.startsWith('file:'))
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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> =
|
|
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(
|
|
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:
|
|
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:
|
|
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(
|
|
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
|
package/src/utils/to-url.ts
CHANGED
|
@@ -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
|
-
*
|
|
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
|
|
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
|
|
30
|
-
* instance of {@linkcode URL}
|
|
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
|
*
|
package/changelog.config.ts
DELETED
|
@@ -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)
|