@fuman/build 0.0.1
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 +8 -0
- package/README.md +108 -0
- package/ci/github-actions.d.ts +3 -0
- package/ci/github-actions.js +28 -0
- package/ci/index.d.ts +1 -0
- package/cli/commands/_utils.d.ts +8 -0
- package/cli/commands/_utils.js +18 -0
- package/cli/commands/build.d.ts +20 -0
- package/cli/commands/build.js +45 -0
- package/cli/commands/bump-version.d.ts +18 -0
- package/cli/commands/bump-version.js +72 -0
- package/cli/commands/cr.d.ts +17 -0
- package/cli/commands/cr.js +76 -0
- package/cli/commands/find-changed-packages.d.ts +12 -0
- package/cli/commands/find-changed-packages.js +44 -0
- package/cli/commands/gen-changelog.d.ts +12 -0
- package/cli/commands/gen-changelog.js +49 -0
- package/cli/commands/gen-deps-graph.d.ts +15 -0
- package/cli/commands/gen-deps-graph.js +78 -0
- package/cli/commands/jsr.d.ts +6 -0
- package/cli/commands/jsr.js +79 -0
- package/cli/commands/publish.d.ts +48 -0
- package/cli/commands/publish.js +197 -0
- package/cli/commands/release.d.ts +34 -0
- package/cli/commands/release.js +226 -0
- package/cli/commands/validate-workspace-deps.d.ts +38 -0
- package/cli/commands/validate-workspace-deps.js +68 -0
- package/cli/index.d.ts +3 -0
- package/cli/main.d.ts +2 -0
- package/config.d.ts +32 -0
- package/fuman-build.d.ts +1 -0
- package/fuman-build.js +33 -0
- package/git/github.d.ts +14 -0
- package/git/github.js +48 -0
- package/git/index.d.ts +1 -0
- package/git/utils.d.ts +38 -0
- package/git/utils.js +110 -0
- package/index.d.ts +7 -0
- package/index.js +46 -0
- package/jsr/build-jsr.d.ts +7 -0
- package/jsr/build-jsr.js +145 -0
- package/jsr/config.d.ts +48 -0
- package/jsr/create-packages.d.ts +8 -0
- package/jsr/create-packages.js +46 -0
- package/jsr/deno-json.d.ts +19 -0
- package/jsr/deno-json.js +80 -0
- package/jsr/generate-workspace.d.ts +9 -0
- package/jsr/generate-workspace.js +174 -0
- package/jsr/index.d.ts +5 -0
- package/jsr/populate.d.ts +45 -0
- package/jsr/populate.js +132 -0
- package/jsr/utils/external-libs.d.ts +8 -0
- package/jsr/utils/external-libs.js +46 -0
- package/jsr/utils/index.d.ts +4 -0
- package/jsr/utils/jsr-api.d.ts +23 -0
- package/jsr/utils/jsr-api.js +115 -0
- package/jsr/utils/jsr-json.d.ts +10 -0
- package/jsr/utils/jsr-json.js +80 -0
- package/jsr/utils/jsr.d.ts +11 -0
- package/jsr/utils/jsr.js +74 -0
- package/jsr.d.ts +1 -0
- package/jsr.js +23 -0
- package/misc/_config.d.ts +1 -0
- package/misc/_config.js +18 -0
- package/misc/exec.d.ts +9 -0
- package/misc/exec.js +40 -0
- package/misc/fs.d.ts +4 -0
- package/misc/fs.js +32 -0
- package/misc/index.d.ts +4 -0
- package/misc/path.d.ts +1 -0
- package/misc/path.js +12 -0
- package/misc/publish-order.d.ts +3 -0
- package/misc/publish-order.js +56 -0
- package/misc/tsconfig.d.ts +2 -0
- package/misc/tsconfig.js +28 -0
- package/npm/index.d.ts +1 -0
- package/npm/npm-api.d.ts +7 -0
- package/npm/npm-api.js +18 -0
- package/package-json/collect-package-jsons.d.ts +8 -0
- package/package-json/collect-package-jsons.js +61 -0
- package/package-json/find-package-json.d.ts +7 -0
- package/package-json/find-package-json.js +28 -0
- package/package-json/index.d.ts +5 -0
- package/package-json/parse.d.ts +4 -0
- package/package-json/parse.js +40 -0
- package/package-json/process-package-json.d.ts +13 -0
- package/package-json/process-package-json.js +132 -0
- package/package-json/types.d.ts +56 -0
- package/package-json/types.js +57 -0
- package/package-json/utils.d.ts +4 -0
- package/package-json/utils.js +27 -0
- package/package.json +67 -0
- package/versioning/bump-version.d.ts +48 -0
- package/versioning/bump-version.js +129 -0
- package/versioning/collect-files.d.ts +22 -0
- package/versioning/collect-files.js +66 -0
- package/versioning/generate-changelog.d.ts +13 -0
- package/versioning/generate-changelog.js +81 -0
- package/versioning/types.d.ts +32 -0
- package/vite/build-plugin.d.ts +73 -0
- package/vite/build-plugin.js +170 -0
- package/vite/config.d.ts +34 -0
- package/vite/index.d.ts +2 -0
- package/vite.d.ts +1 -0
- package/vite.js +4 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
const DEFAULT_FIELDS_TO_COPY_ROOT = ["license", "author", "contributors", "homepage", "repository", "bugs"];
|
|
2
|
+
function processPackageJson(params) {
|
|
3
|
+
const {
|
|
4
|
+
packageJson: packageJsonOrig,
|
|
5
|
+
workspaceVersions,
|
|
6
|
+
rootPackageJson,
|
|
7
|
+
rootFieldsToCopy = DEFAULT_FIELDS_TO_COPY_ROOT,
|
|
8
|
+
bundledWorkspaceDeps,
|
|
9
|
+
fixedVersion
|
|
10
|
+
} = params;
|
|
11
|
+
const packageJson = structuredClone(packageJsonOrig);
|
|
12
|
+
const entrypoints = {};
|
|
13
|
+
for (const field of rootFieldsToCopy) {
|
|
14
|
+
if (rootPackageJson?.[field] != null && packageJson[field] == null) {
|
|
15
|
+
packageJson[field] = rootPackageJson[field];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const newScripts = {};
|
|
19
|
+
if (packageJson.scripts && Array.isArray(packageJson.fuman?.keepScripts)) {
|
|
20
|
+
for (const script of packageJson.fuman.keepScripts) {
|
|
21
|
+
if (typeof script !== "string") continue;
|
|
22
|
+
if (script in packageJson.scripts) continue;
|
|
23
|
+
newScripts[script] = packageJson.scripts[script];
|
|
24
|
+
}
|
|
25
|
+
delete packageJson.keepScripts;
|
|
26
|
+
}
|
|
27
|
+
packageJson.scripts = newScripts;
|
|
28
|
+
delete packageJson.devDependencies;
|
|
29
|
+
delete packageJson.private;
|
|
30
|
+
if (packageJson.fuman?.distOnlyFields) {
|
|
31
|
+
Object.assign(packageJson, packageJson.fuman.distOnlyFields);
|
|
32
|
+
delete packageJson.distOnlyFields;
|
|
33
|
+
}
|
|
34
|
+
function replaceWorkspaceDependencies(field) {
|
|
35
|
+
if (packageJson[field] == null) return;
|
|
36
|
+
const dependencies = packageJson[field];
|
|
37
|
+
for (const name of Object.keys(dependencies)) {
|
|
38
|
+
const value = dependencies[name];
|
|
39
|
+
if (value.startsWith("workspace:")) {
|
|
40
|
+
if (bundledWorkspaceDeps) {
|
|
41
|
+
let found = false;
|
|
42
|
+
for (const dep of bundledWorkspaceDeps) {
|
|
43
|
+
if (dep.test(name)) {
|
|
44
|
+
delete dependencies[name];
|
|
45
|
+
found = true;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (found) continue;
|
|
50
|
+
}
|
|
51
|
+
if (value !== "workspace:^" && value !== "workspace:*") {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`Cannot replace workspace dependency ${name} with ${value} - only workspace:^ and * are supported`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
if (workspaceVersions?.[name] == null) {
|
|
57
|
+
throw new Error(`Cannot replace workspace: dependency ${name} not found in workspace`);
|
|
58
|
+
}
|
|
59
|
+
if (fixedVersion != null) {
|
|
60
|
+
dependencies[name] = fixedVersion;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const workspaceVersion = workspaceVersions?.[name];
|
|
64
|
+
const depVersion = value === "workspace:*" ? workspaceVersion : `^${workspaceVersion}`;
|
|
65
|
+
dependencies[name] = depVersion;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
replaceWorkspaceDependencies("dependencies");
|
|
70
|
+
replaceWorkspaceDependencies("devDependencies");
|
|
71
|
+
replaceWorkspaceDependencies("peerDependencies");
|
|
72
|
+
replaceWorkspaceDependencies("optionalDependencies");
|
|
73
|
+
delete packageJson.typedoc;
|
|
74
|
+
delete packageJson.eslintConfig;
|
|
75
|
+
delete packageJson.eslintIgnore;
|
|
76
|
+
delete packageJson.prettier;
|
|
77
|
+
delete packageJson.fuman;
|
|
78
|
+
if (packageJson.exports != null) {
|
|
79
|
+
let exports = packageJson.exports;
|
|
80
|
+
if (typeof exports === "string") {
|
|
81
|
+
exports = { ".": exports };
|
|
82
|
+
}
|
|
83
|
+
if (typeof exports !== "object") {
|
|
84
|
+
throw new TypeError("package.json exports must be an object");
|
|
85
|
+
}
|
|
86
|
+
const newExports = {};
|
|
87
|
+
for (const [key, value] of Object.entries(exports)) {
|
|
88
|
+
if (typeof value !== "string") {
|
|
89
|
+
throw new TypeError(`package.json exports value must be a string: ${key}`);
|
|
90
|
+
}
|
|
91
|
+
if (value.endsWith(".wasm")) {
|
|
92
|
+
newExports[key] = value;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
let entrypointName = key.replace(/^\.(?:\/|$)/, "").replace(/\.js$/, "");
|
|
96
|
+
if (entrypointName === "") entrypointName = "index";
|
|
97
|
+
entrypoints[entrypointName] = value;
|
|
98
|
+
newExports[key] = {
|
|
99
|
+
import: {
|
|
100
|
+
types: `./${entrypointName}.d.ts`,
|
|
101
|
+
default: `./${entrypointName}.js`
|
|
102
|
+
},
|
|
103
|
+
require: {
|
|
104
|
+
types: `./${entrypointName}.d.cts`,
|
|
105
|
+
default: `./${entrypointName}.cjs`
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
packageJson.exports = newExports;
|
|
110
|
+
}
|
|
111
|
+
if (packageJson.bin != null) {
|
|
112
|
+
const newBin = {};
|
|
113
|
+
for (const [key, value] of Object.entries(packageJson.bin)) {
|
|
114
|
+
if (typeof value !== "string") {
|
|
115
|
+
throw new TypeError(`package.json bin value must be a string: ${key}`);
|
|
116
|
+
}
|
|
117
|
+
let entrypointName = key.replace(/^\.(?:\/|$)/, "").replace(/\.js$/, "");
|
|
118
|
+
if (entrypointName === "") entrypointName = "index";
|
|
119
|
+
entrypoints[entrypointName] = value;
|
|
120
|
+
newBin[key] = `${entrypointName}.js`;
|
|
121
|
+
}
|
|
122
|
+
packageJson.bin = newBin;
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
packageJsonOrig,
|
|
126
|
+
packageJson,
|
|
127
|
+
entrypoints
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
export {
|
|
131
|
+
processPackageJson
|
|
132
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export interface PackageJson {
|
|
3
|
+
name?: string;
|
|
4
|
+
type?: 'module' | 'commonjs';
|
|
5
|
+
version?: string;
|
|
6
|
+
private?: boolean;
|
|
7
|
+
description?: string;
|
|
8
|
+
packageManager?: string;
|
|
9
|
+
license?: string;
|
|
10
|
+
homepage?: string;
|
|
11
|
+
repository?: (string | {
|
|
12
|
+
type: string;
|
|
13
|
+
url: string;
|
|
14
|
+
});
|
|
15
|
+
keywords?: string[];
|
|
16
|
+
workspaces?: string[];
|
|
17
|
+
scripts?: Record<string, string>;
|
|
18
|
+
dependencies?: Record<string, string>;
|
|
19
|
+
devDependencies?: Record<string, string>;
|
|
20
|
+
peerDependencies?: Record<string, string>;
|
|
21
|
+
optionalDependencies?: Record<string, string>;
|
|
22
|
+
bundledDependencies?: Record<string, string>;
|
|
23
|
+
engines?: Record<string, string>;
|
|
24
|
+
pnpm?: {
|
|
25
|
+
overrides: Record<string, string>;
|
|
26
|
+
};
|
|
27
|
+
/** fuman-specific package.json fields */
|
|
28
|
+
fuman?: {
|
|
29
|
+
/**
|
|
30
|
+
* whether the package should be published to jsr
|
|
31
|
+
* (skip – it won't be published to jsr, only – it will only be published to jsr)
|
|
32
|
+
*/
|
|
33
|
+
jsr?: 'skip' | 'only';
|
|
34
|
+
/**
|
|
35
|
+
* whether the package should be published to npm
|
|
36
|
+
* (skip – it won't be published to npm, only – it will only be published to npm)
|
|
37
|
+
*/
|
|
38
|
+
npm?: 'skip' | 'only';
|
|
39
|
+
/** by default @fuman/build strips all scripts, but you can keep some of them by passing their names here */
|
|
40
|
+
keepScripts?: string[];
|
|
41
|
+
/**
|
|
42
|
+
* any additional fields that will be shallowly merged into the resulting package.json.
|
|
43
|
+
* for more complex modifications than shallow merging, consider using build.config.js
|
|
44
|
+
*/
|
|
45
|
+
distOnlyFields?: Record<string, unknown>;
|
|
46
|
+
/**
|
|
47
|
+
* whether this package has its own versioning scheme
|
|
48
|
+
* (be careful with this option! this might break cross-release semver compatibility)
|
|
49
|
+
*/
|
|
50
|
+
ownVersioning?: boolean;
|
|
51
|
+
/** whether this package should not be published */
|
|
52
|
+
private?: boolean;
|
|
53
|
+
};
|
|
54
|
+
[key: string]: any;
|
|
55
|
+
}
|
|
56
|
+
export declare const PackageJsonSchema: z.AnyZodObject;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const PackageJsonSchema = z.object({
|
|
3
|
+
name: z.string(),
|
|
4
|
+
type: z.union([
|
|
5
|
+
z.literal("module"),
|
|
6
|
+
z.literal("commonjs")
|
|
7
|
+
]),
|
|
8
|
+
version: z.string(),
|
|
9
|
+
private: z.boolean(),
|
|
10
|
+
description: z.string(),
|
|
11
|
+
packageManager: z.string(),
|
|
12
|
+
license: z.string(),
|
|
13
|
+
homepage: z.string(),
|
|
14
|
+
repository: z.union([
|
|
15
|
+
z.string(),
|
|
16
|
+
z.object({
|
|
17
|
+
type: z.string(),
|
|
18
|
+
url: z.string()
|
|
19
|
+
})
|
|
20
|
+
]).transform((val) => {
|
|
21
|
+
if (typeof val === "string") {
|
|
22
|
+
return { type: "git", url: val };
|
|
23
|
+
}
|
|
24
|
+
return val;
|
|
25
|
+
}),
|
|
26
|
+
keywords: z.array(z.string()),
|
|
27
|
+
workspaces: z.array(z.string()),
|
|
28
|
+
scripts: z.record(z.string()),
|
|
29
|
+
dependencies: z.record(z.string()),
|
|
30
|
+
devDependencies: z.record(z.string()),
|
|
31
|
+
peerDependencies: z.record(z.string()),
|
|
32
|
+
optionalDependencies: z.record(z.string()),
|
|
33
|
+
bundledDependencies: z.array(z.string()),
|
|
34
|
+
engines: z.record(z.string()),
|
|
35
|
+
pnpm: z.object({
|
|
36
|
+
overrides: z.record(z.string())
|
|
37
|
+
}),
|
|
38
|
+
fuman: z.object({
|
|
39
|
+
jsr: z.union([
|
|
40
|
+
z.literal("skip"),
|
|
41
|
+
z.literal("only")
|
|
42
|
+
]),
|
|
43
|
+
npm: z.union([
|
|
44
|
+
z.literal("skip"),
|
|
45
|
+
z.literal("only")
|
|
46
|
+
]),
|
|
47
|
+
keepScripts: z.array(z.string()),
|
|
48
|
+
distOnlyFields: z.record(z.unknown()),
|
|
49
|
+
ownVersioning: z.boolean(),
|
|
50
|
+
private: z.boolean()
|
|
51
|
+
}).partial(),
|
|
52
|
+
// todo: properly type this
|
|
53
|
+
exports: z.any()
|
|
54
|
+
}).passthrough().partial();
|
|
55
|
+
export {
|
|
56
|
+
PackageJsonSchema
|
|
57
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { WorkspacePackage } from './collect-package-jsons.js';
|
|
2
|
+
export declare function findPackageByName(packages: WorkspacePackage[], name: string): WorkspacePackage;
|
|
3
|
+
export declare function findRootPackage(packages: WorkspacePackage[]): WorkspacePackage;
|
|
4
|
+
export declare function collectVersions(packages: WorkspacePackage[]): Record<string, string>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function findPackageByName(packages, name) {
|
|
2
|
+
const pkg = packages.find((it) => it.json.name === name);
|
|
3
|
+
if (!pkg) {
|
|
4
|
+
throw new Error(`Could not find package.json for ${name}`);
|
|
5
|
+
}
|
|
6
|
+
return pkg;
|
|
7
|
+
}
|
|
8
|
+
function findRootPackage(packages) {
|
|
9
|
+
const pkg = packages.find((it) => it.root);
|
|
10
|
+
if (!pkg) {
|
|
11
|
+
throw new Error("Could not find package.json for workspace root");
|
|
12
|
+
}
|
|
13
|
+
return pkg;
|
|
14
|
+
}
|
|
15
|
+
function collectVersions(packages) {
|
|
16
|
+
const versions = {};
|
|
17
|
+
for (const pkg of packages) {
|
|
18
|
+
if (pkg.root || pkg.json.name == null || pkg.json.version == null) continue;
|
|
19
|
+
versions[pkg.json.name] = pkg.json.version;
|
|
20
|
+
}
|
|
21
|
+
return versions;
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
collectVersions,
|
|
25
|
+
findPackageByName,
|
|
26
|
+
findRootPackage
|
|
27
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fuman/build",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"description": "utils for building packages and managing monorepos",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"scripts": {},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@drizzle-team/brocli": "^0.10.2",
|
|
10
|
+
"@fuman/fetch": "^0.0.1",
|
|
11
|
+
"@fuman/io": "^0.0.1",
|
|
12
|
+
"@fuman/node": "^0.0.1",
|
|
13
|
+
"@fuman/utils": "^0.0.1",
|
|
14
|
+
"cross-spawn": "^7.0.5",
|
|
15
|
+
"detect-indent": "^7.0.1",
|
|
16
|
+
"js-yaml": "^4.1.0",
|
|
17
|
+
"picomatch": "^4.0.2",
|
|
18
|
+
"semver": "^7.6.3",
|
|
19
|
+
"tinyglobby": "^0.2.6",
|
|
20
|
+
"zod": "^3.23.8"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"typescript": "^5.2.2",
|
|
24
|
+
"vite": "^5.4.0"
|
|
25
|
+
},
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./index.d.ts",
|
|
30
|
+
"default": "./index.js"
|
|
31
|
+
},
|
|
32
|
+
"require": {
|
|
33
|
+
"types": "./index.d.cts",
|
|
34
|
+
"default": "./index.cjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"./vite": {
|
|
38
|
+
"import": {
|
|
39
|
+
"types": "./vite.d.ts",
|
|
40
|
+
"default": "./vite.js"
|
|
41
|
+
},
|
|
42
|
+
"require": {
|
|
43
|
+
"types": "./vite.d.cts",
|
|
44
|
+
"default": "./vite.cjs"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"./jsr": {
|
|
48
|
+
"import": {
|
|
49
|
+
"types": "./jsr.d.ts",
|
|
50
|
+
"default": "./jsr.js"
|
|
51
|
+
},
|
|
52
|
+
"require": {
|
|
53
|
+
"types": "./jsr.d.cts",
|
|
54
|
+
"default": "./jsr.cjs"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"sideEffects": false,
|
|
59
|
+
"bin": {
|
|
60
|
+
"fuman-build": "fuman-build.js"
|
|
61
|
+
},
|
|
62
|
+
"author": "",
|
|
63
|
+
"repository": {
|
|
64
|
+
"type": "git",
|
|
65
|
+
"url": "git+https://github.com/teidesu/fuman.git"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ReleaseType } from 'semver';
|
|
2
|
+
import { WorkspacePackage } from '../package-json/collect-package-jsons.js';
|
|
3
|
+
import { VersioningOptions } from './types.js';
|
|
4
|
+
export interface BumpVersionPackage {
|
|
5
|
+
/** info about the package */
|
|
6
|
+
package: WorkspacePackage;
|
|
7
|
+
/**
|
|
8
|
+
* if the package was not changed by itself,
|
|
9
|
+
* but the bump is required because of another package
|
|
10
|
+
* that was changed depending on it, name of that package
|
|
11
|
+
*/
|
|
12
|
+
because?: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface BumpVersionResult {
|
|
15
|
+
/** max version of all packages */
|
|
16
|
+
maxVersion: string;
|
|
17
|
+
/** next version */
|
|
18
|
+
nextVersion: string;
|
|
19
|
+
/** changed packages which will be bumped to `nextVersion` */
|
|
20
|
+
changedPackages: BumpVersionPackage[];
|
|
21
|
+
/** detected release type */
|
|
22
|
+
releaseType: ReleaseType;
|
|
23
|
+
/**
|
|
24
|
+
* whether there are breaking changes
|
|
25
|
+
* (note: will be false if release type is explicitly provided)
|
|
26
|
+
*/
|
|
27
|
+
hasBreakingChanges: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* whether there are new features
|
|
30
|
+
* (note: will be false if release type is explicitly provided)
|
|
31
|
+
*/
|
|
32
|
+
hasFeatures: boolean;
|
|
33
|
+
}
|
|
34
|
+
export declare function bumpVersion(params: {
|
|
35
|
+
/** packages for which to generate the changelog */
|
|
36
|
+
workspace: WorkspacePackage[];
|
|
37
|
+
/** whether to bump version of all packages, not just changed ones */
|
|
38
|
+
all?: boolean;
|
|
39
|
+
type?: ReleaseType;
|
|
40
|
+
/** root of the git repo */
|
|
41
|
+
cwd?: string | URL;
|
|
42
|
+
/** starting point for the changelog (defaults to latest tag) */
|
|
43
|
+
since: string;
|
|
44
|
+
/** versioning params */
|
|
45
|
+
params?: VersioningOptions;
|
|
46
|
+
/** whether to not actually write the files */
|
|
47
|
+
dryRun?: boolean;
|
|
48
|
+
}): Promise<BumpVersionResult>;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import * as fsp from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import { asNonNull } from "@fuman/utils";
|
|
5
|
+
import detectIndent from "detect-indent";
|
|
6
|
+
import { parse, inc, satisfies, gt } from "semver";
|
|
7
|
+
import { getCommitsBetween, parseConventionalCommit } from "../git/utils.js";
|
|
8
|
+
import { collectVersions } from "../package-json/utils.js";
|
|
9
|
+
import { findProjectChangedPackages } from "./collect-files.js";
|
|
10
|
+
async function bumpVersion(params) {
|
|
11
|
+
const {
|
|
12
|
+
workspace,
|
|
13
|
+
all,
|
|
14
|
+
cwd = process.cwd(),
|
|
15
|
+
since,
|
|
16
|
+
dryRun = false
|
|
17
|
+
} = params;
|
|
18
|
+
let maxVersion = null;
|
|
19
|
+
for (const pkg of workspace) {
|
|
20
|
+
const version = asNonNull(pkg.json.version);
|
|
21
|
+
if (pkg.json.fuman?.ownVersioning) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (maxVersion == null || gt(version, maxVersion)) {
|
|
25
|
+
maxVersion = version;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (maxVersion == null) {
|
|
29
|
+
throw new Error("No packages found with fuman-managed versioning");
|
|
30
|
+
}
|
|
31
|
+
const changedPackages = all ? workspace : await findProjectChangedPackages({
|
|
32
|
+
root: cwd,
|
|
33
|
+
since,
|
|
34
|
+
params: params.params
|
|
35
|
+
});
|
|
36
|
+
let type = params.type;
|
|
37
|
+
let hasFeatures = false;
|
|
38
|
+
let hasBreakingChanges = false;
|
|
39
|
+
if (type == null) {
|
|
40
|
+
for (const commit of await getCommitsBetween({
|
|
41
|
+
since,
|
|
42
|
+
cwd
|
|
43
|
+
})) {
|
|
44
|
+
const parsed = parseConventionalCommit(commit.message);
|
|
45
|
+
if (!parsed) continue;
|
|
46
|
+
if (parsed.breaking) hasBreakingChanges = true;
|
|
47
|
+
if (parsed.type === "feat") hasFeatures = true;
|
|
48
|
+
}
|
|
49
|
+
const parsedVersion = parse(maxVersion);
|
|
50
|
+
if (!parsedVersion) {
|
|
51
|
+
throw new Error(`Invalid version: ${maxVersion}`);
|
|
52
|
+
}
|
|
53
|
+
if (hasBreakingChanges) {
|
|
54
|
+
if (parsedVersion.major === 0 && parsedVersion.minor === 0) {
|
|
55
|
+
type = "patch";
|
|
56
|
+
} else if (parsedVersion.major === 0) {
|
|
57
|
+
type = "minor";
|
|
58
|
+
} else {
|
|
59
|
+
type = "major";
|
|
60
|
+
}
|
|
61
|
+
} else if (hasFeatures) {
|
|
62
|
+
type = parsedVersion.major === 0 ? "patch" : "minor";
|
|
63
|
+
} else {
|
|
64
|
+
type = "patch";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const nextVersion = inc(maxVersion, type);
|
|
68
|
+
if (nextVersion == null) {
|
|
69
|
+
throw new Error(`Invalid version increment: ${maxVersion} → ${type}`);
|
|
70
|
+
}
|
|
71
|
+
const workspaceVersions = collectVersions(workspace);
|
|
72
|
+
const result = [];
|
|
73
|
+
for (const pkg of changedPackages) {
|
|
74
|
+
if (pkg.json.fuman?.ownVersioning) continue;
|
|
75
|
+
result.push({ package: pkg });
|
|
76
|
+
}
|
|
77
|
+
for (const pkg of changedPackages) {
|
|
78
|
+
if (pkg.json.fuman?.ownVersioning) continue;
|
|
79
|
+
const pkgName = asNonNull(pkg.json.name);
|
|
80
|
+
for (const otherPkg of workspace) {
|
|
81
|
+
for (const kind of ["dependencies", "peerDependencies"]) {
|
|
82
|
+
const obj = otherPkg.json[kind];
|
|
83
|
+
if (obj == null) continue;
|
|
84
|
+
if (obj[pkgName] == null || typeof obj[pkgName] !== "string") continue;
|
|
85
|
+
let expandedVersion = obj[pkgName];
|
|
86
|
+
if (expandedVersion === "workspace:^") expandedVersion = `^${workspaceVersions[pkgName]}`;
|
|
87
|
+
if (expandedVersion === "workspace:*") expandedVersion = workspaceVersions[pkgName];
|
|
88
|
+
if (!satisfies(nextVersion, expandedVersion)) {
|
|
89
|
+
if (otherPkg.json.fuman?.ownVersioning) {
|
|
90
|
+
throw new Error(`package ${otherPkg.json.name}@${otherPkg.json.version} is marked as "own versioning", and will not be compatible with ${pkgName}@${expandedVersion} after bumping. please bump it manually`);
|
|
91
|
+
}
|
|
92
|
+
const existing = result.find((pkg2) => pkg2.package.json.name === otherPkg.json.name);
|
|
93
|
+
if (existing) {
|
|
94
|
+
if (!existing.because) break;
|
|
95
|
+
existing.because.push(pkgName);
|
|
96
|
+
} else {
|
|
97
|
+
result.push({
|
|
98
|
+
package: otherPkg,
|
|
99
|
+
because: [pkgName]
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (!dryRun) {
|
|
108
|
+
for (const { package: pkg } of result) {
|
|
109
|
+
const pkgJsonPath = join(pkg.path, "package.json");
|
|
110
|
+
const pkgJsonText = await fsp.readFile(pkgJsonPath, "utf8");
|
|
111
|
+
const indent = detectIndent(pkgJsonText).indent || " ";
|
|
112
|
+
const pkgJson = JSON.parse(pkgJsonText);
|
|
113
|
+
pkgJson.version = nextVersion;
|
|
114
|
+
await fsp.writeFile(pkgJsonPath, `${JSON.stringify(pkgJson, null, indent)}
|
|
115
|
+
`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
maxVersion,
|
|
120
|
+
nextVersion,
|
|
121
|
+
changedPackages: result,
|
|
122
|
+
releaseType: type,
|
|
123
|
+
hasBreakingChanges,
|
|
124
|
+
hasFeatures
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export {
|
|
128
|
+
bumpVersion
|
|
129
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { VersioningOptions } from './types.js';
|
|
2
|
+
import { WorkspacePackage } from '../package-json/index.js';
|
|
3
|
+
export interface ProjectChangedFile {
|
|
4
|
+
/** package to which the file belongs */
|
|
5
|
+
package: WorkspacePackage;
|
|
6
|
+
/** path to the file relative to the package root */
|
|
7
|
+
file: string;
|
|
8
|
+
/** path to workspace root */
|
|
9
|
+
root: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function findProjectChangedFiles(params: {
|
|
12
|
+
params?: VersioningOptions;
|
|
13
|
+
root?: string | URL;
|
|
14
|
+
since: string;
|
|
15
|
+
until?: string;
|
|
16
|
+
}): Promise<ProjectChangedFile[]>;
|
|
17
|
+
export declare function findProjectChangedPackages(params: {
|
|
18
|
+
params?: VersioningOptions;
|
|
19
|
+
root?: string | URL;
|
|
20
|
+
since: string;
|
|
21
|
+
until?: string;
|
|
22
|
+
}): Promise<WorkspacePackage[]>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { relative, join } from "node:path";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import picomatch from "picomatch";
|
|
4
|
+
import { findChangedFiles } from "../git/utils.js";
|
|
5
|
+
import { normalizeFilePath } from "../misc/path.js";
|
|
6
|
+
import { getTsconfigFiles } from "../misc/tsconfig.js";
|
|
7
|
+
import { collectPackageJsons } from "../package-json/collect-package-jsons.js";
|
|
8
|
+
async function defaultShouldInclude(file) {
|
|
9
|
+
if (!file.file.endsWith(".ts")) return true;
|
|
10
|
+
if (file.package == null) return false;
|
|
11
|
+
const tsconfigFiles = await getTsconfigFiles(join(file.root, file.package.path));
|
|
12
|
+
return tsconfigFiles.includes(file.file);
|
|
13
|
+
}
|
|
14
|
+
async function findProjectChangedFiles(params) {
|
|
15
|
+
const {
|
|
16
|
+
params: {
|
|
17
|
+
include,
|
|
18
|
+
exclude = ["**/*.test.ts"],
|
|
19
|
+
shouldInclude = defaultShouldInclude
|
|
20
|
+
} = {},
|
|
21
|
+
root: root_ = process.cwd(),
|
|
22
|
+
since,
|
|
23
|
+
until
|
|
24
|
+
} = params;
|
|
25
|
+
const root = normalizeFilePath(root_);
|
|
26
|
+
const changed = await findChangedFiles({
|
|
27
|
+
since,
|
|
28
|
+
until,
|
|
29
|
+
cwd: root
|
|
30
|
+
});
|
|
31
|
+
if (!changed.length) return [];
|
|
32
|
+
const packages = await collectPackageJsons(root);
|
|
33
|
+
for (const pkg of packages) {
|
|
34
|
+
pkg.path = relative(root, pkg.path);
|
|
35
|
+
}
|
|
36
|
+
const files = [];
|
|
37
|
+
const includeGlobs = include == null ? null : picomatch(include);
|
|
38
|
+
const excludeGlobs = exclude == null ? null : picomatch(exclude);
|
|
39
|
+
for (const file of changed) {
|
|
40
|
+
const pkg = packages.find((pkg2) => file.startsWith(pkg2.path));
|
|
41
|
+
if (!pkg) continue;
|
|
42
|
+
const relPath = relative(pkg.path, file);
|
|
43
|
+
if (includeGlobs != null && !includeGlobs(relPath)) continue;
|
|
44
|
+
if (excludeGlobs != null && excludeGlobs(relPath)) continue;
|
|
45
|
+
const info = {
|
|
46
|
+
file: relPath,
|
|
47
|
+
package: pkg,
|
|
48
|
+
root
|
|
49
|
+
};
|
|
50
|
+
if (!await shouldInclude(info)) continue;
|
|
51
|
+
files.push(info);
|
|
52
|
+
}
|
|
53
|
+
return files;
|
|
54
|
+
}
|
|
55
|
+
async function findProjectChangedPackages(params) {
|
|
56
|
+
const files = await findProjectChangedFiles(params);
|
|
57
|
+
const set = /* @__PURE__ */ new Set();
|
|
58
|
+
for (const file of files) {
|
|
59
|
+
if (file.package != null) set.add(file.package);
|
|
60
|
+
}
|
|
61
|
+
return Array.from(set);
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
findProjectChangedFiles,
|
|
65
|
+
findProjectChangedPackages
|
|
66
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { WorkspacePackage } from '../package-json/index.js';
|
|
2
|
+
import { VersioningOptions } from './types.js';
|
|
3
|
+
/** simple changelog generator based on git commits history */
|
|
4
|
+
export declare function generateChangelog(params: {
|
|
5
|
+
/** packages for which to generate the changelog */
|
|
6
|
+
workspace: WorkspacePackage[];
|
|
7
|
+
/** root of the git repo */
|
|
8
|
+
cwd?: string | URL;
|
|
9
|
+
/** starting point for the changelog (defaults to latest tag) */
|
|
10
|
+
since: string;
|
|
11
|
+
/** versioning params */
|
|
12
|
+
params?: VersioningOptions;
|
|
13
|
+
}): Promise<string>;
|