@mxpicture/gcp-functions-code 0.2.0

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 (63) hide show
  1. package/dist/changelog/ChangeDetector.d.ts +25 -0
  2. package/dist/changelog/ChangeDetector.js +47 -0
  3. package/dist/changelog/Changelog.d.ts +15 -0
  4. package/dist/changelog/Changelog.js +98 -0
  5. package/dist/changelog/changelog.util.d.ts +94 -0
  6. package/dist/changelog/changelog.util.js +228 -0
  7. package/dist/changelog/index.d.ts +3 -0
  8. package/dist/changelog/index.js +4 -0
  9. package/dist/common/code.common.d.ts +17 -0
  10. package/dist/common/code.common.js +65 -0
  11. package/dist/common/hash.common.d.ts +1 -0
  12. package/dist/common/hash.common.js +2 -0
  13. package/dist/common/index.d.ts +4 -0
  14. package/dist/common/index.js +5 -0
  15. package/dist/common/string.common.d.ts +4 -0
  16. package/dist/common/string.common.js +8 -0
  17. package/dist/common/types.common.d.ts +20 -0
  18. package/dist/common/types.common.js +1 -0
  19. package/dist/deps/IFixWorkspaceDeps.d.ts +21 -0
  20. package/dist/deps/IFixWorkspaceDeps.js +76 -0
  21. package/dist/deps/fixWorkspaceDeps.d.ts +12 -0
  22. package/dist/deps/fixWorkspaceDeps.js +43 -0
  23. package/dist/deps/index.d.ts +2 -0
  24. package/dist/deps/index.js +3 -0
  25. package/dist/git/GitChanges.d.ts +33 -0
  26. package/dist/git/GitChanges.js +85 -0
  27. package/dist/git/git.util.d.ts +9 -0
  28. package/dist/git/git.util.js +33 -0
  29. package/dist/git/index.d.ts +3 -0
  30. package/dist/git/index.js +4 -0
  31. package/dist/git/types.git.d.ts +22 -0
  32. package/dist/git/types.git.js +1 -0
  33. package/dist/scripts/fix-workspace-deps.d.ts +2 -0
  34. package/dist/scripts/fix-workspace-deps.js +14 -0
  35. package/dist/scripts/generate-barrels.d.ts +1 -0
  36. package/dist/scripts/generate-barrels.js +81 -0
  37. package/dist/scripts/generate-changelog.d.ts +1 -0
  38. package/dist/scripts/generate-changelog.js +13 -0
  39. package/dist/scripts/index.d.ts +3 -0
  40. package/dist/scripts/index.js +4 -0
  41. package/dist/vscode/OSUser.d.ts +15 -0
  42. package/dist/vscode/OSUser.js +62 -0
  43. package/dist/vscode/VSCodeSettings.d.ts +10 -0
  44. package/dist/vscode/VSCodeSettings.js +41 -0
  45. package/dist/vscode/VSCodeWorkspace.d.ts +20 -0
  46. package/dist/vscode/VSCodeWorkspace.js +44 -0
  47. package/dist/vscode/common.vscode.d.ts +4 -0
  48. package/dist/vscode/common.vscode.js +17 -0
  49. package/dist/vscode/config.vscode.d.ts +2 -0
  50. package/dist/vscode/config.vscode.js +4 -0
  51. package/dist/vscode/index.d.ts +10 -0
  52. package/dist/vscode/index.js +11 -0
  53. package/dist/vscode/profiles.vscode.d.ts +5 -0
  54. package/dist/vscode/profiles.vscode.js +29 -0
  55. package/dist/vscode/storage.vscode.d.ts +3 -0
  56. package/dist/vscode/storage.vscode.js +15 -0
  57. package/dist/vscode/types.vscode.d.ts +36 -0
  58. package/dist/vscode/types.vscode.js +6 -0
  59. package/dist/vscode/workspaceAsync.vscode.d.ts +2 -0
  60. package/dist/vscode/workspaceAsync.vscode.js +54 -0
  61. package/dist/vscode/workspaceSync.vscode.d.ts +4 -0
  62. package/dist/vscode/workspaceSync.vscode.js +73 -0
  63. package/package.json +53 -0
