@gadmin2n/cli 0.0.86 → 0.0.88
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/actions/index.d.ts +1 -0
- package/actions/index.js +1 -0
- package/actions/template.action.d.ts +7 -0
- package/actions/template.action.js +570 -0
- package/commands/command.loader.js +2 -0
- package/commands/template.command.d.ts +5 -0
- package/commands/template.command.js +34 -0
- package/package.json +2 -2
- package/.circleci/config.yml +0 -62
- package/.github/ISSUE_TEMPLATE/Bug_report.yml +0 -106
- package/.github/ISSUE_TEMPLATE/Feature_request.yml +0 -52
- package/.github/ISSUE_TEMPLATE/Regression.yml +0 -78
- package/.github/ISSUE_TEMPLATE/config.yml +0 -7
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -41
- package/test/lib/compiler/hooks/__snapshots__/tsconfig-paths.hook.spec.ts.snap +0 -68
- package/test/lib/compiler/hooks/fixtures/aliased-imports/src/bar.tsx +0 -1
- package/test/lib/compiler/hooks/fixtures/aliased-imports/src/baz.js +0 -1
- package/test/lib/compiler/hooks/fixtures/aliased-imports/src/qux.jsx +0 -1
package/actions/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from './build.action';
|
|
|
3
3
|
export * from './generate.action';
|
|
4
4
|
export * from './info.action';
|
|
5
5
|
export * from './new.action';
|
|
6
|
+
export * from './template.action';
|
|
6
7
|
export * from './update.action';
|
|
7
8
|
export * from './start.action';
|
|
8
9
|
export * from './add.action';
|
package/actions/index.js
CHANGED
|
@@ -19,6 +19,7 @@ __exportStar(require("./build.action"), exports);
|
|
|
19
19
|
__exportStar(require("./generate.action"), exports);
|
|
20
20
|
__exportStar(require("./info.action"), exports);
|
|
21
21
|
__exportStar(require("./new.action"), exports);
|
|
22
|
+
__exportStar(require("./template.action"), exports);
|
|
22
23
|
__exportStar(require("./update.action"), exports);
|
|
23
24
|
__exportStar(require("./start.action"), exports);
|
|
24
25
|
__exportStar(require("./add.action"), exports);
|
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.TemplateAction = void 0;
|
|
13
|
+
const chalk = require("chalk");
|
|
14
|
+
const fs = require("fs");
|
|
15
|
+
const path = require("path");
|
|
16
|
+
const inquirer = require("inquirer");
|
|
17
|
+
const child_process_1 = require("child_process");
|
|
18
|
+
const abstract_action_1 = require("./abstract.action");
|
|
19
|
+
const DEFAULT_EXCLUDES = [
|
|
20
|
+
'node_modules',
|
|
21
|
+
'.git',
|
|
22
|
+
'dist',
|
|
23
|
+
'generated',
|
|
24
|
+
'.DS_Store',
|
|
25
|
+
'.env.local',
|
|
26
|
+
'readme.md'
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Convert a glob pattern to a RegExp.
|
|
30
|
+
* Supports: * (any chars except /), ** (any path segments), ? (single char)
|
|
31
|
+
*/
|
|
32
|
+
function globToRegex(pattern) {
|
|
33
|
+
let regexStr = '^';
|
|
34
|
+
let i = 0;
|
|
35
|
+
while (i < pattern.length) {
|
|
36
|
+
const c = pattern[i];
|
|
37
|
+
if (c === '*') {
|
|
38
|
+
if (pattern[i + 1] === '*') {
|
|
39
|
+
// ** matches any path segments
|
|
40
|
+
if (pattern[i + 2] === '/') {
|
|
41
|
+
regexStr += '(?:.+/)?';
|
|
42
|
+
i += 3;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
regexStr += '.*';
|
|
46
|
+
i += 2;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// * matches anything except /
|
|
51
|
+
regexStr += '[^/]*';
|
|
52
|
+
i++;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else if (c === '?') {
|
|
56
|
+
regexStr += '[^/]';
|
|
57
|
+
i++;
|
|
58
|
+
}
|
|
59
|
+
else if (c === '.' || c === '(' || c === ')' || c === '[' || c === ']' || c === '{' || c === '}' || c === '+' || c === '^' || c === '$' || c === '|' || c === '\\') {
|
|
60
|
+
regexStr += '\\' + c;
|
|
61
|
+
i++;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
regexStr += c;
|
|
65
|
+
i++;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
regexStr += '$';
|
|
69
|
+
return new RegExp(regexStr);
|
|
70
|
+
}
|
|
71
|
+
function matchesPattern(filePath, pattern) {
|
|
72
|
+
// Exact match or directory prefix match
|
|
73
|
+
if (filePath === pattern)
|
|
74
|
+
return true;
|
|
75
|
+
if (filePath.startsWith(pattern + '/'))
|
|
76
|
+
return true;
|
|
77
|
+
// Check each path segment for exact match (e.g. "node_modules" matches "a/node_modules/b")
|
|
78
|
+
const parts = filePath.split('/');
|
|
79
|
+
if (!pattern.includes('/') && !pattern.includes('*') && !pattern.includes('?')) {
|
|
80
|
+
if (parts.includes(pattern))
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
// Glob pattern matching
|
|
84
|
+
if (pattern.includes('*') || pattern.includes('?')) {
|
|
85
|
+
const regex = globToRegex(pattern);
|
|
86
|
+
return regex.test(filePath);
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
function loadTemplateConfig() {
|
|
91
|
+
const configPaths = [
|
|
92
|
+
path.join(process.cwd(), 'server/gadmin-cli.json'),
|
|
93
|
+
path.join(process.cwd(), 'gadmin-cli.json'),
|
|
94
|
+
];
|
|
95
|
+
let templateName;
|
|
96
|
+
let userExcludes = [];
|
|
97
|
+
for (const configPath of configPaths) {
|
|
98
|
+
if (fs.existsSync(configPath)) {
|
|
99
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
100
|
+
templateName = config.template;
|
|
101
|
+
if (Array.isArray(config.templateExcludes)) {
|
|
102
|
+
userExcludes = config.templateExcludes;
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (!templateName) {
|
|
108
|
+
throw new Error('Cannot find "template" field in gadmin-cli.json. ' +
|
|
109
|
+
'Make sure you are in a gadmin2 project root directory.');
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
templateName,
|
|
113
|
+
excludes: [...DEFAULT_EXCLUDES, ...userExcludes],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function shouldExclude(filePath, excludes) {
|
|
117
|
+
for (const pattern of excludes) {
|
|
118
|
+
if (matchesPattern(filePath, pattern))
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
function collectFiles(dir, excludes, base = '') {
|
|
124
|
+
const results = [];
|
|
125
|
+
const entries = fs.readdirSync(path.join(dir, base), { withFileTypes: true });
|
|
126
|
+
for (const entry of entries) {
|
|
127
|
+
const rel = base ? `${base}/${entry.name}` : entry.name;
|
|
128
|
+
if (shouldExclude(rel, excludes))
|
|
129
|
+
continue;
|
|
130
|
+
if (entry.isDirectory()) {
|
|
131
|
+
results.push(...collectFiles(dir, excludes, rel));
|
|
132
|
+
}
|
|
133
|
+
else if (entry.isFile()) {
|
|
134
|
+
results.push(rel);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return results.sort();
|
|
138
|
+
}
|
|
139
|
+
function resolveTemplatePath(templateName) {
|
|
140
|
+
// Resolve @gadmin2n/schematics package path
|
|
141
|
+
// Try multiple locations: project's node_modules, CLI's own node_modules
|
|
142
|
+
let schematicsRoot;
|
|
143
|
+
const searchPaths = [
|
|
144
|
+
process.cwd(),
|
|
145
|
+
path.join(process.cwd(), 'server'),
|
|
146
|
+
path.resolve(__dirname, '..'), // CLI package root
|
|
147
|
+
];
|
|
148
|
+
for (const searchPath of searchPaths) {
|
|
149
|
+
try {
|
|
150
|
+
const pkgPath = require.resolve('@gadmin2n/schematics/package.json', {
|
|
151
|
+
paths: [searchPath],
|
|
152
|
+
});
|
|
153
|
+
schematicsRoot = path.dirname(pkgPath);
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
catch (_a) {
|
|
157
|
+
// continue trying next path
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (!schematicsRoot) {
|
|
161
|
+
throw new Error('Cannot resolve @gadmin2n/schematics package. ' +
|
|
162
|
+
'Make sure it is installed.');
|
|
163
|
+
}
|
|
164
|
+
// Check dist path first (published package), then src path (yalc/dev link)
|
|
165
|
+
// Also try with name variants (gadmin2n → gadmin2) for backward compatibility
|
|
166
|
+
const nameVariants = [templateName];
|
|
167
|
+
if (templateName.startsWith('gadmin2n-')) {
|
|
168
|
+
nameVariants.push(templateName.replace('gadmin2n-', 'gadmin2-'));
|
|
169
|
+
}
|
|
170
|
+
else if (templateName.startsWith('gadmin2-')) {
|
|
171
|
+
nameVariants.push(templateName.replace('gadmin2-', 'gadmin2n-'));
|
|
172
|
+
}
|
|
173
|
+
for (const name of nameVariants) {
|
|
174
|
+
const distPath = path.join(schematicsRoot, 'dist/lib/application/files', name);
|
|
175
|
+
const srcPath = path.join(schematicsRoot, 'src/lib/application/files', name);
|
|
176
|
+
if (fs.existsSync(distPath))
|
|
177
|
+
return distPath;
|
|
178
|
+
if (fs.existsSync(srcPath))
|
|
179
|
+
return srcPath;
|
|
180
|
+
}
|
|
181
|
+
throw new Error(`Template directory not found for "${templateName}" in ${schematicsRoot}`);
|
|
182
|
+
}
|
|
183
|
+
function createUnifiedDiff(filePath, instanceContent, templateContent) {
|
|
184
|
+
const instanceLines = instanceContent.split('\n');
|
|
185
|
+
const templateLines = templateContent.split('\n');
|
|
186
|
+
// Simple line-by-line diff output
|
|
187
|
+
const lines = [];
|
|
188
|
+
lines.push(chalk.bold(`--- a/${filePath} (instance)`));
|
|
189
|
+
lines.push(chalk.bold(`+++ b/${filePath} (template)`));
|
|
190
|
+
// Find differing regions using a simple approach
|
|
191
|
+
const maxLen = Math.max(instanceLines.length, templateLines.length);
|
|
192
|
+
const hunks = [];
|
|
193
|
+
let currentHunk = null;
|
|
194
|
+
for (let i = 0; i < maxLen; i++) {
|
|
195
|
+
const a = i < instanceLines.length ? instanceLines[i] : undefined;
|
|
196
|
+
const b = i < templateLines.length ? templateLines[i] : undefined;
|
|
197
|
+
if (a !== b) {
|
|
198
|
+
if (!currentHunk) {
|
|
199
|
+
currentHunk = { start: i, instanceLines: [], templateLines: [] };
|
|
200
|
+
}
|
|
201
|
+
if (a !== undefined)
|
|
202
|
+
currentHunk.instanceLines.push(a);
|
|
203
|
+
if (b !== undefined)
|
|
204
|
+
currentHunk.templateLines.push(b);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
if (currentHunk) {
|
|
208
|
+
hunks.push(currentHunk);
|
|
209
|
+
currentHunk = null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (currentHunk)
|
|
214
|
+
hunks.push(currentHunk);
|
|
215
|
+
// Output hunks with context
|
|
216
|
+
for (const hunk of hunks.slice(0, 10)) { // Limit to first 10 hunks
|
|
217
|
+
const contextStart = Math.max(0, hunk.start - 2);
|
|
218
|
+
lines.push(chalk.cyan(`@@ -${hunk.start + 1},${hunk.instanceLines.length} +${hunk.start + 1},${hunk.templateLines.length} @@`));
|
|
219
|
+
// Context before
|
|
220
|
+
for (let i = contextStart; i < hunk.start; i++) {
|
|
221
|
+
if (i < instanceLines.length) {
|
|
222
|
+
lines.push(` ${instanceLines[i]}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Removed lines (instance)
|
|
226
|
+
for (const line of hunk.instanceLines) {
|
|
227
|
+
lines.push(chalk.red(`-${line}`));
|
|
228
|
+
}
|
|
229
|
+
// Added lines (template)
|
|
230
|
+
for (const line of hunk.templateLines) {
|
|
231
|
+
lines.push(chalk.green(`+${line}`));
|
|
232
|
+
}
|
|
233
|
+
// Context after
|
|
234
|
+
const afterStart = hunk.start + Math.max(hunk.instanceLines.length, hunk.templateLines.length);
|
|
235
|
+
for (let i = afterStart; i < Math.min(afterStart + 2, instanceLines.length); i++) {
|
|
236
|
+
lines.push(` ${instanceLines[i]}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (hunks.length > 10) {
|
|
240
|
+
lines.push(chalk.yellow(` ... and ${hunks.length - 10} more hunks`));
|
|
241
|
+
}
|
|
242
|
+
return lines.join('\n');
|
|
243
|
+
}
|
|
244
|
+
function createConflictContent(instanceContent, templateContent) {
|
|
245
|
+
return [
|
|
246
|
+
'<<<<<<< INSTANCE',
|
|
247
|
+
instanceContent,
|
|
248
|
+
'=======',
|
|
249
|
+
templateContent,
|
|
250
|
+
'>>>>>>> TEMPLATE',
|
|
251
|
+
].join('\n');
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Attempt a 3-way merge using git merge-file with an empty base.
|
|
255
|
+
* Both instance and template are treated as "additions from nothing".
|
|
256
|
+
* Identical sections pass through cleanly; differing sections produce conflicts.
|
|
257
|
+
*/
|
|
258
|
+
function tryAutoMerge(instanceContent, templateContent) {
|
|
259
|
+
const tmpDir = fs.mkdtempSync(path.join(require('os').tmpdir(), 'gadmin-merge-'));
|
|
260
|
+
const basePath = path.join(tmpDir, 'base');
|
|
261
|
+
const oursPath = path.join(tmpDir, 'ours');
|
|
262
|
+
const theirsPath = path.join(tmpDir, 'theirs');
|
|
263
|
+
try {
|
|
264
|
+
fs.writeFileSync(basePath, '', 'utf-8');
|
|
265
|
+
fs.writeFileSync(oursPath, instanceContent, 'utf-8');
|
|
266
|
+
fs.writeFileSync(theirsPath, templateContent, 'utf-8');
|
|
267
|
+
try {
|
|
268
|
+
(0, child_process_1.execSync)(`git merge-file -L "INSTANCE" -L "BASE" -L "TEMPLATE" "${oursPath}" "${basePath}" "${theirsPath}"`, { stdio: 'pipe' });
|
|
269
|
+
const merged = fs.readFileSync(oursPath, 'utf-8');
|
|
270
|
+
return { merged, hasConflicts: false };
|
|
271
|
+
}
|
|
272
|
+
catch (err) {
|
|
273
|
+
if (err.status > 0) {
|
|
274
|
+
const merged = fs.readFileSync(oursPath, 'utf-8');
|
|
275
|
+
return { merged, hasConflicts: true };
|
|
276
|
+
}
|
|
277
|
+
return { merged: createConflictContent(instanceContent, templateContent), hasConflicts: true };
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
finally {
|
|
281
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
class TemplateAction extends abstract_action_1.AbstractAction {
|
|
285
|
+
handle(inputs, options) {
|
|
286
|
+
var _a;
|
|
287
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
288
|
+
const subcommand = (_a = inputs.find((i) => i.name === 'subcommand')) === null || _a === void 0 ? void 0 : _a.value;
|
|
289
|
+
if (subcommand === 'diff') {
|
|
290
|
+
yield this.handleDiff(options);
|
|
291
|
+
}
|
|
292
|
+
else if (subcommand === 'update') {
|
|
293
|
+
yield this.handleUpdate(options);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
handleDiff(options) {
|
|
298
|
+
var _a;
|
|
299
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
300
|
+
const noContent = (_a = options.find((o) => o.name === 'no-content')) === null || _a === void 0 ? void 0 : _a.value;
|
|
301
|
+
let templateDir;
|
|
302
|
+
let excludes;
|
|
303
|
+
try {
|
|
304
|
+
const config = loadTemplateConfig();
|
|
305
|
+
templateDir = resolveTemplatePath(config.templateName);
|
|
306
|
+
excludes = config.excludes;
|
|
307
|
+
}
|
|
308
|
+
catch (err) {
|
|
309
|
+
console.error(chalk.red(err.message));
|
|
310
|
+
process.exit(1);
|
|
311
|
+
}
|
|
312
|
+
const instanceDir = process.cwd();
|
|
313
|
+
console.info(`\n${chalk.gray('Template:')} ${templateDir}`);
|
|
314
|
+
console.info(`${chalk.gray('Instance:')} ${instanceDir}\n`);
|
|
315
|
+
const templateFiles = collectFiles(templateDir, excludes);
|
|
316
|
+
const instanceFiles = collectFiles(instanceDir, excludes);
|
|
317
|
+
const templateSet = new Set(templateFiles);
|
|
318
|
+
const instanceSet = new Set(instanceFiles);
|
|
319
|
+
// Modified: both have, content differs
|
|
320
|
+
const modified = [];
|
|
321
|
+
// Only in template (would be added on update)
|
|
322
|
+
const onlyInTemplate = [];
|
|
323
|
+
// Only in instance (instance-specific)
|
|
324
|
+
const onlyInInstance = [];
|
|
325
|
+
for (const file of templateFiles) {
|
|
326
|
+
if (instanceSet.has(file)) {
|
|
327
|
+
const tContent = fs.readFileSync(path.join(templateDir, file), 'utf-8');
|
|
328
|
+
const iContent = fs.readFileSync(path.join(instanceDir, file), 'utf-8');
|
|
329
|
+
if (tContent !== iContent) {
|
|
330
|
+
modified.push(file);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
onlyInTemplate.push(file);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
for (const file of instanceFiles) {
|
|
338
|
+
if (!templateSet.has(file)) {
|
|
339
|
+
onlyInInstance.push(file);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// Summary
|
|
343
|
+
console.info(chalk.bold('═══════════════════════════════════════════════════'));
|
|
344
|
+
console.info(chalk.bold(' Template Diff Summary'));
|
|
345
|
+
console.info(chalk.bold('═══════════════════════════════════════════════════\n'));
|
|
346
|
+
if (modified.length > 0) {
|
|
347
|
+
console.info(chalk.yellow(`📝 Modified (${modified.length} files)`));
|
|
348
|
+
for (const f of modified) {
|
|
349
|
+
console.info(` ${f}`);
|
|
350
|
+
}
|
|
351
|
+
console.info();
|
|
352
|
+
}
|
|
353
|
+
if (onlyInTemplate.length > 0) {
|
|
354
|
+
console.info(chalk.green(`➕ Only in template (${onlyInTemplate.length} files)`));
|
|
355
|
+
for (const f of onlyInTemplate) {
|
|
356
|
+
console.info(` ${f}`);
|
|
357
|
+
}
|
|
358
|
+
console.info();
|
|
359
|
+
}
|
|
360
|
+
if (onlyInInstance.length > 0) {
|
|
361
|
+
console.info(chalk.cyan(`📄 Only in instance (${onlyInInstance.length} files)`));
|
|
362
|
+
for (const f of onlyInInstance) {
|
|
363
|
+
console.info(` ${f}`);
|
|
364
|
+
}
|
|
365
|
+
console.info();
|
|
366
|
+
}
|
|
367
|
+
if (modified.length === 0 && onlyInTemplate.length === 0 && onlyInInstance.length === 0) {
|
|
368
|
+
console.info(chalk.green('✅ No differences found. Instance matches template.\n'));
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
// Show diff content for modified files
|
|
372
|
+
if (!noContent && modified.length > 0) {
|
|
373
|
+
console.info(chalk.bold('───────────────────────────────────────────────────'));
|
|
374
|
+
console.info(chalk.bold(' File Diffs (instance vs template)'));
|
|
375
|
+
console.info(chalk.bold('───────────────────────────────────────────────────\n'));
|
|
376
|
+
for (const file of modified) {
|
|
377
|
+
const tContent = fs.readFileSync(path.join(templateDir, file), 'utf-8');
|
|
378
|
+
const iContent = fs.readFileSync(path.join(instanceDir, file), 'utf-8');
|
|
379
|
+
const diff = createUnifiedDiff(file, iContent, tContent);
|
|
380
|
+
console.info(diff);
|
|
381
|
+
console.info();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
handleUpdate(options) {
|
|
387
|
+
var _a, _b;
|
|
388
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
389
|
+
const dryRun = (_a = options.find((o) => o.name === 'dry-run')) === null || _a === void 0 ? void 0 : _a.value;
|
|
390
|
+
const autoYes = (_b = options.find((o) => o.name === 'yes')) === null || _b === void 0 ? void 0 : _b.value;
|
|
391
|
+
let templateDir;
|
|
392
|
+
let excludes;
|
|
393
|
+
try {
|
|
394
|
+
const config = loadTemplateConfig();
|
|
395
|
+
templateDir = resolveTemplatePath(config.templateName);
|
|
396
|
+
excludes = config.excludes;
|
|
397
|
+
}
|
|
398
|
+
catch (err) {
|
|
399
|
+
console.error(chalk.red(err.message));
|
|
400
|
+
process.exit(1);
|
|
401
|
+
}
|
|
402
|
+
const instanceDir = process.cwd();
|
|
403
|
+
console.info(`\n${chalk.gray('Template:')} ${templateDir}`);
|
|
404
|
+
console.info(`${chalk.gray('Instance:')} ${instanceDir}\n`);
|
|
405
|
+
const templateFiles = collectFiles(templateDir, excludes);
|
|
406
|
+
const instanceFiles = collectFiles(instanceDir, excludes);
|
|
407
|
+
const instanceSet = new Set(instanceFiles);
|
|
408
|
+
// Categorize changes (template → instance direction)
|
|
409
|
+
const toUpdate = []; // exists in both, content differs
|
|
410
|
+
const toAdd = []; // only in template
|
|
411
|
+
for (const file of templateFiles) {
|
|
412
|
+
if (instanceSet.has(file)) {
|
|
413
|
+
const tContent = fs.readFileSync(path.join(templateDir, file), 'utf-8');
|
|
414
|
+
const iContent = fs.readFileSync(path.join(instanceDir, file), 'utf-8');
|
|
415
|
+
if (tContent !== iContent) {
|
|
416
|
+
toUpdate.push(file);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
toAdd.push(file);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (toUpdate.length === 0 && toAdd.length === 0) {
|
|
424
|
+
console.info(chalk.green('✅ Instance is up to date with template.\n'));
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
// Summary
|
|
428
|
+
console.info(chalk.bold('═══════════════════════════════════════════════════'));
|
|
429
|
+
console.info(chalk.bold(' Template Update Summary'));
|
|
430
|
+
console.info(chalk.bold('═══════════════════════════════════════════════════\n'));
|
|
431
|
+
if (toUpdate.length > 0) {
|
|
432
|
+
console.info(chalk.yellow(`📝 To update (${toUpdate.length} files)`));
|
|
433
|
+
for (const f of toUpdate) {
|
|
434
|
+
console.info(` ${f}`);
|
|
435
|
+
}
|
|
436
|
+
console.info();
|
|
437
|
+
}
|
|
438
|
+
if (toAdd.length > 0) {
|
|
439
|
+
console.info(chalk.green(`➕ To add (${toAdd.length} files)`));
|
|
440
|
+
for (const f of toAdd) {
|
|
441
|
+
console.info(` ${f}`);
|
|
442
|
+
}
|
|
443
|
+
console.info();
|
|
444
|
+
}
|
|
445
|
+
console.info(chalk.gray('───────────────────────────────────────────────────'));
|
|
446
|
+
console.info(chalk.gray(` Total: ${toUpdate.length} update | ${toAdd.length} add`));
|
|
447
|
+
console.info(chalk.gray('───────────────────────────────────────────────────\n'));
|
|
448
|
+
if (dryRun) {
|
|
449
|
+
console.info(chalk.gray('(dry-run mode, no changes made)\n'));
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
// Confirm proceed
|
|
453
|
+
if (!autoYes) {
|
|
454
|
+
const { confirm } = yield inquirer.prompt([
|
|
455
|
+
{
|
|
456
|
+
type: 'confirm',
|
|
457
|
+
name: 'confirm',
|
|
458
|
+
message: 'Proceed with update?',
|
|
459
|
+
default: false,
|
|
460
|
+
},
|
|
461
|
+
]);
|
|
462
|
+
if (!confirm) {
|
|
463
|
+
console.info('Cancelled.\n');
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
// Process modified files — per-file strategy selection
|
|
468
|
+
let skippedCount = 0;
|
|
469
|
+
let overwrittenCount = 0;
|
|
470
|
+
let mergedCount = 0;
|
|
471
|
+
let conflictCount = 0;
|
|
472
|
+
// Track "apply to all" choice
|
|
473
|
+
let applyAll = null;
|
|
474
|
+
for (let i = 0; i < toUpdate.length; i++) {
|
|
475
|
+
const file = toUpdate[i];
|
|
476
|
+
const tContent = fs.readFileSync(path.join(templateDir, file), 'utf-8');
|
|
477
|
+
const iContent = fs.readFileSync(path.join(instanceDir, file), 'utf-8');
|
|
478
|
+
let strategy = applyAll;
|
|
479
|
+
if (!strategy && !autoYes) {
|
|
480
|
+
// Show brief diff summary
|
|
481
|
+
const diff = createUnifiedDiff(file, iContent, tContent);
|
|
482
|
+
console.info(`\n${chalk.bold(`[${i + 1}/${toUpdate.length}]`)} ${chalk.yellow(file)}`);
|
|
483
|
+
console.info(diff);
|
|
484
|
+
console.info();
|
|
485
|
+
const { action } = yield inquirer.prompt([
|
|
486
|
+
{
|
|
487
|
+
type: 'list',
|
|
488
|
+
name: 'action',
|
|
489
|
+
message: `How to handle ${file}?`,
|
|
490
|
+
choices: [
|
|
491
|
+
{ name: 'Skip — keep instance as-is', value: 'skip', short: 'skip' },
|
|
492
|
+
{ name: 'Overwrite — use template version', value: 'overwrite', short: 'overwrite' },
|
|
493
|
+
{ name: 'Auto merge — attempt git merge', value: 'merge', short: 'merge' },
|
|
494
|
+
{ name: 'Conflict markers — write both versions for manual resolve', value: 'conflict', short: 'conflict' },
|
|
495
|
+
new inquirer.Separator(),
|
|
496
|
+
{ name: 'Skip ALL remaining', value: 'skip-all', short: 'skip all' },
|
|
497
|
+
{ name: 'Overwrite ALL remaining', value: 'overwrite-all', short: 'overwrite all' },
|
|
498
|
+
{ name: 'Conflict markers ALL remaining', value: 'conflict-all', short: 'conflict all' },
|
|
499
|
+
],
|
|
500
|
+
},
|
|
501
|
+
]);
|
|
502
|
+
if (action.endsWith('-all')) {
|
|
503
|
+
applyAll = action.replace('-all', '');
|
|
504
|
+
strategy = applyAll;
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
strategy = action;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
else if (autoYes) {
|
|
511
|
+
strategy = 'conflict';
|
|
512
|
+
}
|
|
513
|
+
// Execute strategy
|
|
514
|
+
const destPath = path.join(instanceDir, file);
|
|
515
|
+
switch (strategy) {
|
|
516
|
+
case 'skip':
|
|
517
|
+
skippedCount++;
|
|
518
|
+
break;
|
|
519
|
+
case 'overwrite':
|
|
520
|
+
fs.writeFileSync(destPath, tContent, 'utf-8');
|
|
521
|
+
overwrittenCount++;
|
|
522
|
+
break;
|
|
523
|
+
case 'merge': {
|
|
524
|
+
const result = tryAutoMerge(iContent, tContent);
|
|
525
|
+
fs.writeFileSync(destPath, result.merged, 'utf-8');
|
|
526
|
+
if (result.hasConflicts) {
|
|
527
|
+
conflictCount++;
|
|
528
|
+
console.info(chalk.yellow(` ⚠️ ${file} — merge has conflicts`));
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
mergedCount++;
|
|
532
|
+
console.info(chalk.green(` ✓ ${file} — merged cleanly`));
|
|
533
|
+
}
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
536
|
+
case 'conflict':
|
|
537
|
+
default:
|
|
538
|
+
fs.writeFileSync(destPath, createConflictContent(iContent, tContent), 'utf-8');
|
|
539
|
+
conflictCount++;
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
// Process new files (always add)
|
|
544
|
+
for (const file of toAdd) {
|
|
545
|
+
const destPath = path.join(instanceDir, file);
|
|
546
|
+
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
547
|
+
fs.copyFileSync(path.join(templateDir, file), destPath);
|
|
548
|
+
}
|
|
549
|
+
// Final summary
|
|
550
|
+
console.info(chalk.bold('\n✅ Update complete!\n'));
|
|
551
|
+
const stats = [];
|
|
552
|
+
if (overwrittenCount > 0)
|
|
553
|
+
stats.push(`${overwrittenCount} overwritten`);
|
|
554
|
+
if (mergedCount > 0)
|
|
555
|
+
stats.push(`${mergedCount} merged`);
|
|
556
|
+
if (conflictCount > 0)
|
|
557
|
+
stats.push(`${conflictCount} with conflicts`);
|
|
558
|
+
if (skippedCount > 0)
|
|
559
|
+
stats.push(`${skippedCount} skipped`);
|
|
560
|
+
if (toAdd.length > 0)
|
|
561
|
+
stats.push(`${toAdd.length} added`);
|
|
562
|
+
console.info(` ${stats.join(' | ')}\n`);
|
|
563
|
+
if (conflictCount > 0) {
|
|
564
|
+
console.info(chalk.yellow(`⚠️ ${conflictCount} files have conflict markers. ` +
|
|
565
|
+
`Search for "<<<<<<< INSTANCE" to resolve them.\n`));
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
exports.TemplateAction = TemplateAction;
|
|
@@ -10,6 +10,7 @@ const generate_command_1 = require("./generate.command");
|
|
|
10
10
|
const info_command_1 = require("./info.command");
|
|
11
11
|
const new_command_1 = require("./new.command");
|
|
12
12
|
const start_command_1 = require("./start.command");
|
|
13
|
+
const template_command_1 = require("./template.command");
|
|
13
14
|
const update_command_1 = require("./update.command");
|
|
14
15
|
class CommandLoader {
|
|
15
16
|
static load(program) {
|
|
@@ -18,6 +19,7 @@ class CommandLoader {
|
|
|
18
19
|
new start_command_1.StartCommand(new actions_1.StartAction()).load(program);
|
|
19
20
|
new info_command_1.InfoCommand(new actions_1.InfoAction()).load(program);
|
|
20
21
|
new update_command_1.UpdateCommand(new actions_1.UpdateAction()).load(program);
|
|
22
|
+
new template_command_1.TemplateCommand(new actions_1.TemplateAction()).load(program);
|
|
21
23
|
new add_command_1.AddCommand(new actions_1.AddAction()).load(program);
|
|
22
24
|
new generate_command_1.GenerateCommand(new actions_1.GenerateAction()).load(program);
|
|
23
25
|
this.handleInvalidCommand(program);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.TemplateCommand = void 0;
|
|
13
|
+
const abstract_command_1 = require("./abstract.command");
|
|
14
|
+
class TemplateCommand extends abstract_command_1.AbstractCommand {
|
|
15
|
+
load(program) {
|
|
16
|
+
program
|
|
17
|
+
.command('template <subcommand>')
|
|
18
|
+
.alias('tpl')
|
|
19
|
+
.description('Compare or sync with the project template.')
|
|
20
|
+
.option('--no-content', 'Only show file list, skip inline diff content (for diff).')
|
|
21
|
+
.option('-d, --dry-run', 'Show what would be updated without making changes (for update).')
|
|
22
|
+
.option('-y, --yes', 'Skip confirmation prompt (for update).')
|
|
23
|
+
.action((subcommand, command) => __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
const inputs = [];
|
|
25
|
+
inputs.push({ name: 'subcommand', value: subcommand });
|
|
26
|
+
const options = [];
|
|
27
|
+
options.push({ name: 'no-content', value: !command.content });
|
|
28
|
+
options.push({ name: 'dry-run', value: !!command.dryRun });
|
|
29
|
+
options.push({ name: 'yes', value: !!command.yes });
|
|
30
|
+
yield this.action.handle(inputs, options);
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.TemplateCommand = TemplateCommand;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gadmin2n/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.88",
|
|
4
4
|
"description": "Gadmin - modern, fast, powerful node.js web framework (@cli)",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"@angular-devkit/core": "13.3.2",
|
|
48
48
|
"@angular-devkit/schematics": "13.3.2",
|
|
49
49
|
"@angular-devkit/schematics-cli": "13.3.2",
|
|
50
|
-
"@gadmin2n/schematics": "^0.0.
|
|
50
|
+
"@gadmin2n/schematics": "^0.0.70",
|
|
51
51
|
"abc": "^0.6.1",
|
|
52
52
|
"chalk": "3.0.0",
|
|
53
53
|
"chokidar": "3.5.3",
|
package/.circleci/config.yml
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
version: 2
|
|
2
|
-
|
|
3
|
-
aliases:
|
|
4
|
-
- &restore-cache
|
|
5
|
-
restore_cache:
|
|
6
|
-
key: dependency-cache-{{ checksum "package.json" }}
|
|
7
|
-
- &install-deps
|
|
8
|
-
run:
|
|
9
|
-
name: Install dependencies
|
|
10
|
-
command: npm ci
|
|
11
|
-
- &build-packages
|
|
12
|
-
run:
|
|
13
|
-
name: Build
|
|
14
|
-
command: npm run build
|
|
15
|
-
- &run-unit-tests
|
|
16
|
-
run:
|
|
17
|
-
name: Test
|
|
18
|
-
command: npm run test
|
|
19
|
-
|
|
20
|
-
jobs:
|
|
21
|
-
build:
|
|
22
|
-
working_directory: ~/nest
|
|
23
|
-
docker:
|
|
24
|
-
- image: circleci/node:17
|
|
25
|
-
steps:
|
|
26
|
-
- checkout
|
|
27
|
-
- run:
|
|
28
|
-
name: Update NPM version
|
|
29
|
-
command: 'sudo npm install -g npm@latest'
|
|
30
|
-
- restore_cache:
|
|
31
|
-
key: dependency-cache-{{ checksum "package.json" }}
|
|
32
|
-
- run:
|
|
33
|
-
name: Install dependencies
|
|
34
|
-
command: npm ci
|
|
35
|
-
- save_cache:
|
|
36
|
-
key: dependency-cache-{{ checksum "package.json" }}
|
|
37
|
-
paths:
|
|
38
|
-
- ./node_modules
|
|
39
|
-
- run:
|
|
40
|
-
name: Build
|
|
41
|
-
command: npm run build
|
|
42
|
-
|
|
43
|
-
unit_tests:
|
|
44
|
-
working_directory: ~/nest
|
|
45
|
-
docker:
|
|
46
|
-
- image: circleci/node:17
|
|
47
|
-
steps:
|
|
48
|
-
- checkout
|
|
49
|
-
- *restore-cache
|
|
50
|
-
- *install-deps
|
|
51
|
-
- *build-packages
|
|
52
|
-
- *run-unit-tests
|
|
53
|
-
|
|
54
|
-
workflows:
|
|
55
|
-
version: 2
|
|
56
|
-
build-and-test:
|
|
57
|
-
jobs:
|
|
58
|
-
- build
|
|
59
|
-
- unit_tests:
|
|
60
|
-
requires:
|
|
61
|
-
- build
|
|
62
|
-
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
name: "\U0001F41B Bug Report"
|
|
2
|
-
description: "If something isn't working as expected \U0001F914"
|
|
3
|
-
labels: ["needs triage", "bug"]
|
|
4
|
-
body:
|
|
5
|
-
- type: markdown
|
|
6
|
-
attributes:
|
|
7
|
-
value: |
|
|
8
|
-
## :warning: We use GitHub Issues to track bug reports, feature requests and regressions
|
|
9
|
-
|
|
10
|
-
If you are not sure that your issue is a bug, you could:
|
|
11
|
-
|
|
12
|
-
- use our [Discord community](https://discord.gg/NestJS)
|
|
13
|
-
- use [StackOverflow using the tag `nestjs`](https://stackoverflow.com/questions/tagged/nestjs)
|
|
14
|
-
- If it's just a quick question you can ping [our Twitter](https://twitter.com/nestframework)
|
|
15
|
-
|
|
16
|
-
**NOTE:** You don't need to answer questions that you know that aren't relevant.
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
- type: checkboxes
|
|
21
|
-
attributes:
|
|
22
|
-
label: "Is there an existing issue for this?"
|
|
23
|
-
description: "Please search [here](./?q=is%3Aissue) to see if an issue already exists for the bug you encountered"
|
|
24
|
-
options:
|
|
25
|
-
- label: "I have searched the existing issues"
|
|
26
|
-
required: true
|
|
27
|
-
|
|
28
|
-
- type: textarea
|
|
29
|
-
validations:
|
|
30
|
-
required: true
|
|
31
|
-
attributes:
|
|
32
|
-
label: "Current behavior"
|
|
33
|
-
description: "How the issue manifests?"
|
|
34
|
-
|
|
35
|
-
- type: input
|
|
36
|
-
validations:
|
|
37
|
-
required: true
|
|
38
|
-
attributes:
|
|
39
|
-
label: "Minimum reproduction code"
|
|
40
|
-
description: "An URL to some git repository or gist that reproduces this issue. [Wtf is a minimum reproduction?](https://jmcdo29.github.io/wtf-is-a-minimum-reproduction)"
|
|
41
|
-
placeholder: "https://github.com/..."
|
|
42
|
-
|
|
43
|
-
- type: textarea
|
|
44
|
-
attributes:
|
|
45
|
-
label: "Steps to reproduce"
|
|
46
|
-
description: |
|
|
47
|
-
How the issue manifests?
|
|
48
|
-
You could leave this blank if you alread write this in your reproduction code/repo
|
|
49
|
-
placeholder: |
|
|
50
|
-
1. `npm i`
|
|
51
|
-
2. `npm start:dev`
|
|
52
|
-
3. See error...
|
|
53
|
-
|
|
54
|
-
- type: textarea
|
|
55
|
-
validations:
|
|
56
|
-
required: true
|
|
57
|
-
attributes:
|
|
58
|
-
label: "Expected behavior"
|
|
59
|
-
description: "A clear and concise description of what you expected to happend (or code)"
|
|
60
|
-
|
|
61
|
-
- type: markdown
|
|
62
|
-
attributes:
|
|
63
|
-
value: |
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
- type: input
|
|
67
|
-
validations:
|
|
68
|
-
required: true
|
|
69
|
-
attributes:
|
|
70
|
-
label: "Package version"
|
|
71
|
-
description: |
|
|
72
|
-
Which version of `@nestjs/cli` are you using?
|
|
73
|
-
**Tip**: Make sure that all of yours `@nestjs/*` dependencies are in sync!
|
|
74
|
-
placeholder: "8.1.3"
|
|
75
|
-
|
|
76
|
-
- type: input
|
|
77
|
-
attributes:
|
|
78
|
-
label: "NestJS version"
|
|
79
|
-
description: "Which version of `@nestjs/core` are you using?"
|
|
80
|
-
placeholder: "8.1.3"
|
|
81
|
-
|
|
82
|
-
- type: input
|
|
83
|
-
attributes:
|
|
84
|
-
label: "Node.js version"
|
|
85
|
-
description: "Which version of Node.js are you using?"
|
|
86
|
-
placeholder: "14.17.6"
|
|
87
|
-
|
|
88
|
-
- type: checkboxes
|
|
89
|
-
attributes:
|
|
90
|
-
label: "In which operating systems have you tested?"
|
|
91
|
-
options:
|
|
92
|
-
- label: macOS
|
|
93
|
-
- label: Windows
|
|
94
|
-
- label: Linux
|
|
95
|
-
|
|
96
|
-
- type: markdown
|
|
97
|
-
attributes:
|
|
98
|
-
value: |
|
|
99
|
-
---
|
|
100
|
-
|
|
101
|
-
- type: textarea
|
|
102
|
-
attributes:
|
|
103
|
-
label: "Other"
|
|
104
|
-
description: |
|
|
105
|
-
Anything else relevant? eg: Logs, OS version, IDE, package manager, etc.
|
|
106
|
-
**Tip:** You can attach images, recordings or log files by clicking this area to highlight it and then dragging files in
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
name: "\U0001F680 Feature Request"
|
|
2
|
-
description: "I have a suggestion \U0001F63B!"
|
|
3
|
-
labels: ["feature"]
|
|
4
|
-
body:
|
|
5
|
-
- type: markdown
|
|
6
|
-
attributes:
|
|
7
|
-
value: |
|
|
8
|
-
## :warning: We use GitHub Issues to track bug reports, feature requests and regressions
|
|
9
|
-
|
|
10
|
-
If you are not sure that your issue is a bug, you could:
|
|
11
|
-
|
|
12
|
-
- use our [Discord community](https://discord.gg/NestJS)
|
|
13
|
-
- use [StackOverflow using the tag `nestjs`](https://stackoverflow.com/questions/tagged/nestjs)
|
|
14
|
-
- If it's just a quick question you can ping [our Twitter](https://twitter.com/nestframework)
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
- type: checkboxes
|
|
19
|
-
attributes:
|
|
20
|
-
label: "Is there an existing issue that is already proposing this?"
|
|
21
|
-
description: "Please search [here](./?q=is%3Aissue) to see if an issue already exists for the feature you are requesting"
|
|
22
|
-
options:
|
|
23
|
-
- label: "I have searched the existing issues"
|
|
24
|
-
required: true
|
|
25
|
-
|
|
26
|
-
- type: textarea
|
|
27
|
-
validations:
|
|
28
|
-
required: true
|
|
29
|
-
attributes:
|
|
30
|
-
label: "Is your feature request related to a problem? Please describe it"
|
|
31
|
-
description: "A clear and concise description of what the problem is"
|
|
32
|
-
placeholder: |
|
|
33
|
-
I have an issue when ...
|
|
34
|
-
|
|
35
|
-
- type: textarea
|
|
36
|
-
validations:
|
|
37
|
-
required: true
|
|
38
|
-
attributes:
|
|
39
|
-
label: "Describe the solution you'd like"
|
|
40
|
-
description: "A clear and concise description of what you want to happen. Add any considered drawbacks"
|
|
41
|
-
|
|
42
|
-
- type: textarea
|
|
43
|
-
attributes:
|
|
44
|
-
label: "Teachability, documentation, adoption, migration strategy"
|
|
45
|
-
description: "If you can, explain how users will be able to use this and possibly write out a version the docs. Maybe a screenshot or design?"
|
|
46
|
-
|
|
47
|
-
- type: textarea
|
|
48
|
-
validations:
|
|
49
|
-
required: true
|
|
50
|
-
attributes:
|
|
51
|
-
label: "What is the motivation / use case for changing the behavior?"
|
|
52
|
-
description: "Describe the motivation or the concrete use case"
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
name: "\U0001F4A5 Regression"
|
|
2
|
-
description: "Report an unexpected behavior while upgrading your Nest application!"
|
|
3
|
-
labels: ["needs triage"]
|
|
4
|
-
body:
|
|
5
|
-
- type: markdown
|
|
6
|
-
attributes:
|
|
7
|
-
value: |
|
|
8
|
-
## :warning: We use GitHub Issues to track bug reports, feature requests and regressions
|
|
9
|
-
|
|
10
|
-
If you are not sure that your issue is a bug, you could:
|
|
11
|
-
|
|
12
|
-
- use our [Discord community](https://discord.gg/NestJS)
|
|
13
|
-
- use [StackOverflow using the tag `nestjs`](https://stackoverflow.com/questions/tagged/nestjs)
|
|
14
|
-
- If it's just a quick question you can ping [our Twitter](https://twitter.com/nestframework)
|
|
15
|
-
|
|
16
|
-
**NOTE:** You don't need to answer questions that you know that aren't relevant.
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
- type: checkboxes
|
|
21
|
-
attributes:
|
|
22
|
-
label: "Did you read the migration guide?"
|
|
23
|
-
description: "Check out the [migration guide here](https://docs.nestjs.com/migration-guide)!"
|
|
24
|
-
options:
|
|
25
|
-
- label: "I have read the whole migration guide"
|
|
26
|
-
required: false
|
|
27
|
-
|
|
28
|
-
- type: checkboxes
|
|
29
|
-
attributes:
|
|
30
|
-
label: "Is there an existing issue that is already proposing this?"
|
|
31
|
-
description: "Please search [here](./?q=is%3Aissue) to see if an issue already exists for the feature you are requesting"
|
|
32
|
-
options:
|
|
33
|
-
- label: "I have searched the existing issues"
|
|
34
|
-
required: true
|
|
35
|
-
|
|
36
|
-
- type: input
|
|
37
|
-
attributes:
|
|
38
|
-
label: "Potential Commit/PR that introduced the regression"
|
|
39
|
-
description: "If you have time to investigate, what PR/date/version introduced this issue"
|
|
40
|
-
placeholder: "PR #123 or commit 5b3c4a4"
|
|
41
|
-
|
|
42
|
-
- type: input
|
|
43
|
-
attributes:
|
|
44
|
-
label: "Versions"
|
|
45
|
-
description: "From which version of `@nestjs/cli` to which version you are upgrading"
|
|
46
|
-
placeholder: "8.1.0 -> 8.1.3"
|
|
47
|
-
|
|
48
|
-
- type: textarea
|
|
49
|
-
validations:
|
|
50
|
-
required: true
|
|
51
|
-
attributes:
|
|
52
|
-
label: "Describe the regression"
|
|
53
|
-
description: "A clear and concise description of what the regression is"
|
|
54
|
-
|
|
55
|
-
- type: textarea
|
|
56
|
-
attributes:
|
|
57
|
-
label: "Minimum reproduction code"
|
|
58
|
-
description: |
|
|
59
|
-
Please share a git repo, a gist, or step-by-step instructions. [Wtf is a minimum reproduction?](https://jmcdo29.github.io/wtf-is-a-minimum-reproduction)
|
|
60
|
-
**Tip:** If you leave a minimum repository, we will understand your issue faster!
|
|
61
|
-
value: |
|
|
62
|
-
```ts
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
- type: textarea
|
|
67
|
-
validations:
|
|
68
|
-
required: true
|
|
69
|
-
attributes:
|
|
70
|
-
label: "Expected behavior"
|
|
71
|
-
description: "A clear and concise description of what you expected to happend (or code)"
|
|
72
|
-
|
|
73
|
-
- type: textarea
|
|
74
|
-
attributes:
|
|
75
|
-
label: "Other"
|
|
76
|
-
description: |
|
|
77
|
-
Anything else relevant? eg: Logs, OS version, IDE, package manager, etc.
|
|
78
|
-
**Tip:** You can attach images, recordings or log files by clicking this area to highlight it and then dragging files in
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
## To encourage contributors to use issue templates, we don't allow blank issues
|
|
2
|
-
blank_issues_enabled: false
|
|
3
|
-
|
|
4
|
-
contact_links:
|
|
5
|
-
- name: "\u2753 Discord Community of NestJS"
|
|
6
|
-
url: "https://discord.gg/NestJS"
|
|
7
|
-
about: "Please ask support questions or discuss suggestions/enhancements here."
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
## PR Checklist
|
|
2
|
-
Please check if your PR fulfills the following requirements:
|
|
3
|
-
|
|
4
|
-
- [ ] The commit message follows our guidelines: https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md
|
|
5
|
-
- [ ] Tests for the changes have been added (for bug fixes / features)
|
|
6
|
-
- [ ] Docs have been added / updated (for bug fixes / features)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## PR Type
|
|
10
|
-
What kind of change does this PR introduce?
|
|
11
|
-
|
|
12
|
-
<!-- Please check the one that applies to this PR using "x". -->
|
|
13
|
-
```
|
|
14
|
-
[ ] Bugfix
|
|
15
|
-
[ ] Feature
|
|
16
|
-
[ ] Code style update (formatting, local variables)
|
|
17
|
-
[ ] Refactoring (no functional changes, no api changes)
|
|
18
|
-
[ ] Build related changes
|
|
19
|
-
[ ] CI related changes
|
|
20
|
-
[ ] Other... Please describe:
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## What is the current behavior?
|
|
24
|
-
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->
|
|
25
|
-
|
|
26
|
-
Issue Number: N/A
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
## What is the new behavior?
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
## Does this PR introduce a breaking change?
|
|
33
|
-
```
|
|
34
|
-
[ ] Yes
|
|
35
|
-
[ ] No
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
## Other information
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`tsconfig paths hooks should remove unused imports 1`] = `
|
|
4
|
-
Map {
|
|
5
|
-
"dist/foo.js" => "\\"use strict\\";
|
|
6
|
-
Object.defineProperty(exports, \\"__esModule\\", { value: true });
|
|
7
|
-
exports.Foo = void 0;
|
|
8
|
-
class Foo {
|
|
9
|
-
}
|
|
10
|
-
exports.Foo = Foo;
|
|
11
|
-
",
|
|
12
|
-
"dist/bar.js" => "\\"use strict\\";
|
|
13
|
-
Object.defineProperty(exports, \\"__esModule\\", { value: true });
|
|
14
|
-
exports.Bar = void 0;
|
|
15
|
-
class Bar {
|
|
16
|
-
}
|
|
17
|
-
exports.Bar = Bar;
|
|
18
|
-
",
|
|
19
|
-
"dist/main.js" => "\\"use strict\\";
|
|
20
|
-
Object.defineProperty(exports, \\"__esModule\\", { value: true });
|
|
21
|
-
",
|
|
22
|
-
}
|
|
23
|
-
`;
|
|
24
|
-
|
|
25
|
-
exports[`tsconfig paths hooks should replace path of every import using a path alias by its relative path 1`] = `
|
|
26
|
-
Map {
|
|
27
|
-
"dist/foo.js" => "\\"use strict\\";
|
|
28
|
-
Object.defineProperty(exports, \\"__esModule\\", { value: true });
|
|
29
|
-
exports.Foo = void 0;
|
|
30
|
-
class Foo {
|
|
31
|
-
}
|
|
32
|
-
exports.Foo = Foo;
|
|
33
|
-
",
|
|
34
|
-
"dist/bar.jsx" => "\\"use strict\\";
|
|
35
|
-
Object.defineProperty(exports, \\"__esModule\\", { value: true });
|
|
36
|
-
exports.Bar = void 0;
|
|
37
|
-
class Bar {
|
|
38
|
-
}
|
|
39
|
-
exports.Bar = Bar;
|
|
40
|
-
",
|
|
41
|
-
"dist/baz.js" => "\\"use strict\\";
|
|
42
|
-
Object.defineProperty(exports, \\"__esModule\\", { value: true });
|
|
43
|
-
exports.Baz = void 0;
|
|
44
|
-
class Baz {
|
|
45
|
-
}
|
|
46
|
-
exports.Baz = Baz;
|
|
47
|
-
",
|
|
48
|
-
"dist/qux.jsx" => "\\"use strict\\";
|
|
49
|
-
Object.defineProperty(exports, \\"__esModule\\", { value: true });
|
|
50
|
-
exports.Qux = void 0;
|
|
51
|
-
class Qux {
|
|
52
|
-
}
|
|
53
|
-
exports.Qux = Qux;
|
|
54
|
-
",
|
|
55
|
-
"dist/main.js" => "\\"use strict\\";
|
|
56
|
-
Object.defineProperty(exports, \\"__esModule\\", { value: true });
|
|
57
|
-
const foo_1 = require(\\"./foo\\");
|
|
58
|
-
const bar_1 = require(\\"./bar\\");
|
|
59
|
-
const baz_1 = require(\\"./baz\\");
|
|
60
|
-
const qux_1 = require(\\"./qux\\");
|
|
61
|
-
// use the imports so they do not get eliminated
|
|
62
|
-
console.log(foo_1.Foo);
|
|
63
|
-
console.log(bar_1.Bar);
|
|
64
|
-
console.log(baz_1.Baz);
|
|
65
|
-
console.log(qux_1.Qux);
|
|
66
|
-
",
|
|
67
|
-
}
|
|
68
|
-
`;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export class Bar {}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export class Baz {}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export class Qux {}
|