@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,68 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { satisfies } from "semver";
|
|
3
|
+
import { collectPackageJsons } from "../../package-json/collect-package-jsons.js";
|
|
4
|
+
import * as bc from "@drizzle-team/brocli";
|
|
5
|
+
async function validateWorkspaceDeps(workspaceRoot, params) {
|
|
6
|
+
const { includeRoot = true, skipWorkspaceDeps = true } = params || {};
|
|
7
|
+
const pjs = await collectPackageJsons(workspaceRoot, includeRoot);
|
|
8
|
+
const workspacePackages = new Set(skipWorkspaceDeps ? pjs.map((pj) => pj.json.name) : []);
|
|
9
|
+
const versions = {};
|
|
10
|
+
const errors = [];
|
|
11
|
+
for (const { json: pj } of pjs) {
|
|
12
|
+
if (pj.name === void 0) {
|
|
13
|
+
throw new Error("package.json without name is not supported");
|
|
14
|
+
}
|
|
15
|
+
for (const field of ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]) {
|
|
16
|
+
const deps = pj[field];
|
|
17
|
+
if (!deps) continue;
|
|
18
|
+
for (const [name, version] of Object.entries(deps)) {
|
|
19
|
+
if (workspacePackages.has(name)) continue;
|
|
20
|
+
if (version.startsWith("workspace:")) continue;
|
|
21
|
+
if (versions[name] === void 0) {
|
|
22
|
+
versions[name] = {};
|
|
23
|
+
}
|
|
24
|
+
for (const [pkgName, pkgDepVersions] of Object.entries(versions[name])) {
|
|
25
|
+
if (!satisfies(version, pkgDepVersions)) {
|
|
26
|
+
errors.push({
|
|
27
|
+
package: pj.name,
|
|
28
|
+
dependency: name,
|
|
29
|
+
version,
|
|
30
|
+
at: field,
|
|
31
|
+
otherPackage: pkgName,
|
|
32
|
+
otherVersion: pkgDepVersions
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
versions[name][pj.name] = version;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return errors;
|
|
41
|
+
}
|
|
42
|
+
const validateWorkspaceDepsCli = bc.command({
|
|
43
|
+
name: "validate-workspace-deps",
|
|
44
|
+
desc: "validate the external dependencies of a workspace",
|
|
45
|
+
options: {
|
|
46
|
+
includeRoot: bc.boolean("include-root").desc("whether to also validate the root package.json").default(false),
|
|
47
|
+
noSkipWorkspaceDeps: bc.boolean("no-skip-workspace-deps").desc("whether to not skip validating dependencies of other workspace packages"),
|
|
48
|
+
root: bc.string().desc("path to the root of the workspace (default: cwd)")
|
|
49
|
+
},
|
|
50
|
+
handler: async (args) => {
|
|
51
|
+
const errors = await validateWorkspaceDeps(args.root ?? process.cwd(), {
|
|
52
|
+
includeRoot: args.includeRoot,
|
|
53
|
+
skipWorkspaceDeps: !args.noSkipWorkspaceDeps
|
|
54
|
+
});
|
|
55
|
+
if (errors.length > 0) {
|
|
56
|
+
console.error("⚠️ Found external dependencies mismatch:");
|
|
57
|
+
for (const error of errors) {
|
|
58
|
+
console.error(` - at ${error.package}: ${error.at} has ${error.dependency}@${error.version}, but ${error.otherPackage} has @${error.otherVersion}`);
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
console.log("✅ All external dependencies match!");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
export {
|
|
66
|
+
validateWorkspaceDeps,
|
|
67
|
+
validateWorkspaceDepsCli
|
|
68
|
+
};
|
package/cli/index.d.ts
ADDED
package/cli/main.d.ts
ADDED
package/config.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { JsrConfig } from './jsr/config.js';
|
|
2
|
+
import { PackageJson } from './package-json/types.js';
|
|
3
|
+
import { VersioningOptions } from './versioning/types.js';
|
|
4
|
+
export interface BuildHookContext {
|
|
5
|
+
/** full path to the output directory */
|
|
6
|
+
outDir: string;
|
|
7
|
+
/** full path to the package directory */
|
|
8
|
+
packageDir: string;
|
|
9
|
+
/** name of the package being build */
|
|
10
|
+
packageName: string;
|
|
11
|
+
/**
|
|
12
|
+
* package.json of the package being build
|
|
13
|
+
* should not be modified unless allowed in the hook docs
|
|
14
|
+
*/
|
|
15
|
+
packageJson: PackageJson;
|
|
16
|
+
/** whether this is a jsr build */
|
|
17
|
+
jsr: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface RootConfigObject {
|
|
20
|
+
/**
|
|
21
|
+
* path to vite config to use when building using fuman-build cli,
|
|
22
|
+
* relative to the workspace root
|
|
23
|
+
*
|
|
24
|
+
* @default "vite.config.js"
|
|
25
|
+
*/
|
|
26
|
+
viteConfig?: string;
|
|
27
|
+
/** jsr-specific configuration */
|
|
28
|
+
jsr?: JsrConfig;
|
|
29
|
+
/** configuration for the changelog generator */
|
|
30
|
+
versioning?: VersioningOptions;
|
|
31
|
+
}
|
|
32
|
+
export type RootConfig = RootConfigObject | (() => RootConfigObject);
|
package/fuman-build.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./cli/main.js"
|
package/fuman-build.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import * as bc from "@drizzle-team/brocli";
|
|
4
|
+
import { buildPackageCli } from "./cli/commands/build.js";
|
|
5
|
+
import { bumpVersionCli } from "./cli/commands/bump-version.js";
|
|
6
|
+
import { runContinuousReleaseCli } from "./cli/commands/cr.js";
|
|
7
|
+
import { findChangedPackagesCli } from "./cli/commands/find-changed-packages.js";
|
|
8
|
+
import { generateChangelogCli } from "./cli/commands/gen-changelog.js";
|
|
9
|
+
import { generateDepsGraphCli } from "./cli/commands/gen-deps-graph.js";
|
|
10
|
+
import { jsrCli } from "./cli/commands/jsr.js";
|
|
11
|
+
import { publishPackagesCli } from "./cli/commands/publish.js";
|
|
12
|
+
import { releaseCli } from "./cli/commands/release.js";
|
|
13
|
+
import { validateWorkspaceDepsCli } from "./cli/commands/validate-workspace-deps.js";
|
|
14
|
+
await bc.run([
|
|
15
|
+
validateWorkspaceDepsCli,
|
|
16
|
+
generateDepsGraphCli,
|
|
17
|
+
buildPackageCli,
|
|
18
|
+
jsrCli,
|
|
19
|
+
generateChangelogCli,
|
|
20
|
+
findChangedPackagesCli,
|
|
21
|
+
bumpVersionCli,
|
|
22
|
+
publishPackagesCli,
|
|
23
|
+
releaseCli,
|
|
24
|
+
runContinuousReleaseCli
|
|
25
|
+
], {
|
|
26
|
+
theme: (event) => {
|
|
27
|
+
if (event.type === "error" && event.violation === "unknown_error") {
|
|
28
|
+
console.error(event.error);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
});
|
package/git/github.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function createGithubRelease(params: {
|
|
2
|
+
token: string;
|
|
3
|
+
repo: string;
|
|
4
|
+
tag: string;
|
|
5
|
+
name: string;
|
|
6
|
+
body: string;
|
|
7
|
+
draft?: boolean;
|
|
8
|
+
prerelease?: boolean;
|
|
9
|
+
artifacts?: {
|
|
10
|
+
name: string;
|
|
11
|
+
type: string;
|
|
12
|
+
body: BodyInit;
|
|
13
|
+
}[];
|
|
14
|
+
}): Promise<number>;
|
package/git/github.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ffetchBase, ffetchAddons } from "@fuman/fetch";
|
|
2
|
+
import { ffetchZodAdapter } from "@fuman/fetch/zod";
|
|
3
|
+
import { asyncPool } from "@fuman/utils";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
async function createGithubRelease(params) {
|
|
6
|
+
const ffetch = ffetchBase.extend({
|
|
7
|
+
baseUrl: "https://api.github.com",
|
|
8
|
+
addons: [
|
|
9
|
+
ffetchAddons.retry(),
|
|
10
|
+
ffetchAddons.parser(ffetchZodAdapter())
|
|
11
|
+
],
|
|
12
|
+
headers: {
|
|
13
|
+
"Accept": "application/vnd.github+json",
|
|
14
|
+
"User-Agent": "@fuman/build",
|
|
15
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
16
|
+
"Authorization": `Bearer ${params.token}`
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const release = await ffetch.post(`/repos/${params.repo}/releases`, {
|
|
20
|
+
json: {
|
|
21
|
+
tag_name: params.tag,
|
|
22
|
+
name: params.name,
|
|
23
|
+
body: params.body,
|
|
24
|
+
draft: params.draft,
|
|
25
|
+
prerelease: params.prerelease
|
|
26
|
+
},
|
|
27
|
+
validateResponse: (res) => res.status === 201
|
|
28
|
+
}).parsedJson(z.object({
|
|
29
|
+
id: z.number()
|
|
30
|
+
}));
|
|
31
|
+
if (params.artifacts != null && params.artifacts.length > 0) {
|
|
32
|
+
await asyncPool(params.artifacts, async (file) => {
|
|
33
|
+
await ffetch(`/repos/${params.repo}/releases/${release.id}/assets`, {
|
|
34
|
+
method: "POST",
|
|
35
|
+
query: { name: file.name },
|
|
36
|
+
headers: {
|
|
37
|
+
"Content-Type": file.type
|
|
38
|
+
},
|
|
39
|
+
body: file.body,
|
|
40
|
+
validateResponse: (res) => res.status === 201
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return release.id;
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
createGithubRelease
|
|
48
|
+
};
|
package/git/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './utils.js';
|
package/git/utils.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare function getLatestTag(cwd?: string | URL): Promise<string | null>;
|
|
2
|
+
export declare function getFirstCommit(cwd?: string | URL): Promise<string>;
|
|
3
|
+
export declare function getCurrentCommit(cwd?: string | URL): Promise<string>;
|
|
4
|
+
export declare function getCurrentBranch(cwd?: string | URL): Promise<string>;
|
|
5
|
+
export declare function findChangedFiles(params: {
|
|
6
|
+
since: string;
|
|
7
|
+
/** @default 'HEAD' */
|
|
8
|
+
until?: string;
|
|
9
|
+
cwd?: string | URL;
|
|
10
|
+
}): Promise<string[]>;
|
|
11
|
+
export interface CommitInfo {
|
|
12
|
+
hash: string;
|
|
13
|
+
author: {
|
|
14
|
+
name: string;
|
|
15
|
+
email: string;
|
|
16
|
+
date: Date;
|
|
17
|
+
};
|
|
18
|
+
committer: {
|
|
19
|
+
name: string;
|
|
20
|
+
email: string;
|
|
21
|
+
date: Date;
|
|
22
|
+
};
|
|
23
|
+
message: string;
|
|
24
|
+
description: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function getCommitsBetween(params: {
|
|
27
|
+
since: string;
|
|
28
|
+
/** @default 'HEAD' */
|
|
29
|
+
until?: string;
|
|
30
|
+
cwd?: string | URL;
|
|
31
|
+
}): Promise<CommitInfo[]>;
|
|
32
|
+
export interface ConventionalCommit {
|
|
33
|
+
type: string;
|
|
34
|
+
scope?: string;
|
|
35
|
+
breaking: boolean;
|
|
36
|
+
subject: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function parseConventionalCommit(msg: string): ConventionalCommit | null;
|
package/git/utils.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { exec } from "../misc/exec.js";
|
|
3
|
+
async function getLatestTag(cwd) {
|
|
4
|
+
const res = await exec(["git", "describe", "--abbrev=0", "--tags"], { cwd });
|
|
5
|
+
if (res.exitCode !== 0) {
|
|
6
|
+
if (res.stderr.match(/^fatal: (?:No names found|No tags can describe)/i)) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
throw new Error(`git describe failed: ${res.stderr}`);
|
|
10
|
+
}
|
|
11
|
+
return res.stdout.trim();
|
|
12
|
+
}
|
|
13
|
+
async function getFirstCommit(cwd) {
|
|
14
|
+
return (await exec(["git", "rev-list", "--max-parents=0", "HEAD"], {
|
|
15
|
+
cwd,
|
|
16
|
+
throwOnError: true
|
|
17
|
+
})).stdout.trim();
|
|
18
|
+
}
|
|
19
|
+
async function getCurrentCommit(cwd) {
|
|
20
|
+
const res = await exec(["git", "rev-parse", "HEAD"], {
|
|
21
|
+
cwd,
|
|
22
|
+
throwOnError: true
|
|
23
|
+
});
|
|
24
|
+
return res.stdout.trim();
|
|
25
|
+
}
|
|
26
|
+
async function getCurrentBranch(cwd) {
|
|
27
|
+
const res = await exec(["git", "rev-parse", "--abbrev-ref", "HEAD"], {
|
|
28
|
+
cwd,
|
|
29
|
+
throwOnError: true
|
|
30
|
+
});
|
|
31
|
+
return res.stdout.trim();
|
|
32
|
+
}
|
|
33
|
+
async function findChangedFiles(params) {
|
|
34
|
+
const { since, until = "HEAD", cwd } = params;
|
|
35
|
+
const res = await exec(["git", "diff", "--name-only", since, until], {
|
|
36
|
+
cwd,
|
|
37
|
+
throwOnError: true
|
|
38
|
+
});
|
|
39
|
+
const files = res.stdout.trim().split("\n");
|
|
40
|
+
if (files.length === 1 && files[0] === "") {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
return files;
|
|
44
|
+
}
|
|
45
|
+
async function getCommitsBetween(params) {
|
|
46
|
+
const { since, until = "HEAD", cwd } = params;
|
|
47
|
+
const delim = `---${randomUUID()}---`;
|
|
48
|
+
const res = await exec(["git", "log", `--pretty=format:%H %s%n%an%n%ae%n%aI%n%cn%n%ce%n%cI%n%b%n${delim}`, `${since}..${until}`], {
|
|
49
|
+
cwd,
|
|
50
|
+
throwOnError: true
|
|
51
|
+
});
|
|
52
|
+
const lines = res.stdout.trim().split("\n");
|
|
53
|
+
const items = [];
|
|
54
|
+
let current = null;
|
|
55
|
+
for (let i = 0; i < lines.length; i++) {
|
|
56
|
+
const line = lines[i];
|
|
57
|
+
if (line === delim) {
|
|
58
|
+
if (current) items.push(current);
|
|
59
|
+
current = null;
|
|
60
|
+
} else if (current) {
|
|
61
|
+
if (current.description) current.description += "\n";
|
|
62
|
+
current.description += line;
|
|
63
|
+
} else {
|
|
64
|
+
const [hash, ...msg] = line.split(" ");
|
|
65
|
+
const authorName = lines[++i];
|
|
66
|
+
const authorEmail = lines[++i];
|
|
67
|
+
const authorDate = lines[++i];
|
|
68
|
+
const committerName = lines[++i];
|
|
69
|
+
const committerEmail = lines[++i];
|
|
70
|
+
const committerDate = lines[++i];
|
|
71
|
+
current = {
|
|
72
|
+
hash,
|
|
73
|
+
author: {
|
|
74
|
+
name: authorName,
|
|
75
|
+
email: authorEmail,
|
|
76
|
+
date: new Date(authorDate)
|
|
77
|
+
},
|
|
78
|
+
committer: {
|
|
79
|
+
name: committerName,
|
|
80
|
+
email: committerEmail,
|
|
81
|
+
date: new Date(committerDate)
|
|
82
|
+
},
|
|
83
|
+
message: msg.join(" "),
|
|
84
|
+
description: ""
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (current) items.push(current);
|
|
89
|
+
return items.reverse();
|
|
90
|
+
}
|
|
91
|
+
function parseConventionalCommit(msg) {
|
|
92
|
+
const match = msg.match(/^(\w+)(?:\(([^)]+)\))?(!?): (.+)$/);
|
|
93
|
+
if (!match) return null;
|
|
94
|
+
const [, type, scope, breaking, subject] = match;
|
|
95
|
+
return {
|
|
96
|
+
type,
|
|
97
|
+
scope,
|
|
98
|
+
breaking: Boolean(breaking),
|
|
99
|
+
subject
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export {
|
|
103
|
+
findChangedFiles,
|
|
104
|
+
getCommitsBetween,
|
|
105
|
+
getCurrentBranch,
|
|
106
|
+
getCurrentCommit,
|
|
107
|
+
getFirstCommit,
|
|
108
|
+
getLatestTag,
|
|
109
|
+
parseConventionalCommit
|
|
110
|
+
};
|
package/index.d.ts
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { getGithubActionsInput, isRunningInGithubActions, writeGithubActionsOutput } from "./ci/github-actions.js";
|
|
2
|
+
import { buildPackage } from "./cli/commands/build.js";
|
|
3
|
+
import { generateDepsGraph } from "./cli/commands/gen-deps-graph.js";
|
|
4
|
+
import { validateWorkspaceDeps } from "./cli/commands/validate-workspace-deps.js";
|
|
5
|
+
import { findChangedFiles, getCommitsBetween, getCurrentBranch, getCurrentCommit, getFirstCommit, getLatestTag, parseConventionalCommit } from "./git/utils.js";
|
|
6
|
+
import { exec } from "./misc/exec.js";
|
|
7
|
+
import { normalizeFilePath } from "./misc/path.js";
|
|
8
|
+
import { determinePublishOrder, sortWorkspaceByPublishOrder } from "./misc/publish-order.js";
|
|
9
|
+
import { getTsconfigFiles, getTsconfigFor } from "./misc/tsconfig.js";
|
|
10
|
+
import { NPM_PACKAGE_NAME_REGEX, npmCheckVersion } from "./npm/npm-api.js";
|
|
11
|
+
import { collectPackageJsons, filterPackageJsonsForPublish } from "./package-json/collect-package-jsons.js";
|
|
12
|
+
import { findPackageJson } from "./package-json/find-package-json.js";
|
|
13
|
+
import { parsePackageJson, parsePackageJsonFile, parseWorkspaceRootPackageJson } from "./package-json/parse.js";
|
|
14
|
+
import { processPackageJson } from "./package-json/process-package-json.js";
|
|
15
|
+
import { PackageJsonSchema } from "./package-json/types.js";
|
|
16
|
+
export {
|
|
17
|
+
NPM_PACKAGE_NAME_REGEX,
|
|
18
|
+
PackageJsonSchema,
|
|
19
|
+
buildPackage,
|
|
20
|
+
collectPackageJsons,
|
|
21
|
+
determinePublishOrder,
|
|
22
|
+
exec,
|
|
23
|
+
filterPackageJsonsForPublish,
|
|
24
|
+
findChangedFiles,
|
|
25
|
+
findPackageJson,
|
|
26
|
+
generateDepsGraph,
|
|
27
|
+
getCommitsBetween,
|
|
28
|
+
getCurrentBranch,
|
|
29
|
+
getCurrentCommit,
|
|
30
|
+
getFirstCommit,
|
|
31
|
+
getGithubActionsInput,
|
|
32
|
+
getLatestTag,
|
|
33
|
+
getTsconfigFiles,
|
|
34
|
+
getTsconfigFor,
|
|
35
|
+
isRunningInGithubActions,
|
|
36
|
+
normalizeFilePath,
|
|
37
|
+
npmCheckVersion,
|
|
38
|
+
parseConventionalCommit,
|
|
39
|
+
parsePackageJson,
|
|
40
|
+
parsePackageJsonFile,
|
|
41
|
+
parseWorkspaceRootPackageJson,
|
|
42
|
+
processPackageJson,
|
|
43
|
+
sortWorkspaceByPublishOrder,
|
|
44
|
+
validateWorkspaceDeps,
|
|
45
|
+
writeGithubActionsOutput
|
|
46
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { WorkspacePackage } from '../package-json/collect-package-jsons.js';
|
|
2
|
+
import { JsrConfig } from './config.js';
|
|
3
|
+
export declare function runJsrBuild(params: {
|
|
4
|
+
packageName: string;
|
|
5
|
+
workspacePackages: WorkspacePackage[];
|
|
6
|
+
rootConfig?: JsrConfig;
|
|
7
|
+
}): Promise<void>;
|
package/jsr/build-jsr.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import * as fsp from "node:fs/promises";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
import { asyncPool, asNonNull } from "@fuman/utils";
|
|
4
|
+
import { glob } from "tinyglobby";
|
|
5
|
+
import ts from "typescript";
|
|
6
|
+
import { loadBuildConfig } from "../misc/_config.js";
|
|
7
|
+
import { exec } from "../misc/exec.js";
|
|
8
|
+
import { tryCopy } from "../misc/fs.js";
|
|
9
|
+
import { normalizeFilePath } from "../misc/path.js";
|
|
10
|
+
import { processPackageJson } from "../package-json/process-package-json.js";
|
|
11
|
+
import { findPackageByName, findRootPackage, collectVersions } from "../package-json/utils.js";
|
|
12
|
+
import { packageJsonToDeno } from "./deno-json.js";
|
|
13
|
+
function mergeArrays(a, b, defaultValue = []) {
|
|
14
|
+
if (!a) return b ?? defaultValue;
|
|
15
|
+
if (!b) return a;
|
|
16
|
+
return [...a, ...b];
|
|
17
|
+
}
|
|
18
|
+
async function runJsrBuild(params) {
|
|
19
|
+
const {
|
|
20
|
+
packageName,
|
|
21
|
+
workspacePackages,
|
|
22
|
+
rootConfig
|
|
23
|
+
} = params;
|
|
24
|
+
const ourPackage = findPackageByName(workspacePackages, packageName);
|
|
25
|
+
const rootPackage = findRootPackage(workspacePackages);
|
|
26
|
+
const packageRoot = ourPackage.path;
|
|
27
|
+
const workspaceRoot = rootPackage.path;
|
|
28
|
+
const outDir = join(packageRoot, normalizeFilePath(rootConfig?.outputDir ?? "dist"));
|
|
29
|
+
const packageConfig = await loadBuildConfig(packageRoot);
|
|
30
|
+
const srcDir = join(packageRoot, normalizeFilePath(packageConfig?.jsr?.sourceDir ?? rootConfig?.sourceDir ?? ""));
|
|
31
|
+
const excludeFiles = mergeArrays(rootConfig?.exclude, packageConfig?.jsr?.exclude);
|
|
32
|
+
await fsp.rm(outDir, { recursive: true, force: true });
|
|
33
|
+
await fsp.mkdir(outDir, { recursive: true });
|
|
34
|
+
await asyncPool(await fsp.readdir(srcDir), async (file) => {
|
|
35
|
+
const src = join(srcDir, file);
|
|
36
|
+
if (src === outDir) return;
|
|
37
|
+
await fsp.cp(src, join(outDir, file), { recursive: true });
|
|
38
|
+
});
|
|
39
|
+
const printer = ts.createPrinter();
|
|
40
|
+
const tsFiles = await glob("**/*.ts", {
|
|
41
|
+
cwd: outDir,
|
|
42
|
+
ignore: excludeFiles
|
|
43
|
+
});
|
|
44
|
+
const badImports = [];
|
|
45
|
+
await asyncPool(tsFiles, async (filename) => {
|
|
46
|
+
const fullFilePath = join(outDir, filename);
|
|
47
|
+
let fileContent = await fsp.readFile(fullFilePath, "utf8");
|
|
48
|
+
let changed = false;
|
|
49
|
+
const file = ts.createSourceFile(filename, fileContent, ts.ScriptTarget.ESNext, true);
|
|
50
|
+
let changedTs = false;
|
|
51
|
+
for (const imp of file.statements) {
|
|
52
|
+
if (!ts.isImportDeclaration(imp) && !ts.isExportDeclaration(imp)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (!imp.moduleSpecifier || !ts.isStringLiteral(imp.moduleSpecifier)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const mod = imp.moduleSpecifier.text;
|
|
59
|
+
if (mod[0] !== ".") {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (mod.endsWith(".js")) {
|
|
63
|
+
changedTs = true;
|
|
64
|
+
imp.moduleSpecifier = ts.factory.createStringLiteral(
|
|
65
|
+
mod.replace(/\.js$/, ".ts")
|
|
66
|
+
);
|
|
67
|
+
} else {
|
|
68
|
+
badImports.push(` from ${mod} at ${join(srcDir, filename)}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (rootConfig?.transformAst?.(file)) {
|
|
72
|
+
changedTs = true;
|
|
73
|
+
}
|
|
74
|
+
if (packageConfig?.jsr?.transformAst?.(file)) {
|
|
75
|
+
changedTs = true;
|
|
76
|
+
}
|
|
77
|
+
if (changedTs) {
|
|
78
|
+
fileContent = printer.printFile(file);
|
|
79
|
+
changed = true;
|
|
80
|
+
}
|
|
81
|
+
if (rootConfig?.transformCode || packageConfig?.jsr?.transformCode) {
|
|
82
|
+
const origFileContent = fileContent;
|
|
83
|
+
if (rootConfig?.transformCode) {
|
|
84
|
+
fileContent = rootConfig.transformCode(filename, fileContent);
|
|
85
|
+
}
|
|
86
|
+
if (packageConfig?.jsr?.transformCode) {
|
|
87
|
+
fileContent = packageConfig.jsr.transformCode(filename, fileContent);
|
|
88
|
+
}
|
|
89
|
+
if (fileContent !== origFileContent) {
|
|
90
|
+
changed = true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (changed) {
|
|
94
|
+
await fsp.writeFile(fullFilePath, fileContent);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
if (badImports.length > 0) {
|
|
98
|
+
throw new Error(`Found ${badImports.length} invalid imports (you must specify .js extension):
|
|
99
|
+
${badImports.join("\n")}`);
|
|
100
|
+
}
|
|
101
|
+
const hookContext = {
|
|
102
|
+
outDir: "",
|
|
103
|
+
packageDir: ourPackage.path,
|
|
104
|
+
packageName: asNonNull(ourPackage.json.name),
|
|
105
|
+
packageJson: ourPackage.json,
|
|
106
|
+
jsr: true
|
|
107
|
+
};
|
|
108
|
+
packageConfig?.preparePackageJson?.(hookContext);
|
|
109
|
+
const workspaceVersions = collectVersions(workspacePackages);
|
|
110
|
+
const { packageJson, packageJsonOrig } = processPackageJson({
|
|
111
|
+
packageJson: ourPackage.json,
|
|
112
|
+
rootPackageJson: rootPackage.json,
|
|
113
|
+
workspaceVersions,
|
|
114
|
+
// since there's no bundling, we can't drop any deps.
|
|
115
|
+
// we *could* copy them from node_modules and add to the import map,
|
|
116
|
+
// but maybe sometime later
|
|
117
|
+
bundledWorkspaceDeps: [],
|
|
118
|
+
rootFieldsToCopy: ["license"]
|
|
119
|
+
});
|
|
120
|
+
const denoJson = packageJsonToDeno({
|
|
121
|
+
packageJson,
|
|
122
|
+
packageJsonOrig,
|
|
123
|
+
workspaceVersions,
|
|
124
|
+
buildDirName: relative(packageRoot, outDir),
|
|
125
|
+
baseDir: relative(packageRoot, srcDir),
|
|
126
|
+
exclude: excludeFiles
|
|
127
|
+
});
|
|
128
|
+
await fsp.writeFile(join(outDir, "deno.json"), JSON.stringify(denoJson, null, 4));
|
|
129
|
+
for (const file of mergeArrays(rootConfig?.copyRootFiles, packageConfig?.jsr?.copyRootFiles, ["LICENSE"])) {
|
|
130
|
+
await tryCopy(join(workspaceRoot, file), join(outDir, file), { recursive: true });
|
|
131
|
+
}
|
|
132
|
+
for (const file of mergeArrays(rootConfig?.copyPackageFiles, packageConfig?.jsr?.copyPackageFiles, ["README.md"])) {
|
|
133
|
+
await tryCopy(join(packageRoot, file), join(outDir, file), { recursive: true });
|
|
134
|
+
}
|
|
135
|
+
if (!packageConfig?.jsr?.dryRun && !rootConfig?.dryRun) {
|
|
136
|
+
await exec(["deno", "publish", "--dry-run", "-q", "--allow-dirty"], {
|
|
137
|
+
cwd: outDir,
|
|
138
|
+
stdio: "inherit",
|
|
139
|
+
throwOnError: true
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
export {
|
|
144
|
+
runJsrBuild
|
|
145
|
+
};
|
package/jsr/config.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { MaybePromise } from '@fuman/utils';
|
|
2
|
+
import { default as ts } from 'typescript';
|
|
3
|
+
import { BuildHookContext } from '../config.js';
|
|
4
|
+
import { WorkspacePackage } from '../package-json/collect-package-jsons.js';
|
|
5
|
+
export interface JsrConfig {
|
|
6
|
+
/**
|
|
7
|
+
* jsr build output dir (relative to workspace root)
|
|
8
|
+
*
|
|
9
|
+
* @default "dist"
|
|
10
|
+
*/
|
|
11
|
+
outputDir?: string;
|
|
12
|
+
/**
|
|
13
|
+
* files to copy from the workspace root directory to the package build directory
|
|
14
|
+
*
|
|
15
|
+
* @default ['LICENSE']
|
|
16
|
+
*/
|
|
17
|
+
copyRootFiles?: string[];
|
|
18
|
+
/**
|
|
19
|
+
* files to copy from the package root directory to the package build directory
|
|
20
|
+
*
|
|
21
|
+
* @default ['README.md']
|
|
22
|
+
*/
|
|
23
|
+
copyPackageFiles?: string[];
|
|
24
|
+
/**
|
|
25
|
+
* source dir (relative to package root)
|
|
26
|
+
* anything outside this dir will be copied as-is
|
|
27
|
+
* @default "" (i.e. the package root itself)
|
|
28
|
+
*/
|
|
29
|
+
sourceDir?: string;
|
|
30
|
+
/** globs to exclude from publishing */
|
|
31
|
+
exclude?: string[];
|
|
32
|
+
/** custom predicate for including packages */
|
|
33
|
+
includePackage?: (pkg: WorkspacePackage) => boolean;
|
|
34
|
+
/**
|
|
35
|
+
* whether to run `deno publish --dry-run` after generating the workspace
|
|
36
|
+
* to make sure everything is ok
|
|
37
|
+
* @default true
|
|
38
|
+
*/
|
|
39
|
+
dryRun?: boolean;
|
|
40
|
+
/** hook to run after the deno.json file is generated but before it is written to disk */
|
|
41
|
+
finalizeDenoJson?: (ctx: BuildHookContext, jsr: any) => void;
|
|
42
|
+
/** hook to run *after* the build is done, time to do any final modifications to the package contents */
|
|
43
|
+
finalize?: (ctx: BuildHookContext) => MaybePromise<void>;
|
|
44
|
+
/** hook that will be run on each file as it is being processed, allowing you to change ast as you wish */
|
|
45
|
+
transformAst?: (ast: ts.SourceFile) => boolean;
|
|
46
|
+
/** similar to transformAst, but for the code itself (runs after transformAst) */
|
|
47
|
+
transformCode?: (path: string, code: string) => string;
|
|
48
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { WorkspacePackage } from '../package-json/collect-package-jsons.js';
|
|
2
|
+
export declare function jsrCreatePackages(params: {
|
|
3
|
+
workspaceRoot: string;
|
|
4
|
+
workspacePackages?: WorkspacePackage[];
|
|
5
|
+
registry?: string;
|
|
6
|
+
token?: string;
|
|
7
|
+
githubRepo?: string;
|
|
8
|
+
}): Promise<boolean>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { filterPackageJsonsForPublish, collectPackageJsons } from "../package-json/collect-package-jsons.js";
|
|
3
|
+
import { jsrMaybeCreatePackage, jsrSetGithubRepo } from "./utils/jsr-api.js";
|
|
4
|
+
import { jsrCheckVersion } from "./utils/jsr.js";
|
|
5
|
+
async function jsrCreatePackages(params) {
|
|
6
|
+
const {
|
|
7
|
+
workspaceRoot,
|
|
8
|
+
registry = process.env.JSR_URL ?? "https://jsr.io",
|
|
9
|
+
token,
|
|
10
|
+
githubRepo
|
|
11
|
+
} = params;
|
|
12
|
+
const workspace = filterPackageJsonsForPublish(params.workspacePackages ?? await collectPackageJsons(workspaceRoot, false), "jsr");
|
|
13
|
+
let hasFailed = false;
|
|
14
|
+
for (const pkg of workspace) {
|
|
15
|
+
if (pkg.json.name == null) continue;
|
|
16
|
+
if (await jsrCheckVersion({ registry, package: pkg.json.name })) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const [scope_, packageName] = pkg.json.name.split("/");
|
|
20
|
+
const scope = scope_.slice(1);
|
|
21
|
+
if (token == null) {
|
|
22
|
+
console.log(`ℹ️ to create \x1B[;33m${pkg.json.name}\x1B[;0m follow this link: \x1B[;34m${new URL(`/create?scope=${scope}&package=${packageName}`, registry).href}\x1B[;0m`);
|
|
23
|
+
hasFailed = true;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
await jsrMaybeCreatePackage({
|
|
27
|
+
name: pkg.json.name,
|
|
28
|
+
registry,
|
|
29
|
+
token
|
|
30
|
+
});
|
|
31
|
+
if (githubRepo != null) {
|
|
32
|
+
const [owner, repo] = githubRepo.split("/");
|
|
33
|
+
await jsrSetGithubRepo({
|
|
34
|
+
registry,
|
|
35
|
+
name: pkg.json.name,
|
|
36
|
+
token,
|
|
37
|
+
owner,
|
|
38
|
+
repo
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return hasFailed;
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
jsrCreatePackages
|
|
46
|
+
};
|