@mxpicture/build-api 0.2.8 → 0.2.10

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.
@@ -1,11 +1,13 @@
1
- import { BarrelGroup, BarrelResult } from "../types/types.barrel.js";
1
+ import { BarrelGroup, BarrelParams, BarrelResult } from "../types/types.barrel.js";
2
+ import { WorkspacePaths } from "../workspace/WorkspacePaths.js";
2
3
  export declare const DEFAULT_EXCLUDED_PATTERNS: RegExp[];
3
4
  export declare const DEFAULT_HEADER = "// This file is auto-generated. Do not edit manually.\n";
5
+ export declare const runBarrel: (params: BarrelParams) => Promise<void>;
4
6
  export declare class Barrel {
5
- readonly packagesDir: string;
7
+ protected readonly paths: WorkspacePaths;
6
8
  protected readonly excludes: RegExp[];
7
9
  protected readonly fileHeader: string;
8
- constructor(packagesDir: string, excludes?: RegExp[], fileHeader?: string);
10
+ constructor(paths: WorkspacePaths, excludes: RegExp[], fileHeader: string);
9
11
  run(): Promise<void>;
10
12
  protected isExcluded(fileName: string): boolean;
11
13
  protected persistBarrel(group: BarrelGroup): Promise<BarrelGroup>;
@@ -2,6 +2,7 @@ import { basename, dirname, join, relative } from "node:path";
2
2
  import { readdir, rm, writeFile } from "node:fs/promises";
3
3
  import { Pkg } from "../pkg/Pkg.js";
4
4
  import { logInfo, logSuccess } from "../logger/Logger.js";
5
+ import { WorkspacePaths } from "../workspace/WorkspacePaths.js";
5
6
  // /** File patterns to exclude from barrel exports */
6
7
  export const DEFAULT_EXCLUDED_PATTERNS = [
7
8
  /\.test\.ts$/,
@@ -13,17 +14,18 @@ export const DEFAULT_EXCLUDED_PATTERNS = [
13
14
  ];
14
15
  // /** Header comment added to every generated barrel file */
15
16
  export const DEFAULT_HEADER = "// This file is auto-generated. Do not edit manually.\n";
17
+ export const runBarrel = async (params) => new Barrel(WorkspacePaths.instance(params.repoRoot, params.workspacesName), params.excludes ?? DEFAULT_EXCLUDED_PATTERNS, params.fileHeader ?? DEFAULT_HEADER).run();
16
18
  export class Barrel {
17
- packagesDir;
19
+ paths;
18
20
  excludes;
19
21
  fileHeader;
20
- constructor(packagesDir, excludes, fileHeader) {
21
- this.packagesDir = packagesDir;
22
- this.excludes = excludes ?? DEFAULT_EXCLUDED_PATTERNS;
23
- this.fileHeader = fileHeader ?? DEFAULT_HEADER;
22
+ constructor(paths, excludes, fileHeader) {
23
+ this.paths = paths;
24
+ this.excludes = excludes;
25
+ this.fileHeader = fileHeader;
24
26
  }
25
27
  async run() {
26
- const packageDirs = (await readdir(this.packagesDir)).map((p) => join(this.packagesDir, p));
28
+ const packageDirs = (await readdir(this.paths.workspacesDir)).map((p) => join(this.paths.workspacesDir, p));
27
29
  const promises = [];
28
30
  for (const packageDir of packageDirs) {
29
31
  try {
@@ -93,7 +95,7 @@ export class Barrel {
93
95
  async updatePackageExports(packageDir, packageJsonPath, exports) {
94
96
  try {
95
97
  const pkgJson = new Pkg(packageJsonPath);
96
- const pkgName = relative(this.packagesDir, packageDir);
98
+ const pkgName = relative(this.paths.workspacesDir, packageDir);
97
99
  logInfo(`📦 updating ${pkgName} package.json ...`);
98
100
  const pkg = await pkgJson.readJson();
99
101
  if (!this.hasExportsChanged(exports, pkg.exports)) {
@@ -0,0 +1,14 @@
1
+ import { WorkspacePaths } from "../workspace/WorkspacePaths.js";
2
+ import { ChangesetParams } from "../types/types.changeset.js";
3
+ import { PackageJson } from "../types/types.package.js";
4
+ export declare const runChangeset: (params: ChangesetParams) => Promise<void>;
5
+ export declare class Changeset {
6
+ protected readonly paths: WorkspacePaths;
7
+ constructor(paths: WorkspacePaths);
8
+ run(): Promise<void>;
9
+ protected readPackages(): Promise<PackageJson[]>;
10
+ protected range4Compare(): string;
11
+ protected findChangedPackages(range: string, packages: PackageJson[]): Promise<string[]>;
12
+ protected findChangedInPackage(range: string, pkg: PackageJson): Promise<string[]>;
13
+ protected write(changed: string[]): Promise<void>;
14
+ }
@@ -0,0 +1,82 @@
1
+ import { join } from "node:path";
2
+ import { readPackageJsons } from "../workspace/workspace.common.js";
3
+ import { WorkspacePaths } from "../workspace/WorkspacePaths.js";
4
+ import { execAsync } from "../common/common.fs.js";
5
+ import { mkdir, writeFile } from "node:fs/promises";
6
+ export const runChangeset = async (params) => new Changeset(WorkspacePaths.instance(params.repoRoot, params.workspacesName)).run();
7
+ export class Changeset {
8
+ paths;
9
+ constructor(paths) {
10
+ this.paths = paths;
11
+ }
12
+ async run() {
13
+ const range = this.range4Compare();
14
+ const packages = await this.readPackages();
15
+ const changed = await this.findChangedPackages(range, packages);
16
+ // 4) If nothing changed, exit quietly
17
+ if (changed.length === 0) {
18
+ console.log("No publishable package changes detected.");
19
+ return;
20
+ }
21
+ return this.write(changed);
22
+ }
23
+ // 1) Discover workspace packages (assuming packages/*)
24
+ async readPackages() {
25
+ return (await readPackageJsons(this.paths.repoRoot)).map((p) => p.content);
26
+ }
27
+ // 2) Determine range to compare: last Changesets tag if available, else initial commit
28
+ range4Compare() {
29
+ let lastTag = "";
30
+ try {
31
+ // Tags like @your-scope/pkg-a@0.1.1 or pkg-a@0.1.1 are created by Changesets on publish
32
+ lastTag = execAsync("git tag --list --sort=-creatordate | head -n 1")
33
+ .toString()
34
+ .trim();
35
+ }
36
+ catch { }
37
+ return lastTag ? `${lastTag}..HEAD` : "";
38
+ }
39
+ // 3) Find changed packages
40
+ async findChangedPackages(range, packages) {
41
+ const changed = [];
42
+ const results = await Promise.all(packages.map((pkg) => this.findChangedInPackage(range, pkg)));
43
+ for (const result of results)
44
+ changed.push(...result);
45
+ return changed;
46
+ }
47
+ async findChangedInPackage(range, pkg) {
48
+ const changed = [];
49
+ if (pkg.private)
50
+ return []; // ignore private packages
51
+ const cmd = range
52
+ ? `git diff --name-only ${range} -- "${pkg.dir}"`
53
+ : `git diff --name-only HEAD^ -- "${pkg.dir}" || true`;
54
+ const diff = (await execAsync(cmd, {
55
+ cwd: this.paths.repoRoot,
56
+ }))
57
+ .toString()
58
+ .split("\n")
59
+ .filter(Boolean)
60
+ // optionally ignore docs/tests-only changes:
61
+ .filter((f) => !/\b(README\.md|CHANGELOG\.md|\.md|\.spec\.(t|j)s|\.test\.(t|j)s)\b/i.test(f));
62
+ if (diff.length > 0)
63
+ changed.push(pkg.name);
64
+ return changed;
65
+ }
66
+ // 5) Write a Changeset file marking every changed package as 'patch'
67
+ async write(changed) {
68
+ const changesetDir = join(this.paths.repoRoot, ".changeset");
69
+ await mkdir(changesetDir, { recursive: true });
70
+ const sha = execAsync("git rev-parse --short HEAD").toString().trim();
71
+ const header = changed.map((name) => `"${name}": patch`).join("\n");
72
+ const body = `---
73
+ ${header}
74
+ ---
75
+
76
+ Auto-generated patch release for changed packages in ${sha}.
77
+ `;
78
+ const filePath = join(changesetDir, `auto-${sha}.md`);
79
+ await writeFile(filePath, body, "utf8");
80
+ console.log(`Created ${filePath} for packages:\n - ${changed.join("\n - ")}`);
81
+ }
82
+ }
@@ -0,0 +1 @@
1
+ export * from "./Changeset.js";
@@ -0,0 +1,2 @@
1
+ // This file is auto-generated. Do not edit manually.
2
+ export * from "./Changeset.js";
@@ -0,0 +1,4 @@
1
+ import { exec as execCb } from "node:child_process";
2
+ import { PathLike } from "node:fs";
3
+ export declare const execAsync: typeof execCb.__promisify__;
4
+ export declare const existsAsync: (path: PathLike) => Promise<boolean>;
@@ -0,0 +1,13 @@
1
+ import { exec as execCb } from "node:child_process";
2
+ import { stat } from "node:fs/promises";
3
+ import { promisify } from "node:util";
4
+ export const execAsync = promisify(execCb);
5
+ export const existsAsync = async (path) => {
6
+ try {
7
+ const s = await stat(path);
8
+ return s.isFile() || s.isDirectory();
9
+ }
10
+ catch {
11
+ return false;
12
+ }
13
+ };
@@ -0,0 +1 @@
1
+ export * from "./common.fs.js";
@@ -0,0 +1,2 @@
1
+ // This file is auto-generated. Do not edit manually.
2
+ export * from "./common.fs.js";
@@ -1,10 +1,8 @@
1
- import { readdir } from "fs/promises";
2
- import { join } from "path";
1
+ import { readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
3
  import { readPackageJson } from "../workspace/workspace.common.js";
4
- import { exec as execCb } from "node:child_process";
5
- import { promisify } from "node:util";
6
4
  import { logError, logInfo, logSuccess } from "../logger/Logger.js";
7
- const exec = promisify(execCb);
5
+ import { execAsync } from "../common/common.fs.js";
8
6
  export const runNpmPublisher = async (params) => new NpmPublisher(params.packagesDir).run();
9
7
  export class NpmPublisher {
10
8
  packagesDir;
@@ -33,7 +31,7 @@ export class NpmPublisher {
33
31
  logInfo(`📦 Publishing ${name}@${version} ... (${new Date().toISOString()})`);
34
32
  // Check if this exact version is already published
35
33
  try {
36
- const { stdout } = await exec(`npm view ${name}@${version} version`);
34
+ const { stdout } = await execAsync(`npm view ${name}@${version} version`);
37
35
  const published = stdout.trim();
38
36
  if (published === version) {
39
37
  logInfo(`⏭️ ${name}@${version} already published, skipping.`);
@@ -44,7 +42,7 @@ export class NpmPublisher {
44
42
  // npm view exits non-zero if the package/version doesn't exist — means we should publish
45
43
  }
46
44
  try {
47
- await exec("npm publish --access public", {
45
+ await execAsync("npm publish --access public", {
48
46
  cwd: dir,
49
47
  });
50
48
  logSuccess(`✅ ${name}@${version} published successfully (${new Date().toISOString()}).`);
@@ -1,6 +1,6 @@
1
- import { join, sep } from "path";
2
- import * as os from "os";
3
- import { execSync } from "child_process";
1
+ import { join, sep } from "node:path";
2
+ import * as os from "node:os";
3
+ import { execSync } from "node:child_process";
4
4
  let __info = null;
5
5
  export const osInfo = () => {
6
6
  if (!__info) {
@@ -1,4 +1,5 @@
1
1
  export * from "./types.barrel.js";
2
+ export * from "./types.changeset.js";
2
3
  export * from "./types.cleanup.js";
3
4
  export * from "./types.deps.js";
4
5
  export * from "./types.npm.js";
@@ -1,5 +1,6 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
2
  export * from "./types.barrel.js";
3
+ export * from "./types.changeset.js";
3
4
  export * from "./types.cleanup.js";
4
5
  export * from "./types.deps.js";
5
6
  export * from "./types.npm.js";
@@ -9,3 +9,9 @@ export interface BarrelResult {
9
9
  packageDir: string;
10
10
  packageJsonPath: string;
11
11
  }
12
+ export interface BarrelParams {
13
+ repoRoot: string;
14
+ workspacesName?: string;
15
+ excludes?: RegExp[];
16
+ fileHeader?: string;
17
+ }
@@ -0,0 +1,4 @@
1
+ export interface ChangesetParams {
2
+ repoRoot: string;
3
+ workspacesName?: string;
4
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -6,6 +6,7 @@ export interface PackageVersion {
6
6
  }
7
7
  export interface PackageJson {
8
8
  name: string;
9
+ private?: boolean;
9
10
  version: string;
10
11
  exports?: Record<string, string>;
11
12
  dependencies?: Record<string, string>;
@@ -1,4 +1,4 @@
1
- import { join } from "path";
1
+ import { join } from "node:path";
2
2
  import { osInfo } from "../osInfo/osInfo.common.js";
3
3
  export const configPath = () => join(osInfo().configDir, "Code");
4
4
  export const configUserPath = () => join(configPath(), "User");
@@ -1,8 +1,8 @@
1
- import { join } from "path";
1
+ import { join } from "node:path";
2
2
  import { storage } from "./vscode.storage.js";
3
3
  import { configUserPath } from "./vscode.config.js";
4
4
  import { findWorkspaceRoot } from "../workspace/workspace.common.js";
5
- import { cwd } from "process";
5
+ import { cwd } from "node:process";
6
6
  export const profiles = () => storage().userDataProfiles.map((prof) => ({
7
7
  name: prof.name,
8
8
  location: prof.location,
@@ -1,5 +1,5 @@
1
1
  import { activeProfile, defaultSettingsPath } from "./vscode.profiles.js";
2
- import { readFile } from "fs/promises";
2
+ import { readFile } from "node:fs/promises";
3
3
  import json5 from "json5";
4
4
  let __settings = null;
5
5
  export const vscodeSettings = async (dir) => {
@@ -1,5 +1,5 @@
1
- import * as fs from "fs";
2
- import { join } from "path";
1
+ import * as fs from "node:fs";
2
+ import { join } from "node:path";
3
3
  import json5 from "json5";
4
4
  import { configUserPath } from "./vscode.config.js";
5
5
  export const storagePath = () => join(configUserPath(), "globalStorage", "storage.json");
@@ -1,6 +1,6 @@
1
- import { readFile } from "fs/promises";
1
+ import { readFile } from "node:fs/promises";
2
2
  import json5 from "json5";
3
- import { dirname } from "path";
3
+ import { dirname } from "node:path";
4
4
  const __workspaces = {};
5
5
  export const vscodeWorkspace = async (workspaceFile) => {
6
6
  let found = __workspaces[workspaceFile];
@@ -6,6 +6,7 @@ export declare const findWorkspaceRoot: (startPath: string) => Promise<Workspace
6
6
  export declare const readWorkspaceYaml: (repoRoot: string) => Promise<PnpmWorkspace>;
7
7
  export declare const readPackageJson: (dirOrFilepath: string) => Promise<PackageJson | null>;
8
8
  export declare const readPackageJsonThrow: (dirOrFilepath: string) => Promise<PackageJson>;
9
+ export declare const readPackageJsonSync: (dirOrFilepath: string) => PackageJson;
9
10
  export declare const readPackageJsons: (repoRoot: string) => Promise<PackageEntry[]>;
10
11
  export declare const writePackageJsons: (entries: PackageEntry[]) => Promise<void[]>;
11
12
  export declare const buildMapEntries: (pkgEntries: PackageEntry[]) => MapEntry[];
@@ -1,10 +1,11 @@
1
- import { readdir, readFile, writeFile } from "fs/promises";
1
+ import { readdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { WorkspaceFileType, } from "../types/types.workspace.js";
3
- import { join, relative, resolve } from "path";
3
+ import { join, relative, resolve } from "node:path";
4
4
  import { splitVersion, compareVersions, concatVersion, } from "../pkg/pkg.common.js";
5
5
  import json5 from "json5";
6
6
  import { parse } from "yaml";
7
7
  import { logInfo, logSuccess } from "../logger/Logger.js";
8
+ import { readFileSync } from "node:fs";
8
9
  export const DEFAULT_WORKSPACE_FILE_ENDING = ".code-workspace";
9
10
  export const getFileType = (filename) => filename.endsWith(DEFAULT_WORKSPACE_FILE_ENDING)
10
11
  ? WorkspaceFileType.workspace
@@ -95,6 +96,12 @@ export const readPackageJsonThrow = async (dirOrFilepath) => {
95
96
  : join(dirOrFilepath, "package.json");
96
97
  return json5.parse(await readFile(pkgPath, "utf8"));
97
98
  };
99
+ export const readPackageJsonSync = (dirOrFilepath) => {
100
+ const pkgPath = dirOrFilepath.endsWith("/package.json")
101
+ ? dirOrFilepath
102
+ : join(dirOrFilepath, "package.json");
103
+ return json5.parse(readFileSync(pkgPath, "utf8"));
104
+ };
98
105
  export const readPackageJsons = async (repoRoot) => {
99
106
  try {
100
107
  const pnpmWS = await readWorkspaceYaml(repoRoot);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mxpicture/build-api",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "description": "Build utilities API",
5
5
  "type": "module",
6
6
  "author": "MXPicture",
@@ -11,7 +11,9 @@
11
11
  },
12
12
  "exports": {
13
13
  "./barrel": "./dist/barrel/index.js",
14
+ "./changeset": "./dist/changeset/index.js",
14
15
  "./cleanup": "./dist/cleanup/index.js",
16
+ "./common": "./dist/common/index.js",
15
17
  "./deps": "./dist/deps/index.js",
16
18
  "./logger": "./dist/logger/index.js",
17
19
  "./npmPublish": "./dist/npmPublish/index.js",