@git.zone/cli 2.13.13 → 2.14.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 (39) hide show
  1. package/dist_ts/00_commitinfo_data.js +2 -2
  2. package/dist_ts/gitzone.cli.js +46 -35
  3. package/dist_ts/helpers.climode.d.ts +22 -0
  4. package/dist_ts/helpers.climode.js +158 -0
  5. package/dist_ts/helpers.smartconfig.d.ts +11 -0
  6. package/dist_ts/helpers.smartconfig.js +139 -0
  7. package/dist_ts/mod_commit/index.d.ts +2 -0
  8. package/dist_ts/mod_commit/index.js +204 -92
  9. package/dist_ts/mod_config/index.d.ts +7 -2
  10. package/dist_ts/mod_config/index.js +390 -176
  11. package/dist_ts/mod_format/classes.formatcontext.d.ts +11 -2
  12. package/dist_ts/mod_format/classes.formatcontext.js +14 -4
  13. package/dist_ts/mod_format/formatters/packagejson.formatter.js +1 -67
  14. package/dist_ts/mod_format/formatters/smartconfig.formatter.d.ts +2 -7
  15. package/dist_ts/mod_format/formatters/smartconfig.formatter.js +57 -93
  16. package/dist_ts/mod_format/index.d.ts +4 -1
  17. package/dist_ts/mod_format/index.js +235 -67
  18. package/dist_ts/mod_format/mod.plugins.d.ts +1 -2
  19. package/dist_ts/mod_format/mod.plugins.js +2 -3
  20. package/dist_ts/mod_services/index.d.ts +2 -0
  21. package/dist_ts/mod_services/index.js +366 -168
  22. package/dist_ts/mod_standard/index.d.ts +3 -1
  23. package/dist_ts/mod_standard/index.js +159 -59
  24. package/package.json +1 -1
  25. package/readme.hints.md +25 -32
  26. package/readme.md +87 -65
  27. package/ts/00_commitinfo_data.ts +1 -1
  28. package/ts/gitzone.cli.ts +50 -38
  29. package/ts/helpers.climode.ts +212 -0
  30. package/ts/helpers.smartconfig.ts +192 -0
  31. package/ts/mod_commit/index.ts +325 -98
  32. package/ts/mod_config/index.ts +490 -182
  33. package/ts/mod_format/classes.formatcontext.ts +20 -3
  34. package/ts/mod_format/formatters/packagejson.formatter.ts +0 -91
  35. package/ts/mod_format/formatters/smartconfig.formatter.ts +67 -94
  36. package/ts/mod_format/index.ts +294 -81
  37. package/ts/mod_format/mod.plugins.ts +0 -2
  38. package/ts/mod_services/index.ts +550 -183
  39. package/ts/mod_standard/index.ts +191 -58
@@ -1,14 +1,31 @@
1
- import * as plugins from './mod.plugins.js';
2
- import { FormatStats } from './classes.formatstats.js';
1
+ import * as plugins from "./mod.plugins.js";
2
+ import { FormatStats } from "./classes.formatstats.js";
3
+
4
+ interface IFormatContextOptions {
5
+ interactive?: boolean;
6
+ jsonOutput?: boolean;
7
+ }
3
8
 
