@git.zone/cli 2.9.1 → 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 +31 -21
- 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
|
@@ -1,8 +1,204 @@
|
|
|
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, logVerbose } from '../../gitzone.logging.js';
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
|
|
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
|
+
const [packageName, version] = dependencyArg.includes('@')
|
|
17
|
+
? dependencyArg.split('@').filter(Boolean)
|
|
18
|
+
: [dependencyArg, 'latest'];
|
|
19
|
+
|
|
20
|
+
const targetSections: string[] = [];
|
|
21
|
+
|
|
22
|
+
switch (position) {
|
|
23
|
+
case 'dep':
|
|
24
|
+
targetSections.push('dependencies');
|
|
25
|
+
break;
|
|
26
|
+
case 'devDep':
|
|
27
|
+
targetSections.push('devDependencies');
|
|
28
|
+
break;
|
|
29
|
+
case 'everywhere':
|
|
30
|
+
targetSections.push('dependencies', 'devDependencies');
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (const section of targetSections) {
|
|
35
|
+
if (!packageJsonObject[section]) {
|
|
36
|
+
packageJsonObject[section] = {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
switch (constraint) {
|
|
40
|
+
case 'exclude':
|
|
41
|
+
delete packageJsonObject[section][packageName];
|
|
42
|
+
break;
|
|
43
|
+
case 'include':
|
|
44
|
+
if (!packageJsonObject[section][packageName]) {
|
|
45
|
+
packageJsonObject[section][packageName] =
|
|
46
|
+
version === 'latest' ? '^1.0.0' : version;
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
case 'latest':
|
|
50
|
+
try {
|
|
51
|
+
const registry = new plugins.smartnpm.NpmRegistry();
|
|
52
|
+
const packageInfo = await registry.getPackageInfo(packageName);
|
|
53
|
+
const latestVersion = packageInfo['dist-tags'].latest;
|
|
54
|
+
packageJsonObject[section][packageName] = `^${latestVersion}`;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
logVerbose(
|
|
57
|
+
`Could not fetch latest version for ${packageName}, using existing or default`,
|
|
58
|
+
);
|
|
59
|
+
if (!packageJsonObject[section][packageName]) {
|
|
60
|
+
packageJsonObject[section][packageName] =
|
|
61
|
+
version === 'latest' ? '^1.0.0' : version;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export class PackageJsonFormatter extends BaseFormatter {
|
|
70
|
+
get name(): string {
|
|
71
|
+
return 'packagejson';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async analyze(): Promise<IPlannedChange[]> {
|
|
75
|
+
const changes: IPlannedChange[] = [];
|
|
76
|
+
const packageJsonPath = 'package.json';
|
|
77
|
+
|
|
78
|
+
// Check if file exists
|
|
79
|
+
const exists = await plugins.smartfs.file(packageJsonPath).exists();
|
|
80
|
+
if (!exists) {
|
|
81
|
+
logVerbose('package.json does not exist, skipping');
|
|
82
|
+
return changes;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Read current content
|
|
86
|
+
const currentContent = (await plugins.smartfs
|
|
87
|
+
.file(packageJsonPath)
|
|
88
|
+
.encoding('utf8')
|
|
89
|
+
.read()) as string;
|
|
90
|
+
|
|
91
|
+
// Parse and compute new content
|
|
92
|
+
const packageJson = JSON.parse(currentContent);
|
|
93
|
+
|
|
94
|
+
// Get gitzone config from npmextra
|
|
95
|
+
const npmextraConfig = new plugins.npmextra.Npmextra(paths.cwd);
|
|
96
|
+
const gitzoneData: any = npmextraConfig.dataFor('@git.zone/cli', {});
|
|
97
|
+
|
|
98
|
+
// Set metadata from gitzone config
|
|
99
|
+
if (gitzoneData.module) {
|
|
100
|
+
packageJson.repository = {
|
|
101
|
+
type: 'git',
|
|
102
|
+
url: `https://${gitzoneData.module.githost}/${gitzoneData.module.gitscope}/${gitzoneData.module.gitrepo}.git`,
|
|
103
|
+
};
|
|
104
|
+
packageJson.bugs = {
|
|
105
|
+
url: `https://${gitzoneData.module.githost}/${gitzoneData.module.gitscope}/${gitzoneData.module.gitrepo}/issues`,
|
|
106
|
+
};
|
|
107
|
+
packageJson.homepage = `https://${gitzoneData.module.githost}/${gitzoneData.module.gitscope}/${gitzoneData.module.gitrepo}#readme`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Ensure module type
|
|
111
|
+
if (!packageJson.type) {
|
|
112
|
+
packageJson.type = 'module';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Ensure private field exists
|
|
116
|
+
if (packageJson.private === undefined) {
|
|
117
|
+
packageJson.private = true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Ensure license field exists
|
|
121
|
+
if (!packageJson.license) {
|
|
122
|
+
packageJson.license = 'UNLICENSED';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Ensure scripts object exists
|
|
126
|
+
if (!packageJson.scripts) {
|
|
127
|
+
packageJson.scripts = {};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Ensure build script exists
|
|
131
|
+
if (!packageJson.scripts.build) {
|
|
132
|
+
packageJson.scripts.build = `echo "Not needed for now"`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Ensure buildDocs script exists
|
|
136
|
+
if (!packageJson.scripts.buildDocs) {
|
|
137
|
+
packageJson.scripts.buildDocs = `tsdoc`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Set files array
|
|
141
|
+
packageJson.files = [
|
|
142
|
+
'ts/**/*',
|
|
143
|
+
'ts_web/**/*',
|
|
144
|
+
'dist/**/*',
|
|
145
|
+
'dist_*/**/*',
|
|
146
|
+
'dist_ts/**/*',
|
|
147
|
+
'dist_ts_web/**/*',
|
|
148
|
+
'assets/**/*',
|
|
149
|
+
'cli.js',
|
|
150
|
+
'npmextra.json',
|
|
151
|
+
'readme.md',
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
// Handle dependencies
|
|
155
|
+
await ensureDependency(
|
|
156
|
+
packageJson,
|
|
157
|
+
'devDep',
|
|
158
|
+
'exclude',
|
|
159
|
+
'@push.rocks/tapbundle',
|
|
160
|
+
);
|
|
161
|
+
await ensureDependency(packageJson, 'devDep', 'latest', '@git.zone/tstest');
|
|
162
|
+
await ensureDependency(
|
|
163
|
+
packageJson,
|
|
164
|
+
'devDep',
|
|
165
|
+
'latest',
|
|
166
|
+
'@git.zone/tsbuild',
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
// Set pnpm overrides from assets
|
|
170
|
+
try {
|
|
171
|
+
const overridesContent = (await plugins.smartfs
|
|
172
|
+
.file(plugins.path.join(paths.assetsDir, 'overrides.json'))
|
|
173
|
+
.encoding('utf8')
|
|
174
|
+
.read()) as string;
|
|
175
|
+
const overrides = JSON.parse(overridesContent);
|
|
176
|
+
packageJson.pnpm = packageJson.pnpm || {};
|
|
177
|
+
packageJson.pnpm.overrides = overrides;
|
|
178
|
+
} catch (error) {
|
|
179
|
+
logVerbose(`Could not read overrides.json: ${error.message}`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const newContent = JSON.stringify(packageJson, null, 2);
|
|
183
|
+
|
|
184
|
+
// Only add change if content differs
|
|
185
|
+
if (newContent !== currentContent) {
|
|
186
|
+
changes.push({
|
|
187
|
+
type: 'modify',
|
|
188
|
+
path: packageJsonPath,
|
|
189
|
+
module: this.name,
|
|
190
|
+
description: 'Format package.json',
|
|
191
|
+
content: newContent,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return changes;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async applyChange(change: IPlannedChange): Promise<void> {
|
|
199
|
+
if (change.type !== 'modify' || !change.content) return;
|
|
200
|
+
|
|
201
|
+
await this.modifyFile(change.path, change.content);
|
|
202
|
+
logger.log('info', 'Updated package.json');
|
|
7
203
|
}
|
|
8
204
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseFormatter } from '../classes.baseformatter.js';
|
|
2
|
-
import type { IPlannedChange } from '../interfaces.format.js';
|
|
2
|
+
import type { IPlannedChange, ICheckResult } from '../interfaces.format.js';
|
|
3
3
|
import * as plugins from '../mod.plugins.js';
|
|
4
4
|
import { logger, logVerbose } from '../../gitzone.logging.js';
|
|
5
5
|
|
|
@@ -243,4 +243,53 @@ export class PrettierFormatter extends BaseFormatter {
|
|
|
243
243
|
arrowParens: 'always',
|
|
244
244
|
});
|
|
245
245
|
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Override check() to compute diffs on-the-fly by running prettier
|
|
249
|
+
*/
|
|
250
|
+
async check(): Promise<ICheckResult> {
|
|
251
|
+
const changes = await this.analyze();
|
|
252
|
+
const diffs: ICheckResult['diffs'] = [];
|
|
253
|
+
|
|
254
|
+
for (const change of changes) {
|
|
255
|
+
if (change.type !== 'modify') continue;
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
// Read current content
|
|
259
|
+
const currentContent = (await plugins.smartfs
|
|
260
|
+
.file(change.path)
|
|
261
|
+
.encoding('utf8')
|
|
262
|
+
.read()) as string;
|
|
263
|
+
|
|
264
|
+
// Skip files without extension (prettier can't infer parser)
|
|
265
|
+
const fileExt = plugins.path.extname(change.path).toLowerCase();
|
|
266
|
+
if (!fileExt) continue;
|
|
267
|
+
|
|
268
|
+
// Format with prettier to get what it would produce
|
|
269
|
+
const prettier = await import('prettier');
|
|
270
|
+
const formatted = await prettier.format(currentContent, {
|
|
271
|
+
filepath: change.path,
|
|
272
|
+
...(await this.getPrettierConfig()),
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// Only add to diffs if content differs
|
|
276
|
+
if (formatted !== currentContent) {
|
|
277
|
+
diffs.push({
|
|
278
|
+
path: change.path,
|
|
279
|
+
type: 'modify',
|
|
280
|
+
before: currentContent,
|
|
281
|
+
after: formatted,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
} catch (error) {
|
|
285
|
+
// Skip files that can't be processed
|
|
286
|
+
logVerbose(`Skipping diff for ${change.path}: ${error.message}`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
hasDiff: diffs.length > 0,
|
|
292
|
+
diffs,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
246
295
|
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { BaseFormatter } from '../classes.baseformatter.js';
|
|
2
2
|
import type { IPlannedChange } from '../interfaces.format.js';
|
|
3
|
-
import * as
|
|
3
|
+
import * as plugins from '../mod.plugins.js';
|
|
4
|
+
import { logger } from '../../gitzone.logging.js';
|
|
5
|
+
|
|
6
|
+
const DEFAULT_README_CONTENT = `# Project Readme
|
|
7
|
+
|
|
8
|
+
This is the initial readme file.`;
|
|
9
|
+
|
|
10
|
+
const DEFAULT_README_HINTS_CONTENT = `# Project Readme Hints
|
|
11
|
+
|
|
12
|
+
This is the initial readme hints file.`;
|
|
4
13
|
|
|
5
14
|
export class ReadmeFormatter extends BaseFormatter {
|
|
6
15
|
get name(): string {
|
|
@@ -8,17 +17,39 @@ export class ReadmeFormatter extends BaseFormatter {
|
|
|
8
17
|
}
|
|
9
18
|
|
|
10
19
|
async analyze(): Promise<IPlannedChange[]> {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
20
|
+
const changes: IPlannedChange[] = [];
|
|
21
|
+
|
|
22
|
+
// Check readme.md
|
|
23
|
+
const readmeExists = await plugins.smartfs.file('readme.md').exists();
|
|
24
|
+
if (!readmeExists) {
|
|
25
|
+
changes.push({
|
|
26
|
+
type: 'create',
|
|
14
27
|
path: 'readme.md',
|
|
15
28
|
module: this.name,
|
|
16
|
-
description: '
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
description: 'Create readme.md',
|
|
30
|
+
content: DEFAULT_README_CONTENT,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Check readme.hints.md
|
|
35
|
+
const hintsExists = await plugins.smartfs.file('readme.hints.md').exists();
|
|
36
|
+
if (!hintsExists) {
|
|
37
|
+
changes.push({
|
|
38
|
+
type: 'create',
|
|
39
|
+
path: 'readme.hints.md',
|
|
40
|
+
module: this.name,
|
|
41
|
+
description: 'Create readme.hints.md',
|
|
42
|
+
content: DEFAULT_README_HINTS_CONTENT,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return changes;
|
|
19
47
|
}
|
|
20
48
|
|
|
21
49
|
async applyChange(change: IPlannedChange): Promise<void> {
|
|
22
|
-
|
|
50
|
+
if (change.type !== 'create' || !change.content) return;
|
|
51
|
+
|
|
52
|
+
await this.createFile(change.path, change.content);
|
|
53
|
+
logger.log('info', `Created ${change.path}`);
|
|
23
54
|
}
|
|
24
55
|
}
|
|
@@ -1,8 +1,155 @@
|
|
|
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, logVerbose } from '../../gitzone.logging.js';
|
|
3
6
|
|
|
4
|
-
export class TemplatesFormatter extends
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
export class TemplatesFormatter extends BaseFormatter {
|
|
8
|
+
get name(): string {
|
|
9
|
+
return 'templates';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async analyze(): Promise<IPlannedChange[]> {
|
|
13
|
+
const changes: IPlannedChange[] = [];
|
|
14
|
+
const project = this.project;
|
|
15
|
+
const projectType = project.gitzoneConfig?.data?.projectType;
|
|
16
|
+
|
|
17
|
+
// VSCode template - for all projects
|
|
18
|
+
const vscodeChanges = await this.analyzeTemplate('vscode', [
|
|
19
|
+
{ templatePath: '.vscode/settings.json', destPath: '.vscode/settings.json' },
|
|
20
|
+
{ templatePath: '.vscode/launch.json', destPath: '.vscode/launch.json' },
|
|
21
|
+
]);
|
|
22
|
+
changes.push(...vscodeChanges);
|
|
23
|
+
|
|
24
|
+
// CI and other templates based on projectType
|
|
25
|
+
switch (projectType) {
|
|
26
|
+
case 'npm':
|
|
27
|
+
case 'wcc':
|
|
28
|
+
const accessLevel = project.gitzoneConfig?.data?.npmciOptions?.npmAccessLevel;
|
|
29
|
+
const ciTemplate = accessLevel === 'public' ? 'ci_default' : 'ci_default_private';
|
|
30
|
+
const ciChanges = await this.analyzeTemplate(ciTemplate, [
|
|
31
|
+
{ templatePath: '.gitea/workflows/default_nottags.yaml', destPath: '.gitea/workflows/default_nottags.yaml' },
|
|
32
|
+
{ templatePath: '.gitea/workflows/default_tags.yaml', destPath: '.gitea/workflows/default_tags.yaml' },
|
|
33
|
+
]);
|
|
34
|
+
changes.push(...ciChanges);
|
|
35
|
+
break;
|
|
36
|
+
|
|
37
|
+
case 'service':
|
|
38
|
+
case 'website':
|
|
39
|
+
const dockerCiChanges = await this.analyzeTemplate('ci_docker', [
|
|
40
|
+
{ templatePath: '.gitea/workflows/docker_nottags.yaml', destPath: '.gitea/workflows/docker_nottags.yaml' },
|
|
41
|
+
{ templatePath: '.gitea/workflows/docker_tags.yaml', destPath: '.gitea/workflows/docker_tags.yaml' },
|
|
42
|
+
]);
|
|
43
|
+
changes.push(...dockerCiChanges);
|
|
44
|
+
|
|
45
|
+
const dockerfileChanges = await this.analyzeTemplate('dockerfile_service', [
|
|
46
|
+
{ templatePath: 'Dockerfile', destPath: 'Dockerfile' },
|
|
47
|
+
{ templatePath: 'dockerignore', destPath: '.dockerignore' },
|
|
48
|
+
]);
|
|
49
|
+
changes.push(...dockerfileChanges);
|
|
50
|
+
|
|
51
|
+
const cliChanges = await this.analyzeTemplate('cli', [
|
|
52
|
+
{ templatePath: 'cli.js', destPath: 'cli.js' },
|
|
53
|
+
{ templatePath: 'cli.ts.js', destPath: 'cli.ts.js' },
|
|
54
|
+
]);
|
|
55
|
+
changes.push(...cliChanges);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Update templates based on projectType
|
|
60
|
+
if (projectType === 'website') {
|
|
61
|
+
const websiteChanges = await this.analyzeTemplate('website_update', [
|
|
62
|
+
{ templatePath: 'html/index.html', destPath: 'html/index.html' },
|
|
63
|
+
]);
|
|
64
|
+
changes.push(...websiteChanges);
|
|
65
|
+
} else if (projectType === 'service') {
|
|
66
|
+
const serviceChanges = await this.analyzeTemplate('service_update', []);
|
|
67
|
+
changes.push(...serviceChanges);
|
|
68
|
+
} else if (projectType === 'wcc') {
|
|
69
|
+
const wccChanges = await this.analyzeTemplate('wcc_update', [
|
|
70
|
+
{ templatePath: 'html/index.html', destPath: 'html/index.html' },
|
|
71
|
+
{ templatePath: 'html/index.ts', destPath: 'html/index.ts' },
|
|
72
|
+
]);
|
|
73
|
+
changes.push(...wccChanges);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return changes;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private async analyzeTemplate(
|
|
80
|
+
templateName: string,
|
|
81
|
+
files: Array<{ templatePath: string; destPath: string }>,
|
|
82
|
+
): Promise<IPlannedChange[]> {
|
|
83
|
+
const changes: IPlannedChange[] = [];
|
|
84
|
+
const templateDir = plugins.path.join(paths.templatesDir, templateName);
|
|
85
|
+
|
|
86
|
+
// Check if template exists
|
|
87
|
+
const templateExists = await plugins.smartfs.directory(templateDir).exists();
|
|
88
|
+
if (!templateExists) {
|
|
89
|
+
logVerbose(`Template ${templateName} not found`);
|
|
90
|
+
return changes;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
for (const file of files) {
|
|
94
|
+
const templateFilePath = plugins.path.join(templateDir, file.templatePath);
|
|
95
|
+
const destFilePath = file.destPath;
|
|
96
|
+
|
|
97
|
+
// Check if template file exists
|
|
98
|
+
const fileExists = await plugins.smartfs.file(templateFilePath).exists();
|
|
99
|
+
if (!fileExists) {
|
|
100
|
+
logVerbose(`Template file ${templateFilePath} not found`);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
// Read template content
|
|
106
|
+
const templateContent = (await plugins.smartfs
|
|
107
|
+
.file(templateFilePath)
|
|
108
|
+
.encoding('utf8')
|
|
109
|
+
.read()) as string;
|
|
110
|
+
|
|
111
|
+
// Check if destination file exists
|
|
112
|
+
const destExists = await plugins.smartfs.file(destFilePath).exists();
|
|
113
|
+
let currentContent = '';
|
|
114
|
+
if (destExists) {
|
|
115
|
+
currentContent = (await plugins.smartfs
|
|
116
|
+
.file(destFilePath)
|
|
117
|
+
.encoding('utf8')
|
|
118
|
+
.read()) as string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Only add change if content differs
|
|
122
|
+
if (templateContent !== currentContent) {
|
|
123
|
+
changes.push({
|
|
124
|
+
type: destExists ? 'modify' : 'create',
|
|
125
|
+
path: destFilePath,
|
|
126
|
+
module: this.name,
|
|
127
|
+
description: `Apply template ${templateName}/${file.templatePath}`,
|
|
128
|
+
content: templateContent,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
logVerbose(`Failed to read template ${templateFilePath}: ${error.message}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return changes;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async applyChange(change: IPlannedChange): Promise<void> {
|
|
140
|
+
if (!change.content) return;
|
|
141
|
+
|
|
142
|
+
// Ensure destination directory exists
|
|
143
|
+
const destDir = plugins.path.dirname(change.path);
|
|
144
|
+
if (destDir && destDir !== '.') {
|
|
145
|
+
await plugins.smartfs.directory(destDir).recursive().create();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (change.type === 'create') {
|
|
149
|
+
await this.createFile(change.path, change.content);
|
|
150
|
+
} else {
|
|
151
|
+
await this.modifyFile(change.path, change.content);
|
|
152
|
+
}
|
|
153
|
+
logger.log('info', `Applied template to ${change.path}`);
|
|
7
154
|
}
|
|
8
155
|
}
|
|
@@ -1,8 +1,73 @@
|
|
|
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, logVerbose } from '../../gitzone.logging.js';
|
|
3
6
|
|
|
4
|
-
export class TsconfigFormatter extends
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
export class TsconfigFormatter extends BaseFormatter {
|
|
8
|
+
get name(): string {
|
|
9
|
+
return 'tsconfig';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async analyze(): Promise<IPlannedChange[]> {
|
|
13
|
+
const changes: IPlannedChange[] = [];
|
|
14
|
+
const tsconfigPath = 'tsconfig.json';
|
|
15
|
+
|
|
16
|
+
// Check if file exists
|
|
17
|
+
const exists = await plugins.smartfs.file(tsconfigPath).exists();
|
|
18
|
+
if (!exists) {
|
|
19
|
+
logVerbose('tsconfig.json does not exist, skipping');
|
|
20
|
+
return changes;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Read current content
|
|
24
|
+
const currentContent = (await plugins.smartfs
|
|
25
|
+
.file(tsconfigPath)
|
|
26
|
+
.encoding('utf8')
|
|
27
|
+
.read()) as string;
|
|
28
|
+
|
|
29
|
+
// Parse and compute new content
|
|
30
|
+
const tsconfigObject = JSON.parse(currentContent);
|
|
31
|
+
tsconfigObject.compilerOptions = tsconfigObject.compilerOptions || {};
|
|
32
|
+
tsconfigObject.compilerOptions.baseUrl = '.';
|
|
33
|
+
tsconfigObject.compilerOptions.paths = {};
|
|
34
|
+
|
|
35
|
+
// Get module paths from tspublish
|
|
36
|
+
try {
|
|
37
|
+
const tsPublishMod = await import('@git.zone/tspublish');
|
|
38
|
+
const tsPublishInstance = new tsPublishMod.TsPublish();
|
|
39
|
+
const publishModules = await tsPublishInstance.getModuleSubDirs(paths.cwd);
|
|
40
|
+
|
|
41
|
+
for (const publishModule of Object.keys(publishModules)) {
|
|
42
|
+
const publishConfig = publishModules[publishModule];
|
|
43
|
+
tsconfigObject.compilerOptions.paths[`${publishConfig.name}`] = [
|
|
44
|
+
`./${publishModule}/index.js`,
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
} catch (error) {
|
|
48
|
+
logVerbose(`Could not get tspublish modules: ${error.message}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const newContent = JSON.stringify(tsconfigObject, null, 2);
|
|
52
|
+
|
|
53
|
+
// Only add change if content differs
|
|
54
|
+
if (newContent !== currentContent) {
|
|
55
|
+
changes.push({
|
|
56
|
+
type: 'modify',
|
|
57
|
+
path: tsconfigPath,
|
|
58
|
+
module: this.name,
|
|
59
|
+
description: 'Format tsconfig.json with path mappings',
|
|
60
|
+
content: newContent,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return changes;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async applyChange(change: IPlannedChange): Promise<void> {
|
|
68
|
+
if (change.type !== 'modify' || !change.content) return;
|
|
69
|
+
|
|
70
|
+
await this.modifyFile(change.path, change.content);
|
|
71
|
+
logger.log('info', 'Updated tsconfig.json');
|
|
7
72
|
}
|
|
8
73
|
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { BaseFormatter } from '../classes.baseformatter.js';
|
|
2
|
-
import type { IPlannedChange } from '../interfaces.format.js';
|
|
3
|
-
import { Project } from '../../classes.project.js';
|
|
4
|
-
export declare class LegacyFormatter extends BaseFormatter {
|
|
5
|
-
private moduleName;
|
|
6
|
-
private formatModule;
|
|
7
|
-
constructor(context: any, project: Project, moduleName: string, formatModule: any);
|
|
8
|
-
get name(): string;
|
|
9
|
-
analyze(): Promise<IPlannedChange[]>;
|
|
10
|
-
applyChange(change: IPlannedChange): Promise<void>;
|
|
11
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { BaseFormatter } from '../classes.baseformatter.js';
|
|
2
|
-
import { Project } from '../../classes.project.js';
|
|
3
|
-
import * as plugins from '../mod.plugins.js';
|
|
4
|
-
// This is a wrapper for existing format modules
|
|
5
|
-
export class LegacyFormatter extends BaseFormatter {
|
|
6
|
-
constructor(context, project, moduleName, formatModule) {
|
|
7
|
-
super(context, project);
|
|
8
|
-
this.moduleName = moduleName;
|
|
9
|
-
this.formatModule = formatModule;
|
|
10
|
-
}
|
|
11
|
-
get name() {
|
|
12
|
-
return this.moduleName;
|
|
13
|
-
}
|
|
14
|
-
async analyze() {
|
|
15
|
-
// For legacy modules, we can't easily predict changes
|
|
16
|
-
// So we'll return a generic change that indicates the module will run
|
|
17
|
-
return [
|
|
18
|
-
{
|
|
19
|
-
type: 'modify',
|
|
20
|
-
path: '<various files>',
|
|
21
|
-
module: this.name,
|
|
22
|
-
description: `Run ${this.name} formatter`,
|
|
23
|
-
},
|
|
24
|
-
];
|
|
25
|
-
}
|
|
26
|
-
async applyChange(change) {
|
|
27
|
-
// Run the legacy format module
|
|
28
|
-
await this.formatModule.run(this.project);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGVnYWN5LmZvcm1hdHRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL21vZF9mb3JtYXQvZm9ybWF0dGVycy9sZWdhY3kuZm9ybWF0dGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUU1RCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDbkQsT0FBTyxLQUFLLE9BQU8sTUFBTSxtQkFBbUIsQ0FBQztBQUU3QyxnREFBZ0Q7QUFDaEQsTUFBTSxPQUFPLGVBQWdCLFNBQVEsYUFBYTtJQUloRCxZQUNFLE9BQVksRUFDWixPQUFnQixFQUNoQixVQUFrQixFQUNsQixZQUFpQjtRQUVqQixLQUFLLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3hCLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO1FBQzdCLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO0lBQ25DLENBQUM7SUFFRCxJQUFJLElBQUk7UUFDTixPQUFPLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDekIsQ0FBQztJQUVELEtBQUssQ0FBQyxPQUFPO1FBQ1gsc0RBQXNEO1FBQ3RELHNFQUFzRTtRQUN0RSxPQUFPO1lBQ0w7Z0JBQ0UsSUFBSSxFQUFFLFFBQVE7Z0JBQ2QsSUFBSSxFQUFFLGlCQUFpQjtnQkFDdkIsTUFBTSxFQUFFLElBQUksQ0FBQyxJQUFJO2dCQUNqQixXQUFXLEVBQUUsT0FBTyxJQUFJLENBQUMsSUFBSSxZQUFZO2FBQzFDO1NBQ0YsQ0FBQztJQUNKLENBQUM7SUFFRCxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQXNCO1FBQ3RDLCtCQUErQjtRQUMvQixNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM1QyxDQUFDO0NBQ0YifQ==
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { BaseFormatter } from '../classes.baseformatter.js';
|
|
2
|
-
import type { IPlannedChange } from '../interfaces.format.js';
|
|
3
|
-
import { Project } from '../../classes.project.js';
|
|
4
|
-
import * as plugins from '../mod.plugins.js';
|
|
5
|
-
|
|
6
|
-
// This is a wrapper for existing format modules
|
|
7
|
-
export class LegacyFormatter extends BaseFormatter {
|
|
8
|
-
private moduleName: string;
|
|
9
|
-
private formatModule: any;
|
|
10
|
-
|
|
11
|
-
constructor(
|
|
12
|
-
context: any,
|
|
13
|
-
project: Project,
|
|
14
|
-
moduleName: string,
|
|
15
|
-
formatModule: any,
|
|
16
|
-
) {
|
|
17
|
-
super(context, project);
|
|
18
|
-
this.moduleName = moduleName;
|
|
19
|
-
this.formatModule = formatModule;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
get name(): string {
|
|
23
|
-
return this.moduleName;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async analyze(): Promise<IPlannedChange[]> {
|
|
27
|
-
// For legacy modules, we can't easily predict changes
|
|
28
|
-
// So we'll return a generic change that indicates the module will run
|
|
29
|
-
return [
|
|
30
|
-
{
|
|
31
|
-
type: 'modify',
|
|
32
|
-
path: '<various files>',
|
|
33
|
-
module: this.name,
|
|
34
|
-
description: `Run ${this.name} formatter`,
|
|
35
|
-
},
|
|
36
|
-
];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async applyChange(change: IPlannedChange): Promise<void> {
|
|
40
|
-
// Run the legacy format module
|
|
41
|
-
await this.formatModule.run(this.project);
|
|
42
|
-
}
|
|
43
|
-
}
|