@@ -0,0 +1,25 @@
1
+ import { DocumentData } from "@mxpicture/gcp-functions-common/types";
2
+ import { GitChangesCommit } from "../git/GitChanges.js";
3
+ import { Changelog } from "./Changelog.js";
4
+ import { PackageVersion } from "./changelog.util.js";
5
+ export declare enum ChangeWatchType {
6
+ changelog = "changelog",
7
+ gitHistory = "gitHistory"
8
+ }
9
+ export interface ChangeWatch {
10
+ pattern: string;
11
+ type: ChangeWatchType;
12
+ }
13
+ export type ChangeEventHandler<T extends DocumentData> = (paths: string[], watch: ChangeWatch) => Promise<T | null>;
14
+ export interface ChangeWatchHandler<T extends DocumentData> extends ChangeWatch {
15
+ handler: ChangeEventHandler<T>;
16
+ }
17
+ export declare class ChangeDetector<T extends DocumentData> {
18
+ protected readonly log: Changelog;
19
+ protected readonly git: GitChangesCommit;
20
+ protected readonly sinceVersion?: PackageVersion | undefined;
21
+ protected readonly watches: ChangeWatchHandler<T>[];
22
+ constructor(log: Changelog, git: GitChangesCommit, sinceVersion?: PackageVersion | undefined);
23
+ addWatch(...watches: ChangeWatchHandler<T>[]): void;
24
+ run(): Promise<T[]>;
25
+ }
@@ -0,0 +1,47 @@
1
+ import micromatch from "micromatch";
2
+ export var ChangeWatchType;
3
+ (function (ChangeWatchType) {
4
+ ChangeWatchType["changelog"] = "changelog";
5
+ ChangeWatchType["gitHistory"] = "gitHistory";
6
+ })(ChangeWatchType || (ChangeWatchType = {}));
7
+ export class ChangeDetector {
8
+ log;
9
+ git;
10
+ sinceVersion;
11
+ watches = [];
12
+ constructor(log, git, sinceVersion) {
13
+ this.log = log;
14
+ this.git = git;
15
+ this.sinceVersion = sinceVersion;
16
+ }
17
+ addWatch(...watches) {
18
+ this.watches.push(...watches);
19
+ }
20
+ async run() {
21
+ const results = [];
22
+ const logEntries = await this.log.readChangelogEntries(this.sinceVersion);
23
+ const gitEntries = (await this.git.readChangedFiles()).files;
24
+ for (const watch of this.watches) {
25
+ if (watch.type === ChangeWatchType.changelog) {
26
+ const paths = [];
27
+ for (const logEntry of logEntries)
28
+ for (const file of logEntry.changedFiles)
29
+ if (micromatch.isMatch(file, watch.pattern))
30
+ paths.push(file);
31
+ if (paths.length > 0)
32
+ results.push(watch.handler(paths, watch));
33
+ continue;
34
+ }
35
+ if (watch.type === ChangeWatchType.gitHistory) {
36
+ const paths = [];
37
+ for (const gitEntry of gitEntries)
38
+ if (micromatch.isMatch(gitEntry.repoFilePath, watch.pattern))
39
+ paths.push(gitEntry.repoFilePath);
40
+ if (paths.length > 0)
41
+ results.push(watch.handler(paths, watch));
42
+ continue;
43
+ }
44
+ }
45
+ return (await Promise.all(results)).filter((r) => r !== null);
46
+ }
47
+ }
@@ -0,0 +1,15 @@
1
+ import { GitChanges } from "../git/GitChanges.js";
2
+ import { ChangelogEntry, PackageVersion } from "./changelog.util.js";
3
+ export declare class Changelog {
4
+ protected readonly git: GitChanges;
5
+ protected readonly changelogPath: string;
6
+ protected readonly packageJsonPath: string;
7
+ protected readonly rootDir: string;
8
+ constructor(git: GitChanges);
9
+ run(): Promise<ChangelogEntry | null>;
10
+ readChangelogEntries(sinceVersion?: PackageVersion): Promise<ChangelogEntry[]>;
11
+ protected condenseEntries(entries: ChangelogEntry[]): {
12
+ entries: ChangelogEntry[];
13
+ hasChanged: boolean;
14
+ };
15
+ }
@@ -0,0 +1,98 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, resolve } from "node:path";
3
+ import { changelogEntriesSchema, changelogEntrySchema, resolveBaselineCommit, readChangedTsFiles, mapChangedPackages, mapAffectedPackages, readMinPackageVersion, splitVersion, compareVersionsGT, } from "./changelog.util.js";
4
+ import pkg from "json5";
5
+ import { fileURLToPath } from "node:url";
6
+ import { lastCommitHash } from "../git/git.util.js";
7
+ import { formatJson2Spaces } from "../common/code.common.js";
8
+ const changelogLimit = 10;
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ export class Changelog {
11
+ git;
12
+ changelogPath;
13
+ packageJsonPath;
14
+ rootDir;
15
+ constructor(git) {
16
+ this.git = git;
17
+ this.changelogPath = resolve(__dirname, "../../changelog.json");
18
+ this.packageJsonPath = resolve(__dirname, "../../package.json");
19
+ this.rootDir = resolve(__dirname, "../../../..");
20
+ }
21
+ async run() {
22
+ const existingEntries = await this.readChangelogEntries();
23
+ const currentCommitHash = await lastCommitHash(this.rootDir);
24
+ if (!currentCommitHash)
25
+ throw new Error("No current git commit hash found");
26
+ const baselineCommit = await resolveBaselineCommit(existingEntries, this.git.rootDir, this.packageJsonPath);
27
+ const changedFiles = await readChangedTsFiles(baselineCommit, this.git);
28
+ if (changedFiles.length === 0)
29
+ return null;
30
+ const changedPackages = mapChangedPackages(changedFiles);
31
+ const affectedPackages = mapAffectedPackages(changedPackages);
32
+ const version = await readMinPackageVersion(this.rootDir);
33
+ if (!version)
34
+ throw new Error("No version found");
35
+ const entry = {
36
+ timestamp: new Date().toISOString(),
37
+ gitCommitHashs: [currentCommitHash],
38
+ version,
39
+ versionParts: splitVersion(version),
40
+ changedPackages,
41
+ affectedPackages,
42
+ changedFiles,
43
+ };
44
+ await changelogEntrySchema.parseAsync(entry);
45
+ const condenseResult = this.condenseEntries([entry, ...existingEntries]);
46
+ if (!condenseResult.hasChanged)
47
+ return null;
48
+ await changelogEntriesSchema.parseAsync(condenseResult.entries);
49
+ await writeFile(this.changelogPath, await formatJson2Spaces(pkg.stringify(condenseResult.entries)));
50
+ return entry;
51
+ }
52
+ async readChangelogEntries(sinceVersion) {
53
+ try {
54
+ const content = await readFile(this.changelogPath, "utf8");
55
+ const parsed = pkg.parse(content);
56
+ const entries = await changelogEntriesSchema.parseAsync(parsed);
57
+ if (!sinceVersion)
58
+ return entries;
59
+ return entries.filter((e) => compareVersionsGT(e.versionParts, sinceVersion));
60
+ }
61
+ catch {
62
+ return [];
63
+ }
64
+ }
65
+ condenseEntries(entries) {
66
+ const results = [];
67
+ let hasChanged = false;
68
+ for (const entry of entries) {
69
+ const result = results.find((result) => result.version === entry.version);
70
+ if (!result) {
71
+ results.push({ ...entry });
72
+ hasChanged = true;
73
+ continue;
74
+ }
75
+ for (const item of entry.affectedPackages)
76
+ if (!result.affectedPackages.includes(item)) {
77
+ result.affectedPackages.push(item);
78
+ hasChanged = true;
79
+ }
80
+ for (const item of entry.changedFiles)
81
+ if (!result.changedFiles.includes(item)) {
82
+ result.changedFiles.push(item);
83
+ hasChanged = true;
84
+ }
85
+ for (const item of entry.changedPackages)
86
+ if (!result.changedPackages.includes(item)) {
87
+ result.changedPackages.push(item);
88
+ hasChanged = true;
89
+ }
90
+ for (const item of entry.gitCommitHashs)
91
+ if (!result.gitCommitHashs.includes(item)) {
92
+ result.gitCommitHashs.unshift(item);
93
+ hasChanged = true;
94
+ }
95
+ }
96
+ return { entries: results.splice(0, changelogLimit), hasChanged };
97
+ }
98
+ }
@@ -0,0 +1,94 @@
1
+ import { z } from "zod";
2
+ import { GitChanges } from "../git/GitChanges.js";
3
+ export type ProcessMode = "fix" | "restore";
4
+ export interface PackageVersion {
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"];
41
+ export type ChangelogPackageName = (typeof changelogPackageNames)[number];
42
+ export declare const changelogDependents: Record<ChangelogPackageName, string[]>;
43
+ export interface ChangelogEntry {
44
+ version: string;
45
+ versionParts: PackageVersion;
46
+ timestamp: string;
47
+ gitCommitHashs: string[];
48
+ changedPackages: string[];
49
+ affectedPackages: string[];
50
+ changedFiles: string[];
51
+ }
52
+ export declare const changelogEntrySchema: z.ZodObject<{
53
+ version: z.ZodString;
54
+ versionParts: z.ZodObject<{
55
+ major: z.ZodNumber;
56
+ minor: z.ZodXor<readonly [z.ZodNumber, z.ZodNull]>;
57
+ patch: z.ZodXor<readonly [z.ZodNumber, z.ZodNull]>;
58
+ prefix: z.ZodXor<readonly [z.ZodString, z.ZodNull]>;
59
+ }, z.core.$strip>;
60
+ timestamp: z.ZodISODateTime;
61
+ gitCommitHashs: z.ZodArray<z.ZodString>;
62
+ changedPackages: z.ZodArray<z.ZodString>;
63
+ affectedPackages: z.ZodArray<z.ZodString>;
64
+ changedFiles: z.ZodArray<z.ZodString>;
65
+ }, z.core.$strip>;
66
+ export declare const changelogEntriesSchema: z.ZodArray<z.ZodObject<{
67
+ version: z.ZodString;
68
+ versionParts: z.ZodObject<{
69
+ major: z.ZodNumber;
70
+ minor: z.ZodXor<readonly [z.ZodNumber, z.ZodNull]>;
71
+ patch: z.ZodXor<readonly [z.ZodNumber, z.ZodNull]>;
72
+ prefix: z.ZodXor<readonly [z.ZodString, z.ZodNull]>;
73
+ }, z.core.$strip>;
74
+ timestamp: z.ZodISODateTime;
75
+ gitCommitHashs: z.ZodArray<z.ZodString>;
76
+ changedPackages: z.ZodArray<z.ZodString>;
77
+ affectedPackages: z.ZodArray<z.ZodString>;
78
+ changedFiles: z.ZodArray<z.ZodString>;
79
+ }, 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
+ 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
+ export declare const readChangedTsFiles: (baselineCommit: string, git: GitChanges) => Promise<string[]>;
91
+ export declare const mapChangedPackages: (files: string[]) => string[];
92
+ 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>;
@@ -0,0 +1,228 @@
1
+ import { readdir, readFile, writeFile } from "node:fs/promises";
2
+ import { join, relative, resolve } from "node:path";
3
+ import pkg from "json5";
4
+ import { z } from "zod";
5
+ import { parse } from "yaml";
6
+ import { verifiedGit } from "../git/git.util.js";
7
+ export const packageVersionSchema = z.object({
8
+ major: z.number().min(0),
9
+ minor: z.xor([z.number(), z.null()]),
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
33
+ export const changelogDependents = {
34
+ common: ["common", "backend", "frontend", "code"],
35
+ backend: ["backend", "code"],
36
+ frontend: ["frontend", "code"],
37
+ code: ["code"],
38
+ };
39
+ export const changelogEntrySchema = z.object({
40
+ version: z.string().min(1),
41
+ versionParts: packageVersionSchema,
42
+ timestamp: z.iso.datetime(),
43
+ gitCommitHashs: z.array(z.string().min(1)).min(1),
44
+ changedPackages: z.array(z.string()),
45
+ affectedPackages: z.array(z.string()),
46
+ changedFiles: z.array(z.string()),
47
+ });
48
+ 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
+ export const resolveBaselineCommit = async (entries, rootDir, packageJsonPath) => {
154
+ if (entries.length > 0 &&
155
+ entries[0].gitCommitHashs.length > 0 &&
156
+ entries[0].gitCommitHashs[0])
157
+ return ensureCommitRef(entries[0].gitCommitHashs[0], "HEAD~1", rootDir);
158
+ const packageJson = await readPackageJson(packageJsonPath);
159
+ const versionTag = packageJson?.version ? `v${packageJson.version}` : null;
160
+ if (versionTag) {
161
+ const simplegit = await verifiedGit(rootDir);
162
+ const tags = await simplegit.tags();
163
+ if (tags.all.includes(versionTag)) {
164
+ return ensureCommitRef(versionTag, "HEAD~1", rootDir);
165
+ }
166
+ }
167
+ return ensureCommitRef("HEAD~1", "HEAD", rootDir);
168
+ };
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
+ export const readChangedTsFiles = async (baselineCommit, git) => {
180
+ git.sinceCommit = baselineCommit;
181
+ const [result, simplegit] = await Promise.all([
182
+ git.readChangedFiles(),
183
+ verifiedGit(git.rootDir),
184
+ ]);
185
+ const status = await simplegit.status();
186
+ const targetPrefix = /^packages\/(common|backend|frontend|code)\/src\//;
187
+ const untracked = status.not_added.map((path) => path.replaceAll("\\", "/"));
188
+ return [...result.files.map((file) => file.repoFilePath), ...untracked]
189
+ .map((path) => path.replaceAll("\\", "/"))
190
+ .filter((path) => targetPrefix.test(path) && path.endsWith(".ts"))
191
+ .filter((path, index, arr) => arr.indexOf(path) === index)
192
+ .sort();
193
+ };
194
+ export const mapChangedPackages = (files) => {
195
+ const found = new Set();
196
+ for (const filePath of files) {
197
+ const parts = filePath.split("/");
198
+ const packageName = parts[1];
199
+ if (packageName)
200
+ found.add(packageName);
201
+ }
202
+ return [...found].sort();
203
+ };
204
+ export const mapAffectedPackages = (changedPackages) => {
205
+ const affected = new Set();
206
+ for (const packageName of changedPackages) {
207
+ const typedName = packageName;
208
+ const dependents = changelogDependents[typedName] ?? [packageName];
209
+ for (const dependent of dependents)
210
+ affected.add(dependent);
211
+ }
212
+ return [...affected].sort();
213
+ };
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
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./ChangeDetector.js";
2
+ export * from "./Changelog.js";
3
+ export * from "./changelog.util.js";
@@ -0,0 +1,4 @@
1
+ // This file is auto-generated. Do not edit manually.
2
+ export * from "./ChangeDetector.js";
3
+ export * from "./Changelog.js";
4
+ export * from "./changelog.util.js";
@@ -0,0 +1,17 @@
1
+ import { MetaFileExtension, MetaFileType } from "@mxpicture/gcp-functions-common/meta";
2
+ import { ExtractFileParts, SourceFile } from "./types.common.js";
3
+ export declare const isTemplateFile: (filename: string) => boolean;
4
+ export declare const isTsFile: (filename: string, type: MetaFileType) => boolean;
5
+ export declare const isAnyFile: (filename: string, type?: MetaFileType, ext?: MetaFileExtension) => boolean;
6
+ export declare const extractFileParts: (filename: string) => ExtractFileParts;
7
+ export declare const concatFileParts: (parts: ExtractFileParts) => string;
8
+ export declare const toFilename: (p: {
9
+ filename: string;
10
+ type: MetaFileType;
11
+ generated?: boolean;
12
+ ext?: MetaFileExtension;
13
+ }) => string;
14
+ export declare const formatCode: (...lines: string[]) => Promise<string>;
15
+ export declare const formatJson: (...lines: string[]) => Promise<string>;
16
+ export declare const formatJson2Spaces: (...lines: string[]) => Promise<string>;
17
+ export declare const createSourceFiles: (filePaths: string[]) => SourceFile[];
@@ -0,0 +1,65 @@
1
+ import ts from "typescript";
2
+ import { format } from "prettier";
3
+ import { guardMetaFileExtension, guardMetaFileType, MetaFileExtension, MetaFileType, } from "@mxpicture/gcp-functions-common/meta";
4
+ export const isTemplateFile = (filename) => isTsFile(filename, MetaFileType.template);
5
+ export const isTsFile = (filename, type) => isAnyFile(filename, type, MetaFileExtension.ts);
6
+ export const isAnyFile = (filename, type, ext) => {
7
+ try {
8
+ const parts = extractFileParts(filename);
9
+ if (type && type !== parts.type)
10
+ return false;
11
+ if (ext && ext !== parts.ext)
12
+ return false;
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ return true;
18
+ };
19
+ export const extractFileParts = (filename) => {
20
+ const parts = filename.split(".");
21
+ if (parts.length < 3)
22
+ throw new Error(`Filename "${filename}" invalid (3 parts divided by ".")`);
23
+ const _type = parts.shift();
24
+ const _ext = parts.pop();
25
+ const type = guardMetaFileType(_type);
26
+ const ext = guardMetaFileExtension(_ext);
27
+ if (!type)
28
+ throw new Error(`Filename "${filename}" invalid (type: ${_type})`);
29
+ if (!ext)
30
+ throw new Error(`Filename "${filename}" invalid (extension: ${_ext})`);
31
+ return {
32
+ filename,
33
+ type,
34
+ ext,
35
+ middlePart: parts.join("."),
36
+ };
37
+ };
38
+ export const concatFileParts = (parts) => [parts.type, parts.middlePart, parts.generated ? "gen" : null, parts.ext]
39
+ .filter((p) => !!p)
40
+ .join(".");
41
+ export const toFilename = (p) => concatFileParts({
42
+ ...extractFileParts(p.filename),
43
+ type: p.type,
44
+ ext: p.ext ?? MetaFileExtension.ts,
45
+ generated: p.generated,
46
+ });
47
+ export const formatCode = async (...lines) => format(lines.join("\n"), { parser: "typescript" });
48
+ export const formatJson = async (...lines) => format(lines.join("\n"), { parser: "json" });
49
+ export const formatJson2Spaces = async (...lines) => format(lines.join("\n"), { parser: "json", tabWidth: 2, useTabs: false });
50
+ export const createSourceFiles = (filePaths) => {
51
+ const program = ts.createProgram(filePaths, {
52
+ target: ts.ScriptTarget.ES2023,
53
+ module: ts.ModuleKind.Node20,
54
+ strict: true,
55
+ });
56
+ const checker = program.getTypeChecker();
57
+ const results = [];
58
+ for (const filePath of filePaths) {
59
+ const sourceFile = program.getSourceFile(filePath);
60
+ if (!sourceFile)
61
+ continue;
62
+ results.push({ sourceFile, filePath, checker });
63
+ }
64
+ return results;
65
+ };
@@ -0,0 +1 @@
1
+ export declare const calcHash: (input: string) => string;
@@ -0,0 +1,2 @@
1
+ import { createHash } from "node:crypto";
2
+ export const calcHash = (input) => createHash("sha256").update(input).digest("hex");
@@ -0,0 +1,4 @@
1
+ export * from "./code.common.js";
2
+ export * from "./hash.common.js";
3
+ export * from "./string.common.js";
4
+ export * from "./types.common.js";
@@ -0,0 +1,5 @@
1
+ // This file is auto-generated. Do not edit manually.
2
+ export * from "./code.common.js";
3
+ export * from "./hash.common.js";
4
+ export * from "./string.common.js";
5
+ export * from "./types.common.js";
@@ -0,0 +1,4 @@
1
+ export declare const lowerFirstLetter: (val: string) => string;
2
+ export declare const upperFirstLetter: (val: string) => string;
3
+ export declare const lowerFirstLetterAsync: (val: string) => Promise<string>;
4
+ export declare const upperFirstLetterAsync: (val: string) => Promise<string>;
@@ -0,0 +1,8 @@
1
+ export const lowerFirstLetter = (val) => val.length > 1
2
+ ? val.charAt(0).toLocaleLowerCase() + val.slice(1)
3
+ : val.toLocaleLowerCase();
4
+ export const upperFirstLetter = (val) => val.length > 1
5
+ ? val.charAt(0).toUpperCase() + val.slice(1)
6
+ : val.toUpperCase();
7
+ export const lowerFirstLetterAsync = async (val) => Promise.resolve().then(() => lowerFirstLetter(val));
8
+ export const upperFirstLetterAsync = async (val) => Promise.resolve().then(() => upperFirstLetter(val));
@@ -0,0 +1,20 @@
1
+ import ts from "typescript";
2
+ import type { PackageJson } from "type-fest";
3
+ import { MetaFileExtension, MetaFileType, MetaTargetType } from "@mxpicture/gcp-functions-common/meta";
4
+ export interface ExtractFileParts {
5
+ filename: string;
6
+ type: MetaFileType;
7
+ ext: MetaFileExtension;
8
+ middlePart: string;
9
+ generated?: boolean;
10
+ }
11
+ export interface SourceFile {
12
+ filePath: string;
13
+ checker: ts.TypeChecker;
14
+ sourceFile: ts.SourceFile;
15
+ }
16
+ export interface TargetPackage {
17
+ targetType: MetaTargetType;
18
+ filePath: string;
19
+ pkg: PackageJson;
20
+ }
@@ -0,0 +1 @@
1
+ export {};