@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.
Files changed (105) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +108 -0
  3. package/ci/github-actions.d.ts +3 -0
  4. package/ci/github-actions.js +28 -0
  5. package/ci/index.d.ts +1 -0
  6. package/cli/commands/_utils.d.ts +8 -0
  7. package/cli/commands/_utils.js +18 -0
  8. package/cli/commands/build.d.ts +20 -0
  9. package/cli/commands/build.js +45 -0
  10. package/cli/commands/bump-version.d.ts +18 -0
  11. package/cli/commands/bump-version.js +72 -0
  12. package/cli/commands/cr.d.ts +17 -0
  13. package/cli/commands/cr.js +76 -0
  14. package/cli/commands/find-changed-packages.d.ts +12 -0
  15. package/cli/commands/find-changed-packages.js +44 -0
  16. package/cli/commands/gen-changelog.d.ts +12 -0
  17. package/cli/commands/gen-changelog.js +49 -0
  18. package/cli/commands/gen-deps-graph.d.ts +15 -0
  19. package/cli/commands/gen-deps-graph.js +78 -0
  20. package/cli/commands/jsr.d.ts +6 -0
  21. package/cli/commands/jsr.js +79 -0
  22. package/cli/commands/publish.d.ts +48 -0
  23. package/cli/commands/publish.js +197 -0
  24. package/cli/commands/release.d.ts +34 -0
  25. package/cli/commands/release.js +226 -0
  26. package/cli/commands/validate-workspace-deps.d.ts +38 -0
  27. package/cli/commands/validate-workspace-deps.js +68 -0
  28. package/cli/index.d.ts +3 -0
  29. package/cli/main.d.ts +2 -0
  30. package/config.d.ts +32 -0
  31. package/fuman-build.d.ts +1 -0
  32. package/fuman-build.js +33 -0
  33. package/git/github.d.ts +14 -0
  34. package/git/github.js +48 -0
  35. package/git/index.d.ts +1 -0
  36. package/git/utils.d.ts +38 -0
  37. package/git/utils.js +110 -0
  38. package/index.d.ts +7 -0
  39. package/index.js +46 -0
  40. package/jsr/build-jsr.d.ts +7 -0
  41. package/jsr/build-jsr.js +145 -0
  42. package/jsr/config.d.ts +48 -0
  43. package/jsr/create-packages.d.ts +8 -0
  44. package/jsr/create-packages.js +46 -0
  45. package/jsr/deno-json.d.ts +19 -0
  46. package/jsr/deno-json.js +80 -0
  47. package/jsr/generate-workspace.d.ts +9 -0
  48. package/jsr/generate-workspace.js +174 -0
  49. package/jsr/index.d.ts +5 -0
  50. package/jsr/populate.d.ts +45 -0
  51. package/jsr/populate.js +132 -0
  52. package/jsr/utils/external-libs.d.ts +8 -0
  53. package/jsr/utils/external-libs.js +46 -0
  54. package/jsr/utils/index.d.ts +4 -0
  55. package/jsr/utils/jsr-api.d.ts +23 -0
  56. package/jsr/utils/jsr-api.js +115 -0
  57. package/jsr/utils/jsr-json.d.ts +10 -0
  58. package/jsr/utils/jsr-json.js +80 -0
  59. package/jsr/utils/jsr.d.ts +11 -0
  60. package/jsr/utils/jsr.js +74 -0
  61. package/jsr.d.ts +1 -0
  62. package/jsr.js +23 -0
  63. package/misc/_config.d.ts +1 -0
  64. package/misc/_config.js +18 -0
  65. package/misc/exec.d.ts +9 -0
  66. package/misc/exec.js +40 -0
  67. package/misc/fs.d.ts +4 -0
  68. package/misc/fs.js +32 -0
  69. package/misc/index.d.ts +4 -0
  70. package/misc/path.d.ts +1 -0
  71. package/misc/path.js +12 -0
  72. package/misc/publish-order.d.ts +3 -0
  73. package/misc/publish-order.js +56 -0
  74. package/misc/tsconfig.d.ts +2 -0
  75. package/misc/tsconfig.js +28 -0
  76. package/npm/index.d.ts +1 -0
  77. package/npm/npm-api.d.ts +7 -0
  78. package/npm/npm-api.js +18 -0
  79. package/package-json/collect-package-jsons.d.ts +8 -0
  80. package/package-json/collect-package-jsons.js +61 -0
  81. package/package-json/find-package-json.d.ts +7 -0
  82. package/package-json/find-package-json.js +28 -0
  83. package/package-json/index.d.ts +5 -0
  84. package/package-json/parse.d.ts +4 -0
  85. package/package-json/parse.js +40 -0
  86. package/package-json/process-package-json.d.ts +13 -0
  87. package/package-json/process-package-json.js +132 -0
  88. package/package-json/types.d.ts +56 -0
  89. package/package-json/types.js +57 -0
  90. package/package-json/utils.d.ts +4 -0
  91. package/package-json/utils.js +27 -0
  92. package/package.json +67 -0
  93. package/versioning/bump-version.d.ts +48 -0
  94. package/versioning/bump-version.js +129 -0
  95. package/versioning/collect-files.d.ts +22 -0
  96. package/versioning/collect-files.js +66 -0
  97. package/versioning/generate-changelog.d.ts +13 -0
  98. package/versioning/generate-changelog.js +81 -0
  99. package/versioning/types.d.ts +32 -0
  100. package/vite/build-plugin.d.ts +73 -0
  101. package/vite/build-plugin.js +170 -0
  102. package/vite/config.d.ts +34 -0
  103. package/vite/index.d.ts +2 -0
  104. package/vite.d.ts +1 -0
  105. package/vite.js +4 -0
