@mxpicture/gcp-functions-code 0.2.0 → 0.2.2
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/dist/changelog/ChangeDetector.d.ts +1 -1
- package/dist/changelog/Changelog.d.ts +2 -4
- package/dist/changelog/Changelog.js +9 -16
- package/dist/changelog/changelog.util.d.ts +4 -49
- package/dist/changelog/changelog.util.js +18 -164
- package/dist/common/code.common.d.ts +17 -0
- package/dist/common/code.common.js +48 -0
- package/dist/common/types.common.d.ts +23 -1
- package/dist/deps/IFixWorkspaceDeps.d.ts +2 -1
- package/dist/deps/IFixWorkspaceDeps.js +1 -1
- package/dist/git/git.util.d.ts +1 -0
- package/dist/git/git.util.js +10 -0
- package/dist/vscode/workspaceAsync.vscode.d.ts +9 -0
- package/dist/vscode/workspaceAsync.vscode.js +102 -6
- package/package.json +6 -10
- package/dist/scripts/generate-barrels.d.ts +0 -1
- package/dist/scripts/generate-barrels.js +0 -81
- package/dist/scripts/index.d.ts +0 -3
- package/dist/scripts/index.js +0 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DocumentData } from "@mxpicture/gcp-functions-common/types";
|
|
2
2
|
import { GitChangesCommit } from "../git/GitChanges.js";
|
|
3
3
|
import { Changelog } from "./Changelog.js";
|
|
4
|
-
import { PackageVersion } from "
|
|
4
|
+
import { PackageVersion } from "../common/code.common.js";
|
|
5
5
|
export declare enum ChangeWatchType {
|
|
6
6
|
changelog = "changelog",
|
|
7
7
|
gitHistory = "gitHistory"
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { GitChanges } from "../git/GitChanges.js";
|
|
2
|
-
import { ChangelogEntry
|
|
2
|
+
import { ChangelogEntry } from "./changelog.util.js";
|
|
3
|
+
import { PackageVersion } from "../common/code.common.js";
|
|
3
4
|
export declare class Changelog {
|
|
4
5
|
protected readonly git: GitChanges;
|
|
5
|
-
protected readonly changelogPath: string;
|
|
6
|
-
protected readonly packageJsonPath: string;
|
|
7
|
-
protected readonly rootDir: string;
|
|
8
6
|
constructor(git: GitChanges);
|
|
9
7
|
run(): Promise<ChangelogEntry | null>;
|
|
10
8
|
readChangelogEntries(sinceVersion?: PackageVersion): Promise<ChangelogEntry[]>;
|
|
@@ -1,35 +1,28 @@
|
|
|
1
1
|
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import {
|
|
3
|
-
import { changelogEntriesSchema, changelogEntrySchema, resolveBaselineCommit, readChangedTsFiles, mapChangedPackages, mapAffectedPackages, readMinPackageVersion, splitVersion, compareVersionsGT, } from "./changelog.util.js";
|
|
2
|
+
import { changelogEntriesSchema, changelogEntrySchema, readChangedTsFiles, mapChangedPackages, mapAffectedPackages, resolveBaselineCommit, } from "./changelog.util.js";
|
|
4
3
|
import pkg from "json5";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
4
|
import { lastCommitHash } from "../git/git.util.js";
|
|
7
|
-
import { formatJson2Spaces } from "../common/code.common.js";
|
|
5
|
+
import { compareVersionsGT, formatJson2Spaces, splitVersion, } from "../common/code.common.js";
|
|
6
|
+
import { readMinPackageVersion } from "../vscode/workspaceAsync.vscode.js";
|
|
7
|
+
import { basePaths, changelogPath, packageJsonPath, WsPathType, } from "@mxpicture/gcp-functions-common/path";
|
|
8
8
|
const changelogLimit = 10;
|
|
9
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
9
|
export class Changelog {
|
|
11
10
|
git;
|
|
12
|
-
changelogPath;
|
|
13
|
-
packageJsonPath;
|
|
14
|
-
rootDir;
|
|
15
11
|
constructor(git) {
|
|
16
12
|
this.git = git;
|
|
17
|
-
this.changelogPath = resolve(__dirname, "../../changelog.json");
|
|
18
|
-
this.packageJsonPath = resolve(__dirname, "../../package.json");
|
|
19
|
-
this.rootDir = resolve(__dirname, "../../../..");
|
|
20
13
|
}
|
|
21
14
|
async run() {
|
|
22
15
|
const existingEntries = await this.readChangelogEntries();
|
|
23
|
-
const currentCommitHash = await lastCommitHash(
|
|
16
|
+
const currentCommitHash = await lastCommitHash(basePaths.root);
|
|
24
17
|
if (!currentCommitHash)
|
|
25
18
|
throw new Error("No current git commit hash found");
|
|
26
|
-
const baselineCommit = await resolveBaselineCommit(existingEntries, this.git.rootDir,
|
|
19
|
+
const baselineCommit = await resolveBaselineCommit(existingEntries, this.git.rootDir, packageJsonPath(WsPathType.code));
|
|
27
20
|
const changedFiles = await readChangedTsFiles(baselineCommit, this.git);
|
|
28
21
|
if (changedFiles.length === 0)
|
|
29
22
|
return null;
|
|
30
23
|
const changedPackages = mapChangedPackages(changedFiles);
|
|
31
24
|
const affectedPackages = mapAffectedPackages(changedPackages);
|
|
32
|
-
const version = await readMinPackageVersion(
|
|
25
|
+
const version = await readMinPackageVersion(basePaths.root);
|
|
33
26
|
if (!version)
|
|
34
27
|
throw new Error("No version found");
|
|
35
28
|
const entry = {
|
|
@@ -46,12 +39,12 @@ export class Changelog {
|
|
|
46
39
|
if (!condenseResult.hasChanged)
|
|
47
40
|
return null;
|
|
48
41
|
await changelogEntriesSchema.parseAsync(condenseResult.entries);
|
|
49
|
-
await writeFile(
|
|
42
|
+
await writeFile(changelogPath, await formatJson2Spaces(pkg.stringify(condenseResult.entries)));
|
|
50
43
|
return entry;
|
|
51
44
|
}
|
|
52
45
|
async readChangelogEntries(sinceVersion) {
|
|
53
46
|
try {
|
|
54
|
-
const content = await readFile(
|
|
47
|
+
const content = await readFile(changelogPath, "utf8");
|
|
55
48
|
const parsed = pkg.parse(content);
|
|
56
49
|
const entries = await changelogEntriesSchema.parseAsync(parsed);
|
|
57
50
|
if (!sinceVersion)
|
|
@@ -1,45 +1,11 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { GitChanges } from "../git/GitChanges.js";
|
|
3
|
+
import { PackageVersion } from "../common/code.common.js";
|
|
4
|
+
import { WsPathType } from "@mxpicture/gcp-functions-common/path";
|
|
3
5
|
export type ProcessMode = "fix" | "restore";
|
|
4
|
-
export
|
|
5
|
-
major: number;
|
|
6
|
-
minor: number | null;
|
|
7
|
-
patch: number | null;
|
|
8
|
-
prefix: string | null;
|
|
9
|
-
}
|
|
10
|
-
export declare const packageVersionSchema: z.ZodObject<{
|
|
11
|
-
major: z.ZodNumber;
|
|
12
|
-
minor: z.ZodXor<readonly [z.ZodNumber, z.ZodNull]>;
|
|
13
|
-
patch: z.ZodXor<readonly [z.ZodNumber, z.ZodNull]>;
|
|
14
|
-
prefix: z.ZodXor<readonly [z.ZodString, z.ZodNull]>;
|
|
15
|
-
}, z.core.$strip>;
|
|
16
|
-
export interface PnpmWorkspace {
|
|
17
|
-
packages: string[];
|
|
18
|
-
}
|
|
19
|
-
export interface PackageJson {
|
|
20
|
-
name: string;
|
|
21
|
-
version: string;
|
|
22
|
-
dependencies?: Record<string, string>;
|
|
23
|
-
devDependencies?: Record<string, string>;
|
|
24
|
-
peerDependencies?: Record<string, string>;
|
|
25
|
-
[key: string]: unknown;
|
|
26
|
-
}
|
|
27
|
-
export interface PackageEntry {
|
|
28
|
-
jsonPath: string;
|
|
29
|
-
repoPath: string;
|
|
30
|
-
wsName: string;
|
|
31
|
-
content: PackageJson;
|
|
32
|
-
modified: boolean;
|
|
33
|
-
}
|
|
34
|
-
export interface MapEntry {
|
|
35
|
-
fromPkg: PackageEntry;
|
|
36
|
-
toPkg: PackageEntry;
|
|
37
|
-
relPath: string;
|
|
38
|
-
}
|
|
39
|
-
export declare const readPackageJson: (dirOrFilepath: string) => Promise<PackageJson | null>;
|
|
40
|
-
export declare const changelogPackageNames: readonly ["common", "backend", "frontend", "code"];
|
|
6
|
+
export declare const changelogPackageNames: WsPathType[];
|
|
41
7
|
export type ChangelogPackageName = (typeof changelogPackageNames)[number];
|
|
42
|
-
export declare const changelogDependents: Record<ChangelogPackageName,
|
|
8
|
+
export declare const changelogDependents: Record<ChangelogPackageName, WsPathType[]>;
|
|
43
9
|
export interface ChangelogEntry {
|
|
44
10
|
version: string;
|
|
45
11
|
versionParts: PackageVersion;
|
|
@@ -77,18 +43,7 @@ export declare const changelogEntriesSchema: z.ZodArray<z.ZodObject<{
|
|
|
77
43
|
affectedPackages: z.ZodArray<z.ZodString>;
|
|
78
44
|
changedFiles: z.ZodArray<z.ZodString>;
|
|
79
45
|
}, z.core.$strip>>;
|
|
80
|
-
export declare const splitVersion: (version: string) => PackageVersion;
|
|
81
|
-
export declare const concatVersion: (version: PackageVersion) => string;
|
|
82
|
-
export declare const compareVersions: (a: PackageVersion | string, b: PackageVersion | string) => number;
|
|
83
|
-
export declare const compareVersionsGT: (a: PackageVersion | string, b: PackageVersion | string) => boolean;
|
|
84
|
-
export declare const readWorkspaceYaml: (repoRoot: string) => Promise<PnpmWorkspace>;
|
|
85
|
-
export declare const readPackageJsons: (repoRoot: string) => Promise<PackageEntry[]>;
|
|
86
|
-
export declare const writePackageJsons: (entries: PackageEntry[]) => Promise<void[]>;
|
|
87
|
-
export declare const buildMapEntries: (pkgEntries: PackageEntry[]) => MapEntry[];
|
|
88
46
|
export declare const resolveBaselineCommit: (entries: ChangelogEntry[], rootDir: string, packageJsonPath: string) => Promise<string>;
|
|
89
|
-
export declare const ensureCommitRef: (ref: string, fallback: string, rootDir: string) => Promise<string>;
|
|
90
47
|
export declare const readChangedTsFiles: (baselineCommit: string, git: GitChanges) => Promise<string[]>;
|
|
91
48
|
export declare const mapChangedPackages: (files: string[]) => string[];
|
|
92
49
|
export declare const mapAffectedPackages: (changedPackages: string[]) => string[];
|
|
93
|
-
export declare const readPackageVersions: (rootDir: string) => Promise<Record<string, string>>;
|
|
94
|
-
export declare const readMinPackageVersion: (rootDir: string) => Promise<string | null>;
|
|
@@ -1,40 +1,23 @@
|
|
|
1
|
-
import { readdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import { join, relative, resolve } from "node:path";
|
|
3
|
-
import pkg from "json5";
|
|
4
1
|
import { z } from "zod";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
patch: z.xor([z.number(), z.null()]),
|
|
11
|
-
prefix: z.xor([z.string(), z.null()]),
|
|
12
|
-
});
|
|
13
|
-
export const readPackageJson = async (dirOrFilepath) => {
|
|
14
|
-
try {
|
|
15
|
-
const pkgPath = dirOrFilepath.endsWith("/package.json")
|
|
16
|
-
? dirOrFilepath
|
|
17
|
-
: join(dirOrFilepath, "package.json");
|
|
18
|
-
const content = await readFile(pkgPath, "utf8");
|
|
19
|
-
return pkg.parse(content);
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
// todo get dynamically
|
|
26
|
-
export const changelogPackageNames = [
|
|
27
|
-
"common",
|
|
28
|
-
"backend",
|
|
29
|
-
"frontend",
|
|
30
|
-
"code",
|
|
31
|
-
];
|
|
32
|
-
// todo get dynamically
|
|
2
|
+
import { ensureCommitRef, verifiedGit } from "../git/git.util.js";
|
|
3
|
+
import { packageVersionSchema } from "../common/code.common.js";
|
|
4
|
+
import { readPackageJson } from "../vscode/workspaceAsync.vscode.js";
|
|
5
|
+
import { WsPathType } from "@mxpicture/gcp-functions-common/path";
|
|
6
|
+
export const changelogPackageNames = Object.values(WsPathType);
|
|
33
7
|
export const changelogDependents = {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
8
|
+
[WsPathType.backend]: [WsPathType.backend, WsPathType.generator],
|
|
9
|
+
[WsPathType.code]: [WsPathType.fs, WsPathType.generator],
|
|
10
|
+
[WsPathType.common]: [
|
|
11
|
+
WsPathType.common,
|
|
12
|
+
WsPathType.backend,
|
|
13
|
+
WsPathType.code,
|
|
14
|
+
WsPathType.frontend,
|
|
15
|
+
WsPathType.fs,
|
|
16
|
+
WsPathType.generator,
|
|
17
|
+
],
|
|
18
|
+
[WsPathType.frontend]: [WsPathType.frontend, WsPathType.generator],
|
|
19
|
+
[WsPathType.fs]: [WsPathType.fs],
|
|
20
|
+
[WsPathType.generator]: [WsPathType.generator],
|
|
38
21
|
};
|
|
39
22
|
export const changelogEntrySchema = z.object({
|
|
40
23
|
version: z.string().min(1),
|
|
@@ -46,110 +29,6 @@ export const changelogEntrySchema = z.object({
|
|
|
46
29
|
changedFiles: z.array(z.string()),
|
|
47
30
|
});
|
|
48
31
|
export const changelogEntriesSchema = z.array(changelogEntrySchema);
|
|
49
|
-
export const splitVersion = (version) => {
|
|
50
|
-
const parts = version.split(".");
|
|
51
|
-
let major = parts.shift();
|
|
52
|
-
const prefix = major.startsWith("v") ? "v" : null;
|
|
53
|
-
if (major.startsWith("v"))
|
|
54
|
-
major = major.substring(1);
|
|
55
|
-
const minor = parts.shift();
|
|
56
|
-
const patch = parts.shift();
|
|
57
|
-
return {
|
|
58
|
-
major: Number(major),
|
|
59
|
-
minor: minor ? Number(minor) : null,
|
|
60
|
-
patch: patch ? Number(patch) : null,
|
|
61
|
-
prefix,
|
|
62
|
-
};
|
|
63
|
-
};
|
|
64
|
-
export const concatVersion = (version) => {
|
|
65
|
-
let result = version.major.toString();
|
|
66
|
-
if (version.prefix)
|
|
67
|
-
result = version.prefix + result;
|
|
68
|
-
if (version.minor)
|
|
69
|
-
result += "." + version.minor.toString();
|
|
70
|
-
if (version.patch)
|
|
71
|
-
result += "." + version.patch.toString();
|
|
72
|
-
return result;
|
|
73
|
-
};
|
|
74
|
-
export const compareVersions = (a, b) => {
|
|
75
|
-
a = typeof a === "string" ? splitVersion(a) : a;
|
|
76
|
-
b = typeof b === "string" ? splitVersion(b) : b;
|
|
77
|
-
if (a.major !== b.major)
|
|
78
|
-
return a.major - b.major;
|
|
79
|
-
if (a.minor === null || b.minor === null)
|
|
80
|
-
return 0;
|
|
81
|
-
if (a.minor !== b.minor)
|
|
82
|
-
return a.minor - b.minor;
|
|
83
|
-
if (a.patch === null || b.patch === null)
|
|
84
|
-
return 0;
|
|
85
|
-
if (a.patch !== b.patch)
|
|
86
|
-
return a.patch - b.patch;
|
|
87
|
-
return 0;
|
|
88
|
-
};
|
|
89
|
-
export const compareVersionsGT = (a, b) => compareVersions(a, b) > 0;
|
|
90
|
-
export const readWorkspaceYaml = async (repoRoot) => {
|
|
91
|
-
const workspaceFilePath = resolve(repoRoot, "pnpm-workspace.yaml");
|
|
92
|
-
const fileContent = await readFile(workspaceFilePath, "utf8");
|
|
93
|
-
const parsed = parse(fileContent);
|
|
94
|
-
if (!parsed || !parsed.packages || !Array.isArray(parsed.packages))
|
|
95
|
-
throw new Error("No 'packages' field found in pnpm-workspace.yaml");
|
|
96
|
-
const packageColletions = await Promise.all(parsed.packages.map(async (p) => {
|
|
97
|
-
if (!p.endsWith("/*"))
|
|
98
|
-
return [p];
|
|
99
|
-
const base = p.substring(0, p.length - 2);
|
|
100
|
-
const pkgs = await readdir(join(repoRoot, base));
|
|
101
|
-
return pkgs
|
|
102
|
-
.filter((pkg) => !pkg.startsWith("."))
|
|
103
|
-
.map((pkg) => join(base, pkg));
|
|
104
|
-
}));
|
|
105
|
-
const packages = [];
|
|
106
|
-
for (const packageColletion of packageColletions)
|
|
107
|
-
packages.push(...packageColletion);
|
|
108
|
-
return { packages };
|
|
109
|
-
};
|
|
110
|
-
export const readPackageJsons = async (repoRoot) => {
|
|
111
|
-
try {
|
|
112
|
-
const pnpmWS = await readWorkspaceYaml(repoRoot);
|
|
113
|
-
return Promise.all(pnpmWS.packages.map(async (repoPath) => {
|
|
114
|
-
const jsonPath = join(repoRoot, repoPath, "package.json");
|
|
115
|
-
const content = JSON.parse(await readFile(jsonPath, "utf8"));
|
|
116
|
-
return {
|
|
117
|
-
jsonPath,
|
|
118
|
-
repoPath,
|
|
119
|
-
content,
|
|
120
|
-
modified: false,
|
|
121
|
-
wsName: repoPath.startsWith("packages/")
|
|
122
|
-
? repoPath.substring(9)
|
|
123
|
-
: repoPath,
|
|
124
|
-
};
|
|
125
|
-
}));
|
|
126
|
-
}
|
|
127
|
-
catch {
|
|
128
|
-
return [];
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
export const writePackageJsons = async (entries) => Promise.all(entries.map(async (entry) => {
|
|
132
|
-
if (entry.modified) {
|
|
133
|
-
await writeFile(entry.jsonPath, JSON.stringify(entry.content, null, 2) + "\n", "utf8");
|
|
134
|
-
console.log(` ✅ Updated ${entry.content.name}\n`);
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
console.log(` ⏭️ No workspace dependencies to fix. ${entry.content.name}\n`);
|
|
138
|
-
}
|
|
139
|
-
}));
|
|
140
|
-
// Build a map of package names to their versions
|
|
141
|
-
export const buildMapEntries = (pkgEntries) => {
|
|
142
|
-
const versionEntries = [];
|
|
143
|
-
for (const fromPkg of pkgEntries)
|
|
144
|
-
for (const toPkg of pkgEntries)
|
|
145
|
-
if (fromPkg.content.name !== toPkg.content.name)
|
|
146
|
-
versionEntries.push({
|
|
147
|
-
fromPkg,
|
|
148
|
-
toPkg,
|
|
149
|
-
relPath: relative(fromPkg.repoPath, toPkg.repoPath),
|
|
150
|
-
});
|
|
151
|
-
return versionEntries;
|
|
152
|
-
};
|
|
153
32
|
export const resolveBaselineCommit = async (entries, rootDir, packageJsonPath) => {
|
|
154
33
|
if (entries.length > 0 &&
|
|
155
34
|
entries[0].gitCommitHashs.length > 0 &&
|
|
@@ -166,16 +45,6 @@ export const resolveBaselineCommit = async (entries, rootDir, packageJsonPath) =
|
|
|
166
45
|
}
|
|
167
46
|
return ensureCommitRef("HEAD~1", "HEAD", rootDir);
|
|
168
47
|
};
|
|
169
|
-
export const ensureCommitRef = async (ref, fallback, rootDir) => {
|
|
170
|
-
try {
|
|
171
|
-
await verifiedGit(rootDir, ref);
|
|
172
|
-
return ref;
|
|
173
|
-
}
|
|
174
|
-
catch {
|
|
175
|
-
await verifiedGit(rootDir, fallback);
|
|
176
|
-
return fallback;
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
48
|
export const readChangedTsFiles = async (baselineCommit, git) => {
|
|
180
49
|
git.sinceCommit = baselineCommit;
|
|
181
50
|
const [result, simplegit] = await Promise.all([
|
|
@@ -211,18 +80,3 @@ export const mapAffectedPackages = (changedPackages) => {
|
|
|
211
80
|
}
|
|
212
81
|
return [...affected].sort();
|
|
213
82
|
};
|
|
214
|
-
export const readPackageVersions = async (rootDir) => {
|
|
215
|
-
const versions = {};
|
|
216
|
-
const packageJsons = await readPackageJsons(rootDir);
|
|
217
|
-
for (const packageJson of packageJsons)
|
|
218
|
-
versions[packageJson.repoPath] = packageJson.content.version;
|
|
219
|
-
return versions;
|
|
220
|
-
};
|
|
221
|
-
export const readMinPackageVersion = async (rootDir) => {
|
|
222
|
-
const versions = await readPackageVersions(rootDir);
|
|
223
|
-
const splitVersions = Object.values(versions).map(splitVersion);
|
|
224
|
-
if (splitVersions.length === 0)
|
|
225
|
-
return null;
|
|
226
|
-
splitVersions.sort(compareVersions);
|
|
227
|
-
return concatVersion(splitVersions[0]);
|
|
228
|
-
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MetaFileExtension, MetaFileType } from "@mxpicture/gcp-functions-common/meta";
|
|
2
2
|
import { ExtractFileParts, SourceFile } from "./types.common.js";
|
|
3
|
+
import { z } from "zod";
|
|
3
4
|
export declare const isTemplateFile: (filename: string) => boolean;
|
|
4
5
|
export declare const isTsFile: (filename: string, type: MetaFileType) => boolean;
|
|
5
6
|
export declare const isAnyFile: (filename: string, type?: MetaFileType, ext?: MetaFileExtension) => boolean;
|
|
@@ -15,3 +16,19 @@ export declare const formatCode: (...lines: string[]) => Promise<string>;
|
|
|
15
16
|
export declare const formatJson: (...lines: string[]) => Promise<string>;
|
|
16
17
|
export declare const formatJson2Spaces: (...lines: string[]) => Promise<string>;
|
|
17
18
|
export declare const createSourceFiles: (filePaths: string[]) => SourceFile[];
|
|
19
|
+
export interface PackageVersion {
|
|
20
|
+
major: number;
|
|
21
|
+
minor: number | null;
|
|
22
|
+
patch: number | null;
|
|
23
|
+
prefix: string | null;
|
|
24
|
+
}
|
|
25
|
+
export declare const packageVersionSchema: z.ZodObject<{
|
|
26
|
+
major: z.ZodNumber;
|
|
27
|
+
minor: z.ZodXor<readonly [z.ZodNumber, z.ZodNull]>;
|
|
28
|
+
patch: z.ZodXor<readonly [z.ZodNumber, z.ZodNull]>;
|
|
29
|
+
prefix: z.ZodXor<readonly [z.ZodString, z.ZodNull]>;
|
|
30
|
+
}, z.core.$strip>;
|
|
31
|
+
export declare const splitVersion: (version: string) => PackageVersion;
|
|
32
|
+
export declare const concatVersion: (version: PackageVersion) => string;
|
|
33
|
+
export declare const compareVersions: (a: PackageVersion | string, b: PackageVersion | string) => number;
|
|
34
|
+
export declare const compareVersionsGT: (a: PackageVersion | string, b: PackageVersion | string) => boolean;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
import { format } from "prettier";
|
|
3
3
|
import { guardMetaFileExtension, guardMetaFileType, MetaFileExtension, MetaFileType, } from "@mxpicture/gcp-functions-common/meta";
|
|
4
|
+
import { z } from "zod";
|
|
4
5
|
export const isTemplateFile = (filename) => isTsFile(filename, MetaFileType.template);
|
|
5
6
|
export const isTsFile = (filename, type) => isAnyFile(filename, type, MetaFileExtension.ts);
|
|
6
7
|
export const isAnyFile = (filename, type, ext) => {
|
|
@@ -63,3 +64,50 @@ export const createSourceFiles = (filePaths) => {
|
|
|
63
64
|
}
|
|
64
65
|
return results;
|
|
65
66
|
};
|
|
67
|
+
export const packageVersionSchema = z.object({
|
|
68
|
+
major: z.number().min(0),
|
|
69
|
+
minor: z.xor([z.number(), z.null()]),
|
|
70
|
+
patch: z.xor([z.number(), z.null()]),
|
|
71
|
+
prefix: z.xor([z.string(), z.null()]),
|
|
72
|
+
});
|
|
73
|
+
export const splitVersion = (version) => {
|
|
74
|
+
const parts = version.split(".");
|
|
75
|
+
let major = parts.shift();
|
|
76
|
+
const prefix = major.startsWith("v") ? "v" : null;
|
|
77
|
+
if (major.startsWith("v"))
|
|
78
|
+
major = major.substring(1);
|
|
79
|
+
const minor = parts.shift();
|
|
80
|
+
const patch = parts.shift();
|
|
81
|
+
return {
|
|
82
|
+
major: Number(major),
|
|
83
|
+
minor: minor ? Number(minor) : null,
|
|
84
|
+
patch: patch ? Number(patch) : null,
|
|
85
|
+
prefix,
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
export const concatVersion = (version) => {
|
|
89
|
+
let result = version.major.toString();
|
|
90
|
+
if (version.prefix)
|
|
91
|
+
result = version.prefix + result;
|
|
92
|
+
if (version.minor)
|
|
93
|
+
result += "." + version.minor.toString();
|
|
94
|
+
if (version.patch)
|
|
95
|
+
result += "." + version.patch.toString();
|
|
96
|
+
return result;
|
|
97
|
+
};
|
|
98
|
+
export const compareVersions = (a, b) => {
|
|
99
|
+
a = typeof a === "string" ? splitVersion(a) : a;
|
|
100
|
+
b = typeof b === "string" ? splitVersion(b) : b;
|
|
101
|
+
if (a.major !== b.major)
|
|
102
|
+
return a.major - b.major;
|
|
103
|
+
if (a.minor === null || b.minor === null)
|
|
104
|
+
return 0;
|
|
105
|
+
if (a.minor !== b.minor)
|
|
106
|
+
return a.minor - b.minor;
|
|
107
|
+
if (a.patch === null || b.patch === null)
|
|
108
|
+
return 0;
|
|
109
|
+
if (a.patch !== b.patch)
|
|
110
|
+
return a.patch - b.patch;
|
|
111
|
+
return 0;
|
|
112
|
+
};
|
|
113
|
+
export const compareVersionsGT = (a, b) => compareVersions(a, b) > 0;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import type { PackageJson } from "type-fest";
|
|
3
2
|
import { MetaFileExtension, MetaFileType, MetaTargetType } from "@mxpicture/gcp-functions-common/meta";
|
|
4
3
|
export interface ExtractFileParts {
|
|
5
4
|
filename: string;
|
|
@@ -18,3 +17,26 @@ export interface TargetPackage {
|
|
|
18
17
|
filePath: string;
|
|
19
18
|
pkg: PackageJson;
|
|
20
19
|
}
|
|
20
|
+
export interface PnpmWorkspace {
|
|
21
|
+
packages: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface PackageJson {
|
|
24
|
+
name: string;
|
|
25
|
+
version: string;
|
|
26
|
+
dependencies?: Record<string, string>;
|
|
27
|
+
devDependencies?: Record<string, string>;
|
|
28
|
+
peerDependencies?: Record<string, string>;
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
}
|
|
31
|
+
export interface PackageEntry {
|
|
32
|
+
jsonPath: string;
|
|
33
|
+
repoPath: string;
|
|
34
|
+
wsName: string;
|
|
35
|
+
content: PackageJson;
|
|
36
|
+
modified: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface MapEntry {
|
|
39
|
+
fromPkg: PackageEntry;
|
|
40
|
+
toPkg: PackageEntry;
|
|
41
|
+
relPath: string;
|
|
42
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ProcessMode } from "../changelog/changelog.util.js";
|
|
2
|
+
import { MapEntry, PackageEntry } from "../common/types.common.js";
|
|
2
3
|
export interface FixWorkspaceDepsMain {
|
|
3
4
|
mapEntries: MapEntry[];
|
|
4
5
|
consumingPkg: PackageEntry;
|
package/dist/git/git.util.d.ts
CHANGED
|
@@ -7,3 +7,4 @@ import { GitCommitHash } from "./types.git.js";
|
|
|
7
7
|
export declare const verifiedGit: (rootDir: string, commitRef?: string) => Promise<SimpleGit>;
|
|
8
8
|
export declare const lastCommitHash: (rootDir: string) => Promise<string | null>;
|
|
9
9
|
export declare const commitHashs: (rootDir: string) => Promise<GitCommitHash[]>;
|
|
10
|
+
export declare const ensureCommitRef: (ref: string, fallback: string, rootDir: string) => Promise<string>;
|
package/dist/git/git.util.js
CHANGED
|
@@ -31,3 +31,13 @@ export const commitHashs = async (rootDir) => (await (await verifiedGit(rootDir)
|
|
|
31
31
|
hash: a.hash,
|
|
32
32
|
diff: a.diff,
|
|
33
33
|
}));
|
|
34
|
+
export const ensureCommitRef = async (ref, fallback, rootDir) => {
|
|
35
|
+
try {
|
|
36
|
+
await verifiedGit(rootDir, ref);
|
|
37
|
+
return ref;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
await verifiedGit(rootDir, fallback);
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
@@ -1,2 +1,11 @@
|
|
|
1
1
|
import { WorkspaceFile } from "./types.vscode.js";
|
|
2
|
+
import { MapEntry, PackageEntry, PackageJson, PnpmWorkspace } from "../common/types.common.js";
|
|
2
3
|
export declare const findWorkspaceRootAsync: (startPath?: string) => Promise<WorkspaceFile>;
|
|
4
|
+
export declare const readWorkspaceYaml: (repoRoot: string) => Promise<PnpmWorkspace>;
|
|
5
|
+
export declare const readPackageJson: (dirOrFilepath: string) => Promise<PackageJson | null>;
|
|
6
|
+
export declare const readPackageJsonThrow: (dirOrFilepath: string) => Promise<PackageJson>;
|
|
7
|
+
export declare const readPackageJsons: (repoRoot: string) => Promise<PackageEntry[]>;
|
|
8
|
+
export declare const writePackageJsons: (entries: PackageEntry[]) => Promise<void[]>;
|
|
9
|
+
export declare const buildMapEntries: (pkgEntries: PackageEntry[]) => MapEntry[];
|
|
10
|
+
export declare const readPackageVersions: (rootDir: string) => Promise<Record<string, string>>;
|
|
11
|
+
export declare const readMinPackageVersion: (rootDir: string) => Promise<string | null>;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { dirname, join } from "path";
|
|
1
|
+
import { dirname, join, relative, resolve } from "path";
|
|
2
|
+
import { parse } from "yaml";
|
|
2
3
|
import { fileURLToPath } from "url";
|
|
4
|
+
import pkg from "json5";
|
|
3
5
|
import { WorkspaceFileType } from "./types.vscode.js";
|
|
4
6
|
import { getFileType } from "./common.vscode.js";
|
|
5
|
-
import { readdir } from "fs/promises";
|
|
7
|
+
import { readdir, readFile, writeFile } from "fs/promises";
|
|
8
|
+
import { compareVersions, concatVersion, splitVersion, } from "../common/code.common.js";
|
|
6
9
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
10
|
let __workspaceRoot = null;
|
|
8
|
-
export const findWorkspaceRootAsync = async (startPath) =>
|
|
9
|
-
(__workspaceRoot
|
|
10
|
-
|
|
11
|
-
let path =
|
|
11
|
+
export const findWorkspaceRootAsync = async (startPath) => {
|
|
12
|
+
if (__workspaceRoot)
|
|
13
|
+
return __workspaceRoot;
|
|
14
|
+
let path = startPath ?? __dirname;
|
|
12
15
|
let level = 0;
|
|
13
16
|
const promises = [];
|
|
14
17
|
while (path.length > 0) {
|
|
@@ -50,5 +53,98 @@ const _findWorkspaceRoot = async (dirPath) => {
|
|
|
50
53
|
results.find((r) => r.value.type === WorkspaceFileType.package)?.value;
|
|
51
54
|
if (!result)
|
|
52
55
|
throw new Error("findWorkspaceRoot: no file found");
|
|
56
|
+
__workspaceRoot = result;
|
|
53
57
|
return result;
|
|
54
58
|
};
|
|
59
|
+
export const readWorkspaceYaml = async (repoRoot) => {
|
|
60
|
+
const workspaceFilePath = resolve(repoRoot, "pnpm-workspace.yaml");
|
|
61
|
+
const fileContent = await readFile(workspaceFilePath, "utf8");
|
|
62
|
+
const parsed = parse(fileContent);
|
|
63
|
+
if (!parsed || !parsed.packages || !Array.isArray(parsed.packages))
|
|
64
|
+
throw new Error("No 'packages' field found in pnpm-workspace.yaml");
|
|
65
|
+
const packageColletions = await Promise.all(parsed.packages.map(async (p) => {
|
|
66
|
+
if (!p.endsWith("/*"))
|
|
67
|
+
return [p];
|
|
68
|
+
const base = p.substring(0, p.length - 2);
|
|
69
|
+
const pkgs = await readdir(join(repoRoot, base));
|
|
70
|
+
return pkgs
|
|
71
|
+
.filter((pkg) => !pkg.startsWith("."))
|
|
72
|
+
.map((pkg) => join(base, pkg));
|
|
73
|
+
}));
|
|
74
|
+
const packages = [];
|
|
75
|
+
for (const packageColletion of packageColletions)
|
|
76
|
+
packages.push(...packageColletion);
|
|
77
|
+
return { packages };
|
|
78
|
+
};
|
|
79
|
+
export const readPackageJson = async (dirOrFilepath) => {
|
|
80
|
+
try {
|
|
81
|
+
return readPackageJsonThrow(dirOrFilepath);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
export const readPackageJsonThrow = async (dirOrFilepath) => {
|
|
88
|
+
const pkgPath = dirOrFilepath.endsWith("/package.json")
|
|
89
|
+
? dirOrFilepath
|
|
90
|
+
: join(dirOrFilepath, "package.json");
|
|
91
|
+
return pkg.parse(await readFile(pkgPath, "utf8"));
|
|
92
|
+
};
|
|
93
|
+
export const readPackageJsons = async (repoRoot) => {
|
|
94
|
+
try {
|
|
95
|
+
const pnpmWS = await readWorkspaceYaml(repoRoot);
|
|
96
|
+
return Promise.all(pnpmWS.packages.map(async (repoPath) => {
|
|
97
|
+
const jsonPath = join(repoRoot, repoPath, "package.json");
|
|
98
|
+
const content = await readPackageJsonThrow(jsonPath);
|
|
99
|
+
return {
|
|
100
|
+
jsonPath,
|
|
101
|
+
repoPath,
|
|
102
|
+
content,
|
|
103
|
+
modified: false,
|
|
104
|
+
wsName: repoPath.startsWith("packages/")
|
|
105
|
+
? repoPath.substring(9)
|
|
106
|
+
: repoPath,
|
|
107
|
+
};
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
export const writePackageJsons = async (entries) => Promise.all(entries.map(async (entry) => {
|
|
115
|
+
if (entry.modified) {
|
|
116
|
+
await writeFile(entry.jsonPath, JSON.stringify(entry.content, null, 2) + "\n", "utf8");
|
|
117
|
+
console.log(` ✅ Updated ${entry.content.name}\n`);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
console.log(` ⏭️ No workspace dependencies to fix. ${entry.content.name}\n`);
|
|
121
|
+
}
|
|
122
|
+
}));
|
|
123
|
+
// Build a map of package names to their versions
|
|
124
|
+
export const buildMapEntries = (pkgEntries) => {
|
|
125
|
+
const versionEntries = [];
|
|
126
|
+
for (const fromPkg of pkgEntries)
|
|
127
|
+
for (const toPkg of pkgEntries)
|
|
128
|
+
if (fromPkg.content.name !== toPkg.content.name)
|
|
129
|
+
versionEntries.push({
|
|
130
|
+
fromPkg,
|
|
131
|
+
toPkg,
|
|
132
|
+
relPath: relative(fromPkg.repoPath, toPkg.repoPath),
|
|
133
|
+
});
|
|
134
|
+
return versionEntries;
|
|
135
|
+
};
|
|
136
|
+
export const readPackageVersions = async (rootDir) => {
|
|
137
|
+
const versions = {};
|
|
138
|
+
const packageJsons = await readPackageJsons(rootDir);
|
|
139
|
+
for (const packageJson of packageJsons)
|
|
140
|
+
versions[packageJson.repoPath] = packageJson.content.version;
|
|
141
|
+
return versions;
|
|
142
|
+
};
|
|
143
|
+
export const readMinPackageVersion = async (rootDir) => {
|
|
144
|
+
const versions = await readPackageVersions(rootDir);
|
|
145
|
+
const splitVersions = Object.values(versions).map(splitVersion);
|
|
146
|
+
if (splitVersions.length === 0)
|
|
147
|
+
return null;
|
|
148
|
+
splitVersions.sort(compareVersions);
|
|
149
|
+
return concatVersion(splitVersions[0]);
|
|
150
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mxpicture/gcp-functions-code",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Tools for google cloud functions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "MXPicture",
|
|
@@ -26,28 +26,24 @@
|
|
|
26
26
|
"scripts": {
|
|
27
27
|
"clean": "rm -rf dist .tsbuildinfo tsconfig.tsbuildinfo node_modules",
|
|
28
28
|
"lint": "eslint \"src/**/*.{ts,tsx}\" --ext .ts,.tsx",
|
|
29
|
-
"build": "tsc -b ."
|
|
30
|
-
"test:clean": "rm -rf src/4testing/generator-test-*",
|
|
31
|
-
"run:test": "pnpm exec tsx src/scripts/test.mts"
|
|
29
|
+
"build": "tsc -b ."
|
|
32
30
|
},
|
|
33
31
|
"publishConfig": {
|
|
34
32
|
"access": "public"
|
|
35
33
|
},
|
|
36
34
|
"dependencies": {
|
|
37
|
-
"@mxpicture/gcp-functions-common": "^0.2.
|
|
38
|
-
"json5": "^
|
|
35
|
+
"@mxpicture/gcp-functions-common": "^0.2.2",
|
|
36
|
+
"json5": "^2.2.3",
|
|
39
37
|
"micromatch": "^4.0.8",
|
|
40
38
|
"prettier": "^3.8.1",
|
|
41
39
|
"simple-git": "^3.31.1",
|
|
42
|
-
"type-fest": "^5.4.4",
|
|
43
40
|
"yaml": "^2.8.2",
|
|
44
41
|
"zod": "^4.3.6"
|
|
45
42
|
},
|
|
46
43
|
"devDependencies": {
|
|
47
44
|
"@types/micromatch": "^4.0.10",
|
|
48
|
-
"@types/node": "^25.2.
|
|
49
|
-
"
|
|
50
|
-
"eslint": "^9.39.2",
|
|
45
|
+
"@types/node": "^25.2.3",
|
|
46
|
+
"eslint": "^10.0.2",
|
|
51
47
|
"typescript": "^5.9.3"
|
|
52
48
|
}
|
|
53
49
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { basename, dirname, join } from "node:path";
|
|
2
|
-
import { readdir, writeFile } from "node:fs/promises";
|
|
3
|
-
import { VSCodeWorkspace } from "../vscode/VSCodeWorkspace.js";
|
|
4
|
-
// ─── Configuration ───────────────────────────────────────────────────────────
|
|
5
|
-
// /** File patterns to exclude from barrel exports */
|
|
6
|
-
const EXCLUDED_PATTERNS = [
|
|
7
|
-
/\.test\.ts$/,
|
|
8
|
-
/\.spec\.ts$/,
|
|
9
|
-
/\.d\.ts$/,
|
|
10
|
-
/index\.ts$/,
|
|
11
|
-
];
|
|
12
|
-
// /** Header comment added to every generated barrel file */
|
|
13
|
-
const HEADER = "// This file is auto-generated. Do not edit manually.\n";
|
|
14
|
-
const isExcluded = (fileName) => EXCLUDED_PATTERNS.some((pattern) => pattern.test(fileName));
|
|
15
|
-
// ─── Generator ───────────────────────────────────────────────────────────────
|
|
16
|
-
const createBarrels = async () => {
|
|
17
|
-
const rootDir = (await VSCodeWorkspace.loadAsync()).root;
|
|
18
|
-
const packagesDir = join(rootDir, "packages");
|
|
19
|
-
const packages = (await readdir(packagesDir)).map((p) => join(packagesDir, p));
|
|
20
|
-
const promises = [];
|
|
21
|
-
for (const pkg of packages) {
|
|
22
|
-
try {
|
|
23
|
-
const baseDirPath = join(pkg, "src");
|
|
24
|
-
const items = (await readdir(baseDirPath, { recursive: true })).sort();
|
|
25
|
-
let currentGroup;
|
|
26
|
-
for (const item of items) {
|
|
27
|
-
const filename = basename(item);
|
|
28
|
-
if (isExcluded(filename) || !filename.endsWith(".ts"))
|
|
29
|
-
continue;
|
|
30
|
-
const dirPath = join(baseDirPath, dirname(item));
|
|
31
|
-
if (dirPath !== currentGroup?.dirPath) {
|
|
32
|
-
if (currentGroup)
|
|
33
|
-
promises.push(persistBarrel({ ...currentGroup }));
|
|
34
|
-
currentGroup = { dirPath, files: [] };
|
|
35
|
-
}
|
|
36
|
-
currentGroup.files.push(filename);
|
|
37
|
-
}
|
|
38
|
-
if (currentGroup)
|
|
39
|
-
promises.push(persistBarrel({ ...currentGroup }));
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
await Promise.all(promises);
|
|
46
|
-
};
|
|
47
|
-
const persistBarrel = async (group) => {
|
|
48
|
-
if (group.files.length === 0)
|
|
49
|
-
return;
|
|
50
|
-
const content = `${HEADER}${group.files
|
|
51
|
-
.sort()
|
|
52
|
-
.map((f) => `export * from "./${basename(f, ".ts")}.js";`)
|
|
53
|
-
.join("\n")}\n`;
|
|
54
|
-
const barrelPath = join(group.dirPath, "index.ts");
|
|
55
|
-
return writeFile(barrelPath, content);
|
|
56
|
-
};
|
|
57
|
-
// ─── Entry Point ─────────────────────────────────────────────────────────────
|
|
58
|
-
const run = async () => {
|
|
59
|
-
await createBarrels();
|
|
60
|
-
// // Allow overriding paths via CLI arguments:
|
|
61
|
-
// // npx tsx scripts/generate-barrels.ts ./src/hooks ./src/types
|
|
62
|
-
// const cliPaths = process.argv.slice(2);
|
|
63
|
-
// const paths = cliPaths.length > 0 ? cliPaths : BARREL_PATHS;
|
|
64
|
-
// console.log("🛢️ Generating barrel files...\n");
|
|
65
|
-
// console.log(
|
|
66
|
-
// `📂 Target directories:\n${paths
|
|
67
|
-
// .map((p) => ` - ${resolve(p)}`)
|
|
68
|
-
// .join("\n")}\n`,
|
|
69
|
-
// );
|
|
70
|
-
// let generated = 0;
|
|
71
|
-
// for (const targetPath of paths) {
|
|
72
|
-
// const resolved = resolve(targetPath);
|
|
73
|
-
// if (await generateBarrel(resolved)) {
|
|
74
|
-
// generated++;
|
|
75
|
-
// }
|
|
76
|
-
// }
|
|
77
|
-
// console.log(
|
|
78
|
-
// `\n🎉 Done! Barrels generated for ${generated}/${paths.length} directories.`,
|
|
79
|
-
// );
|
|
80
|
-
};
|
|
81
|
-
run().catch(console.error);
|
package/dist/scripts/index.d.ts
DELETED
package/dist/scripts/index.js
DELETED