create-forgeon 0.2.2 → 0.2.3

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.
@@ -1,6 +1,15 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { copyRecursive, writeJson } from '../utils/fs.mjs';
4
+ import {
5
+ ensureBuildSteps,
6
+ ensureDependency,
7
+ ensureLineAfter,
8
+ ensureLineBefore,
9
+ ensureLoadItem,
10
+ ensureValidatorSchema,
11
+ upsertEnvLines,
12
+ } from './shared/patch-utils.mjs';
4
13
 
5
14
  function copyFromPreset(packageRoot, targetRoot, relativePath) {
6
15
  const source = path.join(packageRoot, 'templates', 'module-presets', 'logger', relativePath);
@@ -11,108 +20,6 @@ function copyFromPreset(packageRoot, targetRoot, relativePath) {
11
20
  copyRecursive(source, destination);
12
21
  }
13
22
 
14
- function ensureDependency(packageJson, name, version) {
15
- if (!packageJson.dependencies) {
16
- packageJson.dependencies = {};
17
- }
18
- packageJson.dependencies[name] = version;
19
- }
20
-
21
- function ensureLineAfter(content, anchorLine, lineToInsert) {
22
- if (content.includes(lineToInsert)) {
23
- return content;
24
- }
25
-
26
- const index = content.indexOf(anchorLine);
27
- if (index < 0) {
28
- return `${content.trimEnd()}\n${lineToInsert}\n`;
29
- }
30
-
31
- const insertAt = index + anchorLine.length;
32
- return `${content.slice(0, insertAt)}\n${lineToInsert}${content.slice(insertAt)}`;
33
- }
34
-
35
- function ensureLineBefore(content, anchorLine, lineToInsert) {
36
- if (content.includes(lineToInsert)) {
37
- return content;
38
- }
39
-
40
- const index = content.indexOf(anchorLine);
41
- if (index < 0) {
42
- return `${content.trimEnd()}\n${lineToInsert}\n`;
43
- }
44
-
45
- return `${content.slice(0, index)}${lineToInsert}\n${content.slice(index)}`;
46
- }
47
-
48
- function upsertEnvLines(filePath, lines) {
49
- let content = '';
50
- if (fs.existsSync(filePath)) {
51
- content = fs.readFileSync(filePath, 'utf8').replace(/\r\n/g, '\n');
52
- }
53
-
54
- const keys = new Set(
55
- content
56
- .split('\n')
57
- .filter(Boolean)
58
- .map((line) => line.split('=')[0]),
59
- );
60
-
61
- const append = [];
62
- for (const line of lines) {
63
- const key = line.split('=')[0];
64
- if (!keys.has(key)) {
65
- append.push(line);
66
- }
67
- }
68
-
69
- const next =
70
- append.length > 0 ? `${content.trimEnd()}\n${append.join('\n')}\n` : `${content.trimEnd()}\n`;
71
- fs.writeFileSync(filePath, next.replace(/^\n/, ''), 'utf8');
72
- }
73
-
74
- function ensureLoadItem(content, itemName) {
75
- const pattern = /load:\s*\[([^\]]*)\]/m;
76
- const match = content.match(pattern);
77
- if (!match) {
78
- return content;
79
- }
80
-
81
- const rawList = match[1];
82
- const items = rawList
83
- .split(',')
84
- .map((item) => item.trim())
85
- .filter(Boolean);
86
-
87
- if (!items.includes(itemName)) {
88
- items.push(itemName);
89
- }
90
-
91
- const next = `load: [${items.join(', ')}]`;
92
- return content.replace(pattern, next);
93
- }
94
-
95
- function ensureValidatorSchema(content, schemaName) {
96
- const pattern = /validate:\s*createEnvValidator\(\[([^\]]*)\]\)/m;
97
- const match = content.match(pattern);
98
- if (!match) {
99
- return content;
100
- }
101
-
102
- const rawList = match[1];
103
- const items = rawList
104
- .split(',')
105
- .map((item) => item.trim())
106
- .filter(Boolean);
107
-
108
- if (!items.includes(schemaName)) {
109
- items.push(schemaName);
110
- }
111
-
112
- const next = `validate: createEnvValidator([${items.join(', ')}])`;
113
- return content.replace(pattern, next);
114
- }
115
-
116
23
  function patchApiPackage(targetRoot) {
117
24
  const packagePath = path.join(targetRoot, 'apps', 'api', 'package.json');
118
25
  if (!fs.existsSync(packagePath)) {
@@ -124,22 +31,7 @@ function patchApiPackage(targetRoot) {
124
31
  packageJson.scripts = {};
125
32
  }
126
33
 
127
- const loggerBuild = 'pnpm --filter @forgeon/logger build';
128
- const currentPredev = packageJson.scripts.predev;
129
- if (typeof currentPredev === 'string') {
130
- if (!currentPredev.includes(loggerBuild)) {
131
- if (currentPredev.includes('pnpm --filter @forgeon/core build')) {
132
- packageJson.scripts.predev = currentPredev.replace(
133
- 'pnpm --filter @forgeon/core build',
134
- `pnpm --filter @forgeon/core build && ${loggerBuild}`,
135
- );
136
- } else {
137
- packageJson.scripts.predev = `${loggerBuild} && ${currentPredev}`;
138
- }
139
- }
140
- } else {
141
- packageJson.scripts.predev = loggerBuild;
142
- }
34
+ ensureBuildSteps(packageJson, 'predev', ['pnpm --filter @forgeon/logger build']);
143
35
 
144
36
  ensureDependency(packageJson, '@forgeon/logger', 'workspace:*');
145
37
  writeJson(packagePath, packageJson);
@@ -0,0 +1,162 @@
1
+ import fs from 'node:fs';
2
+
3
+ export function ensureDependency(packageJson, name, version) {
4
+ if (!packageJson.dependencies) {
5
+ packageJson.dependencies = {};
6
+ }
7
+ packageJson.dependencies[name] = version;
8
+ }
9
+
10
+ export function ensureDevDependency(packageJson, name, version) {
11
+ if (!packageJson.devDependencies) {
12
+ packageJson.devDependencies = {};
13
+ }
14
+ packageJson.devDependencies[name] = version;
15
+ }
16
+
17
+ export function ensureScript(packageJson, name, command) {
18
+ if (!packageJson.scripts) {
19
+ packageJson.scripts = {};
20
+ }
21
+ packageJson.scripts[name] = command;
22
+ }
23
+
24
+ export function ensureBuildSteps(packageJson, scriptName, requiredCommands) {
25
+ if (!packageJson.scripts) {
26
+ packageJson.scripts = {};
27
+ }
28
+
29
+ const current = packageJson.scripts[scriptName];
30
+ const steps =
31
+ typeof current === 'string' && current.trim().length > 0
32
+ ? current
33
+ .split('&&')
34
+ .map((item) => item.trim())
35
+ .filter(Boolean)
36
+ : [];
37
+
38
+ for (const command of requiredCommands) {
39
+ if (!steps.includes(command)) {
40
+ steps.push(command);
41
+ }
42
+ }
43
+
44
+ if (steps.length > 0) {
45
+ packageJson.scripts[scriptName] = steps.join(' && ');
46
+ }
47
+ }
48
+
49
+ export function ensureLineAfter(content, anchorLine, lineToInsert) {
50
+ if (content.includes(lineToInsert)) {
51
+ return content;
52
+ }
53
+
54
+ const index = content.indexOf(anchorLine);
55
+ if (index < 0) {
56
+ return `${content.trimEnd()}\n${lineToInsert}\n`;
57
+ }
58
+
59
+ const insertAt = index + anchorLine.length;
60
+ return `${content.slice(0, insertAt)}\n${lineToInsert}${content.slice(insertAt)}`;
61
+ }
62
+
63
+ export function ensureLineBefore(content, anchorLine, lineToInsert) {
64
+ if (content.includes(lineToInsert)) {
65
+ return content;
66
+ }
67
+
68
+ const index = content.indexOf(anchorLine);
69
+ if (index < 0) {
70
+ return `${content.trimEnd()}\n${lineToInsert}\n`;
71
+ }
72
+
73
+ return `${content.slice(0, index)}${lineToInsert}\n${content.slice(index)}`;
74
+ }
75
+
76
+ export function upsertEnvLines(filePath, lines) {
77
+ let content = '';
78
+ if (fs.existsSync(filePath)) {
79
+ content = fs.readFileSync(filePath, 'utf8').replace(/\r\n/g, '\n');
80
+ }
81
+
82
+ const keys = new Set(
83
+ content
84
+ .split('\n')
85
+ .filter(Boolean)
86
+ .map((line) => line.split('=')[0]),
87
+ );
88
+
89
+ const append = [];
90
+ for (const line of lines) {
91
+ const key = line.split('=')[0];
92
+ if (!keys.has(key)) {
93
+ append.push(line);
94
+ }
95
+ }
96
+
97
+ const next =
98
+ append.length > 0 ? `${content.trimEnd()}\n${append.join('\n')}\n` : `${content.trimEnd()}\n`;
99
+ fs.writeFileSync(filePath, next.replace(/^\n/, ''), 'utf8');
100
+ }
101
+
102
+ export function ensureLoadItem(content, itemName) {
103
+ const pattern = /load:\s*\[([^\]]*)\]/m;
104
+ const match = content.match(pattern);
105
+ if (!match) {
106
+ return content;
107
+ }
108
+
109
+ const rawList = match[1];
110
+ const items = rawList
111
+ .split(',')
112
+ .map((item) => item.trim())
113
+ .filter(Boolean);
114
+
115
+ if (!items.includes(itemName)) {
116
+ items.push(itemName);
117
+ }
118
+
119
+ const next = `load: [${items.join(', ')}]`;
120
+ return content.replace(pattern, next);
121
+ }
122
+
123
+ export function ensureValidatorSchema(content, schemaName) {
124
+ const pattern = /validate:\s*createEnvValidator\(\[([^\]]*)\]\)/m;
125
+ const match = content.match(pattern);
126
+ if (!match) {
127
+ return content;
128
+ }
129
+
130
+ const rawList = match[1];
131
+ const items = rawList
132
+ .split(',')
133
+ .map((item) => item.trim())
134
+ .filter(Boolean);
135
+
136
+ if (!items.includes(schemaName)) {
137
+ items.push(schemaName);
138
+ }
139
+
140
+ const next = `validate: createEnvValidator([${items.join(', ')}])`;
141
+ return content.replace(pattern, next);
142
+ }
143
+
144
+ export function ensureNestCommonImport(content, importName) {
145
+ const pattern = /import\s*\{([^}]*)\}\s*from '@nestjs\/common';/m;
146
+ const match = content.match(pattern);
147
+ if (!match) {
148
+ return `import { ${importName} } from '@nestjs/common';\n${content}`;
149
+ }
150
+
151
+ const names = match[1]
152
+ .split(',')
153
+ .map((item) => item.trim())
154
+ .filter(Boolean);
155
+
156
+ if (!names.includes(importName)) {
157
+ names.push(importName);
158
+ }
159
+
160
+ const replacement = `import { ${names.join(', ')} } from '@nestjs/common';`;
161
+ return content.replace(pattern, replacement);
162
+ }
@@ -1,6 +1,15 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { copyRecursive, writeJson } from '../utils/fs.mjs';
4
+ import {
5
+ ensureBuildSteps,
6
+ ensureDependency,
7
+ ensureLineAfter,
8
+ ensureLineBefore,
9
+ ensureLoadItem,
10
+ ensureValidatorSchema,
11
+ upsertEnvLines,
12
+ } from './shared/patch-utils.mjs';
4
13
 
