create-template-project 1.3.3 → 1.5.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "dependencies": {
3
3
  "vite": {
4
- "version": "8.0.10",
4
+ "version": "8.0.11",
5
5
  "description": "Native-ESM powered web dev build tool"
6
6
  },
7
7
  "@vitejs/plugin-react": {
@@ -25,11 +25,11 @@
25
25
  "description": "A tiny JavaScript debugging utility modelled after Node.js core debugging technique."
26
26
  },
27
27
  "@commitlint/cli": {
28
- "version": "20.5.3",
28
+ "version": "21.0.0",
29
29
  "description": "Lint commit messages to ensure they follow conventional commits."
30
30
  },
31
31
  "@commitlint/config-conventional": {
32
- "version": "20.5.3",
32
+ "version": "21.0.0",
33
33
  "description": "Shareable commitlint config enforcing conventional commits."
34
34
  },
35
35
  "@types/debug": {
@@ -37,7 +37,7 @@
37
37
  "description": "TypeScript definitions for debug."
38
38
  },
39
39
  "@types/node": {
40
- "version": "25.6.0",
40
+ "version": "25.6.2",
41
41
  "description": "TypeScript definitions for Node.js."
42
42
  },
43
43
  "@vitest/coverage-v8": {
@@ -53,7 +53,7 @@
53
53
  "description": "Modern native git hooks made easy."
54
54
  },
55
55
  "oxlint": {
56
- "version": "1.62.0",
56
+ "version": "1.63.0",
57
57
  "description": "A JavaScript linter written in Rust."
58
58
  },
59
59
  "oxlint-tsgolint": {
@@ -61,7 +61,7 @@
61
61
  "description": "TypeScript-specific rules for oxlint."
62
62
  },
63
63
  "oxfmt": {
64
- "version": "0.47.0",
64
+ "version": "0.48.0",
65
65
  "description": "High performance JavaScript / TypeScript formatter."
66
66
  },
67
67
  "typescript": {
@@ -93,19 +93,19 @@
93
93
  "description": "TypeScript definitions for Express."
94
94
  },
95
95
  "react": {
96
- "version": "19.2.5",
96
+ "version": "19.2.6",
97
97
  "description": "A JavaScript library for building user interfaces."
98
98
  },
99
99
  "react-dom": {
100
- "version": "19.2.5",
100
+ "version": "19.2.6",
101
101
  "description": "React package for working with the DOM."
102
102
  },
103
103
  "@mui/material": {
104
- "version": "9.0.0",
104
+ "version": "9.0.1",
105
105
  "description": "Material UI components."
106
106
  },
107
107
  "@mui/icons-material": {
108
- "version": "9.0.0",
108
+ "version": "9.0.1",
109
109
  "description": "Material Design icons distributed as SVG React components."
110
110
  },
111
111
  "@emotion/react": {
@@ -141,15 +141,15 @@
141
141
  "description": "tRPC integration for React Query."
142
142
  },
143
143
  "@tanstack/react-query": {
144
- "version": "5.99.0",
144
+ "version": "5.100.9",
145
145
  "description": "Powerful asynchronous state management for TS/JS."
146
146
  },
147
147
  "zod": {
148
- "version": "4.3.6",
148
+ "version": "4.4.3",
149
149
  "description": "TypeScript-first schema validation with static type inference."
150
150
  },
151
151
  "react-router-dom": {
152
- "version": "7.14.2",
152
+ "version": "7.15.0",
153
153
  "description": "Declarative routing for React web applications."
154
154
  },
155
155
  "release-it": {
package/dist/index.js CHANGED
@@ -79,8 +79,8 @@ var githubWorkflowProcessor = (content, { filePath, opts }) => {
79
79
  let playwrightSetup = "";
80
80
  if (template === "web-fullstack" || template === "web-app" || template === "web-vanilla") playwrightSetup = WORKFLOW_PLAYWRIGHT_SETUP;
81
81
  let processed = content.replaceAll("{{installCommand}}", installCommand).replaceAll("# [PM_SETUP]", pmSetup).replaceAll("# [PLAYWRIGHT_SETUP]", playwrightSetup);
82
- processed = processed.replace(/^\s*# \[PM_SETUP\]\s*\n/m, "");
83
- processed = processed.replace(/^\s*# \[PLAYWRIGHT_SETUP\]\s*\n/m, "");
82
+ processed = processed.replace(/^\s*# \[PM_SETUP\]\s*\n/mu, "");
83
+ processed = processed.replace(/^\s*# \[PLAYWRIGHT_SETUP\]\s*\n/mu, "");
84
84
  return processed;
85
85
  };
86
86
  //#endregion
@@ -99,8 +99,8 @@ var tsconfigProcessor = (content, { filePath, opts }) => {
99
99
  if (filePath !== "tsconfig.json") return content;
100
100
  const { template } = opts;
101
101
  let processed = content;
102
- if (template === "web-fullstack" || template === "web-vanilla" || template === "web-app") processed = processed.replace(/\/\* Language and Environment \*\/[\s\S]*?\/\* Strict Type-Checking Options \*\//, `${WEB_ENV}\n\n\t\t/* Strict Type-Checking Options */`);
103
- if (template === "web-fullstack") processed = processed.replace(/"include":\s*\[\s*"src\/\*\*\/\*"\s*\]/, "\"include\": [\"client/src/**/*\", \"server/src/**/*\"]");
102
+ if (template === "web-fullstack" || template === "web-vanilla" || template === "web-app") processed = processed.replace(/\/\* Language and Environment \*\/[\s\S]*?\/\* Strict Type-Checking Options \*\//u, `${WEB_ENV}\n\n\t\t/* Strict Type-Checking Options */`);
103
+ if (template === "web-fullstack") processed = processed.replace(/"include":\s*\[\s*"src\/\*\*\/\*"\s*\]/u, "\"include\": [\"client/src/**/*\", \"server/src/**/*\"]");
104
104
  return processed;
105
105
  };
106
106
  //#endregion
@@ -1073,6 +1073,7 @@ var isFileRequired = (relativePath, type) => {
1073
1073
  ].includes(type);
1074
1074
  return true;
1075
1075
  };
1076
+ var isCustomConfigFile = (relativePath) => relativePath === "oxlint.config.ts" || relativePath === "oxfmt.config.ts";
1076
1077
  var buildSimpleUnifiedDiff = (filePath, before, after) => {
1077
1078
  const beforeLines = before.split("\n");
1078
1079
  const afterLines = after.split("\n");
@@ -1286,6 +1287,14 @@ var generateProject = async (opts) => {
1286
1287
  relativePath = relativePath.slice(1);
1287
1288
  targetPath = path.join(projectDir, relativePath);
1288
1289
  }
1290
+ if (isUpdate && (relativePath === "oxlint.config.ts" || relativePath === "oxfmt.config.ts")) {
1291
+ actions.push({
1292
+ type: "SKIP",
1293
+ path: relativePath,
1294
+ reason: "Custom config file - preserved on update"
1295
+ });
1296
+ continue;
1297
+ }
1289
1298
  if (relativePath === "package.json") continue;
1290
1299
  const finalTargetPath = targetPath;
1291
1300
  const finalRelativePath = relativePath;
@@ -1306,21 +1315,28 @@ var generateProject = async (opts) => {
1306
1315
  };
1307
1316
  actions.push(action);
1308
1317
  pendingOperations.push(async () => {
1309
- const result = await mergeFile(finalTargetPath, existingContent, content, log);
1310
- if (result === "merged") {
1311
- action.type = "MERGE";
1312
- action.reason = "Merged template updates with your manual changes";
1313
- action.recommendedAction = "Review changes for correct integration";
1314
- log.info(`ℹ Merged: ${finalRelativePath}`);
1315
- } else if (result === "conflict") {
1316
- action.type = "CONFLICT";
1317
- action.reason = "Conflicting changes between template and your code";
1318
- action.recommendedAction = "Resolve git conflict markers in this file";
1319
- log.warn(`⚠ Conflict: ${finalRelativePath}`);
1320
- } else if (result === "updated") {
1318
+ if (finalRelativePath === "oxc.config.ts") {
1319
+ await fs.writeFile(finalTargetPath, content);
1321
1320
  action.type = "UPDATED";
1322
- action.reason = "File was updated to the latest template version";
1321
+ action.reason = "Default config was updated to the latest template version";
1323
1322
  log.info(`✔ Updated: ${finalRelativePath}`);
1323
+ } else {
1324
+ const result = await mergeFile(finalTargetPath, existingContent, content, log);
1325
+ if (result === "merged") {
1326
+ action.type = "MERGE";
1327
+ action.reason = "Merged template updates with your manual changes";
1328
+ action.recommendedAction = "Review changes for correct integration";
1329
+ log.info(`ℹ Merged: ${finalRelativePath}`);
1330
+ } else if (result === "conflict") {
1331
+ action.type = "CONFLICT";
1332
+ action.reason = "Conflicting changes between template and your code";
1333
+ action.recommendedAction = "Resolve git conflict markers in this file";
1334
+ log.warn(`⚠ Conflict: ${finalRelativePath}`);
1335
+ } else if (result === "updated") {
1336
+ action.type = "UPDATED";
1337
+ action.reason = "File was updated to the latest template version";
1338
+ log.info(`✔ Updated: ${finalRelativePath}`);
1339
+ }
1324
1340
  }
1325
1341
  });
1326
1342
  }
@@ -1354,6 +1370,14 @@ var generateProject = async (opts) => {
1354
1370
  });
1355
1371
  continue;
1356
1372
  }
1373
+ if (isUpdate && isCustomConfigFile(file.path)) {
1374
+ actions.push({
1375
+ type: "SKIP",
1376
+ path: file.path,
1377
+ reason: "Custom config file - preserved on update"
1378
+ });
1379
+ continue;
1380
+ }
1357
1381
  if (!isFileRequired(file.path, type)) {
1358
1382
  if (isUpdate && await pathExists(targetPath)) {
1359
1383
  actions.push({
@@ -1385,21 +1409,28 @@ var generateProject = async (opts) => {
1385
1409
  };
1386
1410
  actions.push(action);
1387
1411
  pendingOperations.push(async () => {
1388
- const result = await mergeFile(targetPath, existingContent, content, log);
1389
- if (result === "merged") {
1390
- action.type = "MERGE";
1391
- action.reason = "Merged template updates with your manual changes";
1392
- action.recommendedAction = "Review changes for correct integration";
1393
- log.info(`ℹ Merged: ${file.path}`);
1394
- } else if (result === "conflict") {
1395
- action.type = "CONFLICT";
1396
- action.reason = "Conflicting changes between template and your code";
1397
- action.recommendedAction = "Resolve git conflict markers in this file";
1398
- log.warn(`⚠ Conflict: ${file.path}`);
1399
- } else if (result === "updated") {
1412
+ if (file.path === "oxc.config.ts") {
1413
+ await fs.writeFile(targetPath, content);
1400
1414
  action.type = "UPDATED";
1401
- action.reason = "File was updated to the latest template version";
1415
+ action.reason = "Default config was updated to the latest template version";
1402
1416
  log.info(`✔ Updated: ${file.path}`);
1417
+ } else {
1418
+ const result = await mergeFile(targetPath, existingContent, content, log);
1419
+ if (result === "merged") {
1420
+ action.type = "MERGE";
1421
+ action.reason = "Merged template updates with your manual changes";
1422
+ action.recommendedAction = "Review changes for correct integration";
1423
+ log.info(`ℹ Merged: ${file.path}`);
1424
+ } else if (result === "conflict") {
1425
+ action.type = "CONFLICT";
1426
+ action.reason = "Conflicting changes between template and your code";
1427
+ action.recommendedAction = "Resolve git conflict markers in this file";
1428
+ log.warn(`⚠ Conflict: ${file.path}`);
1429
+ } else if (result === "updated") {
1430
+ action.type = "UPDATED";
1431
+ action.reason = "File was updated to the latest template version";
1432
+ log.info(`✔ Updated: ${file.path}`);
1433
+ }
1403
1434
  }
1404
1435
  });
1405
1436
  }
@@ -65,6 +65,10 @@ export const linter = defineConfig({
65
65
  'eslint/sort-imports': 'off',
66
66
  'eslint/sort-keys': 'off',
67
67
  'eslint/no-ternary': 'off',
68
+ 'eslint/no-void': ['error', {allowAsStatement: true}],
69
+ 'typescript/consistent-type-definitions': ['error', 'type'],
70
+ 'typescript/dot-notation': ['error', {allowPattern: '^[a-zA-Z]+(_[a-zA-Z]+)+$'}],
71
+ 'typescript/no-import-type-side-effects': 'off',
68
72
  'typescript/no-unused-vars': [
69
73
  'error',
70
74
  {
@@ -72,8 +76,6 @@ export const linter = defineConfig({
72
76
  argsIgnorePattern: '^_',
73
77
  },
74
78
  ],
75
- 'typescript/consistent-type-definitions': ['error', 'type'],
76
- 'typescript/no-import-type-side-effects': 'off',
77
79
  'typescript/prefer-readonly-parameter-types': 'off',
78
80
  'import/consistent-type-specifier-style': ['error', 'prefer-inline'],
79
81
  'import/exports-last': 'off',
@@ -151,6 +153,7 @@ export const linter = defineConfig({
151
153
  'unicorn/no-array-sort': 'off', // TODO: consider enabling
152
154
  'unicorn/no-hex-escape': 'off',
153
155
  'unicorn/no-immediate-mutation': 'off',
156
+ 'unicorn/no-negated-condition': 'off',
154
157
  'unicorn/no-nested-ternary': 'off',
155
158
  'unicorn/no-null': 'off', // TODO: consider enabling
156
159
  'unicorn/no-process-exit': 'off', // TODO: consider enabling
@@ -165,8 +168,10 @@ export const linter = defineConfig({
165
168
  'vitest/no-importing-vitest-globals': 'off',
166
169
  'vitest/prefer-describe-function-title': 'off',
167
170
  'vitest/prefer-expect-assertions': 'off',
171
+ 'vitest/prefer-lowercase-title': 'off',
168
172
  'vitest/prefer-to-be-falsy': 'off', // NOTE: Pick strictness: keep prefer-strict-boolean-matchers, disable truthy/falsy rules.
169
173
  'vitest/prefer-to-be-truthy': 'off', // NOTE: Pick strictness: keep prefer-strict-boolean-matchers, disable truthy/falsy rules.
174
+ 'vitest/require-hook': 'off',
170
175
  'vitest/require-test-timeout': 'off',
171
176
  },
172
177
  overrides: [
@@ -1,2 +1,9 @@
1
- import {formatter} from './oxc.config.ts';
2
- export default formatter;
1
+ import {formatter as defaults} from './oxc.config.ts';
2
+
3
+ // Add custom oxfmt formatter overrides here.
4
+ // This file is preserved on template updates.
5
+ const formatter: Partial<typeof defaults> = {};
6
+
7
+ const config = {...defaults, ...formatter};
8
+
9
+ export default config;
@@ -1,2 +1,18 @@
1
- import {linter} from './oxc.config.ts';
2
- export default linter;
1
+ import {linter as defaults} from './oxc.config.ts';
2
+
3
+ // Add custom oxlint rule overrides here.
4
+ // This file is preserved on template updates.
5
+ //
6
+ // Example:
7
+ // rules: { 'no-console': 'off' }
8
+ // overrides: [{ files: ['scripts/**'], rules: { 'no-console': 'off' } }]
9
+ const rules: Partial<typeof defaults.rules> = {};
10
+ const overrides: Partial<NonNullable<typeof defaults.overrides>[number]>[] = [];
11
+
12
+ const config = {
13
+ ...defaults,
14
+ rules: {...defaults.rules, ...rules},
15
+ overrides: [...(defaults.overrides ?? []), ...overrides],
16
+ };
17
+
18
+ export default config;
@@ -6,6 +6,6 @@ import {App} from './App.js';
6
6
  describe('App', () => {
7
7
  it('renders hello message in the browser', async () => {
8
8
  await render(<App />);
9
- await expect.element(page.getByText(/Hello from React!/i)).toBeVisible();
9
+ await expect.element(page.getByText(/Hello from React!/iu)).toBeVisible();
10
10
  });
11
11
  });
@@ -2,7 +2,7 @@ import {test, expect} from '@playwright/test';
2
2
 
3
3
  test('has title', async ({page}) => {
4
4
  await page.goto('/');
5
- await expect(page).toHaveTitle(/{{projectName}}/);
5
+ await expect(page).toHaveTitle(/{{projectName}}/u);
6
6
  });
7
7
 
8
8
  test('api is reachable', async ({page}) => {
@@ -6,6 +6,6 @@ import {App} from './App.js';
6
6
  describe('App', () => {
7
7
  it('should render in the browser', async () => {
8
8
  await render(<App />);
9
- await expect.element(page.getByRole('heading', {name: /Login/i}).or(page.getByRole('heading', {name: /Dashboard/i}))).toBeVisible();
9
+ await expect.element(page.getByRole('heading', {name: /Login/iu}).or(page.getByRole('heading', {name: /Dashboard/iu}))).toBeVisible();
10
10
  });
11
11
  });
@@ -23,6 +23,6 @@ describe('auth router', () => {
23
23
  email: 'wrong@example.com',
24
24
  password: 'password123',
25
25
  }),
26
- ).rejects.toThrow(/Invalid email or password/);
26
+ ).rejects.toThrow(/Invalid email or password/u);
27
27
  });
28
28
  });
@@ -2,7 +2,7 @@ import {test, expect} from '@playwright/test';
2
2
 
3
3
  test('has title', async ({page}) => {
4
4
  await page.goto('/');
5
- await expect(page).toHaveTitle(/{{projectName}}/);
5
+ await expect(page).toHaveTitle(/{{projectName}}/u);
6
6
  });
7
7
 
8
8
  test('can login', async ({page}) => {
@@ -2,7 +2,7 @@ import {test, expect} from '@playwright/test';
2
2
 
3
3
  test('has title', async ({page}) => {
4
4
  await page.goto('/');
5
- await expect(page).toHaveTitle(/{{projectName}}/);
5
+ await expect(page).toHaveTitle(/{{projectName}}/u);
6
6
  });
7
7
 
8
8
  test('header is visible', async ({page}) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-template-project",
3
- "version": "1.3.3",
3
+ "version": "1.5.0",
4
4
  "private": false,
5
5
  "description": "An ultra-modular, type-safe Node.js CLI tool used to scaffold new project templates (CLI, Webpage, Webapp, Fullstack) with best-practice configurations pre-installed.",
6
6
  "keywords": [
@@ -56,27 +56,26 @@
56
56
  "commander": "14.0.3",
57
57
  "debug": "4.4.3",
58
58
  "execa": "9.6.1",
59
- "zod": "4.4.2"
59
+ "zod": "4.4.3"
60
60
  },
61
61
  "devDependencies": {
62
- "@commitlint/cli": "20.5.3",
63
- "@commitlint/config-conventional": "20.5.3",
62
+ "@commitlint/cli": "21.0.0",
63
+ "@commitlint/config-conventional": "21.0.0",
64
64
  "@types/cli-progress": "3.11.6",
65
65
  "@types/debug": "4.1.13",
66
- "@types/node": "25.6.0",
66
+ "@types/node": "25.6.2",
67
67
  "@vitest/coverage-v8": "4.1.5",
68
68
  "conventional-changelog": "7.2.0",
69
69
  "conventional-changelog-angular": "8.3.1",
70
70
  "eslint-plugin-regexp": "3.1.0",
71
71
  "husky": "9.1.7",
72
- "oxfmt": "0.47.0",
73
- "oxlint": "1.62.0",
72
+ "oxfmt": "0.48.0",
73
+ "oxlint": "1.63.0",
74
74
  "oxlint-tsgolint": "0.22.1",
75
- "pnpm": "11.0.3",
76
75
  "release-it": "20.0.1",
77
76
  "rimraf": "6.1.3",
78
77
  "typescript": "6.0.3",
79
- "vite": "8.0.10",
78
+ "vite": "8.0.11",
80
79
  "vitest": "4.1.5"
81
80
  },
82
81
  "engines": {