create-gen-app 0.3.5 → 0.3.6
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/esm/index.js +15 -15
- package/esm/licenses.js +22 -22
- package/esm/template/extract.js +19 -19
- package/esm/template/prompt.js +6 -6
- package/esm/template/replace.js +2 -2
- package/index.d.ts +16 -16
- package/licenses.js +20 -20
- package/package.json +5 -5
- package/template/extract.d.ts +1 -1
- package/template/extract.js +17 -17
- package/template/prompt.d.ts +2 -2
- package/template/prompt.js +5 -5
- package/template/replace.js +2 -2
package/esm/index.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { extractVariables } from
|
|
2
|
-
import { promptUser } from
|
|
3
|
-
import { replaceVariables } from
|
|
1
|
+
import { extractVariables } from './template/extract';
|
|
2
|
+
import { promptUser } from './template/prompt';
|
|
3
|
+
import { replaceVariables } from './template/replace';
|
|
4
4
|
// Export new modular classes
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from
|
|
11
|
-
export * from
|
|
12
|
-
export * from
|
|
5
|
+
export * from './cache/cache-manager';
|
|
6
|
+
export * from './cache/types';
|
|
7
|
+
export * from './git/git-cloner';
|
|
8
|
+
export * from './git/types';
|
|
9
|
+
export * from './template/templatizer';
|
|
10
|
+
export * from './template/types';
|
|
11
|
+
export * from './utils/npm-version-check';
|
|
12
|
+
export * from './utils/types';
|
|
13
13
|
// Export template processing functions
|
|
14
|
-
export * from
|
|
15
|
-
export * from
|
|
16
|
-
export * from
|
|
14
|
+
export * from './template/extract';
|
|
15
|
+
export * from './template/prompt';
|
|
16
|
+
export * from './template/replace';
|
|
17
17
|
// Export shared types
|
|
18
|
-
export * from
|
|
18
|
+
export * from './types';
|
|
19
19
|
// DEPRECATED: Legacy exports for backward compatibility (will be removed in future)
|
|
20
20
|
// Use CacheManager, GitCloner, and Templatizer classes instead
|
|
21
21
|
export { extractVariables, promptUser, replaceVariables };
|
package/esm/licenses.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import * as fs from
|
|
2
|
-
import * as path from
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
3
|
const PLACEHOLDER_PATTERN = /{{(\w+)}}/g;
|
|
4
4
|
let cachedTemplates = null;
|
|
5
|
-
export const LICENSE_VALUE_KEYS = [
|
|
5
|
+
export const LICENSE_VALUE_KEYS = ['LICENSE', 'license'];
|
|
6
6
|
export const LICENSE_AUTHOR_KEYS = [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
'USERFULLNAME',
|
|
8
|
+
'AUTHOR',
|
|
9
|
+
'AUTHORFULLNAME',
|
|
10
|
+
'USERNAME',
|
|
11
|
+
'fullName',
|
|
12
|
+
'author',
|
|
13
|
+
'authorFullName',
|
|
14
|
+
'userName',
|
|
15
15
|
];
|
|
16
|
-
export const LICENSE_EMAIL_KEYS = [
|
|
16
|
+
export const LICENSE_EMAIL_KEYS = ['USEREMAIL', 'EMAIL', 'email', 'userEmail'];
|
|
17
17
|
export function isSupportedLicense(name) {
|
|
18
18
|
if (!name) {
|
|
19
19
|
return false;
|
|
@@ -31,18 +31,18 @@ export function renderLicense(licenseName, context) {
|
|
|
31
31
|
}
|
|
32
32
|
const ctx = {
|
|
33
33
|
year: context.year ?? new Date().getFullYear().toString(),
|
|
34
|
-
author: context.author ??
|
|
35
|
-
email: context.email ??
|
|
34
|
+
author: context.author ?? 'Unknown Author',
|
|
35
|
+
email: context.email ?? '',
|
|
36
36
|
};
|
|
37
|
-
const emailLine = ctx.email ? ` <${ctx.email}>` :
|
|
37
|
+
const emailLine = ctx.email ? ` <${ctx.email}>` : '';
|
|
38
38
|
return template.replace(PLACEHOLDER_PATTERN, (_, rawKey) => {
|
|
39
39
|
const key = rawKey.toUpperCase();
|
|
40
|
-
if (key ===
|
|
40
|
+
if (key === 'EMAIL_LINE') {
|
|
41
41
|
return emailLine;
|
|
42
42
|
}
|
|
43
43
|
const normalizedKey = key.toLowerCase();
|
|
44
44
|
const value = ctx[normalizedKey];
|
|
45
|
-
return value ||
|
|
45
|
+
return value || '';
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
export function listSupportedLicenses() {
|
|
@@ -74,19 +74,19 @@ function loadLicenseTemplates() {
|
|
|
74
74
|
if (!stats.isFile()) {
|
|
75
75
|
continue;
|
|
76
76
|
}
|
|
77
|
-
if (path.extname(file).toLowerCase() !==
|
|
77
|
+
if (path.extname(file).toLowerCase() !== '.txt') {
|
|
78
78
|
continue;
|
|
79
79
|
}
|
|
80
80
|
const key = path.basename(file, path.extname(file)).toUpperCase();
|
|
81
|
-
templates[key] = fs.readFileSync(fullPath,
|
|
81
|
+
templates[key] = fs.readFileSync(fullPath, 'utf8');
|
|
82
82
|
}
|
|
83
83
|
cachedTemplates = templates;
|
|
84
84
|
return cachedTemplates;
|
|
85
85
|
}
|
|
86
86
|
function findTemplatesDir() {
|
|
87
87
|
const candidates = [
|
|
88
|
-
path.resolve(__dirname,
|
|
89
|
-
path.resolve(__dirname,
|
|
88
|
+
path.resolve(__dirname, '..', 'licenses-templates'),
|
|
89
|
+
path.resolve(__dirname, 'licenses-templates'),
|
|
90
90
|
];
|
|
91
91
|
for (const candidate of candidates) {
|
|
92
92
|
if (fs.existsSync(candidate)) {
|
|
@@ -98,7 +98,7 @@ function findTemplatesDir() {
|
|
|
98
98
|
function getAnswerValue(answers, keys) {
|
|
99
99
|
for (const key of keys) {
|
|
100
100
|
const value = answers?.[key];
|
|
101
|
-
if (typeof value ===
|
|
101
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
102
102
|
return value;
|
|
103
103
|
}
|
|
104
104
|
}
|
package/esm/template/extract.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import * as fs from
|
|
2
|
-
import * as path from
|
|
3
|
-
const PLACEHOLDER_BOUNDARY =
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
const PLACEHOLDER_BOUNDARY = '____';
|
|
4
4
|
/**
|
|
5
5
|
* Pattern to match ____variable____ in filenames and content
|
|
6
6
|
*/
|
|
7
|
-
const VARIABLE_PATTERN = new RegExp(`${PLACEHOLDER_BOUNDARY}([A-Za-z_][A-Za-z0-9_]*)${PLACEHOLDER_BOUNDARY}`,
|
|
7
|
+
const VARIABLE_PATTERN = new RegExp(`${PLACEHOLDER_BOUNDARY}([A-Za-z_][A-Za-z0-9_]*)${PLACEHOLDER_BOUNDARY}`, 'g');
|
|
8
8
|
/**
|
|
9
9
|
* Extract all variables from a template directory
|
|
10
10
|
* @param templateDir - Path to the template directory
|
|
@@ -18,8 +18,8 @@ export async function extractVariables(templateDir) {
|
|
|
18
18
|
const projectQuestions = await loadProjectQuestions(templateDir);
|
|
19
19
|
await walkDirectory(templateDir, async (filePath) => {
|
|
20
20
|
const relativePath = path.relative(templateDir, filePath);
|
|
21
|
-
if (relativePath ===
|
|
22
|
-
relativePath ===
|
|
21
|
+
if (relativePath === '.questions.json' ||
|
|
22
|
+
relativePath === '.questions.js') {
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
const matches = relativePath.matchAll(VARIABLE_PATTERN);
|
|
@@ -29,7 +29,7 @@ export async function extractVariables(templateDir) {
|
|
|
29
29
|
fileReplacerVars.add(varName);
|
|
30
30
|
fileReplacers.push({
|
|
31
31
|
variable: varName,
|
|
32
|
-
pattern: new RegExp(`${PLACEHOLDER_BOUNDARY}${varName}${PLACEHOLDER_BOUNDARY}`,
|
|
32
|
+
pattern: new RegExp(`${PLACEHOLDER_BOUNDARY}${varName}${PLACEHOLDER_BOUNDARY}`, 'g'),
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -39,7 +39,7 @@ export async function extractVariables(templateDir) {
|
|
|
39
39
|
contentReplacerVars.add(varName);
|
|
40
40
|
contentReplacers.push({
|
|
41
41
|
variable: varName,
|
|
42
|
-
pattern: new RegExp(`${PLACEHOLDER_BOUNDARY}${varName}${PLACEHOLDER_BOUNDARY}`,
|
|
42
|
+
pattern: new RegExp(`${PLACEHOLDER_BOUNDARY}${varName}${PLACEHOLDER_BOUNDARY}`, 'g'),
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -58,12 +58,12 @@ export async function extractVariables(templateDir) {
|
|
|
58
58
|
async function extractFromFileContent(filePath) {
|
|
59
59
|
const variables = new Set();
|
|
60
60
|
return new Promise((resolve) => {
|
|
61
|
-
const stream = fs.createReadStream(filePath, { encoding:
|
|
62
|
-
let buffer =
|
|
63
|
-
stream.on(
|
|
61
|
+
const stream = fs.createReadStream(filePath, { encoding: 'utf8' });
|
|
62
|
+
let buffer = '';
|
|
63
|
+
stream.on('data', (chunk) => {
|
|
64
64
|
buffer += chunk.toString();
|
|
65
|
-
const lines = buffer.split(
|
|
66
|
-
buffer = lines.pop() ||
|
|
65
|
+
const lines = buffer.split('\n');
|
|
66
|
+
buffer = lines.pop() || ''; // Keep the last incomplete line in buffer
|
|
67
67
|
for (const line of lines) {
|
|
68
68
|
const matches = line.matchAll(VARIABLE_PATTERN);
|
|
69
69
|
for (const match of matches) {
|
|
@@ -71,14 +71,14 @@ async function extractFromFileContent(filePath) {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
|
-
stream.on(
|
|
74
|
+
stream.on('end', () => {
|
|
75
75
|
const matches = buffer.matchAll(VARIABLE_PATTERN);
|
|
76
76
|
for (const match of matches) {
|
|
77
77
|
variables.add(match[1]);
|
|
78
78
|
}
|
|
79
79
|
resolve(variables);
|
|
80
80
|
});
|
|
81
|
-
stream.on(
|
|
81
|
+
stream.on('error', () => {
|
|
82
82
|
resolve(variables);
|
|
83
83
|
});
|
|
84
84
|
});
|
|
@@ -106,10 +106,10 @@ async function walkDirectory(dir, callback) {
|
|
|
106
106
|
* @returns Questions object or null if not found
|
|
107
107
|
*/
|
|
108
108
|
async function loadProjectQuestions(templateDir) {
|
|
109
|
-
const jsonPath = path.join(templateDir,
|
|
109
|
+
const jsonPath = path.join(templateDir, '.questions.json');
|
|
110
110
|
if (fs.existsSync(jsonPath)) {
|
|
111
111
|
try {
|
|
112
|
-
const content = fs.readFileSync(jsonPath,
|
|
112
|
+
const content = fs.readFileSync(jsonPath, 'utf8');
|
|
113
113
|
const questions = JSON.parse(content);
|
|
114
114
|
return validateQuestions(questions) ? normalizeQuestions(questions) : null;
|
|
115
115
|
}
|
|
@@ -118,7 +118,7 @@ async function loadProjectQuestions(templateDir) {
|
|
|
118
118
|
console.warn(`Failed to parse .questions.json: ${errorMessage}`);
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
-
const jsPath = path.join(templateDir,
|
|
121
|
+
const jsPath = path.join(templateDir, '.questions.js');
|
|
122
122
|
if (fs.existsSync(jsPath)) {
|
|
123
123
|
try {
|
|
124
124
|
const module = require(jsPath);
|
|
@@ -152,5 +152,5 @@ function normalizeQuestions(questions) {
|
|
|
152
152
|
* @returns True if valid, false otherwise
|
|
153
153
|
*/
|
|
154
154
|
function validateQuestions(obj) {
|
|
155
|
-
return obj && typeof obj ===
|
|
155
|
+
return obj && typeof obj === 'object' && Array.isArray(obj.questions);
|
|
156
156
|
}
|
package/esm/template/prompt.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Inquirerer } from
|
|
2
|
-
const PLACEHOLDER_BOUNDARY =
|
|
1
|
+
import { Inquirerer } from 'inquirerer';
|
|
2
|
+
const PLACEHOLDER_BOUNDARY = '____';
|
|
3
3
|
/**
|
|
4
4
|
* Generate questions from extracted variables
|
|
5
5
|
* @param extractedVariables - Variables extracted from the template
|
|
@@ -20,7 +20,7 @@ export function generateQuestions(extractedVariables) {
|
|
|
20
20
|
if (!askedVariables.has(replacer.variable)) {
|
|
21
21
|
questions.push({
|
|
22
22
|
name: replacer.variable,
|
|
23
|
-
type:
|
|
23
|
+
type: 'text',
|
|
24
24
|
message: `Enter value for ${replacer.variable}:`,
|
|
25
25
|
required: true
|
|
26
26
|
});
|
|
@@ -31,7 +31,7 @@ export function generateQuestions(extractedVariables) {
|
|
|
31
31
|
if (!askedVariables.has(replacer.variable)) {
|
|
32
32
|
questions.push({
|
|
33
33
|
name: replacer.variable,
|
|
34
|
-
type:
|
|
34
|
+
type: 'text',
|
|
35
35
|
message: `Enter value for ${replacer.variable}:`,
|
|
36
36
|
required: true
|
|
37
37
|
});
|
|
@@ -45,7 +45,7 @@ function normalizeQuestionName(name) {
|
|
|
45
45
|
name.endsWith(PLACEHOLDER_BOUNDARY)) {
|
|
46
46
|
return name.slice(PLACEHOLDER_BOUNDARY.length, -PLACEHOLDER_BOUNDARY.length);
|
|
47
47
|
}
|
|
48
|
-
if (name.startsWith(
|
|
48
|
+
if (name.startsWith('__') && name.endsWith('__')) {
|
|
49
49
|
return name.slice(2, -2);
|
|
50
50
|
}
|
|
51
51
|
return name;
|
|
@@ -74,7 +74,7 @@ export async function promptUser(extractedVariables, argv = {}, noTty = false) {
|
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
finally {
|
|
77
|
-
if (typeof prompter.close ===
|
|
77
|
+
if (typeof prompter.close === 'function') {
|
|
78
78
|
prompter.close();
|
|
79
79
|
}
|
|
80
80
|
}
|
package/esm/template/replace.js
CHANGED
|
@@ -62,8 +62,8 @@ async function ensureLicenseFile(outputDir, answers) {
|
|
|
62
62
|
console.warn(`[create-gen-app] License "${selectedLicense}" is not supported by the built-in templates. Leaving template LICENSE file as-is.`);
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
|
-
const author = findLicenseAuthor(answers) ??
|
|
66
|
-
const email = findLicenseEmail(answers) ??
|
|
65
|
+
const author = findLicenseAuthor(answers) ?? 'Unknown Author';
|
|
66
|
+
const email = findLicenseEmail(answers) ?? '';
|
|
67
67
|
const content = renderLicense(selectedLicense, {
|
|
68
68
|
author: String(author),
|
|
69
69
|
email: String(email || ''),
|
package/index.d.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { extractVariables } from
|
|
2
|
-
import { promptUser } from
|
|
3
|
-
import { replaceVariables } from
|
|
4
|
-
import { CreateGenOptions } from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from
|
|
11
|
-
export * from
|
|
12
|
-
export * from
|
|
13
|
-
export * from
|
|
14
|
-
export * from
|
|
15
|
-
export * from
|
|
16
|
-
export * from
|
|
1
|
+
import { extractVariables } from './template/extract';
|
|
2
|
+
import { promptUser } from './template/prompt';
|
|
3
|
+
import { replaceVariables } from './template/replace';
|
|
4
|
+
import { CreateGenOptions } from './types';
|
|
5
|
+
export * from './cache/cache-manager';
|
|
6
|
+
export * from './cache/types';
|
|
7
|
+
export * from './git/git-cloner';
|
|
8
|
+
export * from './git/types';
|
|
9
|
+
export * from './template/templatizer';
|
|
10
|
+
export * from './template/types';
|
|
11
|
+
export * from './utils/npm-version-check';
|
|
12
|
+
export * from './utils/types';
|
|
13
|
+
export * from './template/extract';
|
|
14
|
+
export * from './template/prompt';
|
|
15
|
+
export * from './template/replace';
|
|
16
|
+
export * from './types';
|
|
17
17
|
export { extractVariables, promptUser, replaceVariables };
|
|
18
18
|
/**
|
|
19
19
|
* @deprecated This function is deprecated and will be removed in the next major version.
|
package/licenses.js
CHANGED
|
@@ -44,18 +44,18 @@ const fs = __importStar(require("fs"));
|
|
|
44
44
|
const path = __importStar(require("path"));
|
|
45
45
|
const PLACEHOLDER_PATTERN = /{{(\w+)}}/g;
|
|
46
46
|
let cachedTemplates = null;
|
|
47
|
-
exports.LICENSE_VALUE_KEYS = [
|
|
47
|
+
exports.LICENSE_VALUE_KEYS = ['LICENSE', 'license'];
|
|
48
48
|
exports.LICENSE_AUTHOR_KEYS = [
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
'USERFULLNAME',
|
|
50
|
+
'AUTHOR',
|
|
51
|
+
'AUTHORFULLNAME',
|
|
52
|
+
'USERNAME',
|
|
53
|
+
'fullName',
|
|
54
|
+
'author',
|
|
55
|
+
'authorFullName',
|
|
56
|
+
'userName',
|
|
57
57
|
];
|
|
58
|
-
exports.LICENSE_EMAIL_KEYS = [
|
|
58
|
+
exports.LICENSE_EMAIL_KEYS = ['USEREMAIL', 'EMAIL', 'email', 'userEmail'];
|
|
59
59
|
function isSupportedLicense(name) {
|
|
60
60
|
if (!name) {
|
|
61
61
|
return false;
|
|
@@ -73,18 +73,18 @@ function renderLicense(licenseName, context) {
|
|
|
73
73
|
}
|
|
74
74
|
const ctx = {
|
|
75
75
|
year: context.year ?? new Date().getFullYear().toString(),
|
|
76
|
-
author: context.author ??
|
|
77
|
-
email: context.email ??
|
|
76
|
+
author: context.author ?? 'Unknown Author',
|
|
77
|
+
email: context.email ?? '',
|
|
78
78
|
};
|
|
79
|
-
const emailLine = ctx.email ? ` <${ctx.email}>` :
|
|
79
|
+
const emailLine = ctx.email ? ` <${ctx.email}>` : '';
|
|
80
80
|
return template.replace(PLACEHOLDER_PATTERN, (_, rawKey) => {
|
|
81
81
|
const key = rawKey.toUpperCase();
|
|
82
|
-
if (key ===
|
|
82
|
+
if (key === 'EMAIL_LINE') {
|
|
83
83
|
return emailLine;
|
|
84
84
|
}
|
|
85
85
|
const normalizedKey = key.toLowerCase();
|
|
86
86
|
const value = ctx[normalizedKey];
|
|
87
|
-
return value ||
|
|
87
|
+
return value || '';
|
|
88
88
|
});
|
|
89
89
|
}
|
|
90
90
|
function listSupportedLicenses() {
|
|
@@ -116,19 +116,19 @@ function loadLicenseTemplates() {
|
|
|
116
116
|
if (!stats.isFile()) {
|
|
117
117
|
continue;
|
|
118
118
|
}
|
|
119
|
-
if (path.extname(file).toLowerCase() !==
|
|
119
|
+
if (path.extname(file).toLowerCase() !== '.txt') {
|
|
120
120
|
continue;
|
|
121
121
|
}
|
|
122
122
|
const key = path.basename(file, path.extname(file)).toUpperCase();
|
|
123
|
-
templates[key] = fs.readFileSync(fullPath,
|
|
123
|
+
templates[key] = fs.readFileSync(fullPath, 'utf8');
|
|
124
124
|
}
|
|
125
125
|
cachedTemplates = templates;
|
|
126
126
|
return cachedTemplates;
|
|
127
127
|
}
|
|
128
128
|
function findTemplatesDir() {
|
|
129
129
|
const candidates = [
|
|
130
|
-
path.resolve(__dirname,
|
|
131
|
-
path.resolve(__dirname,
|
|
130
|
+
path.resolve(__dirname, '..', 'licenses-templates'),
|
|
131
|
+
path.resolve(__dirname, 'licenses-templates'),
|
|
132
132
|
];
|
|
133
133
|
for (const candidate of candidates) {
|
|
134
134
|
if (fs.existsSync(candidate)) {
|
|
@@ -140,7 +140,7 @@ function findTemplatesDir() {
|
|
|
140
140
|
function getAnswerValue(answers, keys) {
|
|
141
141
|
for (const key of keys) {
|
|
142
142
|
const value = answers?.[key];
|
|
143
|
-
if (typeof value ===
|
|
143
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
144
144
|
return value;
|
|
145
145
|
}
|
|
146
146
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-gen-app",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"author": "Constructive <
|
|
3
|
+
"version": "0.3.6",
|
|
4
|
+
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "Clone and customize template repositories with variable replacement",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"module": "esm/index.js",
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
"test:watch": "jest --watch"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"appstash": "0.2.
|
|
32
|
-
"inquirerer": "2.1.
|
|
31
|
+
"appstash": "0.2.6",
|
|
32
|
+
"inquirerer": "2.1.14"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"copyfiles": "^2.4.1",
|
|
36
36
|
"makage": "0.1.8"
|
|
37
37
|
},
|
|
38
38
|
"keywords": [],
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "64ad2e12049b05169df7dc7e3bcc401da6f42842"
|
|
40
40
|
}
|
package/template/extract.d.ts
CHANGED
package/template/extract.js
CHANGED
|
@@ -36,11 +36,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.extractVariables = extractVariables;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
|
-
const PLACEHOLDER_BOUNDARY =
|
|
39
|
+
const PLACEHOLDER_BOUNDARY = '____';
|
|
40
40
|
/**
|
|
41
41
|
* Pattern to match ____variable____ in filenames and content
|
|
42
42
|
*/
|
|
43
|
-
const VARIABLE_PATTERN = new RegExp(`${PLACEHOLDER_BOUNDARY}([A-Za-z_][A-Za-z0-9_]*)${PLACEHOLDER_BOUNDARY}`,
|
|
43
|
+
const VARIABLE_PATTERN = new RegExp(`${PLACEHOLDER_BOUNDARY}([A-Za-z_][A-Za-z0-9_]*)${PLACEHOLDER_BOUNDARY}`, 'g');
|
|
44
44
|
/**
|
|
45
45
|
* Extract all variables from a template directory
|
|
46
46
|
* @param templateDir - Path to the template directory
|
|
@@ -54,8 +54,8 @@ async function extractVariables(templateDir) {
|
|
|
54
54
|
const projectQuestions = await loadProjectQuestions(templateDir);
|
|
55
55
|
await walkDirectory(templateDir, async (filePath) => {
|
|
56
56
|
const relativePath = path.relative(templateDir, filePath);
|
|
57
|
-
if (relativePath ===
|
|
58
|
-
relativePath ===
|
|
57
|
+
if (relativePath === '.questions.json' ||
|
|
58
|
+
relativePath === '.questions.js') {
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
61
|
const matches = relativePath.matchAll(VARIABLE_PATTERN);
|
|
@@ -65,7 +65,7 @@ async function extractVariables(templateDir) {
|
|
|
65
65
|
fileReplacerVars.add(varName);
|
|
66
66
|
fileReplacers.push({
|
|
67
67
|
variable: varName,
|
|
68
|
-
pattern: new RegExp(`${PLACEHOLDER_BOUNDARY}${varName}${PLACEHOLDER_BOUNDARY}`,
|
|
68
|
+
pattern: new RegExp(`${PLACEHOLDER_BOUNDARY}${varName}${PLACEHOLDER_BOUNDARY}`, 'g'),
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
}
|
|
@@ -75,7 +75,7 @@ async function extractVariables(templateDir) {
|
|
|
75
75
|
contentReplacerVars.add(varName);
|
|
76
76
|
contentReplacers.push({
|
|
77
77
|
variable: varName,
|
|
78
|
-
pattern: new RegExp(`${PLACEHOLDER_BOUNDARY}${varName}${PLACEHOLDER_BOUNDARY}`,
|
|
78
|
+
pattern: new RegExp(`${PLACEHOLDER_BOUNDARY}${varName}${PLACEHOLDER_BOUNDARY}`, 'g'),
|
|
79
79
|
});
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -94,12 +94,12 @@ async function extractVariables(templateDir) {
|
|
|
94
94
|
async function extractFromFileContent(filePath) {
|
|
95
95
|
const variables = new Set();
|
|
96
96
|
return new Promise((resolve) => {
|
|
97
|
-
const stream = fs.createReadStream(filePath, { encoding:
|
|
98
|
-
let buffer =
|
|
99
|
-
stream.on(
|
|
97
|
+
const stream = fs.createReadStream(filePath, { encoding: 'utf8' });
|
|
98
|
+
let buffer = '';
|
|
99
|
+
stream.on('data', (chunk) => {
|
|
100
100
|
buffer += chunk.toString();
|
|
101
|
-
const lines = buffer.split(
|
|
102
|
-
buffer = lines.pop() ||
|
|
101
|
+
const lines = buffer.split('\n');
|
|
102
|
+
buffer = lines.pop() || ''; // Keep the last incomplete line in buffer
|
|
103
103
|
for (const line of lines) {
|
|
104
104
|
const matches = line.matchAll(VARIABLE_PATTERN);
|
|
105
105
|
for (const match of matches) {
|
|
@@ -107,14 +107,14 @@ async function extractFromFileContent(filePath) {
|
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
|
-
stream.on(
|
|
110
|
+
stream.on('end', () => {
|
|
111
111
|
const matches = buffer.matchAll(VARIABLE_PATTERN);
|
|
112
112
|
for (const match of matches) {
|
|
113
113
|
variables.add(match[1]);
|
|
114
114
|
}
|
|
115
115
|
resolve(variables);
|
|
116
116
|
});
|
|
117
|
-
stream.on(
|
|
117
|
+
stream.on('error', () => {
|
|
118
118
|
resolve(variables);
|
|
119
119
|
});
|
|
120
120
|
});
|
|
@@ -142,10 +142,10 @@ async function walkDirectory(dir, callback) {
|
|
|
142
142
|
* @returns Questions object or null if not found
|
|
143
143
|
*/
|
|
144
144
|
async function loadProjectQuestions(templateDir) {
|
|
145
|
-
const jsonPath = path.join(templateDir,
|
|
145
|
+
const jsonPath = path.join(templateDir, '.questions.json');
|
|
146
146
|
if (fs.existsSync(jsonPath)) {
|
|
147
147
|
try {
|
|
148
|
-
const content = fs.readFileSync(jsonPath,
|
|
148
|
+
const content = fs.readFileSync(jsonPath, 'utf8');
|
|
149
149
|
const questions = JSON.parse(content);
|
|
150
150
|
return validateQuestions(questions) ? normalizeQuestions(questions) : null;
|
|
151
151
|
}
|
|
@@ -154,7 +154,7 @@ async function loadProjectQuestions(templateDir) {
|
|
|
154
154
|
console.warn(`Failed to parse .questions.json: ${errorMessage}`);
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
|
-
const jsPath = path.join(templateDir,
|
|
157
|
+
const jsPath = path.join(templateDir, '.questions.js');
|
|
158
158
|
if (fs.existsSync(jsPath)) {
|
|
159
159
|
try {
|
|
160
160
|
const module = require(jsPath);
|
|
@@ -188,5 +188,5 @@ function normalizeQuestions(questions) {
|
|
|
188
188
|
* @returns True if valid, false otherwise
|
|
189
189
|
*/
|
|
190
190
|
function validateQuestions(obj) {
|
|
191
|
-
return obj && typeof obj ===
|
|
191
|
+
return obj && typeof obj === 'object' && Array.isArray(obj.questions);
|
|
192
192
|
}
|
package/template/prompt.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Question } from
|
|
2
|
-
import { ExtractedVariables } from
|
|
1
|
+
import { Question } from 'inquirerer';
|
|
2
|
+
import { ExtractedVariables } from '../types';
|
|
3
3
|
/**
|
|
4
4
|
* Generate questions from extracted variables
|
|
5
5
|
* @param extractedVariables - Variables extracted from the template
|
package/template/prompt.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.generateQuestions = generateQuestions;
|
|
4
4
|
exports.promptUser = promptUser;
|
|
5
5
|
const inquirerer_1 = require("inquirerer");
|
|
6
|
-
const PLACEHOLDER_BOUNDARY =
|
|
6
|
+
const PLACEHOLDER_BOUNDARY = '____';
|
|
7
7
|
/**
|
|
8
8
|
* Generate questions from extracted variables
|
|
9
9
|
* @param extractedVariables - Variables extracted from the template
|
|
@@ -24,7 +24,7 @@ function generateQuestions(extractedVariables) {
|
|
|
24
24
|
if (!askedVariables.has(replacer.variable)) {
|
|
25
25
|
questions.push({
|
|
26
26
|
name: replacer.variable,
|
|
27
|
-
type:
|
|
27
|
+
type: 'text',
|
|
28
28
|
message: `Enter value for ${replacer.variable}:`,
|
|
29
29
|
required: true
|
|
30
30
|
});
|
|
@@ -35,7 +35,7 @@ function generateQuestions(extractedVariables) {
|
|
|
35
35
|
if (!askedVariables.has(replacer.variable)) {
|
|
36
36
|
questions.push({
|
|
37
37
|
name: replacer.variable,
|
|
38
|
-
type:
|
|
38
|
+
type: 'text',
|
|
39
39
|
message: `Enter value for ${replacer.variable}:`,
|
|
40
40
|
required: true
|
|
41
41
|
});
|
|
@@ -49,7 +49,7 @@ function normalizeQuestionName(name) {
|
|
|
49
49
|
name.endsWith(PLACEHOLDER_BOUNDARY)) {
|
|
50
50
|
return name.slice(PLACEHOLDER_BOUNDARY.length, -PLACEHOLDER_BOUNDARY.length);
|
|
51
51
|
}
|
|
52
|
-
if (name.startsWith(
|
|
52
|
+
if (name.startsWith('__') && name.endsWith('__')) {
|
|
53
53
|
return name.slice(2, -2);
|
|
54
54
|
}
|
|
55
55
|
return name;
|
|
@@ -78,7 +78,7 @@ async function promptUser(extractedVariables, argv = {}, noTty = false) {
|
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
80
|
finally {
|
|
81
|
-
if (typeof prompter.close ===
|
|
81
|
+
if (typeof prompter.close === 'function') {
|
|
82
82
|
prompter.close();
|
|
83
83
|
}
|
|
84
84
|
}
|
package/template/replace.js
CHANGED
|
@@ -98,8 +98,8 @@ async function ensureLicenseFile(outputDir, answers) {
|
|
|
98
98
|
console.warn(`[create-gen-app] License "${selectedLicense}" is not supported by the built-in templates. Leaving template LICENSE file as-is.`);
|
|
99
99
|
return;
|
|
100
100
|
}
|
|
101
|
-
const author = (0, licenses_1.findLicenseAuthor)(answers) ??
|
|
102
|
-
const email = (0, licenses_1.findLicenseEmail)(answers) ??
|
|
101
|
+
const author = (0, licenses_1.findLicenseAuthor)(answers) ?? 'Unknown Author';
|
|
102
|
+
const email = (0, licenses_1.findLicenseEmail)(answers) ?? '';
|
|
103
103
|
const content = (0, licenses_1.renderLicense)(selectedLicense, {
|
|
104
104
|
author: String(author),
|
|
105
105
|
email: String(email || ''),
|