@valbuild/init 0.51.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/src/init.ts ADDED
@@ -0,0 +1,611 @@
1
+ import chalk from "chalk";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import simpleGit from "simple-git";
5
+ import { confirm } from "@inquirer/prompts";
6
+ import { transformNextAppRouterValProvider } from "./codemods/transformNextAppRouterValProvider";
7
+ import { diffLines } from "diff";
8
+ import jcs from "jscodeshift";
9
+ import semver from "semver";
10
+ import packageJson from "../package.json";
11
+ import {
12
+ VAL_API_ROUTER,
13
+ VAL_APP_PAGE,
14
+ VAL_CLIENT,
15
+ VAL_CONFIG,
16
+ VAL_SERVER,
17
+ } from "./templates";
18
+ import * as logger from "./logger";
19
+
20
+ const MIN_VAL_VERSION = packageJson.version;
21
+ const MIN_NEXT_VERSION = "13.4.0";
22
+
23
+ let maxResetLength = 0;
24
+ export async function init(
25
+ root: string = process.cwd(),
26
+ { yes: defaultAnswers }: { yes?: boolean } = {}
27
+ ) {
28
+ logger.info('Initializing Val in "' + root + '"...\n');
29
+ process.stdout.write("Analyzing project...");
30
+ const analysis = await analyze(path.resolve(root), walk(path.resolve(root)));
31
+ // reset cursor:
32
+ process.stdout.write("\x1b[0G");
33
+ logger.info("Analysis:" + " ".repeat(maxResetLength));
34
+
35
+ const currentPlan = await plan(analysis, defaultAnswers);
36
+ if (currentPlan.abort) {
37
+ return;
38
+ }
39
+
40
+ await execute(currentPlan);
41
+ }
42
+
43
+ const sep = "/";
44
+ function walk(dir: string, skip: RegExp = /node_modules|.git/): string[] {
45
+ if (!fs.existsSync(dir)) return [];
46
+ process.stdout.write("\x1b[0G");
47
+ const m =
48
+ "Analyzing project... " +
49
+ (dir.length > 30 ? "..." : "") +
50
+ dir.slice(Math.max(dir.length - 30, 0));
51
+ maxResetLength = Math.max(maxResetLength, m.length);
52
+ process.stdout.write(m + " ".repeat(maxResetLength - m.length));
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?
55
+ if (fs.statSync(fileOrDirPath).isDirectory() && !skip.test(fileOrDirName)) {
56
+ return files.concat(walk(fileOrDirPath));
57
+ }
58
+
59
+ return files.concat(fileOrDirPath);
60
+ }, [] as string[]);
61
+ }
62
+
63
+ type Analysis = Partial<{
64
+ root: string;
65
+ srcDir: string;
66
+ packageJsonDir: string;
67
+ valConfigPath: string;
68
+ isTypescript: boolean;
69
+ isJavascript: boolean;
70
+
71
+ // Val package:
72
+ isValInstalled: boolean;
73
+ valVersion: string;
74
+ valVersionIsSatisfied: boolean;
75
+
76
+ // eslint:
77
+ eslintRcJsonPath: string;
78
+ eslintRcJsonText: string;
79
+ eslintRcJsPath: string;
80
+ eslintRcJsText: string;
81
+ valEslintVersion: string;
82
+ isValEslintRulesConfigured: boolean;
83
+
84
+ // next:
85
+ nextVersion: string;
86
+ nextVersionIsSatisfied: boolean;
87
+ isNextInstalled: boolean;
88
+ pagesRouter: boolean;
89
+ appRouter: boolean;
90
+ appRouterLayoutFile: string;
91
+ appRouterPath: string;
92
+ appRouterLayoutPath: string;
93
+
94
+ // git:
95
+ hasGit: boolean;
96
+ isGitHub: boolean;
97
+ isGitClean: boolean;
98
+
99
+ // TODO:
100
+ // check if modules are used
101
+ }>;
102
+
103
+ const analyze = async (root: string, files: string[]): Promise<Analysis> => {
104
+ if (!fs.existsSync(root)) {
105
+ return {};
106
+ }
107
+ const analysis: Analysis = { root };
108
+ const packageJsonPath = files.find(
109
+ (file) => file === [root, "package.json"].join(sep)
110
+ );
111
+ analysis.packageJsonDir = packageJsonPath && path.dirname(packageJsonPath);
112
+
113
+ if (packageJsonPath) {
114
+ const packageJsonText = fs.readFileSync(packageJsonPath, "utf8");
115
+ if (packageJsonText) {
116
+ try {
117
+ const packageJson = JSON.parse(packageJsonText);
118
+ analysis.isValInstalled = !!packageJson.dependencies["@valbuild/next"];
119
+ analysis.isNextInstalled = !!packageJson.dependencies["next"];
120
+ analysis.valEslintVersion =
121
+ packageJson.devDependencies["@valbuild/eslint-plugin"] ||
122
+ packageJson.dependencies["@valbuild/eslint-plugin"];
123
+ analysis.nextVersion = packageJson.dependencies["next"];
124
+ analysis.valVersion = packageJson.dependencies["@valbuild/next"];
125
+ } catch (err) {
126
+ throw new Error(
127
+ `Failed to parse package.json in file: ${packageJsonPath}`
128
+ );
129
+ }
130
+ }
131
+ }
132
+ if (analysis.nextVersion) {
133
+ const minNextVersion = semver.minVersion(analysis.nextVersion)?.version;
134
+ if (minNextVersion) {
135
+ analysis.nextVersionIsSatisfied = semver.satisfies(
136
+ minNextVersion,
137
+ ">=" + MIN_NEXT_VERSION
138
+ );
139
+ }
140
+ }
141
+ if (analysis.valVersion) {
142
+ const minValVersion = semver.minVersion(analysis.valVersion)?.version;
143
+ if (minValVersion) {
144
+ analysis.valVersionIsSatisfied = semver.satisfies(
145
+ minValVersion,
146
+ ">=" + MIN_VAL_VERSION
147
+ );
148
+ }
149
+ }
150
+
151
+ analysis.eslintRcJsPath = files.find((file) => file.endsWith(".eslintrc.js"));
152
+ if (analysis.eslintRcJsPath) {
153
+ analysis.eslintRcJsText = fs.readFileSync(analysis.eslintRcJsPath, "utf8");
154
+ if (analysis.eslintRcJsText) {
155
+ // TODO: Evaluate and extract config?
156
+ analysis.isValEslintRulesConfigured = analysis.eslintRcJsText.includes(
157
+ "plugin:@valbuild/recommended"
158
+ );
159
+ }
160
+ }
161
+ analysis.eslintRcJsonPath =
162
+ files.find((file) => file.endsWith(".eslintrc.json")) ||
163
+ files.find((file) => file.endsWith(".eslintrc"));
164
+ if (analysis.eslintRcJsonPath) {
165
+ analysis.eslintRcJsonText = fs.readFileSync(
166
+ analysis.eslintRcJsonPath,
167
+ "utf8"
168
+ );
169
+ if (analysis.eslintRcJsonText) {
170
+ // TODO: Parse properly
171
+ analysis.isValEslintRulesConfigured = analysis.eslintRcJsonText.includes(
172
+ "plugin:@valbuild/recommended"
173
+ );
174
+ }
175
+ }
176
+
177
+ const pagesRouterAppPath =
178
+ files.find((file) => file.endsWith("/pages/_app.tsx")) ||
179
+ files.find((file) => file.endsWith("/pages/_app.jsx"));
180
+ analysis.pagesRouter = !!pagesRouterAppPath;
181
+ if (pagesRouterAppPath) {
182
+ analysis.isTypescript = !!pagesRouterAppPath.endsWith(".tsx");
183
+ analysis.isJavascript = !!pagesRouterAppPath.endsWith(".jsx");
184
+ analysis.srcDir = path.dirname(path.dirname(pagesRouterAppPath));
185
+ }
186
+
187
+ const appRouterLayoutPath =
188
+ files.find((file) => file.endsWith("/app/layout.tsx")) ||
189
+ files.find((file) => file.endsWith("/app/layout.jsx"));
190
+
191
+ if (appRouterLayoutPath) {
192
+ analysis.appRouter = true;
193
+ analysis.appRouterLayoutPath = appRouterLayoutPath;
194
+ analysis.appRouterLayoutFile = fs.readFileSync(appRouterLayoutPath, "utf8");
195
+ analysis.isTypescript = !!appRouterLayoutPath.endsWith(".tsx");
196
+ analysis.isJavascript = !!appRouterLayoutPath.endsWith(".jsx");
197
+ analysis.appRouterPath = path.dirname(appRouterLayoutPath);
198
+ analysis.srcDir = path.dirname(analysis.appRouterPath);
199
+ }
200
+
201
+ try {
202
+ const git = simpleGit(root);
203
+ const gitStatus = await git.status();
204
+ const gitRemoteOrigin = await git.remote(["-v"]);
205
+ analysis.hasGit = true;
206
+ analysis.isGitHub = gitRemoteOrigin
207
+ ? !!gitRemoteOrigin.includes("github.com")
208
+ : false;
209
+ analysis.isGitClean = gitStatus.isClean();
210
+ } catch (err) {
211
+ // console.error(err);
212
+ }
213
+ return analysis;
214
+ };
215
+
216
+ type FileOp = {
217
+ path: string;
218
+ source: string;
219
+ };
220
+ type Plan = Partial<{
221
+ root: string;
222
+ createValServer: FileOp;
223
+ createValRouter: FileOp;
224
+ createValAppPage: FileOp;
225
+ createConfigFile: FileOp;
226
+ createValRsc: false | FileOp;
227
+ createValClient: false | FileOp;
228
+ updateAppLayout: false | FileOp;
229
+ updateEslint: false | FileOp; // TODO: do this
230
+ useTypescript: boolean;
231
+ useJavascript: boolean;
232
+ abort: boolean;
233
+ ignoreGitDirty: boolean;
234
+ }>;
235
+
236
+ async function plan(
237
+ analysis: Readonly<Analysis>,
238
+ defaultAnswers: boolean = false
239
+ ): Promise<Plan> {
240
+ const plan: Plan = { root: analysis.root };
241
+
242
+ if (analysis.root) {
243
+ logger.info(" Root: " + analysis.root, { isGood: true });
244
+ } else {
245
+ logger.error("Failed to find root directory");
246
+ return { abort: true };
247
+ }
248
+ if (
249
+ !analysis.srcDir ||
250
+ !fs.statSync(analysis.srcDir).isDirectory() ||
251
+ !analysis.isNextInstalled
252
+ ) {
253
+ logger.error("Val requires a Next.js project");
254
+ return { abort: true };
255
+ }
256
+ if (analysis.srcDir) {
257
+ logger.info(" Source dir: " + analysis.root, { isGood: true });
258
+ } else {
259
+ logger.error("Failed to determine source directory");
260
+ return { abort: true };
261
+ }
262
+ if (!analysis.isNextInstalled) {
263
+ logger.error("Val requires a Next.js project");
264
+ return { abort: true };
265
+ }
266
+ if (!analysis.isValInstalled) {
267
+ logger.error("Install @valbuild/next first");
268
+ return { abort: true };
269
+ } else {
270
+ logger.info(
271
+ ` Val version: found ${analysis.valVersion} >= ${MIN_VAL_VERSION}`,
272
+ { isGood: true }
273
+ );
274
+ }
275
+ if (!analysis.nextVersionIsSatisfied) {
276
+ logger.error(
277
+ `Val requires Next.js >= ${MIN_NEXT_VERSION}. Found: ${analysis.nextVersion}`
278
+ );
279
+ return { abort: true };
280
+ } else {
281
+ logger.info(
282
+ ` Next.js version: found ${analysis.nextVersion} >= ${MIN_NEXT_VERSION}`,
283
+ { isGood: true }
284
+ );
285
+ }
286
+ if (analysis.isTypescript) {
287
+ logger.info(" Use: TypeScript", { isGood: true });
288
+ plan.useTypescript = true;
289
+ }
290
+ if (analysis.isJavascript) {
291
+ logger.info(" Use: JavaScript", { isGood: true });
292
+ if (!plan.useTypescript) {
293
+ plan.useJavascript = true;
294
+ }
295
+ }
296
+ if (analysis.isTypescript) {
297
+ const tsconfigJsonPath = path.join(analysis.root, "tsconfig.json");
298
+ if (fs.statSync(tsconfigJsonPath).isFile()) {
299
+ logger.info(" tsconfig.json: found", { isGood: true });
300
+ } else {
301
+ logger.error("tsconfig.json: Failed to find tsconfig.json");
302
+ return { abort: true };
303
+ }
304
+ } else {
305
+ const jsconfigJsonPath = path.join(analysis.root, "jsconfig.json");
306
+ if (fs.statSync(jsconfigJsonPath).isFile()) {
307
+ logger.info(" jsconfig.json: found", { isGood: true });
308
+ } else {
309
+ logger.error(" jsconfig.json: failed to find jsconfig.json");
310
+ return { abort: true };
311
+ }
312
+ }
313
+
314
+ if (analysis.valEslintVersion === undefined) {
315
+ const answer = !defaultAnswers
316
+ ? await confirm({
317
+ message:
318
+ "The recommended Val eslint plugin (@valbuild/eslint-plugin) is not installed. Continue?",
319
+ default: false,
320
+ })
321
+ : false;
322
+ if (!answer) {
323
+ logger.error(
324
+ "Aborted: the Val eslint plugin is not installed.\n\nInstall the @valbuild/eslint-plugin package with your favorite package manager.\n\nExample:\n\n npm install -D @valbuild/eslint-plugin\n"
325
+ );
326
+ return { abort: true };
327
+ }
328
+ } else {
329
+ logger.info(" @valbuild/eslint-plugin: installed", { isGood: true });
330
+ }
331
+ if (analysis.appRouter) {
332
+ logger.info(" Use: App Router", { isGood: true });
333
+ }
334
+ if (analysis.pagesRouter) {
335
+ logger.info(" Use: Pages Router", { isGood: true });
336
+ }
337
+ if (analysis.isGitClean) {
338
+ logger.info(" Git state: clean", { isGood: true });
339
+ }
340
+ if (!analysis.isGitClean) {
341
+ logger.warn(" Git state: dirty");
342
+ }
343
+
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
+ if (!analysis.isGitClean) {
390
+ while (plan.ignoreGitDirty === undefined) {
391
+ const answer = !defaultAnswers
392
+ ? await confirm({
393
+ message: "You have uncommitted changes. Continue?",
394
+ default: false,
395
+ })
396
+ : false;
397
+ plan.ignoreGitDirty = answer;
398
+ if (!answer) {
399
+ logger.error("Aborted: git state dirty");
400
+ return { abort: true, ignoreGitDirty: true };
401
+ }
402
+ }
403
+ }
404
+
405
+ // New required files:
406
+ const valConfigPath = path.join(analysis.root, "val.config.ts");
407
+
408
+ plan.createConfigFile = {
409
+ path: valConfigPath,
410
+ source: VAL_CONFIG({}),
411
+ };
412
+
413
+ const valUtilsDir = path.join(analysis.srcDir, "val");
414
+ const valUtilsImportPath = path
415
+ .relative(valUtilsDir, valConfigPath)
416
+ .replace(".js", "")
417
+ .replace(".ts", "");
418
+
419
+ const valServerPath = path.join(
420
+ valUtilsDir,
421
+ analysis.isTypescript ? "val.server.ts" : "val.server.js"
422
+ );
423
+ plan.createValServer = {
424
+ path: valServerPath,
425
+ source: VAL_SERVER(valUtilsImportPath),
426
+ };
427
+
428
+ if (!analysis.appRouterPath) {
429
+ logger.warn('Creating a new "app" router');
430
+ }
431
+
432
+ const valAppPagePath = path.join(
433
+ analysis.appRouterPath || path.join(analysis.srcDir, "app"),
434
+ "(val)",
435
+ "val",
436
+ analysis.isTypescript ? "page.tsx" : "page.jsx"
437
+ );
438
+ const valPageImportPath = path
439
+ .relative(path.dirname(valAppPagePath), valConfigPath)
440
+ .replace(".js", "")
441
+ .replace(".ts", "");
442
+ plan.createValAppPage = {
443
+ path: valAppPagePath,
444
+ source: VAL_APP_PAGE(valPageImportPath),
445
+ };
446
+
447
+ const valRouterPath = path.join(
448
+ analysis.appRouterPath || path.join(analysis.srcDir, "app"),
449
+ "(val)",
450
+ "api",
451
+ "val",
452
+ analysis.isTypescript ? "router.tsx" : "router.jsx"
453
+ );
454
+ const valRouterImportPath = path
455
+ .relative(path.dirname(valRouterPath), valServerPath)
456
+ .replace(".js", "")
457
+ .replace(".ts", "");
458
+ plan.createValRouter = {
459
+ path: valRouterPath,
460
+ source: VAL_API_ROUTER(valRouterImportPath),
461
+ };
462
+
463
+ // Util files:
464
+
465
+ while (plan.createValClient === undefined) {
466
+ const answer = !defaultAnswers
467
+ ? await confirm({
468
+ message: "Setup useVal for Client Components",
469
+ default: true,
470
+ })
471
+ : true;
472
+ if (answer) {
473
+ plan.createValClient = {
474
+ path: path.join(
475
+ valUtilsDir,
476
+ analysis.isTypescript ? "val.client.ts" : "val.client.js"
477
+ ),
478
+ source: VAL_CLIENT(valUtilsImportPath),
479
+ };
480
+ } else {
481
+ plan.createValClient = false;
482
+ }
483
+ }
484
+ while (plan.createValRsc === undefined) {
485
+ const answer = !defaultAnswers
486
+ ? await confirm({
487
+ message: "Setup fetchVal for React Server Components",
488
+ default: true,
489
+ })
490
+ : true;
491
+ if (answer) {
492
+ plan.createValRsc = {
493
+ path: path.join(
494
+ valUtilsDir,
495
+ analysis.isTypescript ? "val.rsc.ts" : "val.rsc.js"
496
+ ),
497
+ source: VAL_SERVER(valUtilsImportPath),
498
+ };
499
+ } else {
500
+ plan.createValRsc = false;
501
+ }
502
+ }
503
+
504
+ if (analysis.eslintRcJsPath) {
505
+ logger.warn("ESLint config found: " + analysis.eslintRcJsPath);
506
+ }
507
+
508
+ // Patches:
509
+
510
+ const NO_PATCH_WARNING =
511
+ "Remember to manually patch your pages/_app.tsx file to use Val Provider.\n";
512
+ if (analysis.appRouterLayoutPath) {
513
+ if (!analysis.appRouterLayoutFile) {
514
+ logger.error("Failed to read app router layout file");
515
+ return { abort: true };
516
+ }
517
+
518
+ const res = transformNextAppRouterValProvider(
519
+ {
520
+ path: analysis.appRouterLayoutPath,
521
+ source: analysis.appRouterLayoutFile,
522
+ },
523
+ {
524
+ j: jcs,
525
+ jscodeshift: jcs.withParser("tsx"),
526
+ stats: () => {},
527
+ report: () => {},
528
+ },
529
+ {
530
+ configImportPath: path
531
+ .relative(path.dirname(analysis.appRouterLayoutPath), valConfigPath)
532
+ .replace(".js", "")
533
+ .replace(".ts", ""),
534
+ }
535
+ );
536
+
537
+ const diff = diffLines(analysis.appRouterLayoutFile, res, {});
538
+
539
+ let s = "";
540
+ diff.forEach((part) => {
541
+ if (part.added) {
542
+ s += chalk.green(part.value);
543
+ } else if (part.removed) {
544
+ s += chalk.red(part.value);
545
+ } else {
546
+ s += part.value;
547
+ }
548
+ });
549
+ const answer = !defaultAnswers
550
+ ? await confirm({
551
+ message: `Automatically patch ${analysis.appRouterLayoutPath} file?`,
552
+ default: true,
553
+ })
554
+ : true;
555
+ if (answer) {
556
+ const answer = !defaultAnswers
557
+ ? await confirm({
558
+ message: `Do you accept the following patch:\n${s}\n`,
559
+ default: true,
560
+ })
561
+ : true;
562
+ if (!answer) {
563
+ logger.warn(NO_PATCH_WARNING);
564
+ plan.updateAppLayout = false;
565
+ } else {
566
+ plan.updateAppLayout = {
567
+ path: analysis.appRouterLayoutPath,
568
+ source: res,
569
+ };
570
+ }
571
+ } else {
572
+ logger.warn(NO_PATCH_WARNING);
573
+ }
574
+ }
575
+ if (analysis.pagesRouter) {
576
+ logger.warn(NO_PATCH_WARNING);
577
+ }
578
+
579
+ return plan;
580
+ }
581
+
582
+ async function execute(plan: Plan) {
583
+ if (plan.abort) {
584
+ return logger.warn("Aborted");
585
+ }
586
+ if (!plan.root) {
587
+ return logger.error("Failed to find root directory");
588
+ }
589
+ logger.info("Executing...");
590
+ for (const [key, fileOp] of Object.entries(plan)) {
591
+ writeFile(fileOp, plan.root, key.startsWith("update"));
592
+ }
593
+ }
594
+
595
+ function writeFile(
596
+ fileOp: string | FileOp | undefined | boolean,
597
+ rootDir: string,
598
+ isUpdate: boolean
599
+ ) {
600
+ if (fileOp && typeof fileOp !== "boolean" && typeof fileOp !== "string") {
601
+ fs.mkdirSync(path.dirname(fileOp.path), { recursive: true });
602
+ fs.writeFileSync(fileOp.path, fileOp.source);
603
+ logger.info(
604
+ ` ${isUpdate ? "Patched" : "Created"} file: ${fileOp.path.replace(
605
+ rootDir,
606
+ ""
607
+ )}`,
608
+ { isGood: true }
609
+ );
610
+ }
611
+ }
package/src/logger.ts ADDED
@@ -0,0 +1,32 @@
1
+ import chalk from "chalk";
2
+
3
+ export function error(message: string) {
4
+ console.error(chalk.red("❌ ERROR: ") + message);
5
+ }
6
+
7
+ export function warn(message: string) {
8
+ console.error(chalk.yellow("⚠️ WARN:") + message);
9
+ }
10
+
11
+ export function info(
12
+ message: string,
13
+ opts: { isCodeSnippet?: true; isGood?: true } = {}
14
+ ) {
15
+ if (opts.isCodeSnippet) {
16
+ console.log(chalk.cyanBright("$ > ") + chalk.cyan(message));
17
+ return;
18
+ }
19
+ if (opts.isGood) {
20
+ console.log(chalk.green("✅ ") + message);
21
+ return;
22
+ }
23
+ console.log(message);
24
+ }
25
+
26
+ export function debugPrint(str: string) {
27
+ /*eslint-disable no-constant-condition */
28
+ if (process.env["DEBUG"] || true) {
29
+ // TODO: remove true
30
+ console.log(`DEBUG: ${str}`);
31
+ }
32
+ }
@@ -0,0 +1,75 @@
1
+ export const VAL_CLIENT = (configImportPath: string) => `import "client-only";
2
+ import { initValClient } from "@valbuild/next/client";
3
+ import { config } from "${configImportPath}";
4
+
5
+ const { useValStega: useVal } = initValClient(config);
6
+
7
+ export { useVal };
8
+ `;
9
+
10
+ export const VAL_RSC = (configImportPath: string) => `import "server-only";
11
+ import { initValRsc } from "@valbuild/next/rsc";
12
+ import { config } from "${configImportPath}";
13
+ import { cookies, draftMode, headers } from "next/headers";
14
+
15
+ const { fetchValStega: fetchVal } = initValRsc(config, {
16
+ draftMode,
17
+ headers,
18
+ cookies,
19
+ });
20
+
21
+ export { fetchVal };
22
+ `;
23
+
24
+ export const VAL_SERVER = (configImportPath: string) => `import "server-only";
25
+ import { initValServer } from "@valbuild/next/server";
26
+ import { config } from "${configImportPath}";
27
+ import { draftMode } from "next/headers";
28
+
29
+ const { valNextAppRouter } = initValServer(
30
+ { ...config },
31
+ {
32
+ draftMode,
33
+ }
34
+ );
35
+
36
+ export { valNextAppRouter };
37
+ `;
38
+
39
+ // TODO: use Val config
40
+ type ValConfig = {
41
+ valCloud?: string;
42
+ gitCommit?: string;
43
+ gitBranch?: string;
44
+ valConfigPath?: string;
45
+ };
46
+ export const VAL_CONFIG = (
47
+ options: ValConfig
48
+ ) => `import { initVal } from "@valbuild/next";
49
+
50
+ const { s, val, config } = initVal(${JSON.stringify(options, null, 2)});
51
+
52
+ export { s, val, config };
53
+ `;
54
+
55
+ export const VAL_API_ROUTER = (
56
+ valServerPath: string
57
+ ) => `import { valNextAppRouter } from "${valServerPath}";
58
+
59
+ export const GET = valNextAppRouter;
60
+ export const POST = valNextAppRouter;
61
+ export const PATCH = valNextAppRouter;
62
+ export const DELETE = valNextAppRouter;
63
+ export const PUT = valNextAppRouter;
64
+ export const HEAD = valNextAppRouter;
65
+ `;
66
+
67
+ export const VAL_APP_PAGE = (
68
+ configImportPath: string
69
+ ) => `import { ValApp } from "@valbuild/next";
70
+ import { config } from "${configImportPath}";
71
+
72
+ export default function Val() {
73
+ return <ValApp config={config} />;
74
+ }
75
+ `;