@@ -0,0 +1,81 @@
1
+ import { join } from "node:path";
2
+ import { asNonNull } from "@fuman/utils";
3
+ import { getCommitsBetween, parseConventionalCommit, findChangedFiles } from "../git/utils.js";
4
+ import { findProjectChangedFiles } from "./collect-files.js";
5
+ function defaultOnParseFailed(commit) {
6
+ console.warn("[warn] Failed to parse commit message: %s", commit.message);
7
+ }
8
+ function defaultCommitFormatter(commit, parsed) {
9
+ const { breaking } = parsed;
10
+ const { hash, message, description } = commit;
11
+ let line = `- ${hash}: ${breaking ? "**❗ BREAKING** " : ""}${message}`;
12
+ if (breaking && description) {
13
+ line += `
14
+ ${commit.description.trim().split("\n").map((line2) => ` ${line2}`).join("\n")}`;
15
+ }
16
+ return line;
17
+ }
18
+ function defaultCommitFilter(commit, parsed) {
19
+ const { type, breaking } = parsed;
20
+ if (breaking) return true;
21
+ if (!type || ["chore", "ci", "docs", "test"].includes(type)) return false;
22
+ return true;
23
+ }
24
+ function defaultPackageCommitsFormatter(packageName, commits) {
25
+ return `### ${packageName}
26
+ ${Object.values(commits).join("\n")}`;
27
+ }
28
+ async function generateChangelog(params) {
29
+ const {
30
+ cwd,
31
+ since,
32
+ params: {
33
+ changelog: {
34
+ onCommitParseFailed = defaultOnParseFailed,
35
+ onCommitsFetched,
36
+ commitFilter = defaultCommitFilter,
37
+ commitFilterWithFiles,
38
+ commitFormatter = defaultCommitFormatter,
39
+ packageCommitsFormatter = defaultPackageCommitsFormatter
40
+ } = {}
41
+ } = {}
42
+ } = params;
43
+ const commitsByPackage = {};
44
+ const changedFiles = await findProjectChangedFiles({
45
+ params: params.params ?? {},
46
+ root: cwd,
47
+ since
48
+ });
49
+ const changedFilesByPackage = /* @__PURE__ */ new Map();
50
+ for (const file of changedFiles) {
51
+ changedFilesByPackage.set(join(file.package.path, file.file), file.package);
52
+ }
53
+ const commits = await getCommitsBetween({ since, cwd });
54
+ await onCommitsFetched?.(commits);
55
+ for (const commit of commits) {
56
+ const parsed = parseConventionalCommit(commit.message);
57
+ if (!parsed) {
58
+ onCommitParseFailed(commit);
59
+ continue;
60
+ }
61
+ if (!commitFilter(commit, parsed)) continue;
62
+ const changed = await findChangedFiles({ since: `${commit.hash}~1`, until: commit.hash, cwd });
63
+ if (commitFilterWithFiles && !commitFilterWithFiles(commit, parsed, changed)) continue;
64
+ for (const file of changed) {
65
+ const pkg = changedFilesByPackage.get(file);
66
+ if (!pkg) continue;
67
+ const packageName = asNonNull(pkg.json.name);
68
+ if (commitsByPackage[packageName] == null) commitsByPackage[packageName] = {};
69
+ commitsByPackage[packageName][commit.hash] = commitFormatter(commit, parsed, changed);
70
+ }
71
+ }
72
+ let ret = "";
73
+ for (const [pkg, commits2] of Object.entries(commitsByPackage)) {
74
+ ret += packageCommitsFormatter(pkg, commits2);
75
+ ret += "\n\n";
76
+ }
77
+ return ret;
78
+ }
79
+ export {
80
+ generateChangelog
81
+ };
@@ -0,0 +1,32 @@
1
+ import { MaybePromise } from '@fuman/utils';
2
+ import { CommitInfo, ConventionalCommit } from '../git/utils.js';
3
+ import { ProjectChangedFile } from './collect-files.js';
4
+ export interface ChangelogGeneratorParams {
5
+ onCommitParseFailed?: (commit: CommitInfo) => void;
6
+ onCommitsFetched?: (commits: CommitInfo[]) => Promise<void>;
7
+ commitFilter?: (commit: CommitInfo) => boolean;
8
+ commitFilterWithFiles?: (commit: CommitInfo, parsed: ConventionalCommit, files: string[]) => boolean;
9
+ commitFormatter?: (commit: CommitInfo, parsed: ConventionalCommit, files: string[]) => string;
10
+ packageCommitsFormatter?: (packageName: string, commits: Record<string, string>) => string;
11
+ }
12
+ export interface VersioningOptions {
13
+ /**
14
+ * globs of files changes to which to white-list (relative to package root)
15
+ *
16
+ * @default all
17
+ */
18
+ include?: string[] | null;
19
+ /**
20
+ * globs of files changes to which to black-list (relative to package root)
21
+ *
22
+ * @default `['**\/*.test.ts', '**\/*.md']`
23
+ */
24
+ exclude?: string[] | null;
25
+ /**
26
+ * custom predicate for inclusion of files
27
+ * (will be called in addition to the globs,
28
+ * defaults to checking if the file is in tsconfig.json)
29
+ */
30
+ shouldInclude?: (file: ProjectChangedFile) => MaybePromise<boolean>;
31
+ changelog?: ChangelogGeneratorParams;
32
+ }
@@ -0,0 +1,73 @@
1
+ import { PluginOption } from 'vite';
2
+ import { BuildHookContext } from '../config.js';
3
+ import { MaybeArray, MaybePromise } from '@fuman/utils';
4
+ export declare function fumanBuild(params: {
5
+ root: URL | string;
6
+ /**
7
+ * package root, will be passed to vite's `root` option
8
+ *
9
+ * @default `process.cwd()`
10
+ */
11
+ packageRoot?: string;
12
+ /**
13
+ * files to copy from the workspace root directory to the build directory
14
+ *
15
+ * @default ['LICENSE']
16
+ */
17
+ copyRootFiles?: string[];
18
+ /**
19
+ * files to copy from the package root directory to the build directory
20
+ *
21
+ * @default ['README.md']
22
+ */
23
+ copyPackageFiles?: string[];
24
+ /**
25
+ * the modifiable part of the chunk file name
26
+ * there will be a prefix of `chunks/[format]/` and a suffix of `.js`
27
+ * @default `[hash]`
28
+ */
29
+ chunkFileName?: string;
30
+ /**
31
+ * workspace dependencies that are bundled with the library,
32
+ * and as such shouldn't present in the final package.json
33
+ */
34
+ bundledWorkspaceDeps?: MaybeArray<string | RegExp>;
35
+ rootFieldsToCopy?: string[];
36
+ /** when true, will automatically add `sideEffects: false` to generated package.json-s */
37
+ autoSideEffectsFalse?: boolean;
38
+ /**
39
+ * hook to run *before* anything is done to the package.json file
40
+ * you **can** modify the .packageJson property of the context
41
+ *
42
+ * this hook is called before vite build has started,
43
+ * and as such `.outDir` is not available yet
44
+ * (note: this hook is run *before* package-level hooks)
45
+ */
46
+ preparePackageJson?: (ctx: BuildHookContext) => void;
47
+ /**
48
+ * hook to run *after* the package.json file is finalized,
49
+ * right before it is written to disk
50
+ * you **can** modify the .packageJson property of the context
51
+ * (note: this hook is run *before* package-level hooks)
52
+ */
53
+ finalizePackageJson?: (ctx: BuildHookContext) => MaybePromise<void>;
54
+ /**
55
+ * hook to run *after* the build is done,
56
+ * time to do any final modifications to the package contents
57
+ * (note: this hook is run *before* package-level hooks)
58
+ */
59
+ finalize?: (ctx: BuildHookContext) => MaybePromise<void>;
60
+ /**
61
+ * when using with `vite-plugin-dts`, use this flag instead of
62
+ * their `insertTypesEntry` option to insert the types entry,
63
+ * as their implementation doesn't always yield the correct result
64
+ *
65
+ * @default false
66
+ */
67
+ insertTypesEntry?: boolean;
68
+ /**
69
+ * when using with `vite-plugin-dts`, this value should match `entryRoot`
70
+ * value passed to the `vite-plugin-dts` plugin
71
+ */
72
+ typesEntryRoot?: string;
73
+ }): Promise<PluginOption[]>;
@@ -0,0 +1,170 @@
1
+ import * as fsp from "node:fs/promises";
2
+ import { join, relative } from "node:path";
3
+ import process from "node:process";
4
+ import { asNonNull, deepMerge, assertStartsWith } from "@fuman/utils";
5
+ import { loadBuildConfig } from "../misc/_config.js";
6
+ import { tryCopy, fileExists, directoryExists } from "../misc/fs.js";
7
+ import { normalizeFilePath } from "../misc/path.js";
8
+ import { collectPackageJsons } from "../package-json/collect-package-jsons.js";
9
+ import { processPackageJson } from "../package-json/process-package-json.js";
10
+ import { collectVersions } from "../package-json/utils.js";
11
+ async function fumanBuild(params) {
12
+ const {
13
+ copyRootFiles = ["LICENSE"],
14
+ copyPackageFiles = ["README.md"],
15
+ chunkFileName = "[hash]",
16
+ rootFieldsToCopy,
17
+ packageRoot = process.cwd(),
18
+ bundledWorkspaceDeps,
19
+ autoSideEffectsFalse = false,
20
+ insertTypesEntry = false,
21
+ typesEntryRoot
22
+ } = params;
23
+ const rootDir = normalizeFilePath(params.root);
24
+ const fixedVersion = process.env.__FUMAN_INTERNAL_FIXED_VERSION;
25
+ const cachedWorkspace = process.env.__FUMAN_INTERNAL_PACKAGES_LIST;
26
+ const allPackageJsons = cachedWorkspace !== void 0 ? JSON.parse(cachedWorkspace) : await collectPackageJsons(rootDir, true);
27
+ const rootPackageJson = allPackageJsons.find((it) => it.root)?.json;
28
+ if (!rootPackageJson) {
29
+ throw new Error("Could not find root package.json");
30
+ }
31
+ const ourPackageJson = allPackageJsons.find((it) => it.path.replace(/\/$/g, "") === packageRoot.replace(/\/$/g, ""))?.json;
32
+ if (!ourPackageJson) {
33
+ throw new Error(`Could not find package.json for ${packageRoot}`);
34
+ }
35
+ if (rootPackageJson === ourPackageJson) {
36
+ return [
37
+ {
38
+ name: "vite-plugin-fuman-build",
39
+ config(ctx, env) {
40
+ if (env.command === "build" && env.mode === "production") {
41
+ throw new Error("[@fuman/build] Cannot build the root package from root. Please change cwd to the package directory, or pass it via `packageRoot` option.");
42
+ }
43
+ }
44
+ }
45
+ ];
46
+ }
47
+ const workspaceVersions = collectVersions(allPackageJsons);
48
+ let isNoop = false;
49
+ const packageConfig = await loadBuildConfig(packageRoot);
50
+ const hookContext = {
51
+ outDir: "",
52
+ packageDir: packageRoot,
53
+ packageName: asNonNull(ourPackageJson.name),
54
+ packageJson: ourPackageJson,
55
+ jsr: false
56
+ };
57
+ params.preparePackageJson?.(hookContext);
58
+ packageConfig?.preparePackageJson?.(hookContext);
59
+ const { packageJson, entrypoints } = processPackageJson({
60
+ packageJson: ourPackageJson,
61
+ rootPackageJson,
62
+ workspaceVersions,
63
+ bundledWorkspaceDeps: (bundledWorkspaceDeps === void 0 || Array.isArray(bundledWorkspaceDeps) ? bundledWorkspaceDeps : [bundledWorkspaceDeps])?.map((dep) => typeof dep === "string" ? new RegExp(dep) : dep),
64
+ rootFieldsToCopy,
65
+ fixedVersion
66
+ });
67
+ hookContext.packageJson = packageJson;
68
+ if (packageJson.sideEffects == null) {
69
+ if (autoSideEffectsFalse) {
70
+ packageJson.sideEffects = false;
71
+ } else {
72
+ console.warn("[@fuman/build] package.json for %s has no sideEffects field, this may cause issues with tree-shaking", packageJson.name);
73
+ console.warn("[@fuman/build] (tip: set `autoSideEffectsFalse: true` in plugin params to add it automatically)");
74
+ }
75
+ }
76
+ let buildCjs = false;
77
+ let buildDir;
78
+ return [
79
+ ...packageConfig?.pluginsPre ?? [],
80
+ {
81
+ name: "vite-plugin-fuman-build",
82
+ async config(config, env) {
83
+ if (env.command !== "build") {
84
+ isNoop = true;
85
+ return null;
86
+ }
87
+ buildDir = join(packageRoot, config.build?.outDir ?? "dist");
88
+ hookContext.outDir = buildDir;
89
+ const libOptions = config?.build?.lib;
90
+ const libOptionsCustom = packageConfig?.viteConfig?.build?.lib;
91
+ const outputFormats = (libOptions === false ? void 0 : libOptions?.formats) ?? (libOptionsCustom === false ? void 0 : libOptionsCustom?.formats) ?? ["es", "cjs"];
92
+ buildCjs = outputFormats.includes("cjs");
93
+ return deepMerge({
94
+ root: packageRoot,
95
+ build: {
96
+ emptyOutDir: true,
97
+ target: "es2022",
98
+ minify: false,
99
+ rollupOptions: {
100
+ output: {
101
+ minifyInternalExports: false,
102
+ chunkFileNames: buildCjs ? `chunks/[format]/${chunkFileName}.js` : `chunks/${chunkFileName}.js`
103
+ }
104
+ },
105
+ lib: {
106
+ entry: entrypoints,
107
+ formats: outputFormats
108
+ }
109
+ }
110
+ }, packageConfig?.viteConfig ?? {});
111
+ },
112
+ async closeBundle() {
113
+ if (isNoop) return;
114
+ await params.finalizePackageJson?.(hookContext);
115
+ await packageConfig?.finalizePackageJson?.(hookContext);
116
+ await fsp.writeFile(join(buildDir, "package.json"), JSON.stringify(packageJson, null, 4));
117
+ for (const file of copyRootFiles) {
118
+ await tryCopy(join(rootDir, file), join(buildDir, file));
119
+ }
120
+ for (const file of copyPackageFiles) {
121
+ await tryCopy(join(packageRoot, file), join(buildDir, file));
122
+ }
123
+ if (insertTypesEntry) {
124
+ for (const [name, value] of Object.entries(entrypoints)) {
125
+ const dTsFile = join(buildDir, `${name}.d.ts`);
126
+ if (await fileExists(dTsFile)) continue;
127
+ let entrypointFile = value;
128
+ if (!value.endsWith(".ts")) continue;
129
+ if (typesEntryRoot == null) {
130
+ assertStartsWith(entrypointFile, "./");
131
+ while (true) {
132
+ if (await fileExists(join(buildDir, entrypointFile.replace(/\.ts$/, ".d.ts")))) break;
133
+ const idx = entrypointFile.indexOf("/", 2);
134
+ if (idx === -1) {
135
+ throw new Error(`Could not find d.ts for entrypoint ${entrypointFile}, please pass typesEntryRoot explicitly`);
136
+ }
137
+ entrypointFile = `./${entrypointFile.slice(idx + 1)}`;
138
+ }
139
+ } else {
140
+ const fullEntrypointFile = join(packageRoot, entrypointFile);
141
+ entrypointFile = relative(typesEntryRoot, fullEntrypointFile);
142
+ if (!entrypointFile.startsWith(".")) {
143
+ entrypointFile = `./${entrypointFile}`;
144
+ }
145
+ }
146
+ entrypointFile = entrypointFile.replace(/\.ts$/, ".js");
147
+ await fsp.writeFile(dTsFile, `export * from ${JSON.stringify(entrypointFile)}`);
148
+ }
149
+ }
150
+ if (buildCjs && await directoryExists(join(buildDir, "chunks/cjs"))) {
151
+ const cjsFile = join(buildDir, "chunks/cjs/package.json");
152
+ await fsp.writeFile(cjsFile, JSON.stringify({ type: "commonjs" }));
153
+ for (const name of Object.keys(entrypoints)) {
154
+ const dTsFile = join(buildDir, `${name}.d.ts`);
155
+ if (!await fileExists(dTsFile)) {
156
+ continue;
157
+ }
158
+ await fsp.cp(dTsFile, dTsFile.replace(/\.d\.ts$/, ".d.cts"));
159
+ }
160
+ }
161
+ await params.finalize?.(hookContext);
162
+ await packageConfig?.finalize?.(hookContext);
163
+ },
164
+ ...packageConfig?.pluginsPost ?? []
165
+ }
166
+ ];
167
+ }
168
+ export {
169
+ fumanBuild
170
+ };
@@ -0,0 +1,34 @@
1
+ import { MaybePromise } from '@fuman/utils';
2
+ import { Plugin, UserConfig } from 'vite';
3
+ import { BuildHookContext } from '../config.js';
4
+ import { JsrConfig } from '../jsr/config.js';
5
+ export interface CustomBuildConfigObject {
6
+ /** jsr-specific configuration */
7
+ jsr?: JsrConfig;
8
+ /** any additional vite plugins to be added before the fuman-build plugin */
9
+ pluginsPre?: Plugin[];
10
+ /** any additional vite plugins to be added after the fuman-build plugin */
11
+ pluginsPost?: Plugin[];
12
+ /** vite config to be merged into the base config */
13
+ viteConfig?: UserConfig;
14
+ /**
15
+ * hook to run *before* anything is done to the package.json file
16
+ * you **can** modify the .packageJson property of the context
17
+ *
18
+ * this hook is called before vite build has started,
19
+ * and as such `.outDir` is not available yet
20
+ */
21
+ preparePackageJson?: (ctx: BuildHookContext) => void;
22
+ /**
23
+ * hook to run *after* the package.json file is finalized,
24
+ * right before it is written to disk
25
+ * you **can** modify the .packageJson property of the context
26
+ */
27
+ finalizePackageJson?: (ctx: BuildHookContext) => MaybePromise<void>;
28
+ /**
29
+ * hook to run *after* the build is done,
30
+ * time to do any final modifications to the package contents
31
+ */
32
+ finalize?: (ctx: BuildHookContext) => MaybePromise<void>;
33
+ }
34
+ export type CustomBuildConfig = CustomBuildConfigObject | (() => CustomBuildConfigObject);
@@ -0,0 +1,2 @@
1
+ export * from './build-plugin.js';
2
+ export * from './config.js';
package/vite.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./vite/index.js"
package/vite.js ADDED
@@ -0,0 +1,4 @@
1
+ import { fumanBuild } from "./vite/build-plugin.js";
2
+ export {
3
+ fumanBuild
4
+ };