@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,80 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { parseConfigFileTextToJson } from "typescript";
|
|
4
|
+
import { parseImportSpecifier } from "./external-libs.js";
|
|
5
|
+
function parseJsrJson(json) {
|
|
6
|
+
const res = parseConfigFileTextToJson("jsr.json", json);
|
|
7
|
+
if (res.error) {
|
|
8
|
+
throw new Error(res.error.messageText.toString());
|
|
9
|
+
}
|
|
10
|
+
const obj = res.config;
|
|
11
|
+
if (typeof obj !== "object" || obj === null) {
|
|
12
|
+
throw new Error("Expected object");
|
|
13
|
+
}
|
|
14
|
+
if (typeof obj.name !== "string") {
|
|
15
|
+
throw new TypeError('Expected "name" to be a string');
|
|
16
|
+
}
|
|
17
|
+
if (typeof obj.version !== "string") {
|
|
18
|
+
throw new TypeError('Expected "version" to be a string');
|
|
19
|
+
}
|
|
20
|
+
if (typeof obj.exports !== "string" && (typeof obj.exports !== "object" || obj.exports === null)) {
|
|
21
|
+
throw new TypeError('Expected "exports" to be a string or an object');
|
|
22
|
+
}
|
|
23
|
+
if (typeof obj.exports !== "string") {
|
|
24
|
+
for (const key in obj.exports) {
|
|
25
|
+
if (typeof key !== "string") {
|
|
26
|
+
throw new TypeError("exports: Expected key to be a string");
|
|
27
|
+
}
|
|
28
|
+
if (typeof obj.exports[key] !== "string") {
|
|
29
|
+
throw new TypeError("exports: Expected value to be a string");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (obj.imports !== void 0) {
|
|
34
|
+
if (typeof obj.imports !== "object" || obj.imports === null) {
|
|
35
|
+
throw new TypeError('Expected "imports" to be an object');
|
|
36
|
+
}
|
|
37
|
+
for (const key in obj.imports) {
|
|
38
|
+
if (typeof key !== "string") {
|
|
39
|
+
throw new TypeError("imports: Expected key to be a string");
|
|
40
|
+
}
|
|
41
|
+
if (typeof obj.imports[key] !== "string") {
|
|
42
|
+
throw new TypeError("imports: Expected value to be a string");
|
|
43
|
+
}
|
|
44
|
+
obj.imports[key] = parseImportSpecifier(obj.imports[key]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (obj.compilerOptions !== void 0) {
|
|
48
|
+
if (typeof obj.compilerOptions !== "object" || obj.compilerOptions === null) {
|
|
49
|
+
throw new TypeError('Expected "compilerOptions" to be an object');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return obj;
|
|
53
|
+
}
|
|
54
|
+
const _findClosestJsrJsonCache = /* @__PURE__ */ new Map();
|
|
55
|
+
function findClosestJsrJson(path) {
|
|
56
|
+
while (true) {
|
|
57
|
+
if (_findClosestJsrJsonCache.has(path)) {
|
|
58
|
+
return _findClosestJsrJsonCache.get(path);
|
|
59
|
+
}
|
|
60
|
+
for (const file of ["jsr.json", "deno.json", "jsr.jsonc", "deno.jsonc"]) {
|
|
61
|
+
if (existsSync(join(path, file))) {
|
|
62
|
+
_findClosestJsrJsonCache.set(path, join(path, file));
|
|
63
|
+
return join(path, file);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (existsSync(join(path, "package.json"))) {
|
|
67
|
+
_findClosestJsrJsonCache.set(path, null);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const parent = join(path, "..");
|
|
71
|
+
if (parent === path) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
path = parent;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
findClosestJsrJson,
|
|
79
|
+
parseJsrJson
|
|
80
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ImportSpecifier } from './external-libs.js';
|
|
2
|
+
/** check if a specific version (or a package at all) is available in the jsr registry */
|
|
3
|
+
export declare function jsrCheckVersion(params: {
|
|
4
|
+
registry?: string;
|
|
5
|
+
package: string;
|
|
6
|
+
version?: string;
|
|
7
|
+
}): Promise<boolean>;
|
|
8
|
+
export declare function downloadJsrPackage(specifier: ImportSpecifier, params?: {
|
|
9
|
+
registry?: string;
|
|
10
|
+
force?: boolean;
|
|
11
|
+
}): Promise<string>;
|
package/jsr/utils/jsr.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as fsp from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { ffetchBase, ffetchAddons } from "@fuman/fetch";
|
|
6
|
+
import { ffetchZodAdapter } from "@fuman/fetch/zod";
|
|
7
|
+
import { write, webReadableToFuman } from "@fuman/io";
|
|
8
|
+
import { nodeWritableToFuman } from "@fuman/node";
|
|
9
|
+
import { asyncPool } from "@fuman/utils";
|
|
10
|
+
import semver from "semver";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { directoryExists } from "../../misc/fs.js";
|
|
13
|
+
import { getModuleCacheDirectory } from "./external-libs.js";
|
|
14
|
+
const DEFAULT_REGISTRY = process.env.JSR_URL ?? "https://jsr.io";
|
|
15
|
+
async function jsrCheckVersion(params) {
|
|
16
|
+
const {
|
|
17
|
+
registry = DEFAULT_REGISTRY,
|
|
18
|
+
package: packageName,
|
|
19
|
+
version
|
|
20
|
+
} = params;
|
|
21
|
+
const res = await ffetchBase(`/${packageName}/meta${version != null ? `_${version}` : ""}.json`, {
|
|
22
|
+
baseUrl: registry,
|
|
23
|
+
validateResponse: false
|
|
24
|
+
});
|
|
25
|
+
return res.status === 200;
|
|
26
|
+
}
|
|
27
|
+
async function downloadJsrPackage(specifier, params) {
|
|
28
|
+
if (specifier.registry !== "jsr") {
|
|
29
|
+
throw new Error("Invalid registry");
|
|
30
|
+
}
|
|
31
|
+
const registry = params?.registry ?? DEFAULT_REGISTRY;
|
|
32
|
+
const ffetch = ffetchBase.extend({
|
|
33
|
+
baseUrl: registry,
|
|
34
|
+
addons: [
|
|
35
|
+
ffetchAddons.parser(ffetchZodAdapter())
|
|
36
|
+
]
|
|
37
|
+
});
|
|
38
|
+
const targetDir = `${specifier.packageName.replace(/\//g, "+")}@${specifier.version}`;
|
|
39
|
+
const registryHost = new URL(registry).host;
|
|
40
|
+
const cacheDir = join(getModuleCacheDirectory(), "jsr", registryHost, targetDir);
|
|
41
|
+
if (await directoryExists(cacheDir)) {
|
|
42
|
+
if (params?.force) {
|
|
43
|
+
await fsp.rm(cacheDir, { recursive: true });
|
|
44
|
+
} else {
|
|
45
|
+
return cacheDir;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const meta = await ffetch(`${specifier.packageName}/meta.json`).parsedJson(z.object({
|
|
49
|
+
versions: z.record(z.unknown())
|
|
50
|
+
}));
|
|
51
|
+
const availableVersions = Object.keys(meta.versions);
|
|
52
|
+
const version = semver.maxSatisfying(availableVersions, specifier.version);
|
|
53
|
+
if (version == null) {
|
|
54
|
+
throw new Error(`No matching version for ${specifier.packageName}@${specifier.version}`);
|
|
55
|
+
}
|
|
56
|
+
await fsp.mkdir(cacheDir, { recursive: true });
|
|
57
|
+
const versionMeta = await ffetch(`${specifier.packageName}/${version}_meta.json`).parsedJson(z.object({
|
|
58
|
+
manifest: z.record(z.unknown())
|
|
59
|
+
}));
|
|
60
|
+
const fetchFile = async (file) => {
|
|
61
|
+
file = file.replace(/^\//, "");
|
|
62
|
+
const filePath = join(cacheDir, file);
|
|
63
|
+
await fsp.mkdir(join(filePath, ".."), { recursive: true });
|
|
64
|
+
const from = await ffetch(`${specifier.packageName}/${version}/${file}`).stream();
|
|
65
|
+
const into = nodeWritableToFuman(fs.createWriteStream(filePath));
|
|
66
|
+
await write.pipe(into, webReadableToFuman(from));
|
|
67
|
+
};
|
|
68
|
+
await asyncPool(Object.keys(versionMeta.manifest), fetchFile, { limit: 16 });
|
|
69
|
+
return cacheDir;
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
downloadJsrPackage,
|
|
73
|
+
jsrCheckVersion
|
|
74
|
+
};
|
package/jsr.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./jsr/index.js"
|
package/jsr.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { runJsrBuild } from "./jsr/build-jsr.js";
|
|
2
|
+
import { packageJsonToDeno } from "./jsr/deno-json.js";
|
|
3
|
+
import { populateFromUpstream } from "./jsr/populate.js";
|
|
4
|
+
import { getModuleCacheDirectory, parseImportSpecifier, splitImportRequest } from "./jsr/utils/external-libs.js";
|
|
5
|
+
import { jsrCreateScope, jsrGetScopeInfo, jsrMaybeCreatePackage, jsrSetGithubRepo } from "./jsr/utils/jsr-api.js";
|
|
6
|
+
import { findClosestJsrJson, parseJsrJson } from "./jsr/utils/jsr-json.js";
|
|
7
|
+
import { downloadJsrPackage, jsrCheckVersion } from "./jsr/utils/jsr.js";
|
|
8
|
+
export {
|
|
9
|
+
downloadJsrPackage,
|
|
10
|
+
findClosestJsrJson,
|
|
11
|
+
getModuleCacheDirectory,
|
|
12
|
+
jsrCheckVersion,
|
|
13
|
+
jsrCreateScope,
|
|
14
|
+
jsrGetScopeInfo,
|
|
15
|
+
jsrMaybeCreatePackage,
|
|
16
|
+
jsrSetGithubRepo,
|
|
17
|
+
packageJsonToDeno,
|
|
18
|
+
parseImportSpecifier,
|
|
19
|
+
parseJsrJson,
|
|
20
|
+
populateFromUpstream,
|
|
21
|
+
runJsrBuild,
|
|
22
|
+
splitImportRequest
|
|
23
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function loadBuildConfig<T>(packageRoot: string, configName?: string): Promise<T | undefined>;
|
package/misc/_config.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
async function loadBuildConfig(packageRoot, configName = "build.config.js") {
|
|
3
|
+
try {
|
|
4
|
+
const mod = (await import(join(packageRoot, configName))).default;
|
|
5
|
+
if (typeof mod === "function") {
|
|
6
|
+
return mod();
|
|
7
|
+
} else {
|
|
8
|
+
return mod;
|
|
9
|
+
}
|
|
10
|
+
} catch (e) {
|
|
11
|
+
if (!(e instanceof Error && e.code === "ERR_MODULE_NOT_FOUND")) {
|
|
12
|
+
throw new Error(`Could not load ${configName}`, { cause: e });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
loadBuildConfig
|
|
18
|
+
};
|
package/misc/exec.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SpawnOptions } from 'node:child_process';
|
|
2
|
+
export interface ExecResult {
|
|
3
|
+
stdout: string;
|
|
4
|
+
stderr: string;
|
|
5
|
+
exitCode: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function exec(cmd: string[], options?: SpawnOptions & {
|
|
8
|
+
throwOnError?: boolean;
|
|
9
|
+
}): Promise<ExecResult>;
|
package/misc/exec.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
function exec(cmd, options) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
if (options?.stdio === "inherit") {
|
|
5
|
+
console.log("\x1B[;34m$\x1B[;0m", cmd.map((it) => it.includes(" ") ? `"${it.replace(/"/g, '\\"')}"` : it).join(" "));
|
|
6
|
+
}
|
|
7
|
+
const proc = spawn(cmd[0], cmd.slice(1), {
|
|
8
|
+
stdio: "pipe",
|
|
9
|
+
...options
|
|
10
|
+
});
|
|
11
|
+
const stdout = [];
|
|
12
|
+
const stderr = [];
|
|
13
|
+
proc.stdout?.on("data", (data) => {
|
|
14
|
+
stdout.push(data);
|
|
15
|
+
});
|
|
16
|
+
proc.stderr?.on("data", (data) => {
|
|
17
|
+
stderr.push(data);
|
|
18
|
+
});
|
|
19
|
+
proc.on("error", reject);
|
|
20
|
+
proc.on("close", (code) => {
|
|
21
|
+
if (code !== 0 && options?.throwOnError) {
|
|
22
|
+
reject(new Error(`Command exited with code ${code}`, {
|
|
23
|
+
cause: {
|
|
24
|
+
stderr: Buffer.concat(stderr).toString(),
|
|
25
|
+
exitCode: code,
|
|
26
|
+
cmd
|
|
27
|
+
}
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
resolve({
|
|
31
|
+
stdout: Buffer.concat(stdout).toString(),
|
|
32
|
+
stderr: Buffer.concat(stderr).toString(),
|
|
33
|
+
exitCode: code ?? -1
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
exec
|
|
40
|
+
};
|
package/misc/fs.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { CopyOptions } from 'node:fs';
|
|
2
|
+
export declare function fileExists(path: string): Promise<boolean>;
|
|
3
|
+
export declare function directoryExists(path: string): Promise<boolean>;
|
|
4
|
+
export declare function tryCopy(src: string, dest: string, options?: CopyOptions): Promise<void>;
|
package/misc/fs.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as fsp from "node:fs/promises";
|
|
2
|
+
async function fileExists(path) {
|
|
3
|
+
try {
|
|
4
|
+
const stat = await fsp.stat(path);
|
|
5
|
+
return stat.isFile();
|
|
6
|
+
} catch {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
async function directoryExists(path) {
|
|
11
|
+
try {
|
|
12
|
+
const stat = await fsp.stat(path);
|
|
13
|
+
return stat.isDirectory();
|
|
14
|
+
} catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function tryCopy(src, dest, options) {
|
|
19
|
+
try {
|
|
20
|
+
await fsp.cp(src, dest, options);
|
|
21
|
+
} catch (err) {
|
|
22
|
+
if (err.code === "ENOENT") ;
|
|
23
|
+
else {
|
|
24
|
+
throw err;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
directoryExists,
|
|
30
|
+
fileExists,
|
|
31
|
+
tryCopy
|
|
32
|
+
};
|
package/misc/index.d.ts
ADDED
package/misc/path.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function normalizeFilePath(filePath: string | URL): string;
|
package/misc/path.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
function normalizeFilePath(filePath) {
|
|
3
|
+
if (filePath instanceof URL) {
|
|
4
|
+
return fileURLToPath(filePath);
|
|
5
|
+
} else if (filePath.startsWith("file://")) {
|
|
6
|
+
return fileURLToPath(new URL(filePath));
|
|
7
|
+
}
|
|
8
|
+
return filePath;
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
normalizeFilePath
|
|
12
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { WorkspacePackage } from '../package-json/collect-package-jsons.js';
|
|
2
|
+
export declare function sortWorkspaceByPublishOrder(packages: WorkspacePackage[]): WorkspacePackage[];
|
|
3
|
+
export declare function determinePublishOrder(dependencies: Record<string, string[]>): string[];
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { asNonNull } from "@fuman/utils";
|
|
2
|
+
function sortWorkspaceByPublishOrder(packages) {
|
|
3
|
+
const workspacePackages = /* @__PURE__ */ new Map();
|
|
4
|
+
for (const pkg of packages) {
|
|
5
|
+
workspacePackages.set(asNonNull(pkg.json.name), pkg);
|
|
6
|
+
}
|
|
7
|
+
const dependencies = {};
|
|
8
|
+
for (const pkg of packages) {
|
|
9
|
+
if (pkg.json.name == null) continue;
|
|
10
|
+
const list = [];
|
|
11
|
+
for (const key of ["dependencies", "peerDependencies"]) {
|
|
12
|
+
const deps = pkg.json[key];
|
|
13
|
+
if (!deps) continue;
|
|
14
|
+
for (const name in deps) {
|
|
15
|
+
if (workspacePackages.has(name)) {
|
|
16
|
+
list.push(name);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
dependencies[pkg.json.name] = list;
|
|
21
|
+
}
|
|
22
|
+
const order = determinePublishOrder(dependencies);
|
|
23
|
+
const res = [];
|
|
24
|
+
for (const name of order) {
|
|
25
|
+
res.push(asNonNull(workspacePackages.get(name)));
|
|
26
|
+
}
|
|
27
|
+
return res;
|
|
28
|
+
}
|
|
29
|
+
function determinePublishOrder(dependencies) {
|
|
30
|
+
const result = [];
|
|
31
|
+
const visited = /* @__PURE__ */ new Set();
|
|
32
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
33
|
+
function visit(name) {
|
|
34
|
+
if (visited.has(name)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (visiting.has(name)) {
|
|
38
|
+
throw new Error(`Circular dependency detected: ${name}`);
|
|
39
|
+
}
|
|
40
|
+
visiting.add(name);
|
|
41
|
+
for (const dep of dependencies[name] ?? []) {
|
|
42
|
+
visit(dep);
|
|
43
|
+
}
|
|
44
|
+
visiting.delete(name);
|
|
45
|
+
visited.add(name);
|
|
46
|
+
result.push(name);
|
|
47
|
+
}
|
|
48
|
+
for (const name in dependencies) {
|
|
49
|
+
visit(name);
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
determinePublishOrder,
|
|
55
|
+
sortWorkspaceByPublishOrder
|
|
56
|
+
};
|
package/misc/tsconfig.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { LruMap } from "@fuman/utils";
|
|
2
|
+
import { exec } from "./exec.js";
|
|
3
|
+
async function getTsconfigFor(cwd) {
|
|
4
|
+
const res = await exec(["npx", "tsc", "--showConfig"], {
|
|
5
|
+
cwd,
|
|
6
|
+
throwOnError: true
|
|
7
|
+
});
|
|
8
|
+
return JSON.parse(res.stdout);
|
|
9
|
+
}
|
|
10
|
+
const _tsconfigFilesCache = new LruMap(32);
|
|
11
|
+
async function getTsconfigFiles(cwd) {
|
|
12
|
+
const cached = _tsconfigFilesCache.get(cwd);
|
|
13
|
+
if (cached) return cached;
|
|
14
|
+
const config = await getTsconfigFor(cwd);
|
|
15
|
+
if (typeof config !== "object" || config === null) {
|
|
16
|
+
throw new Error("tsconfig.json is not an object");
|
|
17
|
+
}
|
|
18
|
+
if (!("files" in config) || !Array.isArray(config.files)) {
|
|
19
|
+
throw new Error("tsconfig.json > .files is not an array");
|
|
20
|
+
}
|
|
21
|
+
const files = config.files.map((file) => file.replace(/^\.\//, ""));
|
|
22
|
+
_tsconfigFilesCache.set(cwd, files);
|
|
23
|
+
return files;
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
getTsconfigFiles,
|
|
27
|
+
getTsconfigFor
|
|
28
|
+
};
|
package/npm/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './npm-api.js';
|
package/npm/npm-api.d.ts
ADDED
package/npm/npm-api.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ffetchBase } from "@fuman/fetch";
|
|
2
|
+
const NPM_PACKAGE_NAME_REGEX = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
|
|
3
|
+
async function npmCheckVersion(params) {
|
|
4
|
+
const {
|
|
5
|
+
registry = "https://registry.npmjs.org",
|
|
6
|
+
package: packageName,
|
|
7
|
+
version
|
|
8
|
+
} = params;
|
|
9
|
+
const res = await ffetchBase(`/${packageName}/${version}`, {
|
|
10
|
+
baseUrl: registry,
|
|
11
|
+
validateResponse: false
|
|
12
|
+
});
|
|
13
|
+
return res.status === 200;
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
NPM_PACKAGE_NAME_REGEX,
|
|
17
|
+
npmCheckVersion
|
|
18
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PackageJson } from './types.js';
|
|
2
|
+
export interface WorkspacePackage {
|
|
3
|
+
path: string;
|
|
4
|
+
root: boolean;
|
|
5
|
+
json: PackageJson;
|
|
6
|
+
}
|
|
7
|
+
export declare function collectPackageJsons(workspaceRoot: string | URL, includeRoot?: boolean): Promise<WorkspacePackage[]>;
|
|
8
|
+
export declare function filterPackageJsonsForPublish(packages: WorkspacePackage[], registry: 'jsr' | 'npm'): WorkspacePackage[];
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { glob } from "tinyglobby";
|
|
4
|
+
import { normalizeFilePath } from "../misc/path.js";
|
|
5
|
+
import { parseWorkspaceRootPackageJson, parsePackageJsonFile } from "./parse.js";
|
|
6
|
+
const maxDepth = process.env.FUMAN_BUILD_MAX_DEPTH !== void 0 ? Number(process.env.FUMAN_BUILD_MAX_DEPTH) : 5;
|
|
7
|
+
async function collectPackageJsons(workspaceRoot, includeRoot = false) {
|
|
8
|
+
workspaceRoot = normalizeFilePath(workspaceRoot);
|
|
9
|
+
const packageJsons = [];
|
|
10
|
+
const rootPackageJson = await parseWorkspaceRootPackageJson(workspaceRoot);
|
|
11
|
+
if (!rootPackageJson.workspaces) {
|
|
12
|
+
throw new Error("No workspaces found in package.json");
|
|
13
|
+
}
|
|
14
|
+
if (includeRoot) {
|
|
15
|
+
packageJsons.push({
|
|
16
|
+
path: workspaceRoot,
|
|
17
|
+
root: true,
|
|
18
|
+
json: rootPackageJson
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
for (const dir of await glob({
|
|
22
|
+
patterns: rootPackageJson.workspaces,
|
|
23
|
+
cwd: workspaceRoot,
|
|
24
|
+
onlyDirectories: true,
|
|
25
|
+
followSymbolicLinks: true,
|
|
26
|
+
deep: maxDepth
|
|
27
|
+
})) {
|
|
28
|
+
try {
|
|
29
|
+
const packageJson = await parsePackageJsonFile(path.join(workspaceRoot, dir, "package.json"));
|
|
30
|
+
packageJsons.push({
|
|
31
|
+
path: path.join(workspaceRoot, dir),
|
|
32
|
+
root: false,
|
|
33
|
+
json: packageJson
|
|
34
|
+
});
|
|
35
|
+
} catch (err) {
|
|
36
|
+
if (err.code === "ENOENT") ;
|
|
37
|
+
else {
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return packageJsons;
|
|
43
|
+
}
|
|
44
|
+
function filterPackageJsonsForPublish(packages, registry) {
|
|
45
|
+
const otherRegistry = registry === "npm" ? "jsr" : "npm";
|
|
46
|
+
return packages.filter((pkg) => {
|
|
47
|
+
if (pkg.root) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const fumanConfig = pkg.json.fuman;
|
|
51
|
+
if (!fumanConfig) return true;
|
|
52
|
+
if (fumanConfig.private) return false;
|
|
53
|
+
if (fumanConfig[registry] === "skip") return false;
|
|
54
|
+
if (fumanConfig[otherRegistry] === "only") return false;
|
|
55
|
+
return true;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
collectPackageJsons,
|
|
60
|
+
filterPackageJsonsForPublish
|
|
61
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find the closest package.json file
|
|
3
|
+
*
|
|
4
|
+
* @param from The directory (or file) to start searching from
|
|
5
|
+
* @example `findPackageJson(import.meta.url)` // returns the package.json file of this package
|
|
6
|
+
*/
|
|
7
|
+
export declare function findPackageJson(from: string | URL): Promise<string | null>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { LruMap } from "@fuman/utils";
|
|
3
|
+
import { fileExists } from "../misc/fs.js";
|
|
4
|
+
import { normalizeFilePath } from "../misc/path.js";
|
|
5
|
+
const _findPackageJsonCache = new LruMap(32);
|
|
6
|
+
async function findPackageJson(from) {
|
|
7
|
+
from = normalizeFilePath(from);
|
|
8
|
+
const cached = _findPackageJsonCache.get(from);
|
|
9
|
+
if (cached != null) return cached;
|
|
10
|
+
let current = from;
|
|
11
|
+
while (true) {
|
|
12
|
+
if (current === "/") return null;
|
|
13
|
+
const file = path.join(current, "package.json");
|
|
14
|
+
if (await fileExists(file)) {
|
|
15
|
+
_findPackageJsonCache.set(from, file);
|
|
16
|
+
return file;
|
|
17
|
+
}
|
|
18
|
+
const parent = path.join(current, "..");
|
|
19
|
+
if (parent === current) {
|
|
20
|
+
_findPackageJsonCache.set(from, null);
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
current = parent;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
findPackageJson
|
|
28
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { PackageJson } from './types.js';
|
|
2
|
+
export declare function parsePackageJson(packageJson: string): PackageJson;
|
|
3
|
+
export declare function parsePackageJsonFile(packageJsonPath: string | URL): Promise<PackageJson>;
|
|
4
|
+
export declare function parseWorkspaceRootPackageJson(workspaceRoot: string | URL): Promise<PackageJson>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as fsp from "node:fs/promises";
|
|
2
|
+
import path__default from "node:path";
|
|
3
|
+
import * as jsyaml from "js-yaml";
|
|
4
|
+
import { normalizeFilePath } from "../misc/path.js";
|
|
5
|
+
import { PackageJsonSchema } from "./types.js";
|
|
6
|
+
function parsePackageJson(packageJson) {
|
|
7
|
+
return PackageJsonSchema.parse(JSON.parse(packageJson));
|
|
8
|
+
}
|
|
9
|
+
async function parsePackageJsonFile(packageJsonPath) {
|
|
10
|
+
return parsePackageJson(await fsp.readFile(normalizeFilePath(packageJsonPath), "utf8"));
|
|
11
|
+
}
|
|
12
|
+
async function parseWorkspaceRootPackageJson(workspaceRoot) {
|
|
13
|
+
workspaceRoot = normalizeFilePath(workspaceRoot);
|
|
14
|
+
const packageJsonPath = path__default.join(workspaceRoot, "package.json");
|
|
15
|
+
const parsed = await parsePackageJsonFile(packageJsonPath);
|
|
16
|
+
if (!parsed.workspaces) {
|
|
17
|
+
const pnpmWorkspacePath = path__default.join(workspaceRoot, "pnpm-workspace.yaml");
|
|
18
|
+
let yaml;
|
|
19
|
+
try {
|
|
20
|
+
yaml = await fsp.readFile(pnpmWorkspacePath, "utf8");
|
|
21
|
+
} catch (e) {
|
|
22
|
+
if (e.code !== "ENOENT") throw e;
|
|
23
|
+
return parsed;
|
|
24
|
+
}
|
|
25
|
+
const workspace = jsyaml.load(yaml);
|
|
26
|
+
if (!workspace.packages) {
|
|
27
|
+
throw new Error("No packages found in pnpm-workspace.yaml");
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
...parsed,
|
|
31
|
+
workspaces: workspace.packages
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return parsed;
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
parsePackageJson,
|
|
38
|
+
parsePackageJsonFile,
|
|
39
|
+
parseWorkspaceRootPackageJson
|
|
40
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PackageJson } from './types.js';
|
|
2
|
+
export declare function processPackageJson(params: {
|
|
3
|
+
packageJson: PackageJson;
|
|
4
|
+
workspaceVersions?: Record<string, string>;
|
|
5
|
+
bundledWorkspaceDeps?: RegExp[];
|
|
6
|
+
rootPackageJson?: PackageJson;
|
|
7
|
+
rootFieldsToCopy?: string[];
|
|
8
|
+
fixedVersion?: string;
|
|
9
|
+
}): {
|
|
10
|
+
packageJson: PackageJson;
|
|
11
|
+
packageJsonOrig: PackageJson;
|
|
12
|
+
entrypoints: Record<string, string>;
|
|
13
|
+
};
|