@elench/testkit 0.1.66 → 0.1.68

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.
@@ -18,11 +18,11 @@ export function defineHttpProfile(profile) {
18
18
  return profile || {};
19
19
  }
20
20
 
21
- export function service(config) {
22
- return config || {};
21
+ export function defineTestkitFile(metadata) {
22
+ return metadata || {};
23
23
  }
24
24
 
25
- export function localDatabase(options = {}) {
25
+ export function postgresDatabase(options = {}) {
26
26
  return {
27
27
  provider: "local",
28
28
  ...options,
@@ -76,7 +76,7 @@ export function verifyModule(specifier, options = {}) {
76
76
  return moduleStep(specifier, options);
77
77
  }
78
78
 
79
- export function seededDatabaseTemplate(options = {}) {
79
+ function buildDatabaseTemplateConfig(options = {}) {
80
80
  const migrate = normalizeTemplateStepList(options.migrate);
81
81
  const seed = normalizeTemplateStepList(options.seed);
82
82
  const verify = normalizeTemplateStepList(options.verify);
@@ -90,6 +90,52 @@ export function seededDatabaseTemplate(options = {}) {
90
90
  };
91
91
  }
92
92
 
93
+ export function templateDatabase(options = {}) {
94
+ const {
95
+ inputs,
96
+ schema,
97
+ migrate,
98
+ seed,
99
+ verify,
100
+ ...databaseOptions
101
+ } = options;
102
+ return postgresDatabase({
103
+ ...databaseOptions,
104
+ template: buildDatabaseTemplateConfig(options.template || { inputs, schema, migrate, seed, verify }),
105
+ });
106
+ }
107
+
108
+ export function postgresFixture(options = {}) {
109
+ const { discovery, envFiles, ...databaseOptions } = options;
110
+ return {
111
+ discovery: discovery || {
112
+ roots: [".testkit-fixture"],
113
+ },
114
+ envFiles,
115
+ local: false,
116
+ database: postgresDatabase(databaseOptions),
117
+ };
118
+ }
119
+
120
+ export function databaseServiceEnv(prefix, serviceName) {
121
+ const normalizedPrefix = String(prefix || "").trim().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
122
+ if (!normalizedPrefix) {
123
+ throw new Error("databaseServiceEnv prefix must be a non-empty string");
124
+ }
125
+ if (!serviceName || !String(serviceName).trim()) {
126
+ throw new Error("databaseServiceEnv serviceName must be a non-empty string");
127
+ }
128
+
129
+ return {
130
+ [`${normalizedPrefix}_DATABASE_HOST`]: `{dbHost:${serviceName}}`,
131
+ [`${normalizedPrefix}_DATABASE_PORT`]: `{dbPort:${serviceName}}`,
132
+ [`${normalizedPrefix}_DATABASE_NAME`]: `{dbName:${serviceName}}`,
133
+ [`${normalizedPrefix}_DATABASE_USER`]: `{dbUser:${serviceName}}`,
134
+ [`${normalizedPrefix}_DATABASE_PASSWORD`]: `{dbPassword:${serviceName}}`,
135
+ [`${normalizedPrefix}_DATABASE_SSL`]: "0",
136
+ };
137
+ }
138
+
93
139
  export function nodeToolchain(options = {}) {
94
140
  return {
95
141
  kind: "node",
@@ -97,61 +143,154 @@ export function nodeToolchain(options = {}) {
97
143
  };
98
144
  }
99
145
 
100
- export function goService(options = {}) {
101
- const cwd = options.cwd || ".";
102
- const port = requiredNumber(options.port, "goService port");
103
- const readyPath = options.readyPath || "/health";
104
- const baseUrl = options.baseUrl || "http://127.0.0.1:{port}";
146
+ export function tscBuild(options = {}) {
147
+ return {
148
+ kind: "tsc",
149
+ cwd: options.cwd,
150
+ entry: options.entry || "src/index.ts",
151
+ tsconfig: options.tsconfig || "tsconfig.json",
152
+ outDir: options.outDir || "dist",
153
+ inputs: Array.isArray(options.inputs) ? [...options.inputs] : undefined,
154
+ };
155
+ }
105
156
 
157
+ export function scriptBuild(script, options = {}) {
106
158
  return {
107
- ...service(options),
108
- local: {
109
- cwd,
110
- start: options.start || defaultGoStartCommand(options),
111
- port,
112
- baseUrl,
113
- readyUrl: options.readyUrl || `${baseUrl}${readyPath}`,
114
- readyTimeoutMs: options.readyTimeoutMs,
115
- env: options.env || {},
116
- },
159
+ kind: "script",
160
+ script,
161
+ cwd: options.cwd,
162
+ inputs: Array.isArray(options.inputs) ? [...options.inputs] : undefined,
117
163
  };
118
164
  }
119
165
 
120
- export function nextService(options = {}) {
121
- const cwd = options.cwd || ".";
122
- const port = requiredNumber(options.port, "nextService port");
123
- const baseUrl = options.baseUrl || "http://127.0.0.1:{port}";
166
+ export function stepsBuild(options = {}) {
167
+ return {
168
+ kind: "steps",
169
+ inputs: Array.isArray(options.inputs) ? [...options.inputs] : undefined,
170
+ steps: Array.isArray(options.steps) ? [...options.steps] : [],
171
+ };
172
+ }
124
173
 
174
+ export function nextBuild(options = {}) {
125
175
  return {
126
- ...service(options),
176
+ kind: "next",
177
+ cwd: options.cwd,
178
+ distDir: options.distDir || "dist",
179
+ tsconfig: options.tsconfig || "tsconfig.json",
180
+ inputs: Array.isArray(options.inputs) ? [...options.inputs] : undefined,
181
+ };
182
+ }
183
+
184
+ export function nodeApp(options = {}) {
185
+ const {
186
+ baseUrl: explicitBaseUrl,
187
+ build: explicitBuild,
188
+ buildInputs,
189
+ cwd = ".",
190
+ entry = "src/index.ts",
191
+ env = {},
192
+ envFiles,
193
+ outDir = "dist",
194
+ port,
195
+ readyPath = "/health",
196
+ readyTimeoutMs,
197
+ readyUrl: explicitReadyUrl,
198
+ runtime,
199
+ start: explicitStart,
200
+ toolchain,
201
+ tsconfig = "tsconfig.json",
202
+ ...serviceConfig
203
+ } = options;
204
+
205
+ const normalizedPort = requiredNumber(port, "nodeApp port");
206
+ const baseUrl = explicitBaseUrl || "http://127.0.0.1:{port}";
207
+ const build = explicitBuild === undefined ? tscBuild({
208
+ cwd,
209
+ entry,
210
+ tsconfig,
211
+ outDir,
212
+ inputs: buildInputs,
213
+ }) : explicitBuild;
214
+ const start = explicitStart || resolveNodeAppStart(build, entry);
215
+
216
+ return {
217
+ ...serviceConfig,
218
+ envFiles,
219
+ runtime: {
220
+ ...(runtime || {}),
221
+ build,
222
+ toolchain: toolchain ?? runtime?.toolchain,
223
+ },
127
224
  local: {
128
225
  cwd,
129
- start: options.start || "./node_modules/.bin/next dev -p {port}",
130
- port,
226
+ start,
227
+ port: normalizedPort,
131
228
  baseUrl,
132
- readyUrl: options.readyUrl || baseUrl,
133
- readyTimeoutMs: options.readyTimeoutMs,
134
- env: options.env || {},
229
+ readyUrl: explicitReadyUrl || `${baseUrl}${readyPath}`,
230
+ readyTimeoutMs,
231
+ env,
135
232
  },
136
233
  };
137
234
  }
138
235
 
139
- export function tsxService(options = {}) {
140
- const cwd = options.cwd || ".";
141
- const port = requiredNumber(options.port, "tsxService port");
142
- const baseUrl = options.baseUrl || "http://127.0.0.1:{port}";
143
- const entry = options.entry || "src/index.ts";
236
+ export function nextApp(options = {}) {
237
+ const {
238
+ baseUrl: explicitBaseUrl,
239
+ browser,
240
+ build: explicitBuild,
241
+ buildInputs,
242
+ cwd = ".",
243
+ dependsOn,
244
+ env = {},
245
+ envFiles,
246
+ mode = "dev",
247
+ port,
248
+ readyTimeoutMs,
249
+ readyUrl: explicitReadyUrl,
250
+ runtime,
251
+ start: explicitStart,
252
+ toolchain,
253
+ ...serviceConfig
254
+ } = options;
255
+
256
+ const normalizedPort = requiredNumber(port, "nextApp port");
257
+ const baseUrl = explicitBaseUrl || "http://127.0.0.1:{port}";
258
+ const build =
259
+ explicitBuild === undefined
260
+ ? mode === "start"
261
+ ? nextBuild({ cwd, inputs: buildInputs })
262
+ : null
263
+ : explicitBuild;
264
+ const start =
265
+ explicitStart ||
266
+ (mode === "start"
267
+ ? "./node_modules/.bin/next start --port {port}"
268
+ : "./node_modules/.bin/next dev -p {port}");
144
269
 
145
270
  return {
146
- ...service(options),
271
+ ...serviceConfig,
272
+ envFiles,
273
+ dependsOn: Array.isArray(dependsOn) ? [...dependsOn] : dependsOn,
274
+ browser,
275
+ runtime: {
276
+ ...(runtime || {}),
277
+ build,
278
+ toolchain: toolchain ?? runtime?.toolchain,
279
+ },
147
280
  local: {
148
281
  cwd,
149
- start: options.start || `./node_modules/.bin/tsx watch ${entry}`,
150
- port,
282
+ start,
283
+ port: normalizedPort,
151
284
  baseUrl,
152
- readyUrl: options.readyUrl || `${baseUrl}${options.readyPath || "/health"}`,
153
- readyTimeoutMs: options.readyTimeoutMs,
154
- env: options.env || {},
285
+ readyUrl: explicitReadyUrl || baseUrl,
286
+ readyTimeoutMs,
287
+ env: mode === "start"
288
+ ? {
289
+ NEXT_DIST_DIR: env.NEXT_DIST_DIR || "{prepareDir}/dist",
290
+ NEXT_TSCONFIG_PATH: env.NEXT_TSCONFIG_PATH || "{prepareDir}/tsconfig.json",
291
+ ...env,
292
+ }
293
+ : env,
155
294
  },
156
295
  };
157
296
  }
@@ -235,16 +374,6 @@ export {
235
374
  runtimeJson,
236
375
  };
237
376
 
238
- function defaultGoStartCommand(options) {
239
- if (options.command) {
240
- return `go run ${options.command}`;
241
- }
242
- if (options.entrypoint) {
243
- return `go run ${options.entrypoint}`;
244
- }
245
- return "go run ./cmd/server";
246
- }
247
-
248
377
  function requiredNumber(value, label) {
249
378
  if (!Number.isInteger(value) || value <= 0) {
250
379
  throw new Error(`${label} must be a positive integer`);
@@ -252,6 +381,14 @@ function requiredNumber(value, label) {
252
381
  return value;
253
382
  }
254
383
 
384
+ function resolveNodeAppStart(build, entry) {
385
+ if (build?.kind === "tsc") {
386
+ const compiled = compiledEntryFromSource(entry || build.entry || "src/index.ts", build.outDir || "dist");
387
+ return `node {prepareDir}/${compiled}`;
388
+ }
389
+ return `./node_modules/.bin/tsx ${entry || "src/index.ts"}`;
390
+ }
391
+
255
392
  function normalizeTemplateStepList(value) {
256
393
  if (value == null) return [];
257
394
  return Array.isArray(value) ? [...value] : [value];
@@ -265,6 +402,13 @@ function normalizeSchemaStep(value) {
265
402
  return value;
266
403
  }
267
404
 
405
+ function compiledEntryFromSource(entry, outDir) {
406
+ const normalized = String(entry || "src/index.ts").replaceAll("\\", "/");
407
+ const compiled = normalized.replace(/\.[cm]?[jt]sx?$/i, ".js");
408
+ const relative = compiled.startsWith("src/") ? compiled.slice(4) : compiled;
409
+ return `${outDir}/${relative}`.replace(/\/+/g, "/");
410
+ }
411
+
268
412
  function envValue(name) {
269
413
  const env = getRuntimeEnv();
270
414
  const value = env?.rawEnv?.[name] || env?.[name];
@@ -1,38 +1,76 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import {
3
- goService,
4
- nextService,
3
+ databaseServiceEnv,
4
+ defineTestkitFile,
5
+ nextApp,
6
+ nextBuild,
5
7
  nodeToolchain,
8
+ nodeApp,
9
+ postgresDatabase,
10
+ postgresFixture,
6
11
  schemaSql,
7
12
  seedCommand,
8
13
  seedModule,
9
- seededDatabaseTemplate,
10
- tsxService,
14
+ stepsBuild,
15
+ templateDatabase,
16
+ tscBuild,
11
17
  verifyCommand,
12
18
  verifyModule,
13
19
  } from "./index.mjs";
14
20
 
15
21
  describe("setup helpers", () => {
16
- it("emits plain next start commands without an exec prefix", () => {
17
- const config = nextService({ port: 3000 });
22
+ it("defines file-local metadata plainly", () => {
23
+ expect(defineTestkitFile({ skip: "Auth is stubbed", locks: ["background-workers"] })).toEqual({
24
+ skip: "Auth is stubbed",
25
+ locks: ["background-workers"],
26
+ });
27
+ });
28
+
29
+ it("builds a Next app preset for dev mode", () => {
30
+ const config = nextApp({ port: 3000 });
18
31
 
19
32
  expect(config.local.start).toBe("./node_modules/.bin/next dev -p {port}");
20
33
  });
21
34
 
22
- it("emits plain tsx start commands without an exec prefix", () => {
23
- const config = tsxService({ port: 3000, entry: "src/server.ts" });
35
+ it("builds a Next app preset for start mode with managed runtime env defaults", () => {
36
+ const config = nextApp({ cwd: "frontend", port: 3000, mode: "start" });
37
+
38
+ expect(config.local.start).toBe("./node_modules/.bin/next start --port {port}");
39
+ expect(config.local.env).toMatchObject({
40
+ NEXT_DIST_DIR: "{prepareDir}/dist",
41
+ NEXT_TSCONFIG_PATH: "{prepareDir}/tsconfig.json",
42
+ });
43
+ expect(config.runtime.build).toEqual({
44
+ kind: "next",
45
+ cwd: "frontend",
46
+ distDir: "dist",
47
+ tsconfig: "tsconfig.json",
48
+ inputs: undefined,
49
+ });
50
+ });
51
+
52
+ it("allows Next start apps to disable managed builds explicitly", () => {
53
+ const config = nextApp({ cwd: "frontend", port: 3000, mode: "start", build: null });
24
54
 
25
- expect(config.local.start).toBe("./node_modules/.bin/tsx watch src/server.ts");
55
+ expect(config.runtime.build).toBeNull();
56
+ expect(config.local.env).toMatchObject({
57
+ NEXT_DIST_DIR: "{prepareDir}/dist",
58
+ NEXT_TSCONFIG_PATH: "{prepareDir}/tsconfig.json",
59
+ });
26
60
  });
27
61
 
28
- it("emits plain go start commands without an exec prefix", () => {
29
- expect(goService({ port: 3000 }).local.start).toBe("go run ./cmd/server");
30
- expect(goService({ port: 3000, entrypoint: "./cmd/api" }).local.start).toBe(
31
- "go run ./cmd/api"
32
- );
33
- expect(goService({ port: 3000, command: "./cmd/worker" }).local.start).toBe(
34
- "go run ./cmd/worker"
35
- );
62
+ it("builds a Node app preset with tsc build defaults", () => {
63
+ const config = nodeApp({ port: 3000, entry: "src/server.ts" });
64
+
65
+ expect(config.local.start).toBe("node {prepareDir}/dist/server.js");
66
+ expect(config.runtime.build).toEqual({
67
+ kind: "tsc",
68
+ cwd: ".",
69
+ entry: "src/server.ts",
70
+ tsconfig: "tsconfig.json",
71
+ outDir: "dist",
72
+ inputs: undefined,
73
+ });
36
74
  });
37
75
 
38
76
  it("builds node toolchain profiles with a node kind", () => {
@@ -43,6 +81,41 @@ describe("setup helpers", () => {
43
81
  });
44
82
  });
45
83
 
84
+ it("builds explicit build presets", () => {
85
+ expect(tscBuild({ entry: "src/server.ts", outDir: "build" })).toEqual({
86
+ kind: "tsc",
87
+ cwd: undefined,
88
+ entry: "src/server.ts",
89
+ tsconfig: "tsconfig.json",
90
+ outDir: "build",
91
+ inputs: undefined,
92
+ });
93
+ expect(nextBuild({ cwd: "frontend" })).toEqual({
94
+ kind: "next",
95
+ cwd: "frontend",
96
+ distDir: "dist",
97
+ tsconfig: "tsconfig.json",
98
+ inputs: undefined,
99
+ });
100
+ expect(
101
+ stepsBuild({
102
+ inputs: ["scripts/prepare.mjs"],
103
+ steps: [seedCommand("node scripts/prepare.mjs")],
104
+ })
105
+ ).toEqual({
106
+ kind: "steps",
107
+ inputs: ["scripts/prepare.mjs"],
108
+ steps: [
109
+ {
110
+ kind: "command",
111
+ cmd: "node scripts/prepare.mjs",
112
+ cwd: undefined,
113
+ inputs: undefined,
114
+ },
115
+ ],
116
+ });
117
+ });
118
+
46
119
  it("emits semantic database template steps using the underlying step shapes", () => {
47
120
  expect(schemaSql("db/schema.sql")).toEqual({
48
121
  kind: "sql-file",
@@ -76,67 +149,152 @@ describe("setup helpers", () => {
76
149
  });
77
150
  });
78
151
 
79
- it("builds a seeded database template from schema, seed, and verify intents", () => {
152
+ it("builds declarative template databases from schema, seed, and verify intents", () => {
80
153
  expect(
81
- seededDatabaseTemplate({
154
+ templateDatabase({
82
155
  inputs: ["db/schema.sql", "scripts/seed.ts"],
83
156
  schema: "db/schema.sql",
84
157
  seed: seedCommand("npm run db:seed"),
85
158
  verify: verifyModule("scripts/verify.ts#verifySeed"),
86
159
  })
87
160
  ).toEqual({
88
- inputs: ["db/schema.sql", "scripts/seed.ts"],
89
- migrate: [
90
- {
91
- kind: "sql-file",
92
- path: "db/schema.sql",
93
- cwd: undefined,
94
- inputs: undefined,
95
- },
96
- ],
97
- seed: [
98
- {
99
- kind: "command",
100
- cmd: "npm run db:seed",
101
- cwd: undefined,
102
- inputs: undefined,
103
- },
104
- ],
105
- verify: [
106
- {
107
- kind: "module",
108
- specifier: "scripts/verify.ts#verifySeed",
109
- cwd: undefined,
110
- inputs: undefined,
111
- },
112
- ],
161
+ provider: "local",
162
+ template: {
163
+ inputs: ["db/schema.sql", "scripts/seed.ts"],
164
+ migrate: [
165
+ {
166
+ kind: "sql-file",
167
+ path: "db/schema.sql",
168
+ cwd: undefined,
169
+ inputs: undefined,
170
+ },
171
+ ],
172
+ seed: [
173
+ {
174
+ kind: "command",
175
+ cmd: "npm run db:seed",
176
+ cwd: undefined,
177
+ inputs: undefined,
178
+ },
179
+ ],
180
+ verify: [
181
+ {
182
+ kind: "module",
183
+ specifier: "scripts/verify.ts#verifySeed",
184
+ cwd: undefined,
185
+ inputs: undefined,
186
+ },
187
+ ],
188
+ },
113
189
  });
114
190
  });
115
191
 
116
192
  it("prepends schema before explicit migrate steps and normalizes singletons to arrays", () => {
117
193
  expect(
118
- seededDatabaseTemplate({
194
+ templateDatabase({
119
195
  schema: schemaSql("db/schema.sql", { cwd: "db" }),
120
196
  migrate: seedCommand("echo migrate"),
121
197
  })
122
198
  ).toEqual({
123
- inputs: undefined,
124
- migrate: [
125
- {
126
- kind: "sql-file",
127
- path: "db/schema.sql",
128
- cwd: "db",
129
- inputs: undefined,
130
- },
131
- {
132
- kind: "command",
133
- cmd: "echo migrate",
134
- cwd: undefined,
135
- inputs: undefined,
136
- },
137
- ],
138
- seed: [],
139
- verify: [],
199
+ provider: "local",
200
+ template: {
201
+ inputs: undefined,
202
+ migrate: [
203
+ {
204
+ kind: "sql-file",
205
+ path: "db/schema.sql",
206
+ cwd: "db",
207
+ inputs: undefined,
208
+ },
209
+ {
210
+ kind: "command",
211
+ cmd: "echo migrate",
212
+ cwd: undefined,
213
+ inputs: undefined,
214
+ },
215
+ ],
216
+ seed: [],
217
+ verify: [],
218
+ },
219
+ });
220
+ });
221
+
222
+ it("builds declarative postgres database helpers", () => {
223
+ expect(postgresDatabase({ reset: false })).toEqual({
224
+ provider: "local",
225
+ reset: false,
226
+ });
227
+ expect(
228
+ templateDatabase({
229
+ reset: true,
230
+ schema: "db/schema.sql",
231
+ seed: seedCommand("npm run db:seed"),
232
+ })
233
+ ).toEqual({
234
+ provider: "local",
235
+ reset: true,
236
+ template: {
237
+ inputs: undefined,
238
+ migrate: [
239
+ {
240
+ kind: "sql-file",
241
+ path: "db/schema.sql",
242
+ cwd: undefined,
243
+ inputs: undefined,
244
+ },
245
+ ],
246
+ seed: [
247
+ {
248
+ kind: "command",
249
+ cmd: "npm run db:seed",
250
+ cwd: undefined,
251
+ inputs: undefined,
252
+ },
253
+ ],
254
+ verify: [],
255
+ },
140
256
  });
141
257
  });
258
+
259
+ it("builds support database presets and env bindings", () => {
260
+ expect(
261
+ postgresFixture({
262
+ reset: true,
263
+ })
264
+ ).toEqual({
265
+ discovery: {
266
+ roots: [".testkit-fixture"],
267
+ },
268
+ envFiles: undefined,
269
+ local: false,
270
+ database: {
271
+ provider: "local",
272
+ reset: true,
273
+ },
274
+ });
275
+ expect(databaseServiceEnv("ONIX", "catalog")).toEqual({
276
+ ONIX_DATABASE_HOST: "{dbHost:catalog}",
277
+ ONIX_DATABASE_PORT: "{dbPort:catalog}",
278
+ ONIX_DATABASE_NAME: "{dbName:catalog}",
279
+ ONIX_DATABASE_USER: "{dbUser:catalog}",
280
+ ONIX_DATABASE_PASSWORD: "{dbPassword:catalog}",
281
+ ONIX_DATABASE_SSL: "0",
282
+ });
283
+ });
284
+
285
+ it("does not leak preset-only helper fields into node app configs", () => {
286
+ const config = nodeApp({
287
+ port: 3000,
288
+ entry: "src/server.ts",
289
+ buildInputs: ["src", "package.json"],
290
+ env: { API_KEY: "test" },
291
+ readyPath: "/live",
292
+ });
293
+
294
+ expect(config).not.toHaveProperty("entry");
295
+ expect(config).not.toHaveProperty("buildInputs");
296
+ expect(config).not.toHaveProperty("readyPath");
297
+ expect(config.local.env).toEqual({ API_KEY: "test" });
298
+ expect(config.local.readyUrl).toBe("http://127.0.0.1:{port}/live");
299
+ });
142
300
  });
@@ -0,0 +1,43 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ export async function writeNextRuntimeTsconfig(context = {}) {
5
+ const serviceDir = context.cwd || context.productDir;
6
+ const prepareDir = context.prepareDir;
7
+ if (!serviceDir || !prepareDir) {
8
+ throw new Error("writeNextRuntimeTsconfig requires cwd and prepareDir");
9
+ }
10
+
11
+ const outputPath = path.join(prepareDir, "tsconfig.json");
12
+ const outputDir = path.dirname(outputPath);
13
+ const relative = (target) => path.relative(outputDir, target).replaceAll(path.sep, "/");
14
+ const srcDir = path.join(serviceDir, "src");
15
+ const testsDir = path.join(serviceDir, "tests");
16
+
17
+ const config = {
18
+ extends: relative(path.join(serviceDir, "tsconfig.json")),
19
+ compilerOptions: {
20
+ paths: {
21
+ "@/*": [relative(path.join(srcDir, "*"))],
22
+ },
23
+ },
24
+ include: [
25
+ relative(path.join(serviceDir, "next-env.d.ts")),
26
+ `${relative(srcDir)}/**/*.ts`,
27
+ `${relative(srcDir)}/**/*.tsx`,
28
+ `${relative(srcDir)}/**/*.mts`,
29
+ `${relative(path.join(prepareDir, "dist", "types"))}/**/*.ts`,
30
+ `${relative(path.join(prepareDir, "dist", "dev", "types"))}/**/*.ts`,
31
+ ],
32
+ exclude: [
33
+ "node_modules",
34
+ `${relative(srcDir)}/**/__testkit__/**`,
35
+ `${relative(testsDir)}/**`,
36
+ ".next/cache",
37
+ ".next/dev",
38
+ ],
39
+ };
40
+
41
+ fs.mkdirSync(outputDir, { recursive: true });
42
+ fs.writeFileSync(outputPath, `${JSON.stringify(config, null, 2)}\n`);
43
+ }