@pgpmjs/core 6.31.0 → 6.32.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.
@@ -137,10 +137,35 @@ export declare class PgpmPackage {
137
137
  private createSqlFiles;
138
138
  publishToDist(distFolder?: string): void;
139
139
  /**
140
- * Installs an extension npm package into the local skitch extensions directory,
141
- * and automatically adds it to the current module’s package.json dependencies.
140
+ * Installs an extension npm package into the workspace extensions directory.
141
+ *
142
+ * When run inside a module, the installed version is recorded in the
143
+ * module's package.json dependencies and its .control requires list.
144
+ * When run at the workspace root, the installed version is recorded in
145
+ * the workspace pgpm.json `dependencies` field instead — no .control
146
+ * file is needed.
142
147
  */
143
148
  installModules(...pkgstrs: string[]): Promise<void>;
149
+ /**
150
+ * Returns the workspace-level pgpm module dependencies recorded in
151
+ * the workspace pgpm.json `dependencies` field.
152
+ */
153
+ getWorkspaceDependencies(): Record<string, string>;
154
+ /**
155
+ * Records installed module versions into the workspace pgpm.json
156
+ * `dependencies` field. No-op when the workspace uses pgpm.config.js.
157
+ */
158
+ recordWorkspaceDependencies(versions: Record<string, string>): void;
159
+ /**
160
+ * Installs the workspace-level dependencies declared in pgpm.json into
161
+ * the workspace extensions/ directory. Skips modules already present
162
+ * unless `force` is set.
163
+ *
164
+ * @returns The list of installed package specs (name@version)
165
+ */
166
+ installWorkspaceDependencies(options?: {
167
+ force?: boolean;
168
+ }): Promise<string[]>;
144
169
  /**
145
170
  * Returns information about which of the specified modules are installed.
146
171
  * Checks the module's package.json dependencies to determine installation status.
@@ -236,7 +236,15 @@ class PgpmPackage {
236
236
  listModules() {
237
237
  if (!this.workspacePath)
238
238
  return {};
239
- const moduleFiles = glob.sync(`${this.workspacePath}/**/*.control`).filter((file) => !/node_modules/.test(file)).sort((a, b) => a.localeCompare(b));
239
+ // Workspace membership is first-class: modules are discovered from the
240
+ // workspace's declared `packages` globs plus the installed extensions/
241
+ // directory — never from an unscoped workspace-wide scan. This keeps
242
+ // nested workspaces (e.g. test fixtures) out of the module map.
243
+ const packageDirs = [
244
+ ...this.allowedDirs,
245
+ ...glob.sync(path_1.default.join(this.workspacePath, EXTENSIONS_DIR, '{*,@*/*}'))
246
+ ];
247
+ const moduleFiles = [...new Set(packageDirs.flatMap(dir => glob.sync(`${dir}/**/*.control`)))].filter((file) => !/node_modules/.test(file)).sort((a, b) => a.localeCompare(b));
240
248
  // Group files by module name to handle collisions
241
249
  const filesByName = new Map();
242
250
  moduleFiles.forEach((file) => {
@@ -790,21 +798,31 @@ ${dependencies.length > 0 ? dependencies.map(dep => `-- requires: ${dep}`).join(
790
798
  }
791
799
  }
792
800
  /**
793
- * Installs an extension npm package into the local skitch extensions directory,
794
- * and automatically adds it to the current module’s package.json dependencies.
801
+ * Installs an extension npm package into the workspace extensions directory.
802
+ *
803
+ * When run inside a module, the installed version is recorded in the
804
+ * module's package.json dependencies and its .control requires list.
805
+ * When run at the workspace root, the installed version is recorded in
806
+ * the workspace pgpm.json `dependencies` field instead — no .control
807
+ * file is needed.
795
808
  */
796
809
  async installModules(...pkgstrs) {
797
810
  this.ensureWorkspace();
798
- this.ensureModule();
811
+ const inModule = this.isInModule();
799
812
  const originalDir = process.cwd();
800
813
  const skitchExtDir = path_1.default.join(this.workspacePath, EXTENSIONS_DIR);
801
- const pkgJsonPath = path_1.default.join(this.modulePath, 'package.json');
802
- if (!fs_1.default.existsSync(pkgJsonPath)) {
803
- throw new Error(`No package.json found at module path: ${this.modulePath}`);
814
+ let pkgJsonPath;
815
+ let pkgData;
816
+ if (inModule) {
817
+ pkgJsonPath = path_1.default.join(this.modulePath, 'package.json');
818
+ if (!fs_1.default.existsSync(pkgJsonPath)) {
819
+ throw new Error(`No package.json found at module path: ${this.modulePath}`);
820
+ }
821
+ pkgData = JSON.parse(fs_1.default.readFileSync(pkgJsonPath, 'utf-8'));
822
+ pkgData.dependencies = pkgData.dependencies || {};
804
823
  }
805
- const pkgData = JSON.parse(fs_1.default.readFileSync(pkgJsonPath, 'utf-8'));
806
- pkgData.dependencies = pkgData.dependencies || {};
807
824
  const newlyAdded = [];
825
+ const installedVersions = {};
808
826
  for (const pkgstr of pkgstrs) {
809
827
  const { name } = (0, parse_package_name_1.parse)(pkgstr);
810
828
  const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'pgpm-install-'));
@@ -837,7 +855,10 @@ ${dependencies.length > 0 ? dependencies.map(dep => `-- requires: ${dep}`).join(
837
855
  throw new Error(`Missing package.json in installed extension: ${dst}`);
838
856
  }
839
857
  const { version } = JSON.parse(fs_1.default.readFileSync(pkgJsonFile, 'utf-8'));
840
- pkgData.dependencies[name] = `${version}`;
858
+ installedVersions[name] = `${version}`;
859
+ if (pkgData) {
860
+ pkgData.dependencies[name] = `${version}`;
861
+ }
841
862
  const extensionName = (0, files_2.getExtensionName)(dst);
842
863
  newlyAdded.push(extensionName);
843
864
  }
@@ -847,20 +868,80 @@ ${dependencies.length > 0 ? dependencies.map(dep => `-- requires: ${dep}`).join(
847
868
  process.chdir(originalDir);
848
869
  }
849
870
  }
850
- const { dependencies, devDependencies, ...rest } = pkgData;
851
- const finalPkgData = { ...rest };
852
- if (dependencies) {
853
- finalPkgData.dependencies = sortObjectByKey(dependencies);
871
+ if (inModule && pkgData && pkgJsonPath) {
872
+ const { dependencies, devDependencies, ...rest } = pkgData;
873
+ const finalPkgData = { ...rest };
874
+ if (dependencies) {
875
+ finalPkgData.dependencies = sortObjectByKey(dependencies);
876
+ }
877
+ if (devDependencies) {
878
+ finalPkgData.devDependencies = sortObjectByKey(devDependencies);
879
+ }
880
+ fs_1.default.writeFileSync(pkgJsonPath, JSON.stringify(finalPkgData, null, 2));
881
+ logger.success(`📦 Updated package.json with: ${pkgstrs.join(', ')}`);
882
+ // ─── Update .control file with actual extension names ──────────────
883
+ const currentDeps = this.getRequiredModules();
884
+ const updatedDeps = Array.from(new Set([...currentDeps, ...newlyAdded])).sort();
885
+ (0, files_2.writeExtensions)(this.modulePath, updatedDeps);
886
+ }
887
+ else {
888
+ this.recordWorkspaceDependencies(installedVersions);
889
+ }
890
+ }
891
+ /**
892
+ * Returns the workspace-level pgpm module dependencies recorded in
893
+ * the workspace pgpm.json `dependencies` field.
894
+ */
895
+ getWorkspaceDependencies() {
896
+ this.ensureWorkspace();
897
+ const configPath = path_1.default.join(this.workspacePath, 'pgpm.json');
898
+ if (!fs_1.default.existsSync(configPath)) {
899
+ return {};
900
+ }
901
+ const config = JSON.parse(fs_1.default.readFileSync(configPath, 'utf-8'));
902
+ return config.dependencies || {};
903
+ }
904
+ /**
905
+ * Records installed module versions into the workspace pgpm.json
906
+ * `dependencies` field. No-op when the workspace uses pgpm.config.js.
907
+ */
908
+ recordWorkspaceDependencies(versions) {
909
+ this.ensureWorkspace();
910
+ if (Object.keys(versions).length === 0)
911
+ return;
912
+ const configPath = path_1.default.join(this.workspacePath, 'pgpm.json');
913
+ if (!fs_1.default.existsSync(configPath)) {
914
+ logger.warn('No pgpm.json found at workspace root — skipping dependency recording.');
915
+ return;
854
916
  }
855
- if (devDependencies) {
856
- finalPkgData.devDependencies = sortObjectByKey(devDependencies);
917
+ const config = JSON.parse(fs_1.default.readFileSync(configPath, 'utf-8'));
918
+ config.dependencies = sortObjectByKey({
919
+ ...(config.dependencies || {}),
920
+ ...versions
921
+ });
922
+ fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
923
+ logger.success(`📦 Updated pgpm.json dependencies with: ${Object.keys(versions).join(', ')}`);
924
+ }
925
+ /**
926
+ * Installs the workspace-level dependencies declared in pgpm.json into
927
+ * the workspace extensions/ directory. Skips modules already present
928
+ * unless `force` is set.
929
+ *
930
+ * @returns The list of installed package specs (name@version)
931
+ */
932
+ async installWorkspaceDependencies(options) {
933
+ this.ensureWorkspace();
934
+ const { force = false } = options || {};
935
+ const dependencies = this.getWorkspaceDependencies();
936
+ const installedModules = this.getWorkspaceInstalledModules();
937
+ const toInstall = Object.entries(dependencies)
938
+ .filter(([name]) => force || !installedModules.includes(name))
939
+ .map(([name, version]) => `${name}@${version}`);
940
+ if (toInstall.length === 0) {
941
+ return [];
857
942
  }
858
- fs_1.default.writeFileSync(pkgJsonPath, JSON.stringify(finalPkgData, null, 2));
859
- logger.success(`📦 Updated package.json with: ${pkgstrs.join(', ')}`);
860
- // ─── Update .control file with actual extension names ──────────────
861
- const currentDeps = this.getRequiredModules();
862
- const updatedDeps = Array.from(new Set([...currentDeps, ...newlyAdded])).sort();
863
- (0, files_2.writeExtensions)(this.modulePath, updatedDeps);
943
+ await this.installModules(...toInstall);
944
+ return toInstall;
864
945
  }
865
946
  /**
866
947
  * Returns information about which of the specified modules are installed.
@@ -197,7 +197,15 @@ export class PgpmPackage {
197
197
  listModules() {
198
198
  if (!this.workspacePath)
199
199
  return {};
200
- const moduleFiles = glob.sync(`${this.workspacePath}/**/*.control`).filter((file) => !/node_modules/.test(file)).sort((a, b) => a.localeCompare(b));
200
+ // Workspace membership is first-class: modules are discovered from the
201
+ // workspace's declared `packages` globs plus the installed extensions/
202
+ // directory — never from an unscoped workspace-wide scan. This keeps
203
+ // nested workspaces (e.g. test fixtures) out of the module map.
204
+ const packageDirs = [
205
+ ...this.allowedDirs,
206
+ ...glob.sync(path.join(this.workspacePath, EXTENSIONS_DIR, '{*,@*/*}'))
207
+ ];
208
+ const moduleFiles = [...new Set(packageDirs.flatMap(dir => glob.sync(`${dir}/**/*.control`)))].filter((file) => !/node_modules/.test(file)).sort((a, b) => a.localeCompare(b));
201
209
  // Group files by module name to handle collisions
202
210
  const filesByName = new Map();
203
211
  moduleFiles.forEach((file) => {
@@ -751,21 +759,31 @@ ${dependencies.length > 0 ? dependencies.map(dep => `-- requires: ${dep}`).join(
751
759
  }
752
760
  }
753
761
  /**
754
- * Installs an extension npm package into the local skitch extensions directory,
755
- * and automatically adds it to the current module’s package.json dependencies.
762
+ * Installs an extension npm package into the workspace extensions directory.
763
+ *
764
+ * When run inside a module, the installed version is recorded in the
765
+ * module's package.json dependencies and its .control requires list.
766
+ * When run at the workspace root, the installed version is recorded in
767
+ * the workspace pgpm.json `dependencies` field instead — no .control
768
+ * file is needed.
756
769
  */
757
770
  async installModules(...pkgstrs) {
758
771
  this.ensureWorkspace();
759
- this.ensureModule();
772
+ const inModule = this.isInModule();
760
773
  const originalDir = process.cwd();
761
774
  const skitchExtDir = path.join(this.workspacePath, EXTENSIONS_DIR);
762
- const pkgJsonPath = path.join(this.modulePath, 'package.json');
763
- if (!fs.existsSync(pkgJsonPath)) {
764
- throw new Error(`No package.json found at module path: ${this.modulePath}`);
775
+ let pkgJsonPath;
776
+ let pkgData;
777
+ if (inModule) {
778
+ pkgJsonPath = path.join(this.modulePath, 'package.json');
779
+ if (!fs.existsSync(pkgJsonPath)) {
780
+ throw new Error(`No package.json found at module path: ${this.modulePath}`);
781
+ }
782
+ pkgData = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
783
+ pkgData.dependencies = pkgData.dependencies || {};
765
784
  }
766
- const pkgData = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
767
- pkgData.dependencies = pkgData.dependencies || {};
768
785
  const newlyAdded = [];
786
+ const installedVersions = {};
769
787
  for (const pkgstr of pkgstrs) {
770
788
  const { name } = parse(pkgstr);
771
789
  const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pgpm-install-'));
@@ -798,7 +816,10 @@ ${dependencies.length > 0 ? dependencies.map(dep => `-- requires: ${dep}`).join(
798
816
  throw new Error(`Missing package.json in installed extension: ${dst}`);
799
817
  }
800
818
  const { version } = JSON.parse(fs.readFileSync(pkgJsonFile, 'utf-8'));
801
- pkgData.dependencies[name] = `${version}`;
819
+ installedVersions[name] = `${version}`;
820
+ if (pkgData) {
821
+ pkgData.dependencies[name] = `${version}`;
822
+ }
802
823
  const extensionName = getExtensionName(dst);
803
824
  newlyAdded.push(extensionName);
804
825
  }
@@ -808,20 +829,80 @@ ${dependencies.length > 0 ? dependencies.map(dep => `-- requires: ${dep}`).join(
808
829
  process.chdir(originalDir);
809
830
  }
810
831
  }
811
- const { dependencies, devDependencies, ...rest } = pkgData;
812
- const finalPkgData = { ...rest };
813
- if (dependencies) {
814
- finalPkgData.dependencies = sortObjectByKey(dependencies);
832
+ if (inModule && pkgData && pkgJsonPath) {
833
+ const { dependencies, devDependencies, ...rest } = pkgData;
834
+ const finalPkgData = { ...rest };
835
+ if (dependencies) {
836
+ finalPkgData.dependencies = sortObjectByKey(dependencies);
837
+ }
838
+ if (devDependencies) {
839
+ finalPkgData.devDependencies = sortObjectByKey(devDependencies);
840
+ }
841
+ fs.writeFileSync(pkgJsonPath, JSON.stringify(finalPkgData, null, 2));
842
+ logger.success(`📦 Updated package.json with: ${pkgstrs.join(', ')}`);
843
+ // ─── Update .control file with actual extension names ──────────────
844
+ const currentDeps = this.getRequiredModules();
845
+ const updatedDeps = Array.from(new Set([...currentDeps, ...newlyAdded])).sort();
846
+ writeExtensions(this.modulePath, updatedDeps);
847
+ }
848
+ else {
849
+ this.recordWorkspaceDependencies(installedVersions);
850
+ }
851
+ }
852
+ /**
853
+ * Returns the workspace-level pgpm module dependencies recorded in
854
+ * the workspace pgpm.json `dependencies` field.
855
+ */
856
+ getWorkspaceDependencies() {
857
+ this.ensureWorkspace();
858
+ const configPath = path.join(this.workspacePath, 'pgpm.json');
859
+ if (!fs.existsSync(configPath)) {
860
+ return {};
861
+ }
862
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
863
+ return config.dependencies || {};
864
+ }
865
+ /**
866
+ * Records installed module versions into the workspace pgpm.json
867
+ * `dependencies` field. No-op when the workspace uses pgpm.config.js.
868
+ */
869
+ recordWorkspaceDependencies(versions) {
870
+ this.ensureWorkspace();
871
+ if (Object.keys(versions).length === 0)
872
+ return;
873
+ const configPath = path.join(this.workspacePath, 'pgpm.json');
874
+ if (!fs.existsSync(configPath)) {
875
+ logger.warn('No pgpm.json found at workspace root — skipping dependency recording.');
876
+ return;
815
877
  }
816
- if (devDependencies) {
817
- finalPkgData.devDependencies = sortObjectByKey(devDependencies);
878
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
879
+ config.dependencies = sortObjectByKey({
880
+ ...(config.dependencies || {}),
881
+ ...versions
882
+ });
883
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
884
+ logger.success(`📦 Updated pgpm.json dependencies with: ${Object.keys(versions).join(', ')}`);
885
+ }
886
+ /**
887
+ * Installs the workspace-level dependencies declared in pgpm.json into
888
+ * the workspace extensions/ directory. Skips modules already present
889
+ * unless `force` is set.
890
+ *
891
+ * @returns The list of installed package specs (name@version)
892
+ */
893
+ async installWorkspaceDependencies(options) {
894
+ this.ensureWorkspace();
895
+ const { force = false } = options || {};
896
+ const dependencies = this.getWorkspaceDependencies();
897
+ const installedModules = this.getWorkspaceInstalledModules();
898
+ const toInstall = Object.entries(dependencies)
899
+ .filter(([name]) => force || !installedModules.includes(name))
900
+ .map(([name, version]) => `${name}@${version}`);
901
+ if (toInstall.length === 0) {
902
+ return [];
818
903
  }
819
- fs.writeFileSync(pkgJsonPath, JSON.stringify(finalPkgData, null, 2));
820
- logger.success(`📦 Updated package.json with: ${pkgstrs.join(', ')}`);
821
- // ─── Update .control file with actual extension names ──────────────
822
- const currentDeps = this.getRequiredModules();
823
- const updatedDeps = Array.from(new Set([...currentDeps, ...newlyAdded])).sort();
824
- writeExtensions(this.modulePath, updatedDeps);
904
+ await this.installModules(...toInstall);
905
+ return toInstall;
825
906
  }
826
907
  /**
827
908
  * Returns information about which of the specified modules are installed.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pgpmjs/core",
3
- "version": "6.31.0",
3
+ "version": "6.32.0",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "PGPM Package and Migration Tools",
6
6
  "main": "index.js",
@@ -48,21 +48,21 @@
48
48
  "makage": "^0.3.0"
49
49
  },
50
50
  "dependencies": {
51
- "@pgpmjs/env": "^2.28.0",
51
+ "@pgpmjs/env": "^2.28.1",
52
52
  "@pgpmjs/logger": "^2.14.0",
53
- "@pgpmjs/server-utils": "^3.15.1",
54
- "@pgpmjs/types": "^2.34.0",
53
+ "@pgpmjs/server-utils": "^3.15.2",
54
+ "@pgpmjs/types": "^2.35.0",
55
55
  "csv-to-pg": "^3.21.0",
56
56
  "genomic": "^5.6.2",
57
57
  "glob": "^13.0.6",
58
58
  "minimatch": "^10.2.5",
59
59
  "parse-package-name": "^1.0.0",
60
60
  "pg": "^8.21.0",
61
- "pg-cache": "^3.15.0",
61
+ "pg-cache": "^3.15.1",
62
62
  "pg-env": "^1.18.0",
63
63
  "pgsql-deparser": "^17.18.3",
64
64
  "pgsql-parser": "^17.9.15",
65
65
  "yanse": "^0.2.1"
66
66
  },
67
- "gitHead": "ff6c442b789cbe8803f33036110f6e09124e65df"
67
+ "gitHead": "dd2accb683fe20c7278a0d58fd36a04a3b07ac63"
68
68
  }