@git.zone/cli 2.9.2 → 2.10.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.
- package/dist_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/mod_format/formatters/copy.formatter.d.ts +6 -3
- package/dist_ts/mod_format/formatters/copy.formatter.js +90 -6
- package/dist_ts/mod_format/formatters/gitignore.formatter.d.ts +6 -3
- package/dist_ts/mod_format/formatters/gitignore.formatter.js +101 -6
- package/dist_ts/mod_format/formatters/license.formatter.d.ts +7 -3
- package/dist_ts/mod_format/formatters/license.formatter.js +48 -6
- package/dist_ts/mod_format/formatters/npmextra.formatter.d.ts +6 -3
- package/dist_ts/mod_format/formatters/npmextra.formatter.js +130 -6
- package/dist_ts/mod_format/formatters/packagejson.formatter.d.ts +6 -3
- package/dist_ts/mod_format/formatters/packagejson.formatter.js +162 -6
- package/dist_ts/mod_format/formatters/prettier.formatter.d.ts +5 -1
- package/dist_ts/mod_format/formatters/prettier.formatter.js +46 -1
- package/dist_ts/mod_format/formatters/readme.formatter.js +35 -9
- package/dist_ts/mod_format/formatters/templates.formatter.d.ts +7 -3
- package/dist_ts/mod_format/formatters/templates.formatter.js +135 -6
- package/dist_ts/mod_format/formatters/tsconfig.formatter.d.ts +6 -3
- package/dist_ts/mod_format/formatters/tsconfig.formatter.js +61 -6
- package/package.json +30 -20
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/mod_format/formatters/copy.formatter.ts +114 -5
- package/ts/mod_format/formatters/gitignore.formatter.ts +108 -5
- package/ts/mod_format/formatters/license.formatter.ts +59 -5
- package/ts/mod_format/formatters/npmextra.formatter.ts +162 -5
- package/ts/mod_format/formatters/packagejson.formatter.ts +201 -5
- package/ts/mod_format/formatters/prettier.formatter.ts +50 -1
- package/ts/mod_format/formatters/readme.formatter.ts +39 -8
- package/ts/mod_format/formatters/templates.formatter.ts +152 -5
- package/ts/mod_format/formatters/tsconfig.formatter.ts +70 -5
- package/dist_ts/mod_format/formatters/legacy.formatter.d.ts +0 -11
- package/dist_ts/mod_format/formatters/legacy.formatter.js +0 -31
- package/ts/mod_format/formatters/legacy.formatter.ts +0 -43
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@git.zone/cli",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.10.0",
|
|
5
5
|
"description": "A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.",
|
|
6
6
|
"main": "dist_ts/index.ts",
|
|
7
7
|
"typings": "dist_ts/index.d.ts",
|
|
@@ -10,6 +10,24 @@
|
|
|
10
10
|
"gitzone": "./cli.js",
|
|
11
11
|
"gzone": "./cli.js"
|
|
12
12
|
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"test": "(npm run clean && npm run prepareTest && npm run testCli && npm run testFormat && npm run testCommit && npm run testDeprecate && npm run testVersion && npm run testReadme && npm run testUpdate && npm run testTemplateNpm && npm run testTemplateLit) && rm -rf test",
|
|
15
|
+
"build": "tsbuild tsfolders",
|
|
16
|
+
"clean": "(rm -rf test/)",
|
|
17
|
+
"prepareTest": "(git clone https://gitlab.com/sandboxzone/sandbox-npmts.git test/)",
|
|
18
|
+
"testBuild": "npm run build && rm -r dist/",
|
|
19
|
+
"testCli": "(cd test && node ../cli.ts.js)",
|
|
20
|
+
"testCommit": "(cd test && node ../cli.ts.js commit)",
|
|
21
|
+
"testDeprecate": "(cd test && node ../cli.ts.js deprecate)",
|
|
22
|
+
"testOpen": "(cd test && node ../cli.ts.js open ci)",
|
|
23
|
+
"testReadme": "(cd test && node ../cli.ts.js readme)",
|
|
24
|
+
"testFormat": "(cd test && node ../cli.ts.js format)",
|
|
25
|
+
"testTemplateNpm": "(rm -rf test/testtemplate_npm/ && mkdir test/testtemplate_npm && cd test/testtemplate_npm && node ../../cli.ts.js template npm)",
|
|
26
|
+
"testTemplateLit": "(rm -rf test/testtemplate_lit/ && mkdir test/testtemplate_lit && cd test/testtemplate_lit && node ../../cli.ts.js template lit)",
|
|
27
|
+
"testUpdate": "(cd test && node ../cli.ts.js update)",
|
|
28
|
+
"testVersion": "(cd test && node ../cli.ts.js -v)",
|
|
29
|
+
"buildDocs": "tsdoc"
|
|
30
|
+
},
|
|
13
31
|
"repository": {
|
|
14
32
|
"type": "git",
|
|
15
33
|
"url": "https://gitlab.com/gitzone/private/gitzone.git"
|
|
@@ -95,22 +113,14 @@
|
|
|
95
113
|
"browserslist": [
|
|
96
114
|
"last 1 chrome versions"
|
|
97
115
|
],
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
"testFormat": "(cd test && node ../cli.ts.js format)",
|
|
110
|
-
"testTemplateNpm": "(rm -rf test/testtemplate_npm/ && mkdir test/testtemplate_npm && cd test/testtemplate_npm && node ../../cli.ts.js template npm)",
|
|
111
|
-
"testTemplateLit": "(rm -rf test/testtemplate_lit/ && mkdir test/testtemplate_lit && cd test/testtemplate_lit && node ../../cli.ts.js template lit)",
|
|
112
|
-
"testUpdate": "(cd test && node ../cli.ts.js update)",
|
|
113
|
-
"testVersion": "(cd test && node ../cli.ts.js -v)",
|
|
114
|
-
"buildDocs": "tsdoc"
|
|
115
|
-
}
|
|
116
|
-
}
|
|
116
|
+
"pnpm": {
|
|
117
|
+
"overrides": {},
|
|
118
|
+
"onlyBuiltDependencies": [
|
|
119
|
+
"esbuild",
|
|
120
|
+
"mongodb-memory-server",
|
|
121
|
+
"puppeteer",
|
|
122
|
+
"sharp"
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
|
|
126
|
+
}
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@git.zone/cli',
|
|
6
|
-
version: '2.
|
|
6
|
+
version: '2.10.0',
|
|
7
7
|
description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.'
|
|
8
8
|
}
|
|
@@ -1,8 +1,117 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
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';
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
interface ICopyPattern {
|
|
7
|
+
from: string;
|
|
8
|
+
to: string;
|
|
9
|
+
preservePath?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class CopyFormatter extends BaseFormatter {
|
|
13
|
+
get name(): string {
|
|
14
|
+
return 'copy';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async analyze(): Promise<IPlannedChange[]> {
|
|
18
|
+
const changes: IPlannedChange[] = [];
|
|
19
|
+
|
|
20
|
+
// Get copy configuration from npmextra.json
|
|
21
|
+
const npmextraConfig = new plugins.npmextra.Npmextra();
|
|
22
|
+
const copyConfig = npmextraConfig.dataFor<{ patterns: ICopyPattern[] }>(
|
|
23
|
+
'gitzone.format.copy',
|
|
24
|
+
{ patterns: [] },
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
if (!copyConfig.patterns || copyConfig.patterns.length === 0) {
|
|
28
|
+
logVerbose('No copy patterns configured in npmextra.json');
|
|
29
|
+
return changes;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
for (const pattern of copyConfig.patterns) {
|
|
33
|
+
if (!pattern.from || !pattern.to) {
|
|
34
|
+
logVerbose('Invalid copy pattern - missing "from" or "to" field');
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
// Handle glob patterns
|
|
40
|
+
const entries = await plugins.smartfs
|
|
41
|
+
.directory('.')
|
|
42
|
+
.recursive()
|
|
43
|
+
.filter(pattern.from)
|
|
44
|
+
.list();
|
|
45
|
+
const files = entries.map((entry) => entry.path);
|
|
46
|
+
|
|
47
|
+
for (const file of files) {
|
|
48
|
+
const sourcePath = file;
|
|
49
|
+
let destPath = pattern.to;
|
|
50
|
+
|
|
51
|
+
// If destination is a directory, preserve filename
|
|
52
|
+
if (pattern.to.endsWith('/')) {
|
|
53
|
+
const filename = plugins.path.basename(file);
|
|
54
|
+
destPath = plugins.path.join(pattern.to, filename);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Handle template variables in destination path
|
|
58
|
+
if (pattern.preservePath) {
|
|
59
|
+
const relativePath = plugins.path.relative(
|
|
60
|
+
plugins.path.dirname(pattern.from.replace(/\*/g, '')),
|
|
61
|
+
file,
|
|
62
|
+
);
|
|
63
|
+
destPath = plugins.path.join(pattern.to, relativePath);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Read source content
|
|
67
|
+
const content = (await plugins.smartfs
|
|
68
|
+
.file(sourcePath)
|
|
69
|
+
.encoding('utf8')
|
|
70
|
+
.read()) as string;
|
|
71
|
+
|
|
72
|
+
// Check if destination exists and has same content
|
|
73
|
+
let needsCopy = true;
|
|
74
|
+
const destExists = await plugins.smartfs.file(destPath).exists();
|
|
75
|
+
if (destExists) {
|
|
76
|
+
const existingContent = (await plugins.smartfs
|
|
77
|
+
.file(destPath)
|
|
78
|
+
.encoding('utf8')
|
|
79
|
+
.read()) as string;
|
|
80
|
+
if (existingContent === content) {
|
|
81
|
+
needsCopy = false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (needsCopy) {
|
|
86
|
+
changes.push({
|
|
87
|
+
type: destExists ? 'modify' : 'create',
|
|
88
|
+
path: destPath,
|
|
89
|
+
module: this.name,
|
|
90
|
+
description: `Copy from ${sourcePath}`,
|
|
91
|
+
content: content,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
logVerbose(`Failed to process pattern ${pattern.from}: ${error.message}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return changes;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async applyChange(change: IPlannedChange): Promise<void> {
|
|
104
|
+
if (!change.content) return;
|
|
105
|
+
|
|
106
|
+
// Ensure destination directory exists
|
|
107
|
+
const destDir = plugins.path.dirname(change.path);
|
|
108
|
+
await plugins.smartfs.directory(destDir).recursive().create();
|
|
109
|
+
|
|
110
|
+
if (change.type === 'create') {
|
|
111
|
+
await this.createFile(change.path, change.content);
|
|
112
|
+
} else {
|
|
113
|
+
await this.modifyFile(change.path, change.content);
|
|
114
|
+
}
|
|
115
|
+
logger.log('info', `Copied to ${change.path}`);
|
|
7
116
|
}
|
|
8
117
|
}
|
|
@@ -1,8 +1,111 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
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 } from '../../gitzone.logging.js';
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
// Standard gitignore template content (without front-matter)
|
|
7
|
+
const GITIGNORE_TEMPLATE = `.nogit/
|
|
8
|
+
|
|
9
|
+
# artifacts
|
|
10
|
+
coverage/
|
|
11
|
+
public/
|
|
12
|
+
|
|
13
|
+
# installs
|
|
14
|
+
node_modules/
|
|
15
|
+
|
|
16
|
+
# caches
|
|
17
|
+
.yarn/
|
|
18
|
+
.cache/
|
|
19
|
+
.rpt2_cache
|
|
20
|
+
|
|
21
|
+
# builds
|
|
22
|
+
dist/
|
|
23
|
+
dist_*/
|
|
24
|
+
|
|
25
|
+
# AI
|
|
26
|
+
.claude/
|
|
27
|
+
.serena/
|
|
28
|
+
|
|
29
|
+
#------# custom`;
|
|
30
|
+
|
|
31
|
+
export class GitignoreFormatter extends BaseFormatter {
|
|
32
|
+
get name(): string {
|
|
33
|
+
return 'gitignore';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async analyze(): Promise<IPlannedChange[]> {
|
|
37
|
+
const changes: IPlannedChange[] = [];
|
|
38
|
+
const gitignorePath = '.gitignore';
|
|
39
|
+
|
|
40
|
+
// Check if file exists and extract custom content
|
|
41
|
+
let customContent = '';
|
|
42
|
+
const exists = await plugins.smartfs.file(gitignorePath).exists();
|
|
43
|
+
|
|
44
|
+
if (exists) {
|
|
45
|
+
const existingContent = (await plugins.smartfs
|
|
46
|
+
.file(gitignorePath)
|
|
47
|
+
.encoding('utf8')
|
|
48
|
+
.read()) as string;
|
|
49
|
+
|
|
50
|
+
// Extract custom section content
|
|
51
|
+
const customMarkers = ['#------# custom', '# custom'];
|
|
52
|
+
for (const marker of customMarkers) {
|
|
53
|
+
const splitResult = existingContent.split(marker);
|
|
54
|
+
if (splitResult.length > 1) {
|
|
55
|
+
customContent = splitResult[1].trim();
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Compute new content
|
|
62
|
+
let newContent = GITIGNORE_TEMPLATE;
|
|
63
|
+
if (customContent) {
|
|
64
|
+
newContent = GITIGNORE_TEMPLATE + '\n' + customContent + '\n';
|
|
65
|
+
} else {
|
|
66
|
+
newContent = GITIGNORE_TEMPLATE + '\n';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Read current content to compare
|
|
70
|
+
let currentContent = '';
|
|
71
|
+
if (exists) {
|
|
72
|
+
currentContent = (await plugins.smartfs
|
|
73
|
+
.file(gitignorePath)
|
|
74
|
+
.encoding('utf8')
|
|
75
|
+
.read()) as string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Determine change type
|
|
79
|
+
if (!exists) {
|
|
80
|
+
changes.push({
|
|
81
|
+
type: 'create',
|
|
82
|
+
path: gitignorePath,
|
|
83
|
+
module: this.name,
|
|
84
|
+
description: 'Create .gitignore',
|
|
85
|
+
content: newContent,
|
|
86
|
+
});
|
|
87
|
+
} else if (newContent !== currentContent) {
|
|
88
|
+
changes.push({
|
|
89
|
+
type: 'modify',
|
|
90
|
+
path: gitignorePath,
|
|
91
|
+
module: this.name,
|
|
92
|
+
description: 'Update .gitignore (preserving custom section)',
|
|
93
|
+
content: newContent,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return changes;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async applyChange(change: IPlannedChange): Promise<void> {
|
|
101
|
+
if (!change.content) return;
|
|
102
|
+
|
|
103
|
+
if (change.type === 'create') {
|
|
104
|
+
await this.createFile(change.path, change.content);
|
|
105
|
+
logger.log('info', 'Created .gitignore');
|
|
106
|
+
} else if (change.type === 'modify') {
|
|
107
|
+
await this.modifyFile(change.path, change.content);
|
|
108
|
+
logger.log('info', 'Updated .gitignore (preserved custom section)');
|
|
109
|
+
}
|
|
7
110
|
}
|
|
8
111
|
}
|
|
@@ -1,8 +1,62 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
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 * as paths from '../../paths.js';
|
|
5
|
+
import { logger } from '../../gitzone.logging.js';
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
const INCOMPATIBLE_LICENSES: string[] = ['AGPL', 'GPL', 'SSPL'];
|
|
8
|
+
|
|
9
|
+
export class LicenseFormatter extends BaseFormatter {
|
|
10
|
+
get name(): string {
|
|
11
|
+
return 'license';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async analyze(): Promise<IPlannedChange[]> {
|
|
15
|
+
// License formatter only checks for incompatible licenses
|
|
16
|
+
// It does not modify any files, so return empty array
|
|
17
|
+
// The actual check happens in execute() for reporting purposes
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async execute(changes: IPlannedChange[]): Promise<void> {
|
|
22
|
+
const startTime = this.stats.moduleStartTime(this.name);
|
|
23
|
+
this.stats.startModule(this.name);
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
// Check if node_modules exists
|
|
27
|
+
const nodeModulesPath = plugins.path.join(paths.cwd, 'node_modules');
|
|
28
|
+
const nodeModulesExists = await plugins.smartfs
|
|
29
|
+
.directory(nodeModulesPath)
|
|
30
|
+
.exists();
|
|
31
|
+
|
|
32
|
+
if (!nodeModulesExists) {
|
|
33
|
+
logger.log('warn', 'No node_modules found. Skipping license check');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Run license check
|
|
38
|
+
const licenseChecker = await plugins.smartlegal.createLicenseChecker();
|
|
39
|
+
const licenseCheckResult = await licenseChecker.excludeLicenseWithinPath(
|
|
40
|
+
paths.cwd,
|
|
41
|
+
INCOMPATIBLE_LICENSES,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
if (licenseCheckResult.failingModules.length === 0) {
|
|
45
|
+
logger.log('info', 'License check passed - no incompatible licenses found');
|
|
46
|
+
} else {
|
|
47
|
+
logger.log('error', 'License check failed - incompatible licenses found:');
|
|
48
|
+
for (const failedModule of licenseCheckResult.failingModules) {
|
|
49
|
+
console.log(
|
|
50
|
+
` ${failedModule.name} has license ${failedModule.license}`,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
} finally {
|
|
55
|
+
this.stats.endModule(this.name, startTime);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async applyChange(change: IPlannedChange): Promise<void> {
|
|
60
|
+
// No file changes for license formatter
|
|
7
61
|
}
|
|
8
62
|
}
|
|
@@ -1,8 +1,165 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
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';
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Migrates npmextra.json from old namespace keys to new package-scoped keys
|
|
8
|
+
*/
|
|
9
|
+
const migrateNamespaceKeys = (npmextraJson: any): boolean => {
|
|
10
|
+
let migrated = false;
|
|
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' },
|
|
17
|
+
];
|
|
18
|
+
for (const { oldKey, newKey } of migrations) {
|
|
19
|
+
if (npmextraJson[oldKey] && !npmextraJson[newKey]) {
|
|
20
|
+
npmextraJson[newKey] = npmextraJson[oldKey];
|
|
21
|
+
delete npmextraJson[oldKey];
|
|
22
|
+
migrated = true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return migrated;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Migrates npmAccessLevel from @ship.zone/szci to @git.zone/cli.release.accessLevel
|
|
30
|
+
*/
|
|
31
|
+
const migrateAccessLevel = (npmextraJson: any): boolean => {
|
|
32
|
+
const szciConfig = npmextraJson['@ship.zone/szci'];
|
|
33
|
+
|
|
34
|
+
if (!szciConfig?.npmAccessLevel) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const gitzoneConfig = npmextraJson['@git.zone/cli'] || {};
|
|
39
|
+
if (gitzoneConfig?.release?.accessLevel) {
|
|
40
|
+
delete szciConfig.npmAccessLevel;
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!npmextraJson['@git.zone/cli']) {
|
|
45
|
+
npmextraJson['@git.zone/cli'] = {};
|
|
46
|
+
}
|
|
47
|
+
if (!npmextraJson['@git.zone/cli'].release) {
|
|
48
|
+
npmextraJson['@git.zone/cli'].release = {};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
npmextraJson['@git.zone/cli'].release.accessLevel = szciConfig.npmAccessLevel;
|
|
52
|
+
delete szciConfig.npmAccessLevel;
|
|
53
|
+
|
|
54
|
+
return true;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export class NpmextraFormatter extends BaseFormatter {
|
|
58
|
+
get name(): string {
|
|
59
|
+
return 'npmextra';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async analyze(): Promise<IPlannedChange[]> {
|
|
63
|
+
const changes: IPlannedChange[] = [];
|
|
64
|
+
const npmextraPath = 'npmextra.json';
|
|
65
|
+
|
|
66
|
+
// Check if file exists
|
|
67
|
+
const exists = await plugins.smartfs.file(npmextraPath).exists();
|
|
68
|
+
if (!exists) {
|
|
69
|
+
logVerbose('npmextra.json does not exist, skipping');
|
|
70
|
+
return changes;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Read current content
|
|
74
|
+
const currentContent = (await plugins.smartfs
|
|
75
|
+
.file(npmextraPath)
|
|
76
|
+
.encoding('utf8')
|
|
77
|
+
.read()) as string;
|
|
78
|
+
|
|
79
|
+
// Parse and compute new content
|
|
80
|
+
const npmextraJson = JSON.parse(currentContent);
|
|
81
|
+
|
|
82
|
+
// Apply migrations (these are automatic, non-interactive)
|
|
83
|
+
migrateNamespaceKeys(npmextraJson);
|
|
84
|
+
migrateAccessLevel(npmextraJson);
|
|
85
|
+
|
|
86
|
+
// Ensure namespaces exist
|
|
87
|
+
if (!npmextraJson['@git.zone/cli']) {
|
|
88
|
+
npmextraJson['@git.zone/cli'] = {};
|
|
89
|
+
}
|
|
90
|
+
if (!npmextraJson['@ship.zone/szci']) {
|
|
91
|
+
npmextraJson['@ship.zone/szci'] = {};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const newContent = JSON.stringify(npmextraJson, null, 2);
|
|
95
|
+
|
|
96
|
+
// Only add change if content differs
|
|
97
|
+
if (newContent !== currentContent) {
|
|
98
|
+
changes.push({
|
|
99
|
+
type: 'modify',
|
|
100
|
+
path: npmextraPath,
|
|
101
|
+
module: this.name,
|
|
102
|
+
description: 'Migrate and format npmextra.json',
|
|
103
|
+
content: newContent,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return changes;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async applyChange(change: IPlannedChange): Promise<void> {
|
|
111
|
+
if (change.type !== 'modify' || !change.content) return;
|
|
112
|
+
|
|
113
|
+
// Parse the content to check for missing required fields
|
|
114
|
+
const npmextraJson = JSON.parse(change.content);
|
|
115
|
+
|
|
116
|
+
// Check for missing required module information
|
|
117
|
+
const expectedRepoInformation: string[] = [
|
|
118
|
+
'projectType',
|
|
119
|
+
'module.githost',
|
|
120
|
+
'module.gitscope',
|
|
121
|
+
'module.gitrepo',
|
|
122
|
+
'module.description',
|
|
123
|
+
'module.npmPackagename',
|
|
124
|
+
'module.license',
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
const interactInstance = new plugins.smartinteract.SmartInteract();
|
|
128
|
+
for (const expectedRepoInformationItem of expectedRepoInformation) {
|
|
129
|
+
if (
|
|
130
|
+
!plugins.smartobject.smartGet(
|
|
131
|
+
npmextraJson['@git.zone/cli'],
|
|
132
|
+
expectedRepoInformationItem,
|
|
133
|
+
)
|
|
134
|
+
) {
|
|
135
|
+
interactInstance.addQuestions([
|
|
136
|
+
{
|
|
137
|
+
message: `What is the value of ${expectedRepoInformationItem}`,
|
|
138
|
+
name: expectedRepoInformationItem,
|
|
139
|
+
type: 'input',
|
|
140
|
+
default: 'undefined variable',
|
|
141
|
+
},
|
|
142
|
+
]);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const answerbucket = await interactInstance.runQueue();
|
|
147
|
+
for (const expectedRepoInformationItem of expectedRepoInformation) {
|
|
148
|
+
const cliProvidedValue = answerbucket.getAnswerFor(
|
|
149
|
+
expectedRepoInformationItem,
|
|
150
|
+
);
|
|
151
|
+
if (cliProvidedValue) {
|
|
152
|
+
plugins.smartobject.smartAdd(
|
|
153
|
+
npmextraJson['@git.zone/cli'],
|
|
154
|
+
expectedRepoInformationItem,
|
|
155
|
+
cliProvidedValue,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Write the final content
|
|
161
|
+
const finalContent = JSON.stringify(npmextraJson, null, 2);
|
|
162
|
+
await this.modifyFile(change.path, finalContent);
|
|
163
|
+
logger.log('info', 'Updated npmextra.json');
|
|
7
164
|
}
|
|
8
165
|
}
|