@typokit/cli 0.1.4
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/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +13 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/build.d.ts +42 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +302 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/dev.d.ts +106 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +536 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/generate.d.ts +65 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +430 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/inspect.d.ts +26 -0
- package/dist/commands/inspect.d.ts.map +1 -0
- package/dist/commands/inspect.js +579 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/migrate.d.ts +70 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +570 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/scaffold.d.ts +70 -0
- package/dist/commands/scaffold.d.ts.map +1 -0
- package/dist/commands/scaffold.js +483 -0
- package/dist/commands/scaffold.js.map +1 -0
- package/dist/commands/test.d.ts +56 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +248 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/config.d.ts +20 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +69 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +245 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +12 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +33 -0
- package/dist/logger.js.map +1 -0
- package/package.json +33 -0
- package/src/bin.ts +22 -0
- package/src/commands/build.ts +433 -0
- package/src/commands/dev.ts +822 -0
- package/src/commands/generate.ts +640 -0
- package/src/commands/inspect.ts +885 -0
- package/src/commands/migrate.ts +800 -0
- package/src/commands/scaffold.ts +627 -0
- package/src/commands/test.ts +353 -0
- package/src/config.ts +93 -0
- package/src/dev.test.ts +285 -0
- package/src/env.d.ts +86 -0
- package/src/generate.test.ts +304 -0
- package/src/index.test.ts +217 -0
- package/src/index.ts +397 -0
- package/src/inspect.test.ts +411 -0
- package/src/logger.ts +49 -0
- package/src/migrate.test.ts +205 -0
- package/src/scaffold.test.ts +256 -0
- package/src/test.test.ts +230 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
// @typokit/cli — Test Commands
|
|
2
|
+
|
|
3
|
+
import type { CliLogger } from "../logger.js";
|
|
4
|
+
import type { TypoKitConfig } from "../config.js";
|
|
5
|
+
|
|
6
|
+
export type TestRunner = "jest" | "vitest" | "rstest";
|
|
7
|
+
|
|
8
|
+
export interface TestCommandOptions {
|
|
9
|
+
/** Project root directory */
|
|
10
|
+
rootDir: string;
|
|
11
|
+
/** Resolved configuration */
|
|
12
|
+
config: Required<TypoKitConfig>;
|
|
13
|
+
/** Logger instance */
|
|
14
|
+
logger: CliLogger;
|
|
15
|
+
/** Test subcommand: "all" | "contracts" | "integration" */
|
|
16
|
+
subcommand: string;
|
|
17
|
+
/** CLI flags */
|
|
18
|
+
flags: Record<string, string | boolean>;
|
|
19
|
+
/** Whether verbose mode is enabled */
|
|
20
|
+
verbose: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TestResult {
|
|
24
|
+
/** Whether all tests passed */
|
|
25
|
+
success: boolean;
|
|
26
|
+
/** Which test runner was used */
|
|
27
|
+
runner: TestRunner;
|
|
28
|
+
/** Duration in milliseconds */
|
|
29
|
+
duration: number;
|
|
30
|
+
/** Errors encountered */
|
|
31
|
+
errors: string[];
|
|
32
|
+
/** Whether contract tests were regenerated before running */
|
|
33
|
+
contractsRegenerated: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Config file patterns used to auto-detect test runners.
|
|
38
|
+
*/
|
|
39
|
+
const RUNNER_CONFIG_PATTERNS: Record<TestRunner, string[]> = {
|
|
40
|
+
jest: [
|
|
41
|
+
"jest.config.js",
|
|
42
|
+
"jest.config.ts",
|
|
43
|
+
"jest.config.mjs",
|
|
44
|
+
"jest.config.cjs",
|
|
45
|
+
],
|
|
46
|
+
vitest: [
|
|
47
|
+
"vitest.config.js",
|
|
48
|
+
"vitest.config.ts",
|
|
49
|
+
"vitest.config.mjs",
|
|
50
|
+
"vitest.config.cjs",
|
|
51
|
+
],
|
|
52
|
+
rstest: [
|
|
53
|
+
"rstest.config.js",
|
|
54
|
+
"rstest.config.ts",
|
|
55
|
+
"rstest.config.mjs",
|
|
56
|
+
"rstest.config.cjs",
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Auto-detect the test runner by checking for config files in the project root.
|
|
62
|
+
* Returns the first match found, or "vitest" as default.
|
|
63
|
+
*/
|
|
64
|
+
export async function detectTestRunner(rootDir: string): Promise<TestRunner> {
|
|
65
|
+
const { join } = (await import(/* @vite-ignore */ "path")) as {
|
|
66
|
+
join: (...args: string[]) => string;
|
|
67
|
+
};
|
|
68
|
+
const { existsSync } = (await import(/* @vite-ignore */ "fs")) as {
|
|
69
|
+
existsSync: (p: string) => boolean;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
for (const [runner, patterns] of Object.entries(RUNNER_CONFIG_PATTERNS) as [
|
|
73
|
+
TestRunner,
|
|
74
|
+
string[],
|
|
75
|
+
][]) {
|
|
76
|
+
for (const pattern of patterns) {
|
|
77
|
+
if (existsSync(join(rootDir, pattern))) {
|
|
78
|
+
return runner;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return "vitest";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Build the command and arguments for each test runner.
|
|
88
|
+
*/
|
|
89
|
+
export function buildRunnerCommand(
|
|
90
|
+
runner: TestRunner,
|
|
91
|
+
subcommand: string,
|
|
92
|
+
rootDir: string,
|
|
93
|
+
verbose: boolean,
|
|
94
|
+
): { command: string; args: string[] } {
|
|
95
|
+
const args: string[] = [];
|
|
96
|
+
|
|
97
|
+
switch (runner) {
|
|
98
|
+
case "jest": {
|
|
99
|
+
const cmd = "jest";
|
|
100
|
+
if (subcommand === "contracts") {
|
|
101
|
+
args.push("--testPathPattern", "__generated__/.*\\.contract\\.test");
|
|
102
|
+
} else if (subcommand === "integration") {
|
|
103
|
+
args.push("--testPathPattern", "integration");
|
|
104
|
+
}
|
|
105
|
+
if (verbose) {
|
|
106
|
+
args.push("--verbose");
|
|
107
|
+
}
|
|
108
|
+
args.push("--passWithNoTests");
|
|
109
|
+
return { command: cmd, args };
|
|
110
|
+
}
|
|
111
|
+
case "vitest": {
|
|
112
|
+
const cmd = "vitest";
|
|
113
|
+
args.push("run");
|
|
114
|
+
if (subcommand === "contracts") {
|
|
115
|
+
args.push("__generated__/");
|
|
116
|
+
} else if (subcommand === "integration") {
|
|
117
|
+
args.push("--dir", "tests/integration");
|
|
118
|
+
}
|
|
119
|
+
if (verbose) {
|
|
120
|
+
args.push("--reporter", "verbose");
|
|
121
|
+
}
|
|
122
|
+
args.push("--passWithNoTests");
|
|
123
|
+
return { command: cmd, args };
|
|
124
|
+
}
|
|
125
|
+
case "rstest": {
|
|
126
|
+
const cmd = "rstest";
|
|
127
|
+
args.push("run");
|
|
128
|
+
if (subcommand === "contracts") {
|
|
129
|
+
args.push("--testPathPattern", "__generated__/.*\\.contract\\.test");
|
|
130
|
+
} else if (subcommand === "integration") {
|
|
131
|
+
args.push("--testPathPattern", "integration");
|
|
132
|
+
}
|
|
133
|
+
args.push("--passWithNoTests");
|
|
134
|
+
return { command: cmd, args };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Check whether schemas have changed since last contract test generation.
|
|
141
|
+
* Compares the content hash in .typokit/build-cache.json against current type files.
|
|
142
|
+
*/
|
|
143
|
+
export async function schemasChanged(
|
|
144
|
+
rootDir: string,
|
|
145
|
+
config: Required<TypoKitConfig>,
|
|
146
|
+
): Promise<boolean> {
|
|
147
|
+
const { join } = (await import(/* @vite-ignore */ "path")) as {
|
|
148
|
+
join: (...args: string[]) => string;
|
|
149
|
+
};
|
|
150
|
+
const { existsSync } = (await import(/* @vite-ignore */ "fs")) as {
|
|
151
|
+
existsSync: (p: string) => boolean;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const cacheFile = join(rootDir, config.outputDir, "build-cache.json");
|
|
155
|
+
|
|
156
|
+
// If no cache exists, schemas have effectively "changed" (never built)
|
|
157
|
+
if (!existsSync(cacheFile)) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// If the generated contracts directory doesn't exist, need to regenerate
|
|
162
|
+
const generatedDir = join(rootDir, "__generated__");
|
|
163
|
+
if (!existsSync(generatedDir)) {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Cache exists and generated dir exists — assume up to date
|
|
168
|
+
// A full implementation would compare file hashes, but for now
|
|
169
|
+
// we rely on the build pipeline's cache mechanism
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Regenerate contract tests by invoking the generate:tests pipeline.
|
|
175
|
+
*/
|
|
176
|
+
async function regenerateContracts(
|
|
177
|
+
options: TestCommandOptions,
|
|
178
|
+
): Promise<{ success: boolean; errors: string[] }> {
|
|
179
|
+
const { logger, rootDir, config, verbose } = options;
|
|
180
|
+
|
|
181
|
+
logger.step("test", "Regenerating contract tests from schemas...");
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const { executeGenerate } = await import("./generate.js");
|
|
185
|
+
const result = await executeGenerate({
|
|
186
|
+
rootDir,
|
|
187
|
+
config,
|
|
188
|
+
logger,
|
|
189
|
+
subcommand: "tests",
|
|
190
|
+
flags: options.flags,
|
|
191
|
+
verbose,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
if (!result.success) {
|
|
195
|
+
return { success: false, errors: result.errors };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
logger.success(
|
|
199
|
+
`Contract tests regenerated — ${result.filesWritten.length} files`,
|
|
200
|
+
);
|
|
201
|
+
return { success: true, errors: [] };
|
|
202
|
+
} catch (err: unknown) {
|
|
203
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
204
|
+
return {
|
|
205
|
+
success: false,
|
|
206
|
+
errors: [`Failed to regenerate contracts: ${message}`],
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Execute test commands.
|
|
213
|
+
*
|
|
214
|
+
* Subcommands:
|
|
215
|
+
* "all" — runs all tests
|
|
216
|
+
* "contracts" — runs only contract tests from __generated__/
|
|
217
|
+
* "integration" — runs integration tests with in-memory database
|
|
218
|
+
*/
|
|
219
|
+
export async function executeTest(
|
|
220
|
+
options: TestCommandOptions,
|
|
221
|
+
): Promise<TestResult> {
|
|
222
|
+
const startTime = Date.now();
|
|
223
|
+
const { logger, rootDir, config, flags, verbose } = options;
|
|
224
|
+
const subcommand = options.subcommand || "all";
|
|
225
|
+
const errors: string[] = [];
|
|
226
|
+
let contractsRegenerated = false;
|
|
227
|
+
|
|
228
|
+
// Determine test runner: --runner flag overrides auto-detection
|
|
229
|
+
let runner: TestRunner;
|
|
230
|
+
if (typeof flags["runner"] === "string") {
|
|
231
|
+
const requested = flags["runner"] as string;
|
|
232
|
+
if (
|
|
233
|
+
requested === "jest" ||
|
|
234
|
+
requested === "vitest" ||
|
|
235
|
+
requested === "rstest"
|
|
236
|
+
) {
|
|
237
|
+
runner = requested;
|
|
238
|
+
logger.step("test", `Using runner: ${runner} (from --runner flag)`);
|
|
239
|
+
} else {
|
|
240
|
+
logger.error(
|
|
241
|
+
`Unknown test runner: ${requested}. Use jest, vitest, or rstest.`,
|
|
242
|
+
);
|
|
243
|
+
return {
|
|
244
|
+
success: false,
|
|
245
|
+
runner: "vitest",
|
|
246
|
+
duration: Date.now() - startTime,
|
|
247
|
+
errors: [`Unknown test runner: ${requested}`],
|
|
248
|
+
contractsRegenerated: false,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
runner = await detectTestRunner(rootDir);
|
|
253
|
+
logger.step("test", `Auto-detected runner: ${runner}`);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Regenerate contract tests if schemas have changed
|
|
257
|
+
if (subcommand === "all" || subcommand === "contracts") {
|
|
258
|
+
const changed = await schemasChanged(rootDir, config);
|
|
259
|
+
if (changed) {
|
|
260
|
+
const regenResult = await regenerateContracts(options);
|
|
261
|
+
contractsRegenerated = true;
|
|
262
|
+
if (!regenResult.success) {
|
|
263
|
+
logger.warn(
|
|
264
|
+
"Contract test regeneration failed — running existing tests",
|
|
265
|
+
);
|
|
266
|
+
for (const e of regenResult.errors) {
|
|
267
|
+
errors.push(e);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Build runner command
|
|
274
|
+
const { command, args } = buildRunnerCommand(
|
|
275
|
+
runner,
|
|
276
|
+
subcommand,
|
|
277
|
+
rootDir,
|
|
278
|
+
verbose,
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
logger.step("test", `Running: ${command} ${args.join(" ")}`);
|
|
282
|
+
|
|
283
|
+
// Execute the test runner
|
|
284
|
+
const { spawnSync } = (await import(/* @vite-ignore */ "child_process")) as {
|
|
285
|
+
spawnSync: (
|
|
286
|
+
cmd: string,
|
|
287
|
+
args: string[],
|
|
288
|
+
opts: {
|
|
289
|
+
cwd?: string;
|
|
290
|
+
encoding?: string;
|
|
291
|
+
stdio?: string;
|
|
292
|
+
},
|
|
293
|
+
) => {
|
|
294
|
+
status: number | null;
|
|
295
|
+
stdout: string;
|
|
296
|
+
stderr: string;
|
|
297
|
+
error?: Error;
|
|
298
|
+
};
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const result = spawnSync(command, args, {
|
|
302
|
+
cwd: rootDir,
|
|
303
|
+
encoding: "utf-8",
|
|
304
|
+
stdio: "pipe",
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
if (result.error) {
|
|
308
|
+
logger.error(`Failed to start test runner: ${result.error.message}`);
|
|
309
|
+
return {
|
|
310
|
+
success: false,
|
|
311
|
+
runner,
|
|
312
|
+
duration: Date.now() - startTime,
|
|
313
|
+
errors: [`Failed to start ${runner}: ${result.error.message}`],
|
|
314
|
+
contractsRegenerated,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Output test results
|
|
319
|
+
if (result.stdout) {
|
|
320
|
+
// Print test output lines
|
|
321
|
+
for (const line of result.stdout.split("\n")) {
|
|
322
|
+
if (line.trim()) {
|
|
323
|
+
logger.info(line);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (result.stderr && (verbose || result.status !== 0)) {
|
|
329
|
+
for (const line of result.stderr.split("\n")) {
|
|
330
|
+
if (line.trim()) {
|
|
331
|
+
logger.error(line);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const success = result.status === 0;
|
|
337
|
+
const duration = Date.now() - startTime;
|
|
338
|
+
|
|
339
|
+
if (success) {
|
|
340
|
+
logger.success(`Tests passed in ${duration}ms`);
|
|
341
|
+
} else {
|
|
342
|
+
logger.error(`Tests failed (exit code: ${result.status})`);
|
|
343
|
+
errors.push(`Test runner exited with code ${result.status}`);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return {
|
|
347
|
+
success,
|
|
348
|
+
runner,
|
|
349
|
+
duration,
|
|
350
|
+
errors,
|
|
351
|
+
contractsRegenerated,
|
|
352
|
+
};
|
|
353
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// @typokit/cli — Configuration loading
|
|
2
|
+
|
|
3
|
+
export interface TypoKitConfig {
|
|
4
|
+
/** Glob patterns or paths for type definition files */
|
|
5
|
+
typeFiles?: string[];
|
|
6
|
+
/** Glob patterns or paths for route contract files */
|
|
7
|
+
routeFiles?: string[];
|
|
8
|
+
/** Output directory for generated files (default: ".typokit") */
|
|
9
|
+
outputDir?: string;
|
|
10
|
+
/** Output directory for compiled output (default: "dist") */
|
|
11
|
+
distDir?: string;
|
|
12
|
+
/** TypeScript compiler to use: "tsc" | "tsup" | "swc" (default: "tsc") */
|
|
13
|
+
compiler?: "tsc" | "tsup" | "swc";
|
|
14
|
+
/** Additional compiler args */
|
|
15
|
+
compilerArgs?: string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const DEFAULT_CONFIG: Required<TypoKitConfig> = {
|
|
19
|
+
typeFiles: ["src/**/*.types.ts", "src/**/types.ts"],
|
|
20
|
+
routeFiles: ["src/**/*.routes.ts", "src/**/routes.ts", "src/**/contracts.ts"],
|
|
21
|
+
outputDir: ".typokit",
|
|
22
|
+
distDir: "dist",
|
|
23
|
+
compiler: "tsc",
|
|
24
|
+
compilerArgs: [],
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Load TypoKit configuration from typokit.config.ts or package.json.
|
|
29
|
+
* Searches in the given root directory.
|
|
30
|
+
*/
|
|
31
|
+
export async function loadConfig(
|
|
32
|
+
rootDir: string,
|
|
33
|
+
): Promise<Required<TypoKitConfig>> {
|
|
34
|
+
const { join } = (await import(/* @vite-ignore */ "path")) as {
|
|
35
|
+
join: (...args: string[]) => string;
|
|
36
|
+
};
|
|
37
|
+
const { existsSync, readFileSync } = (await import(
|
|
38
|
+
/* @vite-ignore */ "fs"
|
|
39
|
+
)) as {
|
|
40
|
+
existsSync: (p: string) => boolean;
|
|
41
|
+
readFileSync: (p: string, encoding: string) => string;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Try typokit.config.ts (compiled to .js)
|
|
45
|
+
const configTsPath = join(rootDir, "typokit.config.ts");
|
|
46
|
+
const configJsPath = join(rootDir, "typokit.config.js");
|
|
47
|
+
|
|
48
|
+
if (existsSync(configJsPath)) {
|
|
49
|
+
try {
|
|
50
|
+
const { pathToFileURL } = (await import(/* @vite-ignore */ "url")) as {
|
|
51
|
+
pathToFileURL: (p: string) => { href: string };
|
|
52
|
+
};
|
|
53
|
+
const mod = (await import(pathToFileURL(configJsPath).href)) as {
|
|
54
|
+
default?: TypoKitConfig;
|
|
55
|
+
};
|
|
56
|
+
return mergeConfig(mod.default ?? {});
|
|
57
|
+
} catch {
|
|
58
|
+
// Fall through to package.json
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (existsSync(configTsPath)) {
|
|
63
|
+
// Config exists as TS but not compiled — return defaults with a note
|
|
64
|
+
// Users should compile it or use package.json field
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Try package.json "typokit" field
|
|
68
|
+
const pkgPath = join(rootDir, "package.json");
|
|
69
|
+
if (existsSync(pkgPath)) {
|
|
70
|
+
try {
|
|
71
|
+
const pkgContent = readFileSync(pkgPath, "utf-8");
|
|
72
|
+
const pkg = JSON.parse(pkgContent) as Record<string, unknown>;
|
|
73
|
+
if (pkg["typokit"] && typeof pkg["typokit"] === "object") {
|
|
74
|
+
return mergeConfig(pkg["typokit"] as TypoKitConfig);
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
// Fall through to defaults
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { ...DEFAULT_CONFIG };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function mergeConfig(partial: TypoKitConfig): Required<TypoKitConfig> {
|
|
85
|
+
return {
|
|
86
|
+
typeFiles: partial.typeFiles ?? DEFAULT_CONFIG.typeFiles,
|
|
87
|
+
routeFiles: partial.routeFiles ?? DEFAULT_CONFIG.routeFiles,
|
|
88
|
+
outputDir: partial.outputDir ?? DEFAULT_CONFIG.outputDir,
|
|
89
|
+
distDir: partial.distDir ?? DEFAULT_CONFIG.distDir,
|
|
90
|
+
compiler: partial.compiler ?? DEFAULT_CONFIG.compiler,
|
|
91
|
+
compilerArgs: partial.compilerArgs ?? DEFAULT_CONFIG.compilerArgs,
|
|
92
|
+
};
|
|
93
|
+
}
|