5
14
  function copyFromPreset(packageRoot, targetRoot, relativePath) {
6
15
  const source = path.join(packageRoot, 'templates', 'module-presets', 'swagger', relativePath);
@@ -11,126 +20,6 @@ function copyFromPreset(packageRoot, targetRoot, relativePath) {
11
20
  copyRecursive(source, destination);
12
21
  }
13
22
 
14
- function ensureDependency(packageJson, name, version) {
15
- if (!packageJson.dependencies) {
16
- packageJson.dependencies = {};
17
- }
18
- packageJson.dependencies[name] = version;
19
- }
20
-
21
- function ensureLineAfter(content, anchorLine, lineToInsert) {
22
- if (content.includes(lineToInsert)) {
23
- return content;
24
- }
25
-
26
- const index = content.indexOf(anchorLine);
27
- if (index < 0) {
28
- return `${content.trimEnd()}\n${lineToInsert}\n`;
29
- }
30
-
31
- const insertAt = index + anchorLine.length;
32
- return `${content.slice(0, insertAt)}\n${lineToInsert}${content.slice(insertAt)}`;
33
- }
34
-
35
- function ensureLineBefore(content, anchorLine, lineToInsert) {
36
- if (content.includes(lineToInsert)) {
37
- return content;
38
- }
39
-
40
- const index = content.indexOf(anchorLine);
41
- if (index < 0) {
42
- return `${content.trimEnd()}\n${lineToInsert}\n`;
43
- }
44
-
45
- return `${content.slice(0, index)}${lineToInsert}\n${content.slice(index)}`;
46
- }
47
-
48
- function upsertEnvLines(filePath, lines) {
49
- let content = '';
50
- if (fs.existsSync(filePath)) {
51
- content = fs.readFileSync(filePath, 'utf8').replace(/\r\n/g, '\n');
52
- }
53
-
54
- const keys = new Set(
55
- content
56
- .split('\n')
57
- .filter(Boolean)
58
- .map((line) => line.split('=')[0]),
59
- );
60
-
61
- const append = [];
62
- for (const line of lines) {
63
- const key = line.split('=')[0];
64
- if (!keys.has(key)) {
65
- append.push(line);
66
- }
67
- }
68
-
69
- const next =
70
- append.length > 0 ? `${content.trimEnd()}\n${append.join('\n')}\n` : `${content.trimEnd()}\n`;
71
- fs.writeFileSync(filePath, next.replace(/^\n/, ''), 'utf8');
72
- }
73
-
74
- function ensureBuildStep(packageJson, buildCommand) {
75
- if (!packageJson.scripts) {
76
- packageJson.scripts = {};
77
- }
78
-
79
- const current = packageJson.scripts.predev;
80
- if (typeof current !== 'string' || current.trim().length === 0) {
81
- packageJson.scripts.predev = buildCommand;
82
- return;
83
- }
84
-
85
- if (current.includes(buildCommand)) {
86
- return;
87
- }
88
-
89
- packageJson.scripts.predev = `${buildCommand} && ${current}`;
90
- }
91
-
92
- function ensureLoadItem(content, itemName) {
93
- const pattern = /load:\s*\[([^\]]*)\]/m;
94
- const match = content.match(pattern);
95
- if (!match) {
96
- return content;
97
- }
98
-
99
- const rawList = match[1];
100
- const items = rawList
101
- .split(',')
102
- .map((item) => item.trim())
103
- .filter(Boolean);
104
-
105
- if (!items.includes(itemName)) {
106
- items.push(itemName);
107
- }
108
-
109
- const next = `load: [${items.join(', ')}]`;
110
- return content.replace(pattern, next);
111
- }
112
-
113
- function ensureValidatorSchema(content, schemaName) {
114
- const pattern = /validate:\s*createEnvValidator\(\[([^\]]*)\]\)/m;
115
- const match = content.match(pattern);
116
- if (!match) {
117
- return content;
118
- }
119
-
120
- const rawList = match[1];
121
- const items = rawList
122
- .split(',')
123
- .map((item) => item.trim())
124
- .filter(Boolean);
125
-
126
- if (!items.includes(schemaName)) {
127
- items.push(schemaName);
128
- }
129
-
130
- const next = `validate: createEnvValidator([${items.join(', ')}])`;
131
- return content.replace(pattern, next);
132
- }
133
-
134
23
  function patchApiPackage(targetRoot) {
135
24
  const packagePath = path.join(targetRoot, 'apps', 'api', 'package.json');
136
25
  if (!fs.existsSync(packagePath)) {
@@ -139,7 +28,7 @@ function patchApiPackage(targetRoot) {
139
28
 
140
29
  const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
141
30
  ensureDependency(packageJson, '@forgeon/swagger', 'workspace:*');
142
- ensureBuildStep(packageJson, 'pnpm --filter @forgeon/swagger build');
31
+ ensureBuildSteps(packageJson, 'predev', ['pnpm --filter @forgeon/swagger build']);
143
32
  writeJson(packagePath, packageJson);
144
33
  }
145
34