4
9
  export class FormatContext {
5
10
  private formatStats: FormatStats;
11
+ private interactive: boolean;
12
+ private jsonOutput: boolean;
6
13
 
7
- constructor() {
14
+ constructor(options: IFormatContextOptions = {}) {
8
15
  this.formatStats = new FormatStats();
16
+ this.interactive = options.interactive ?? true;
17
+ this.jsonOutput = options.jsonOutput ?? false;
9
18
  }
10
19
 
11
20
  getFormatStats(): FormatStats {
12
21
  return this.formatStats;
13
22
  }
23
+
24
+ isInteractive(): boolean {
25
+ return this.interactive;
26
+ }
27
+
28
+ isJsonOutput(): boolean {
29
+ return this.jsonOutput;
30
+ }
14
31
  }
@@ -4,77 +4,6 @@ import * as plugins from '../mod.plugins.js';
4
4
  import * as paths from '../../paths.js';
5
5
  import { logger, logVerbose } from '../../gitzone.logging.js';
6
6
 
7
- /**
8
- * Ensures a certain dependency exists or is excluded
9
- */
10
- const ensureDependency = async (
11
- packageJsonObject: any,
12
- position: 'dep' | 'devDep' | 'everywhere',
13
- constraint: 'exclude' | 'include' | 'latest',
14
- dependencyArg: string,
15
- ): Promise<void> => {
16
- // Parse package name and version, handling scoped packages like @scope/name@version
17
- const isScoped = dependencyArg.startsWith('@');
18
- const lastAtIndex = dependencyArg.lastIndexOf('@');
19
-
20
- // For scoped packages, the version @ must come after the /
21
- // For unscoped packages, any @ indicates a version
22
- const hasVersion = isScoped
23
- ? lastAtIndex > dependencyArg.indexOf('/')
24
- : lastAtIndex >= 0;
25
-
26
- const packageName = hasVersion ? dependencyArg.slice(0, lastAtIndex) : dependencyArg;
27
- const version = hasVersion ? dependencyArg.slice(lastAtIndex + 1) : 'latest';
28
-
29
- const targetSections: string[] = [];
30
-
31
- switch (position) {
32
- case 'dep':
33
- targetSections.push('dependencies');
34
- break;
35
- case 'devDep':
36
- targetSections.push('devDependencies');
37
- break;
38
- case 'everywhere':
39
- targetSections.push('dependencies', 'devDependencies');
40
- break;
41
- }
42
-
43
- for (const section of targetSections) {
44
- if (!packageJsonObject[section]) {
45
- packageJsonObject[section] = {};
46
- }
47
-
48
- switch (constraint) {
49
- case 'exclude':
50
- delete packageJsonObject[section][packageName];
51
- break;
52
- case 'include':
53
- if (!packageJsonObject[section][packageName]) {
54
- packageJsonObject[section][packageName] =
55
- version === 'latest' ? '^1.0.0' : version;
56
- }
57
- break;
58
- case 'latest':
59
- try {
60
- const registry = new plugins.smartnpm.NpmRegistry();
61
- const packageInfo = await registry.getPackageInfo(packageName);
62
- const latestVersion = packageInfo['dist-tags'].latest;
63
- packageJsonObject[section][packageName] = `^${latestVersion}`;
64
- } catch (error) {
65
- logVerbose(
66
- `Could not fetch latest version for ${packageName}, using existing or default`,
67
- );
68
- if (!packageJsonObject[section][packageName]) {
69
- packageJsonObject[section][packageName] =
70
- version === 'latest' ? '^1.0.0' : version;
71
- }
72
- }
73
- break;
74
- }
75
- }
76
- };
77
-
78
7
  export class PackageJsonFormatter extends BaseFormatter {
79
8
  get name(): string {
80
9
  return 'packagejson';
@@ -141,11 +70,6 @@ export class PackageJsonFormatter extends BaseFormatter {
141
70
  packageJson.scripts.build = `echo "Not needed for now"`;
142
71
  }
143
72
 
144
- // Ensure buildDocs script exists
145
- if (!packageJson.scripts.buildDocs) {
146
- packageJson.scripts.buildDocs = `tsdoc`;
147
- }
148
-
149
73
  // Set files array
150
74
  packageJson.files = [
151
75
  'ts/**/*',
@@ -160,21 +84,6 @@ export class PackageJsonFormatter extends BaseFormatter {
160
84
  'readme.md',
161
85
  ];
162
86
 
163
- // Handle dependencies
164
- await ensureDependency(
165
- packageJson,
166
- 'devDep',
167
- 'exclude',
168
- '@push.rocks/tapbundle',
169
- );
170
- await ensureDependency(packageJson, 'devDep', 'latest', '@git.zone/tstest');
171
- await ensureDependency(
172
- packageJson,
173
- 'devDep',
174
- 'latest',
175
- '@git.zone/tsbuild',
176
- );
177
-
178
87
  // Set pnpm overrides from assets
179
88
  try {
180
89
  const overridesContent = (await plugins.smartfs
@@ -1,7 +1,7 @@
1
- import { BaseFormatter } from '../classes.baseformatter.js';
2
- import type { IPlannedChange } from '../interfaces.format.js';
3
- import * as plugins from '../mod.plugins.js';
4
- import { logger, logVerbose } from '../../gitzone.logging.js';
1
+ import { BaseFormatter } from "../classes.baseformatter.js";
2
+ import type { IPlannedChange } from "../interfaces.format.js";
3
+ import * as plugins from "../mod.plugins.js";
4
+ import { logger, logVerbose } from "../../gitzone.logging.js";
5
5
 
6
6
  /**
7
7
  * Migrates .smartconfig.json from old namespace keys to new package-scoped keys
@@ -9,11 +9,11 @@ import { logger, logVerbose } from '../../gitzone.logging.js';
9
9
  const migrateNamespaceKeys = (smartconfigJson: any): boolean => {
10
10
  let migrated = false;
11
11
  const migrations = [
12
- { oldKey: 'gitzone', newKey: '@git.zone/cli' },
13
- { oldKey: 'tsdoc', newKey: '@git.zone/tsdoc' },
14
- { oldKey: 'npmdocker', newKey: '@git.zone/tsdocker' },
15
- { oldKey: 'npmci', newKey: '@ship.zone/szci' },
16
- { oldKey: 'szci', newKey: '@ship.zone/szci' },
12
+ { oldKey: "gitzone", newKey: "@git.zone/cli" },
13
+ { oldKey: "tsdoc", newKey: "@git.zone/tsdoc" },
14
+ { oldKey: "npmdocker", newKey: "@git.zone/tsdocker" },
15
+ { oldKey: "npmci", newKey: "@ship.zone/szci" },
16
+ { oldKey: "szci", newKey: "@ship.zone/szci" },
17
17
  ];
18
18
  for (const { oldKey, newKey } of migrations) {
19
19
  if (smartconfigJson[oldKey]) {
@@ -36,109 +36,78 @@ const migrateNamespaceKeys = (smartconfigJson: any): boolean => {
36
36
  * Migrates npmAccessLevel from @ship.zone/szci to @git.zone/cli.release.accessLevel
37
37
  */
38
38
  const migrateAccessLevel = (smartconfigJson: any): boolean => {
39
- const szciConfig = smartconfigJson['@ship.zone/szci'];
39
+ const szciConfig = smartconfigJson["@ship.zone/szci"];
40
40
 
41
41
  if (!szciConfig?.npmAccessLevel) {
42
42
  return false;
43
43
  }
44
44
 
45
- const gitzoneConfig = smartconfigJson['@git.zone/cli'] || {};
45
+ const gitzoneConfig = smartconfigJson["@git.zone/cli"] || {};
46
46
  if (gitzoneConfig?.release?.accessLevel) {
47
47
  delete szciConfig.npmAccessLevel;
48
48
  return true;
49
49
  }
50
50
 
51
- if (!smartconfigJson['@git.zone/cli']) {
52
- smartconfigJson['@git.zone/cli'] = {};
51
+ if (!smartconfigJson["@git.zone/cli"]) {
52
+ smartconfigJson["@git.zone/cli"] = {};
53
53
  }
54
- if (!smartconfigJson['@git.zone/cli'].release) {
55
- smartconfigJson['@git.zone/cli'].release = {};
54
+ if (!smartconfigJson["@git.zone/cli"].release) {
55
+ smartconfigJson["@git.zone/cli"].release = {};
56
56
  }
57
57
 
58
- smartconfigJson['@git.zone/cli'].release.accessLevel = szciConfig.npmAccessLevel;
58
+ smartconfigJson["@git.zone/cli"].release.accessLevel =
59
+ szciConfig.npmAccessLevel;
59
60
  delete szciConfig.npmAccessLevel;
60
61
 
61
62
  return true;
62
63
  };
63
64
 
64
- // Config file names in priority order (newest → oldest)
65
- const CONFIG_FILE_NAMES = ['.smartconfig.json', 'smartconfig.json', 'npmextra.json'];
66
- const TARGET_CONFIG_FILE = '.smartconfig.json';
65
+ const CONFIG_FILE = ".smartconfig.json";
67
66
 
68
67
  export class SmartconfigFormatter extends BaseFormatter {
69
68
  get name(): string {
70
- return 'smartconfig';
71
- }
72
-
73
- /**
74
- * Find the config file, checking in priority order.
75
- * Returns the path and whether it needs renaming.
76
- */
77
- private async findConfigFile(): Promise<{ path: string; needsRename: boolean } | null> {
78
- for (const filename of CONFIG_FILE_NAMES) {
79
- const exists = await plugins.smartfs.file(filename).exists();
80
- if (exists) {
81
- return {
82
- path: filename,
83
- needsRename: filename !== TARGET_CONFIG_FILE,
84
- };
85
- }
86
- }
87
- return null;
69
+ return "smartconfig";
88
70
  }
89
71
 
90
72
  async analyze(): Promise<IPlannedChange[]> {
91
73
  const changes: IPlannedChange[] = [];
92
74
 
93
- const configFile = await this.findConfigFile();
94
- if (!configFile) {
95
- logVerbose('No config file found (.smartconfig.json, smartconfig.json, or npmextra.json), skipping');
75
+ // File rename (npmextra.json/smartconfig.json .smartconfig.json)
76
+ // is handled by the orchestrator before analysis.
77
+ // This formatter only operates on .smartconfig.json.
78
+ const exists = await plugins.smartfs.file(CONFIG_FILE).exists();
79
+ if (!exists) {
80
+ logVerbose(".smartconfig.json does not exist, skipping");
96
81
  return changes;
97
82
  }
98
83
 
99
- // Read current content
100
84
  const currentContent = (await plugins.smartfs
101
- .file(configFile.path)
102
- .encoding('utf8')
85
+ .file(CONFIG_FILE)
86
+ .encoding("utf8")
103
87
  .read()) as string;
104
88
 
105
- // Parse and apply migrations
106
89
  const smartconfigJson = JSON.parse(currentContent);
90
+
91
+ // Apply key migrations
107
92
  migrateNamespaceKeys(smartconfigJson);
108
93
  migrateAccessLevel(smartconfigJson);
109
94
 
110
95
  // Ensure namespaces exist
111
- if (!smartconfigJson['@git.zone/cli']) {
112
- smartconfigJson['@git.zone/cli'] = {};
96
+ if (!smartconfigJson["@git.zone/cli"]) {
97
+ smartconfigJson["@git.zone/cli"] = {};
113
98
  }
114
- if (!smartconfigJson['@ship.zone/szci']) {
115
- smartconfigJson['@ship.zone/szci'] = {};
99
+ if (!smartconfigJson["@ship.zone/szci"]) {
100
+ smartconfigJson["@ship.zone/szci"] = {};
116
101
  }
117
102
 
118
103
  const newContent = JSON.stringify(smartconfigJson, null, 2);
119
104
 
120
- // If file needs renaming, plan a create + delete
121
- if (configFile.needsRename) {
105
+ if (newContent !== currentContent) {
122
106
  changes.push({
123
- type: 'create',
124
- path: TARGET_CONFIG_FILE,
107
+ type: "modify",
108
+ path: CONFIG_FILE,
125
109
  module: this.name,
126
- description: `Migrate ${configFile.path} to ${TARGET_CONFIG_FILE}`,
127
- content: newContent,
128
- });
129
- changes.push({
130
- type: 'delete',
131
- path: configFile.path,
132
- module: this.name,
133
- description: `Remove old ${configFile.path}`,
134
- });
135
- } else if (newContent !== currentContent) {
136
- // File is already .smartconfig.json, just needs content update
137
- changes.push({
138
- type: 'modify',
139
- path: TARGET_CONFIG_FILE,
140
- module: this.name,
141
- description: 'Migrate and format .smartconfig.json',
110
+ description: "Migrate and format .smartconfig.json",
142
111
  content: newContent,
143
112
  });
144
113
  }
@@ -147,32 +116,41 @@ export class SmartconfigFormatter extends BaseFormatter {
147
116
  }
148
117
 
149
118
  async applyChange(change: IPlannedChange): Promise<void> {
150
- if (change.type === 'delete') {
151
- await this.deleteFile(change.path);
152
- logger.log('info', `Removed old config file ${change.path}`);
153
- return;
154
- }
155
-
156
- if (!change.content) return;
119
+ if (change.type !== "modify" || !change.content) return;
157
120
 
158
- // Parse the content to check for missing required fields
159
121
  const smartconfigJson = JSON.parse(change.content);
160
122
 
123
+ // Check for missing required module information
161
124
  const expectedRepoInformation: string[] = [
162
- 'projectType',
163
- 'module.githost',
164
- 'module.gitscope',
165
- 'module.gitrepo',
166
- 'module.description',
167
- 'module.npmPackagename',
168
- 'module.license',
125
+ "projectType",
126
+ "module.githost",
127
+ "module.gitscope",
128
+ "module.gitrepo",
129
+ "module.description",
130
+ "module.npmPackagename",
131
+ "module.license",
169
132
  ];
170
133
 
171
134
  const interactInstance = new plugins.smartinteract.SmartInteract();
135
+ const missingRepoInformation = expectedRepoInformation.filter(
136
+ (expectedRepoInformationItem) => {
137
+ return !plugins.smartobject.smartGet(
138
+ smartconfigJson["@git.zone/cli"],
139
+ expectedRepoInformationItem,
140
+ );
141
+ },
142
+ );
143
+
144
+ if (missingRepoInformation.length > 0 && !this.context.isInteractive()) {
145
+ throw new Error(
146
+ `Missing required .smartconfig.json fields: ${missingRepoInformation.join(", ")}`,
147
+ );
148
+ }
149
+
172
150
  for (const expectedRepoInformationItem of expectedRepoInformation) {
173
151
  if (
174
152
  !plugins.smartobject.smartGet(
175
- smartconfigJson['@git.zone/cli'],
153
+ smartconfigJson["@git.zone/cli"],
176
154
  expectedRepoInformationItem,
177
155
  )
178
156
  ) {
@@ -180,8 +158,8 @@ export class SmartconfigFormatter extends BaseFormatter {
180
158
  {
181
159
  message: `What is the value of ${expectedRepoInformationItem}`,
182
160
  name: expectedRepoInformationItem,
183
- type: 'input',
184
- default: 'undefined variable',
161
+ type: "input",
162
+ default: "undefined variable",
185
163
  },
186
164
  ]);
187
165
  }
@@ -194,7 +172,7 @@ export class SmartconfigFormatter extends BaseFormatter {
194
172
  );
195
173
  if (cliProvidedValue) {
196
174
  plugins.smartobject.smartAdd(
197
- smartconfigJson['@git.zone/cli'],
175
+ smartconfigJson["@git.zone/cli"],
198
176
  expectedRepoInformationItem,
199
177
  cliProvidedValue,
200
178
  );
@@ -202,12 +180,7 @@ export class SmartconfigFormatter extends BaseFormatter {
202
180
  }
203
181
 
204
182
  const finalContent = JSON.stringify(smartconfigJson, null, 2);
205
-
206
- if (change.type === 'create') {
207
- await this.createFile(change.path, finalContent);
208
- } else {
209
- await this.modifyFile(change.path, finalContent);
210
- }
211
- logger.log('info', `Updated ${change.path}`);
183
+ await this.modifyFile(change.path, finalContent);
184
+ logger.log("info", "Updated .smartconfig.json");
212
185
  }
213
186
  }