@valbuild/init 0.53.0 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valbuild/init",
3
- "version": "0.53.0",
3
+ "version": "0.55.0",
4
4
  "description": "Initialize a new val.build project",
5
5
  "exports": {
6
6
  "./main": {
@@ -10,6 +10,7 @@
10
10
  "./package.json": "./package.json"
11
11
  },
12
12
  "scripts": {
13
+ "typecheck": "tsc --noEmit",
13
14
  "test": "jest"
14
15
  },
15
16
  "bin": {
package/src/init.ts CHANGED
@@ -51,7 +51,7 @@ function walk(dir: string, skip: RegExp = /node_modules|.git/): string[] {
51
51
  maxResetLength = Math.max(maxResetLength, m.length);
52
52
  process.stdout.write(m + " ".repeat(maxResetLength - m.length));
53
53
  return fs.readdirSync(dir).reduce((files, fileOrDirName) => {
54
- const fileOrDirPath = [dir, fileOrDirName].join("/"); // always use / as path separator - should work on windows as well?
54
+ const fileOrDirPath = [dir, fileOrDirName].join("/"); // always use / as path separator since we are doing .endsWith("/foo/bar.ts") when checking for files and we thought this would make it easier (if you are reading this and wondering wtf, then maybe not :) - should work on windows as well?
55
55
  if (fs.statSync(fileOrDirPath).isDirectory() && !skip.test(fileOrDirName)) {
56
56
  return files.concat(walk(fileOrDirPath));
57
57
  }
@@ -65,8 +65,8 @@ type Analysis = Partial<{
65
65
  srcDir: string;
66
66
  packageJsonDir: string;
67
67
  valConfigPath: string;
68
- isTypescript: boolean;
69
- isJavascript: boolean;
68
+ isTypeScript: boolean;
69
+ isJavaScript: boolean;
70
70
 
71
71
  // Val package:
72
72
  isValInstalled: boolean;
@@ -179,8 +179,8 @@ const analyze = async (root: string, files: string[]): Promise<Analysis> => {
179
179
  files.find((file) => file.endsWith("/pages/_app.jsx"));
180
180
  analysis.pagesRouter = !!pagesRouterAppPath;
181
181
  if (pagesRouterAppPath) {
182
- analysis.isTypescript = !!pagesRouterAppPath.endsWith(".tsx");
183
- analysis.isJavascript = !!pagesRouterAppPath.endsWith(".jsx");
182
+ analysis.isTypeScript = !!pagesRouterAppPath.endsWith(".tsx");
183
+ analysis.isJavaScript = !!pagesRouterAppPath.endsWith(".jsx");
184
184
  analysis.srcDir = path.dirname(path.dirname(pagesRouterAppPath));
185
185
  }
186
186
 
@@ -192,8 +192,8 @@ const analyze = async (root: string, files: string[]): Promise<Analysis> => {
192
192
  analysis.appRouter = true;
193
193
  analysis.appRouterLayoutPath = appRouterLayoutPath;
194
194
  analysis.appRouterLayoutFile = fs.readFileSync(appRouterLayoutPath, "utf8");
195
- analysis.isTypescript = !!appRouterLayoutPath.endsWith(".tsx");
196
- analysis.isJavascript = !!appRouterLayoutPath.endsWith(".jsx");
195
+ analysis.isTypeScript = !!appRouterLayoutPath.endsWith(".tsx");
196
+ analysis.isJavaScript = !!appRouterLayoutPath.endsWith(".jsx");
197
197
  analysis.appRouterPath = path.dirname(appRouterLayoutPath);
198
198
  analysis.srcDir = path.dirname(analysis.appRouterPath);
199
199
  }
@@ -267,10 +267,28 @@ async function plan(
267
267
  logger.error("Install @valbuild/next first");
268
268
  return { abort: true };
269
269
  } else {
270
- logger.info(
271
- ` Val version: found ${analysis.valVersion} >= ${MIN_VAL_VERSION}`,
272
- { isGood: true }
273
- );
270
+ if (!analysis.valVersionIsSatisfied) {
271
+ logger.warn(
272
+ ` This init script expects @valbuild/next >= ${MIN_VAL_VERSION}. Found: ${analysis.valVersion}`
273
+ );
274
+ const answer = !defaultAnswers
275
+ ? await confirm({
276
+ message: "Continue?",
277
+ default: false,
278
+ })
279
+ : false;
280
+ if (!answer) {
281
+ logger.error(
282
+ `Aborted: val version is not satisfied.\n\nInstall the @valbuild/next@${MIN_VAL_VERSION} package with your favorite package manager.\n\nExample:\n\n npm install -D @valbuild/next@${MIN_VAL_VERSION}\n`
283
+ );
284
+ return { abort: true };
285
+ }
286
+ } else {
287
+ logger.info(
288
+ ` Val version: found ${analysis.valVersion} >= ${MIN_VAL_VERSION}`,
289
+ { isGood: true }
290
+ );
291
+ }
274
292
  }
275
293
  if (!analysis.nextVersionIsSatisfied) {
276
294
  logger.error(
@@ -283,17 +301,17 @@ async function plan(
283
301
  { isGood: true }
284
302
  );
285
303
  }
286
- if (analysis.isTypescript) {
304
+ if (analysis.isTypeScript) {
287
305
  logger.info(" Use: TypeScript", { isGood: true });
288
306
  plan.useTypescript = true;
289
307
  }
290
- if (analysis.isJavascript) {
308
+ if (analysis.isJavaScript) {
291
309
  logger.info(" Use: JavaScript", { isGood: true });
292
310
  if (!plan.useTypescript) {
293
311
  plan.useJavascript = true;
294
312
  }
295
313
  }
296
- if (analysis.isTypescript) {
314
+ if (analysis.isTypeScript) {
297
315
  const tsconfigJsonPath = path.join(analysis.root, "tsconfig.json");
298
316
  if (fs.statSync(tsconfigJsonPath).isFile()) {
299
317
  logger.info(" tsconfig.json: found", { isGood: true });
@@ -341,51 +359,6 @@ async function plan(
341
359
  logger.warn(" Git state: dirty");
342
360
  }
343
361
 
344
- if (analysis.valEslintVersion) {
345
- if (analysis.isValEslintRulesConfigured) {
346
- logger.info(" @valbuild/eslint-plugin rules configured", {
347
- isGood: true,
348
- });
349
- } else {
350
- if (analysis.eslintRcJsPath) {
351
- logger.warn(
352
- 'Cannot patch eslint: found .eslintrc.js but can only patch JSON files (at the moment).\nAdd the following to your eslint config:\n\n "extends": ["plugin:@valbuild/recommended"]\n'
353
- );
354
- } else if (analysis.eslintRcJsonPath) {
355
- const answer = !defaultAnswers
356
- ? await confirm({
357
- message:
358
- "Patch eslintrc.json to use the recommended Val eslint rules?",
359
- default: true,
360
- })
361
- : true;
362
- if (answer) {
363
- const currentEslintRc = fs.readFileSync(
364
- analysis.eslintRcJsonPath,
365
- "utf-8"
366
- );
367
- const parsedEslint = JSON.parse(currentEslintRc);
368
- if (typeof parsedEslint !== "object") {
369
- logger.error(
370
- `Could not patch eslint: ${analysis.eslintRcJsonPath} was not an object`
371
- );
372
- return { abort: true };
373
- }
374
- if (typeof parsedEslint.extends === "string") {
375
- parsedEslint.extends = [parsedEslint.extends];
376
- }
377
- parsedEslint.extends = parsedEslint.extends || [];
378
- parsedEslint.extends.push("plugin:@valbuild/recommended");
379
- plan.updateEslint = {
380
- path: analysis.eslintRcJsonPath,
381
- source: JSON.stringify(parsedEslint, null, 2) + "\n",
382
- };
383
- }
384
- } else {
385
- logger.warn("Cannot patch eslint: failed to find eslint config file");
386
- }
387
- }
388
- }
389
362
  if (!analysis.isGitClean) {
390
363
  while (plan.ignoreGitDirty === undefined) {
391
364
  const answer = !defaultAnswers
@@ -397,17 +370,26 @@ async function plan(
397
370
  plan.ignoreGitDirty = answer;
398
371
  if (!answer) {
399
372
  logger.error("Aborted: git state dirty");
400
- return { abort: true, ignoreGitDirty: true };
373
+ return { abort: true };
401
374
  }
402
375
  }
403
376
  }
404
377
 
405
378
  // New required files:
406
- const valConfigPath = path.join(analysis.root, "val.config.ts");
379
+ const valConfigPath = path.join(
380
+ analysis.root,
381
+ analysis.isTypeScript ? "val.config.ts" : "val.config.js"
382
+ );
383
+ if (fs.existsSync(valConfigPath)) {
384
+ logger.error(
385
+ `Aborted: a Val config file: ${valConfigPath} already exists.`
386
+ );
387
+ return { abort: true };
388
+ }
407
389
 
408
390
  plan.createConfigFile = {
409
391
  path: valConfigPath,
410
- source: VAL_CONFIG({}),
392
+ source: VAL_CONFIG(!!analysis.isTypeScript, {}),
411
393
  };
412
394
 
413
395
  const valUtilsDir = path.join(analysis.srcDir, "val");
@@ -418,7 +400,7 @@ async function plan(
418
400
 
419
401
  const valServerPath = path.join(
420
402
  valUtilsDir,
421
- analysis.isTypescript ? "val.server.ts" : "val.server.js"
403
+ analysis.isTypeScript ? "val.server.ts" : "val.server.js"
422
404
  );
423
405
  plan.createValServer = {
424
406
  path: valServerPath,
@@ -433,7 +415,8 @@ async function plan(
433
415
  analysis.appRouterPath || path.join(analysis.srcDir, "app"),
434
416
  "(val)",
435
417
  "val",
436
- analysis.isTypescript ? "page.tsx" : "page.jsx"
418
+ "[[...val]]",
419
+ analysis.isTypeScript ? "page.tsx" : "page.jsx"
437
420
  );
438
421
  const valPageImportPath = path
439
422
  .relative(path.dirname(valAppPagePath), valConfigPath)
@@ -449,7 +432,8 @@ async function plan(
449
432
  "(val)",
450
433
  "api",
451
434
  "val",
452
- analysis.isTypescript ? "router.tsx" : "router.jsx"
435
+ "[[...val]]",
436
+ analysis.isTypeScript ? "router.tsx" : "router.jsx"
453
437
  );
454
438
  const valRouterImportPath = path
455
439
  .relative(path.dirname(valRouterPath), valServerPath)
@@ -473,7 +457,7 @@ async function plan(
473
457
  plan.createValClient = {
474
458
  path: path.join(
475
459
  valUtilsDir,
476
- analysis.isTypescript ? "val.client.ts" : "val.client.js"
460
+ analysis.isTypeScript ? "val.client.ts" : "val.client.js"
477
461
  ),
478
462
  source: VAL_CLIENT(valUtilsImportPath),
479
463
  };
@@ -492,7 +476,7 @@ async function plan(
492
476
  plan.createValRsc = {
493
477
  path: path.join(
494
478
  valUtilsDir,
495
- analysis.isTypescript ? "val.rsc.ts" : "val.rsc.js"
479
+ analysis.isTypeScript ? "val.rsc.ts" : "val.rsc.js"
496
480
  ),
497
481
  source: VAL_SERVER(valUtilsImportPath),
498
482
  };
@@ -501,10 +485,6 @@ async function plan(
501
485
  }
502
486
  }
503
487
 
504
- if (analysis.eslintRcJsPath) {
505
- logger.warn("ESLint config found: " + analysis.eslintRcJsPath);
506
- }
507
-
508
488
  // Patches:
509
489
 
510
490
  const NO_PATCH_WARNING =
@@ -576,6 +556,50 @@ async function plan(
576
556
  logger.warn(NO_PATCH_WARNING);
577
557
  }
578
558
 
559
+ if (analysis.valEslintVersion) {
560
+ if (analysis.isValEslintRulesConfigured) {
561
+ logger.warn(" @valbuild/eslint-plugin rules: already configured");
562
+ } else {
563
+ if (analysis.eslintRcJsPath) {
564
+ logger.warn(
565
+ 'Cannot patch eslint: found .eslintrc.js but can only patch JSON files (at the moment).\nAdd the following to your eslint config:\n\n "extends": ["plugin:@valbuild/recommended"]\n'
566
+ );
567
+ } else if (analysis.eslintRcJsonPath) {
568
+ const answer = !defaultAnswers
569
+ ? await confirm({
570
+ message:
571
+ "Patch eslintrc.json to use the recommended Val eslint rules?",
572
+ default: true,
573
+ })
574
+ : true;
575
+ if (answer) {
576
+ const currentEslintRc = fs.readFileSync(
577
+ analysis.eslintRcJsonPath,
578
+ "utf-8"
579
+ );
580
+ const parsedEslint = JSON.parse(currentEslintRc);
581
+ if (typeof parsedEslint !== "object") {
582
+ logger.error(
583
+ `Could not patch eslint: ${analysis.eslintRcJsonPath} was not an object`
584
+ );
585
+ return { abort: true };
586
+ }
587
+ if (typeof parsedEslint.extends === "string") {
588
+ parsedEslint.extends = [parsedEslint.extends];
589
+ }
590
+ parsedEslint.extends = parsedEslint.extends || [];
591
+ parsedEslint.extends.push("plugin:@valbuild/recommended");
592
+ plan.updateEslint = {
593
+ path: analysis.eslintRcJsonPath,
594
+ source: JSON.stringify(parsedEslint, null, 2) + "\n",
595
+ };
596
+ }
597
+ } else {
598
+ logger.warn("Cannot patch eslint: failed to find eslint config file");
599
+ }
600
+ }
601
+ }
602
+
579
603
  return plan;
580
604
  }
581
605
 
package/src/templates.ts CHANGED
@@ -44,12 +44,14 @@ type ValConfig = {
44
44
  valConfigPath?: string;
45
45
  };
46
46
  export const VAL_CONFIG = (
47
+ isTypeScript: boolean,
47
48
  options: ValConfig
48
49
  ) => `import { initVal } from "@valbuild/next";
49
50
 
50
- const { s, val, config } = initVal(${JSON.stringify(options, null, 2)});
51
+ const { s, c, val, config } = initVal(${JSON.stringify(options, null, 2)});
51
52
 
52
- export { s, val, config };
53
+ ${isTypeScript ? 'export type { t } from "@valbuild/next";' : ""};
54
+ export { s, c, val, config };
53
55
  `;
54
56
 
55
57
  export const VAL_API_ROUTER = (