@jterrazz/typescript 8.1.3 → 9.0.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/README.md +1 -0
- package/bin/commands/check.sh +37 -1
- package/bin/typescript.sh +19 -1
- package/lib/check-gitignore.js +260 -0
- package/package.json +1 -1
- package/presets/tsconfig/expo.json +3 -1
- package/presets/tsconfig/next.json +1 -0
- package/presets/tsconfig/node.json +2 -0
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@ npx typescript dev # Build, run, and rebuild on changes
|
|
|
18
18
|
npx typescript docs # Compile the committed docs/reference tree from source
|
|
19
19
|
npx typescript check # Type-check, lint, format-check, and unused-code in parallel
|
|
20
20
|
npx typescript fix # Auto-fix lint and formatting issues
|
|
21
|
+
npx typescript clean # Remove .artifacts/ (dist/ stays — it is the product)
|
|
21
22
|
```
|
|
22
23
|
|
|
23
24
|
## How it works
|
package/bin/commands/check.sh
CHANGED
|
@@ -269,6 +269,11 @@ run_checks() {
|
|
|
269
269
|
# Merge base config (from this package) with optional project-local knip.json.
|
|
270
270
|
# Root-only on purpose: knip reads the workspace globs itself and reports per
|
|
271
271
|
# member from one run — a second invocation per member would double-report.
|
|
272
|
+
#
|
|
273
|
+
# Deliberately UNCACHED. Knip's `--cache` validates a cached glob against the
|
|
274
|
+
# mtimes of the directories that held a match; a file added to a directory
|
|
275
|
+
# that held none is invisible to it, and the run exits 0 where the uncached
|
|
276
|
+
# run exits 1. A gate that can pass on stale knowledge is worse than a slow one.
|
|
272
277
|
local knip_pid=""
|
|
273
278
|
local knip_status=0
|
|
274
279
|
if [ "$FIX_MODE" = false ]; then
|
|
@@ -282,6 +287,23 @@ run_checks() {
|
|
|
282
287
|
knip_pid=$!
|
|
283
288
|
fi
|
|
284
289
|
|
|
290
|
+
# Gitignore (artefacts): the convention — every artefact under
|
|
291
|
+
# `.artifacts/<tool>/`, `dist` excepted — read off the project's own
|
|
292
|
+
# `.gitignore`. Opt-in by existence: a project with no `.gitignore` names no
|
|
293
|
+
# artefact path, so the gate has no question to ask. Root-only, because
|
|
294
|
+
# `.artifacts/` sits at the project ROOT. Runs in fix mode too — it is the
|
|
295
|
+
# one gate whose remedy is a rewrite rather than a deletion.
|
|
296
|
+
local gitignore_pid=""
|
|
297
|
+
local gitignore_status=0
|
|
298
|
+
if [ -f ".gitignore" ]; then
|
|
299
|
+
if [ "$FIX_MODE" = true ]; then
|
|
300
|
+
node "$PACKAGE_ROOT/lib/check-gitignore.js" --fix > "$tmp_dir/gitignore.log" 2>&1 &
|
|
301
|
+
else
|
|
302
|
+
node "$PACKAGE_ROOT/lib/check-gitignore.js" > "$tmp_dir/gitignore.log" 2>&1 &
|
|
303
|
+
fi
|
|
304
|
+
gitignore_pid=$!
|
|
305
|
+
fi
|
|
306
|
+
|
|
285
307
|
# Conventions checker: only in check mode, once per specs root the workspace
|
|
286
308
|
# owns, gated by the package that OWNS that root — a member may depend on
|
|
287
309
|
# @jterrazz/test while the root does not, and the reverse.
|
|
@@ -326,6 +348,7 @@ run_checks() {
|
|
|
326
348
|
wait $lint_pid; local lint_status=$?
|
|
327
349
|
wait $format_pid; local format_status=$?
|
|
328
350
|
[ -n "$knip_pid" ] && { wait $knip_pid; knip_status=$?; }
|
|
351
|
+
[ -n "$gitignore_pid" ] && { wait $gitignore_pid; gitignore_status=$?; }
|
|
329
352
|
|
|
330
353
|
# One pass, N runs: the pass fails if any run failed, and only the logs of
|
|
331
354
|
# the runs that FAILED are printed — a green member stays silent.
|
|
@@ -380,6 +403,19 @@ run_checks() {
|
|
|
380
403
|
printf "${GREEN}✓ Passed${NC}\n"
|
|
381
404
|
fi
|
|
382
405
|
|
|
406
|
+
# The one pass that speaks on success: a rewrite changed a file the operator
|
|
407
|
+
# owns, and silence would hide it. In check mode a green gate writes nothing,
|
|
408
|
+
# so the green output stays byte-identical with the others.
|
|
409
|
+
if [ -n "$gitignore_pid" ]; then
|
|
410
|
+
printf "\n${CYAN_BG}${BRIGHT_WHITE} RUN ${NC} Gitignore (artefacts)\n\n"
|
|
411
|
+
[ -s "$tmp_dir/gitignore.log" ] && cat "$tmp_dir/gitignore.log"
|
|
412
|
+
if [ $gitignore_status -ne 0 ]; then
|
|
413
|
+
printf "${RED}✗ Failed with exit code %d${NC}\n" $gitignore_status
|
|
414
|
+
else
|
|
415
|
+
printf "${GREEN}✓ Passed${NC}\n"
|
|
416
|
+
fi
|
|
417
|
+
fi
|
|
418
|
+
|
|
383
419
|
if [ "$FIX_MODE" = false ]; then
|
|
384
420
|
printf "\n${CYAN_BG}${BRIGHT_WHITE} RUN ${NC} Knip (unused code)\n\n"
|
|
385
421
|
if [ $knip_status -ne 0 ]; then
|
|
@@ -421,7 +457,7 @@ run_checks() {
|
|
|
421
457
|
printf "\n${CYAN_BG}${BRIGHT_WHITE} END ${NC} Finalizing quality checks\n\n"
|
|
422
458
|
fi
|
|
423
459
|
|
|
424
|
-
if [ $type_status -eq 0 ] && [ $lint_status -eq 0 ] && [ $format_status -eq 0 ] && [ $knip_status -eq 0 ] && [ $checker_status -eq 0 ] && [ $docs_status -eq 0 ]; then
|
|
460
|
+
if [ $type_status -eq 0 ] && [ $lint_status -eq 0 ] && [ $format_status -eq 0 ] && [ $knip_status -eq 0 ] && [ $gitignore_status -eq 0 ] && [ $checker_status -eq 0 ] && [ $docs_status -eq 0 ]; then
|
|
425
461
|
printf "${GREEN}✓ All checks passed${NC}\n"
|
|
426
462
|
exit 0
|
|
427
463
|
else
|
package/bin/typescript.sh
CHANGED
|
@@ -144,6 +144,22 @@ case "$COMMAND" in
|
|
|
144
144
|
fi
|
|
145
145
|
;;
|
|
146
146
|
|
|
147
|
+
clean)
|
|
148
|
+
# Every tool writes under .artifacts/<tool>/, so removing that one
|
|
149
|
+
# directory is the whole cleanup. dist/ is NOT touched: it is the
|
|
150
|
+
# build's product, published from beside src/, not an artefact.
|
|
151
|
+
cd "$PROJECT_ROOT"
|
|
152
|
+
|
|
153
|
+
printf "${CYAN_BG}${BRIGHT_WHITE} TYPESCRIPT ${NC} Removing artefacts...\n\n"
|
|
154
|
+
|
|
155
|
+
if [ -d ".artifacts" ]; then
|
|
156
|
+
rm -rf .artifacts
|
|
157
|
+
printf "${GREEN}Removed .artifacts/${NC}\n"
|
|
158
|
+
else
|
|
159
|
+
printf "${GREEN}Nothing to remove — .artifacts/ is already absent${NC}\n"
|
|
160
|
+
fi
|
|
161
|
+
;;
|
|
162
|
+
|
|
147
163
|
check|fix)
|
|
148
164
|
exec bash "$SCRIPT_DIR/commands/check.sh" "$COMMAND" "$@"
|
|
149
165
|
;;
|
|
@@ -158,7 +174,8 @@ case "$COMMAND" in
|
|
|
158
174
|
printf " dev Build, run, and rebuild on changes\n"
|
|
159
175
|
printf " docs Generate the committed docs/reference tree; --check verifies sync\n"
|
|
160
176
|
printf " check Check types, lint, formatting, and unused code\n"
|
|
161
|
-
printf " fix Auto-fix lint and formatting issues\n
|
|
177
|
+
printf " fix Auto-fix lint and formatting issues\n"
|
|
178
|
+
printf " clean Remove .artifacts/ — dist/ stays, it is the build's product\n\n"
|
|
162
179
|
printf "Examples:\n"
|
|
163
180
|
printf " typescript build\n"
|
|
164
181
|
printf " typescript bundle\n"
|
|
@@ -168,6 +185,7 @@ case "$COMMAND" in
|
|
|
168
185
|
printf " typescript docs --check\n"
|
|
169
186
|
printf " typescript check\n"
|
|
170
187
|
printf " typescript fix\n"
|
|
188
|
+
printf " typescript clean\n"
|
|
171
189
|
exit 1
|
|
172
190
|
;;
|
|
173
191
|
esac
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The artefact convention, read off a project's `.gitignore`.
|
|
5
|
+
*
|
|
6
|
+
* Every build, test and lint artefact lives under `.artifacts/<tool>/` at the
|
|
7
|
+
* project root — one folder per tool that writes. A `.gitignore` line naming an
|
|
8
|
+
* artefact ANYWHERE else is the old layout, and this gate says so; `.artifacts/`
|
|
9
|
+
* itself must be ignored, so the convention's own folder never reaches a commit.
|
|
10
|
+
*
|
|
11
|
+
* Usage: node check-gitignore.js [--fix] [root]
|
|
12
|
+
*
|
|
13
|
+
* `--fix` rewrites the `.gitignore`: the artefact lines go, `.artifacts/` arrives,
|
|
14
|
+
* and everything else — comments, blank lines, order, the project's own paths —
|
|
15
|
+
* survives untouched. A `!` line is NEVER rewritten: it rescues a tracked file,
|
|
16
|
+
* and deleting the line it negates could hide a real path. Those are reported.
|
|
17
|
+
*
|
|
18
|
+
* Exit code: 0 when the project holds the convention, 1 otherwise. In `--fix`
|
|
19
|
+
* mode only what the rewrite cannot repair — a committed artefact — still fails.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { execFileSync } from 'node:child_process';
|
|
23
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
24
|
+
import { join } from 'node:path';
|
|
25
|
+
import { argv, exit, stdout } from 'node:process';
|
|
26
|
+
|
|
27
|
+
/** The convention's own directory: the one path that MUST be ignored. */
|
|
28
|
+
const ARTIFACTS = '.artifacts';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The one exception to the convention: a build's product stays beside `src/`
|
|
32
|
+
* and is published from there, so `dist` is a legitimate ignored path.
|
|
33
|
+
*/
|
|
34
|
+
const PRODUCT = 'dist';
|
|
35
|
+
|
|
36
|
+
/** Directories a tool writes, and the `.artifacts/` home each one moves to. */
|
|
37
|
+
const ARTEFACT_DIRECTORIES = new Map([
|
|
38
|
+
['.cache', '.artifacts/<tool>/'],
|
|
39
|
+
['.next', '.artifacts/next/'],
|
|
40
|
+
['.turbo', '.artifacts/turbo/'],
|
|
41
|
+
['.vite', '.artifacts/vite/'],
|
|
42
|
+
['bin', '.artifacts/go/'],
|
|
43
|
+
['build', '.artifacts/<tool>/'],
|
|
44
|
+
['coverage', '.artifacts/coverage/'],
|
|
45
|
+
['out', '.artifacts/next/'],
|
|
46
|
+
['playwright-report', '.artifacts/playwright/'],
|
|
47
|
+
['target', '.artifacts/cargo/'],
|
|
48
|
+
['test-results', '.artifacts/playwright/'],
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
/** Files a tool writes, matched on their extension, and where they belong. */
|
|
52
|
+
const ARTEFACT_EXTENSIONS = [
|
|
53
|
+
['.tsbuildinfo', '.artifacts/tsc/'],
|
|
54
|
+
['.log', '.artifacts/logs/'],
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The closed list of ignored paths that are NOT artefacts of the convention:
|
|
59
|
+
* platform working directories a toolchain owns and cannot be told to move,
|
|
60
|
+
* generated files a framework expects at a fixed path, and `node_modules`.
|
|
61
|
+
*/
|
|
62
|
+
const EXCEPTIONS = new Set([
|
|
63
|
+
'.build',
|
|
64
|
+
'.expo',
|
|
65
|
+
'.gradle',
|
|
66
|
+
'.swiftpm',
|
|
67
|
+
'.vercel',
|
|
68
|
+
'DerivedData',
|
|
69
|
+
'Package.resolved',
|
|
70
|
+
'android',
|
|
71
|
+
'ios',
|
|
72
|
+
'next-env.d.ts',
|
|
73
|
+
'node_modules',
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
/** The one exception spelled as a prefix — Expo stamps a suffix onto it. */
|
|
77
|
+
const EXCEPTION_PREFIXES = ['.metro-health-check'];
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Directories whose every tracked file is a committed artefact. Narrower than
|
|
81
|
+
* the list above on purpose: `bin`, `out`, `build` and `target` are ignorable
|
|
82
|
+
* as OUTPUT, but a tracked file under them may be a project's own source —
|
|
83
|
+
* a `.gitignore` line declares intent, a tracked path declares nothing.
|
|
84
|
+
*/
|
|
85
|
+
const TRACKED_ARTEFACT_DIRECTORIES = new Set([
|
|
86
|
+
'.artifacts',
|
|
87
|
+
'.cache',
|
|
88
|
+
'.next',
|
|
89
|
+
'.turbo',
|
|
90
|
+
'.vite',
|
|
91
|
+
'coverage',
|
|
92
|
+
'playwright-report',
|
|
93
|
+
'test-results',
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
/** The extension no tracked file may carry — a buildinfo is never source. */
|
|
97
|
+
const TRACKED_ARTEFACT_EXTENSION = '.tsbuildinfo';
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* What a `.gitignore` pattern names, reduced to the one segment that carries
|
|
101
|
+
* the meaning: an anchored form, a nested form and a doubled-star form all name
|
|
102
|
+
* the same directory. A trailing `*` is dropped so `npm-debug.log*` reads as a
|
|
103
|
+
* log, and a `**` segment never wins over the name that follows it.
|
|
104
|
+
*/
|
|
105
|
+
function subject(pattern) {
|
|
106
|
+
const segments = pattern
|
|
107
|
+
.replace(/\/+$/, '')
|
|
108
|
+
.split('/')
|
|
109
|
+
.filter((segment) => segment !== '' && segment !== '**');
|
|
110
|
+
|
|
111
|
+
return (segments.at(-1) ?? '').replace(/\*$/, '');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** The `.artifacts/` home of the artefact a pattern names, or null. */
|
|
115
|
+
function artefactHome(pattern) {
|
|
116
|
+
const name = subject(pattern);
|
|
117
|
+
|
|
118
|
+
if (name === '' || name === PRODUCT || EXCEPTIONS.has(name)) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
if (EXCEPTION_PREFIXES.some((prefix) => name.startsWith(prefix))) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
if (ARTEFACT_DIRECTORIES.has(name)) {
|
|
125
|
+
return ARTEFACT_DIRECTORIES.get(name);
|
|
126
|
+
}
|
|
127
|
+
for (const [extension, home] of ARTEFACT_EXTENSIONS) {
|
|
128
|
+
if (name.endsWith(extension)) {
|
|
129
|
+
return home;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Every line of the file, classified once — the rewrite reads the same list. */
|
|
137
|
+
function readLines(gitignorePath) {
|
|
138
|
+
const text = readFileSync(gitignorePath, 'utf8').split('\n');
|
|
139
|
+
|
|
140
|
+
// The empty string a trailing newline leaves behind is not a line.
|
|
141
|
+
// Putting that newline back is the rewrite's job.
|
|
142
|
+
if (text.at(-1) === '') {
|
|
143
|
+
text.pop();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return text.map((line) => {
|
|
147
|
+
const pattern = line.trim();
|
|
148
|
+
const isPattern = pattern !== '' && !pattern.startsWith('#');
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
home: isPattern && !pattern.startsWith('!') ? artefactHome(pattern) : null,
|
|
152
|
+
isNegation: isPattern && pattern.startsWith('!'),
|
|
153
|
+
pattern,
|
|
154
|
+
text: line,
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The artefacts a project COMMITTED. Outside a git tree the question has no
|
|
161
|
+
* answer, and silence is the right one — a fixture directory is not a repo.
|
|
162
|
+
*/
|
|
163
|
+
function trackedArtefacts(root) {
|
|
164
|
+
let listed;
|
|
165
|
+
try {
|
|
166
|
+
listed = execFileSync('git', ['ls-files', '-z'], {
|
|
167
|
+
cwd: root,
|
|
168
|
+
encoding: 'utf8',
|
|
169
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
170
|
+
});
|
|
171
|
+
} catch {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return listed
|
|
176
|
+
.split('\0')
|
|
177
|
+
.filter((path) => path !== '')
|
|
178
|
+
.filter((path) => {
|
|
179
|
+
const segments = path.split('/');
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
segments
|
|
183
|
+
.slice(0, -1)
|
|
184
|
+
.some((segment) => TRACKED_ARTEFACT_DIRECTORIES.has(segment)) ||
|
|
185
|
+
path.endsWith(TRACKED_ARTEFACT_EXTENSION)
|
|
186
|
+
);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** The rewritten file: artefact lines dropped, `.artifacts/` present, rest kept. */
|
|
191
|
+
function rewrite(lines) {
|
|
192
|
+
const kept = lines.filter((line) => line.home === null);
|
|
193
|
+
const isIgnored = kept.some((line) => !line.isNegation && subject(line.pattern) === ARTIFACTS);
|
|
194
|
+
const body = kept.map((line) => line.text);
|
|
195
|
+
|
|
196
|
+
if (!isIgnored) {
|
|
197
|
+
while (body.length > 0 && body.at(-1).trim() === '') {
|
|
198
|
+
body.pop();
|
|
199
|
+
}
|
|
200
|
+
body.push('', '# Build, test and lint artefacts (@jterrazz/typescript)', `${ARTIFACTS}/`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return `${body.join('\n')}\n`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const isFix = argv.includes('--fix');
|
|
207
|
+
const root = argv.slice(2).find((argument) => !argument.startsWith('--')) ?? '.';
|
|
208
|
+
const gitignorePath = join(root, '.gitignore');
|
|
209
|
+
|
|
210
|
+
// A project with no `.gitignore` declares no artefact path and nothing to fix.
|
|
211
|
+
// The gate has no question to ask of it, and stays silent.
|
|
212
|
+
if (!existsSync(gitignorePath)) {
|
|
213
|
+
exit(0);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const lines = readLines(gitignorePath);
|
|
217
|
+
const misplaced = lines.filter((line) => line.home !== null);
|
|
218
|
+
const negations = lines.filter((line) => line.isNegation);
|
|
219
|
+
const isIgnored = lines.some(
|
|
220
|
+
(line) => !line.isNegation && line.home === null && subject(line.pattern) === ARTIFACTS,
|
|
221
|
+
);
|
|
222
|
+
const tracked = trackedArtefacts(root);
|
|
223
|
+
|
|
224
|
+
if (isFix) {
|
|
225
|
+
const changed = misplaced.length > 0 || !isIgnored;
|
|
226
|
+
if (changed) {
|
|
227
|
+
writeFileSync(gitignorePath, rewrite(lines));
|
|
228
|
+
stdout.write('.gitignore rewritten:\n');
|
|
229
|
+
for (const line of misplaced) {
|
|
230
|
+
stdout.write(` - ${line.pattern}\n`);
|
|
231
|
+
}
|
|
232
|
+
if (!isIgnored) {
|
|
233
|
+
stdout.write(` + ${ARTIFACTS}/\n`);
|
|
234
|
+
}
|
|
235
|
+
for (const line of negations) {
|
|
236
|
+
stdout.write(` · ${line.pattern} — a negation rescues a tracked file, kept\n`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
} else if (misplaced.length > 0 || !isIgnored) {
|
|
240
|
+
stdout.write('Artefacts belong under .artifacts/<tool>/ at the project root:\n');
|
|
241
|
+
for (const line of misplaced) {
|
|
242
|
+
stdout.write(` ✗ .gitignore names ${line.pattern} — its home is ${line.home}\n`);
|
|
243
|
+
}
|
|
244
|
+
if (!isIgnored) {
|
|
245
|
+
stdout.write(` ✗ .gitignore does not ignore ${ARTIFACTS}/ — add it\n`);
|
|
246
|
+
}
|
|
247
|
+
for (const line of negations) {
|
|
248
|
+
stdout.write(` · ${line.pattern} — a negation rescues a tracked file, left for you\n`);
|
|
249
|
+
}
|
|
250
|
+
stdout.write("Run 'typescript fix' to rewrite .gitignore.\n");
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (tracked.length > 0) {
|
|
254
|
+
stdout.write('Artefacts must never be committed:\n');
|
|
255
|
+
for (const path of tracked) {
|
|
256
|
+
stdout.write(` ✗ ${path} is tracked — git rm --cached ${path}\n`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
exit(tracked.length > 0 || (!isFix && (misplaced.length > 0 || !isIgnored)) ? 1 : 0);
|
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
"allowJs": true,
|
|
8
8
|
"baseUrl": ".",
|
|
9
9
|
"esModuleInterop": true,
|
|
10
|
+
"incremental": true,
|
|
10
11
|
"jsx": "react-native",
|
|
11
12
|
"lib": ["DOM", "ESNext"],
|
|
12
13
|
"moduleResolution": "node",
|
|
@@ -16,6 +17,7 @@
|
|
|
16
17
|
},
|
|
17
18
|
"resolveJsonModule": true,
|
|
18
19
|
"skipLibCheck": true,
|
|
19
|
-
"target": "ESNext"
|
|
20
|
+
"target": "ESNext",
|
|
21
|
+
"tsBuildInfoFile": "${configDir}/.artifacts/tsc/tsconfig.tsbuildinfo"
|
|
20
22
|
}
|
|
21
23
|
}
|