@companion-module/tools 3.0.2 → 3.1.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.
@@ -0,0 +1,371 @@
1
+ import { createRequire as _createRequire } from "module";
2
+ const __require = _createRequire(import.meta.url);
3
+ const parse = __require("spdx-expression-parse");
4
+ import { correctedPackageLicense } from './known-package-licenses.js';
5
+ export class LicensePolicyError extends Error {
6
+ issues;
7
+ constructor(issues) {
8
+ super(`License validation failed with ${issues.length} error${issues.length === 1 ? '' : 's'}.`);
9
+ this.issues = issues;
10
+ this.name = 'LicensePolicyError';
11
+ }
12
+ }
13
+ /** Permissive licenses which may be shipped by a module under any of the supported project licenses */
14
+ const PERMISSIVE_DEPENDENCY_LICENSES = [
15
+ 'MIT',
16
+ 'MIT-0',
17
+ 'ISC',
18
+ 'BSD-2-Clause',
19
+ 'BSD-3-Clause',
20
+ '0BSD',
21
+ 'CC0-1.0',
22
+ 'Unlicense',
23
+ 'BlueOak-1.0.0',
24
+ 'Python-2.0',
25
+ 'Zlib',
26
+ 'BSL-1.0',
27
+ // Not an SPDX identifier, SPDX has none for a public domain dedication. Recording it as CC0-1.0 or Unlicense
28
+ // would name a specific legal instrument the package never used, and public domain carries no obligation at all.
29
+ 'Public-Domain',
30
+ ];
31
+ const GPL2_DEPENDENCY_LICENSES = [
32
+ 'GPL-2.0-only',
33
+ 'GPL-2.0-or-later',
34
+ 'GPL-2.0', // Deprecated SPDX id for GPL-2.0-only, still widely declared on npm
35
+ ];
36
+ const GPL3_DEPENDENCY_LICENSES = [
37
+ 'GPL-3.0-only',
38
+ 'GPL-3.0-or-later',
39
+ 'GPL-3.0', // Deprecated SPDX id for GPL-3.0-only, still widely declared on npm
40
+ ];
41
+ // The LGPL families split by which GPL version their relicensing clause can reach. LGPL-2.x section 3 offers "version
42
+ // 2 of the ordinary GPL or any later version", so it suits either GPL policy, while LGPL-3.0 only reaches GPL-3.0.
43
+ const LGPL2_DEPENDENCY_LICENSES = [
44
+ 'LGPL-2.0-only',
45
+ 'LGPL-2.0-or-later',
46
+ 'LGPL-2.0', // Deprecated SPDX id for LGPL-2.0-only, still widely declared on npm
47
+ 'LGPL-2.1-only',
48
+ 'LGPL-2.1-or-later',
49
+ 'LGPL-2.1', // Deprecated SPDX id for LGPL-2.1-only
50
+ ];
51
+ const LGPL3_DEPENDENCY_LICENSES = [
52
+ 'LGPL-3.0-only',
53
+ 'LGPL-3.0-or-later',
54
+ 'LGPL-3.0', // Deprecated SPDX id for LGPL-3.0-only
55
+ ];
56
+ // Each policy pins the combined work to a single GPL version, so no mix of allowed dependencies can end up
57
+ // unlicensable. Offering GPL-2.0-or-later would break that, a GPL-2.0-only and a GPL-3.0-only dependency could then
58
+ // both be accepted while no version satisfies both.
59
+ const PROJECT_LICENSE_POLICIES = {
60
+ MIT: {
61
+ allowedDependencyLicenses: new Set([
62
+ ...PERMISSIVE_DEPENDENCY_LICENSES,
63
+ 'Apache-2.0',
64
+ 'CC-BY-3.0',
65
+ 'CC-BY-4.0',
66
+ 'MPL-2.0', // File level copyleft, allows bundling if source is available (links bundled LICENSE)
67
+ ]),
68
+ // An MIT bundle cannot offer the relinking static linking would require, but the LGPL is written to let a
69
+ // work under any terms use the library as a separate one, so every LGPL version is fine as an external
70
+ externalOnlyLicenses: new Set([...LGPL2_DEPENDENCY_LICENSES, ...LGPL3_DEPENDENCY_LICENSES]),
71
+ },
72
+ // Apache-2.0 and the CC-BY licenses are deliberately absent, they cannot be combined with GPL-2.0-only
73
+ 'GPL-2.0-only': {
74
+ allowedDependencyLicenses: new Set([
75
+ ...PERMISSIVE_DEPENDENCY_LICENSES,
76
+ ...GPL2_DEPENDENCY_LICENSES,
77
+ // Section 3 relicenses these to GPL-2.0, so the bundle stays distributable under this policy
78
+ ...LGPL2_DEPENDENCY_LICENSES,
79
+ 'MPL-2.0',
80
+ ]),
81
+ // LGPL-3.0 is absent entirely rather than external only. It is GPL-3.0 plus permissions, so it carries terms
82
+ // GPL-2.0 section 6 forbids adding, and linking still forms a combined work whichever way it is shipped.
83
+ externalOnlyLicenses: new Set(),
84
+ },
85
+ 'GPL-3.0-only': {
86
+ allowedDependencyLicenses: new Set([
87
+ ...PERMISSIVE_DEPENDENCY_LICENSES,
88
+ ...GPL3_DEPENDENCY_LICENSES,
89
+ 'GPL-2.0-or-later', // GPL-2.0-only is absent, only the "or later" form can be taken to GPL-3.0
90
+ // Both families reach GPL-3.0, the 2.x one through its "or any later version" offer
91
+ ...LGPL2_DEPENDENCY_LICENSES,
92
+ ...LGPL3_DEPENDENCY_LICENSES,
93
+ 'Apache-2.0',
94
+ 'MPL-2.0',
95
+ ]),
96
+ externalOnlyLicenses: new Set(),
97
+ },
98
+ };
99
+ export const SUPPORTED_PROJECT_LICENSES = Object.keys(PROJECT_LICENSE_POLICIES);
100
+ /** Policy applied to dependencies while the module itself has no usable license declaration */
101
+ const FALLBACK_PROJECT_LICENSE = 'MIT';
102
+ /** Suggested to module authors, as the one which can use the most of npm and be reused most freely */
103
+ const RECOMMENDED_PROJECT_LICENSE = 'MIT';
104
+ const LICENSE_HELP_MESSAGE = 'Not sure what to do about these? Ask in the Bitfocus community Slack, we are happy to help you work out what they mean for your module.';
105
+ function isProjectLicense(declaration) {
106
+ return SUPPORTED_PROJECT_LICENSES.includes(declaration);
107
+ }
108
+ function orList(items) {
109
+ const remaining = [...items];
110
+ const last = remaining.pop();
111
+ return remaining.length ? `${remaining.join(', ')} or ${last}` : `${last}`;
112
+ }
113
+ function supportedProjectLicenseAdvice() {
114
+ const alternatives = SUPPORTED_PROJECT_LICENSES.filter((license) => license !== RECOMMENDED_PROJECT_LICENSE);
115
+ return `We recommend ${RECOMMENDED_PROJECT_LICENSE} for the widest compatibility, but also accept ${orList(alternatives)} when necessary.`;
116
+ }
117
+ function evaluate(node, allowedLicenses) {
118
+ if ('license' in node) {
119
+ const license = node.plus ? `${node.license}-or-later` : node.license; // "GPL-2.0+" is deprecated for "GPL-2.0-or-later"
120
+ return {
121
+ allowed: !node.exception && allowedLicenses.has(license),
122
+ incompatibleAnd: false,
123
+ };
124
+ }
125
+ const left = evaluate(node.left, allowedLicenses);
126
+ const right = evaluate(node.right, allowedLicenses);
127
+ if (node.conjunction === 'or') {
128
+ const allowed = left.allowed || right.allowed;
129
+ return {
130
+ allowed,
131
+ incompatibleAnd: !allowed && (left.incompatibleAnd || right.incompatibleAnd),
132
+ };
133
+ }
134
+ return {
135
+ allowed: left.allowed && right.allowed,
136
+ incompatibleAnd: left.allowed !== right.allowed || left.incompatibleAnd || right.incompatibleAnd,
137
+ };
138
+ }
139
+ /**
140
+ * spdx-expression-parse rejects the whole expression when any leaf is not a valid SPDX identifier, so a legacy
141
+ * declaration like "(MIT OR GPL)" never reaches the OR logic at all. Re-read those keeping only the boolean
142
+ * structure, so an unrecognised identifier becomes a license which is simply never allowed. OR then still offers a
143
+ * real choice, and AND still requires every branch, so nothing unknown can be accepted on its own.
144
+ */
145
+ function parseLenient(declaration) {
146
+ const tokens = declaration.match(/\(|\)|[^\s()]+/g);
147
+ if (!tokens)
148
+ return undefined;
149
+ let index = 0;
150
+ const keyword = (token, word) => token !== undefined && token.toUpperCase() === word;
151
+ function parseExpression() {
152
+ let node = parseTerm();
153
+ if (!node)
154
+ return undefined;
155
+ while (keyword(tokens[index], 'OR')) {
156
+ index++;
157
+ const right = parseTerm();
158
+ if (!right)
159
+ return undefined;
160
+ node = { left: node, conjunction: 'or', right };
161
+ }
162
+ return node;
163
+ }
164
+ function parseTerm() {
165
+ let node = parseFactor();
166
+ if (!node)
167
+ return undefined;
168
+ while (keyword(tokens[index], 'AND')) {
169
+ index++;
170
+ const right = parseFactor();
171
+ if (!right)
172
+ return undefined;
173
+ node = { left: node, conjunction: 'and', right };
174
+ }
175
+ return node;
176
+ }
177
+ function parseFactor() {
178
+ const token = tokens[index];
179
+ if (token === undefined || token === ')')
180
+ return undefined;
181
+ if (token === '(') {
182
+ index++;
183
+ const node = parseExpression();
184
+ if (!node || tokens[index] !== ')')
185
+ return undefined;
186
+ index++;
187
+ return node;
188
+ }
189
+ if (keyword(token, 'AND') || keyword(token, 'OR') || keyword(token, 'WITH'))
190
+ return undefined;
191
+ index++;
192
+ const plus = token.endsWith('+');
193
+ const node = { license: plus ? token.slice(0, -1) : token };
194
+ if (plus)
195
+ node.plus = true;
196
+ if (keyword(tokens[index], 'WITH')) {
197
+ index++;
198
+ if (tokens[index] === undefined)
199
+ return undefined;
200
+ node.exception = tokens[index];
201
+ index++;
202
+ }
203
+ return node;
204
+ }
205
+ const node = parseExpression();
206
+ return node && index === tokens.length ? node : undefined;
207
+ }
208
+ function parseDeclaration(declaration) {
209
+ try {
210
+ return { node: parse(declaration), strict: true };
211
+ }
212
+ catch {
213
+ const node = parseLenient(declaration);
214
+ return node ? { node, strict: false } : undefined;
215
+ }
216
+ }
217
+ function normalizedDeclaration(packageInfo) {
218
+ return packageInfo.declaredLicense?.trim() ?? '';
219
+ }
220
+ function packageLabel(packageInfo) {
221
+ return `${packageInfo.name}${packageInfo.version ? `@${packageInfo.version}` : ''}`;
222
+ }
223
+ function displayDeclaration(declaration) {
224
+ return declaration.replace(/[\u0000-\u001f\u007f]/g, (character) => {
225
+ switch (character) {
226
+ case '\r':
227
+ return '\\r';
228
+ case '\n':
229
+ return '\\n';
230
+ case '\t':
231
+ return '\\t';
232
+ default:
233
+ return `\\u${character.codePointAt(0).toString(16).padStart(4, '0')}`;
234
+ }
235
+ });
236
+ }
237
+ function ambiguitySuffix(evaluation) {
238
+ return evaluation.incompatibleAnd
239
+ ? ' Both licenses may apply, making this declaration ambiguous and incompatible. Ask package author to use OR if either license may be chosen, or clarify package licensing.'
240
+ : '';
241
+ }
242
+ function packageSort(a, b) {
243
+ if (a.kind === 'project' && b.kind !== 'project')
244
+ return -1;
245
+ if (a.kind !== 'project' && b.kind === 'project')
246
+ return 1;
247
+ return (a.name.localeCompare(b.name) ||
248
+ (a.version ?? '').localeCompare(b.version ?? '') ||
249
+ normalizedDeclaration(a).localeCompare(normalizedDeclaration(b)) ||
250
+ a.kind.localeCompare(b.kind));
251
+ }
252
+ function issue(packageInfo, message) {
253
+ return {
254
+ packageName: packageInfo.name,
255
+ packageVersion: packageInfo.version,
256
+ packageKind: packageInfo.kind,
257
+ message,
258
+ };
259
+ }
260
+ /** Resolve the license the packaged module is distributed under, which selects the policy applied to its dependencies */
261
+ export function resolveProjectLicense(inventory) {
262
+ const projectPackage = inventory.packages.find((packageInfo) => packageInfo.kind === 'project');
263
+ const declaration = projectPackage ? normalizedDeclaration(projectPackage) : '';
264
+ return { declaration, license: isProjectLicense(declaration) ? declaration : undefined };
265
+ }
266
+ // For now module source must be MIT, so it stays portable whatever the packaged module is distributed as. Relaxing
267
+ // this means checking the source license is compatible with the distribution license instead of equal to this one.
268
+ const REQUIRED_SOURCE_LICENSE = 'MIT';
269
+ function createSourceLicenseIssue(packageInfo) {
270
+ const sourceLicense = packageInfo.sourceLicense?.trim() ?? '';
271
+ if (sourceLicense === REQUIRED_SOURCE_LICENSE)
272
+ return undefined;
273
+ if (!sourceLicense) {
274
+ return issue(packageInfo, `Your module source does not declare a license in package.json, but the Companion project requires module source to be ${REQUIRED_SOURCE_LICENSE} so it stays portable.`);
275
+ }
276
+ return issue(packageInfo, `Your module source is licensed as ${displayDeclaration(sourceLicense)} in package.json, but the Companion project requires module source to be ${REQUIRED_SOURCE_LICENSE} so it stays portable. Declare the license the module is distributed under in companion/manifest.json instead.`);
277
+ }
278
+ function createDistributionLicenseIssue(packageInfo) {
279
+ const declaration = normalizedDeclaration(packageInfo);
280
+ if (!declaration) {
281
+ return issue(packageInfo, `Your module does not declare a license in companion/manifest.json. ${supportedProjectLicenseAdvice()} Talk to us if you have a reason to use a different license.`);
282
+ }
283
+ if (isProjectLicense(declaration))
284
+ return undefined;
285
+ let reason = 'which is not supported';
286
+ try {
287
+ // A declaration with a conjunction is dual licensing, which a module must pick a single license from
288
+ if (!('license' in parse(declaration)))
289
+ reason = 'and dual licensing is not supported';
290
+ }
291
+ catch {
292
+ // Report the declaration as unsupported, even when SPDX parsing fails.
293
+ }
294
+ return issue(packageInfo, `Your module is published under ${displayDeclaration(declaration)}, ${reason}. ${supportedProjectLicenseAdvice()} Talk to us if you have a reason to use a different license.`);
295
+ }
296
+ /** The distribution and source licenses are declared in different files, and are reported independently */
297
+ function createProjectIssues(packageInfo) {
298
+ return [createDistributionLicenseIssue(packageInfo), createSourceLicenseIssue(packageInfo)].filter((projectIssue) => projectIssue !== undefined);
299
+ }
300
+ export function createLicensePolicyIssues(inventory) {
301
+ const result = [];
302
+ const seen = new Set();
303
+ const projectLicense = resolveProjectLicense(inventory).license ?? FALLBACK_PROJECT_LICENSE;
304
+ const policy = PROJECT_LICENSE_POLICIES[projectLicense];
305
+ const bundledLicenses = policy.allowedDependencyLicenses;
306
+ // Identical to the bundled set where the policy has nothing which only works as an external, so that no issue is
307
+ // ever reported as fixable by externalising it when externalising would not in fact help
308
+ const externalLicenses = policy.externalOnlyLicenses.size
309
+ ? new Set([...bundledLicenses, ...policy.externalOnlyLicenses])
310
+ : bundledLicenses;
311
+ for (const packageInfo of [...inventory.packages].sort(packageSort)) {
312
+ const declaration = normalizedDeclaration(packageInfo);
313
+ const identity = packageInfo.kind === 'project'
314
+ ? 'project'
315
+ : `dependency:${packageInfo.name}@${packageInfo.version ?? ''}:${declaration}`;
316
+ if (seen.has(identity))
317
+ continue;
318
+ seen.add(identity);
319
+ if (packageInfo.kind === 'project') {
320
+ result.push(...createProjectIssues(packageInfo));
321
+ continue;
322
+ }
323
+ if (!declaration) {
324
+ result.push(issue(packageInfo, `Dependency ${packageLabel(packageInfo)} has no declared license.`));
325
+ continue;
326
+ }
327
+ let parsed = parseDeclaration(declaration);
328
+ // Only ever replaces a declaration which is not valid SPDX, so a correction can never launder a real license
329
+ if (!parsed || !parsed.strict) {
330
+ const corrected = correctedPackageLicense(packageInfo.name, packageInfo.version);
331
+ if (corrected)
332
+ parsed = parseDeclaration(corrected) ?? parsed;
333
+ }
334
+ if (!parsed) {
335
+ result.push(issue(packageInfo, `Dependency ${packageLabel(packageInfo)} has unparseable license declaration ${displayDeclaration(declaration)}.`));
336
+ continue;
337
+ }
338
+ const allowedLicenses = packageInfo.kind === 'external' ? externalLicenses : bundledLicenses;
339
+ const evaluation = evaluate(parsed.node, allowedLicenses);
340
+ if (evaluation.allowed)
341
+ continue;
342
+ // Only reachable for a bundled package, externals are already evaluated against the wider set
343
+ if (evaluate(parsed.node, externalLicenses).allowed) {
344
+ result.push(issue(packageInfo, `Dependency ${packageLabel(packageInfo)} has license declaration ${displayDeclaration(declaration)} which may only be shipped as an external dependency, not built into the bundle. Add it to the externals in build-config.cjs so it is installed alongside the module and loaded at runtime.`));
345
+ continue;
346
+ }
347
+ if (!parsed.strict) {
348
+ // Reaching here means no branch we could recognise was allowed, so the unrecognised ones are the problem
349
+ result.push(issue(packageInfo, `Dependency ${packageLabel(packageInfo)} has license declaration ${displayDeclaration(declaration)} which is not a valid SPDX identifier, so it cannot be checked against the ${projectLicense} license policy. Ask the package author to declare a specific SPDX license.`));
350
+ continue;
351
+ }
352
+ result.push(issue(packageInfo, `Dependency ${packageLabel(packageInfo)} has license declaration ${displayDeclaration(declaration)} which is not compatible with the ${projectLicense} license policy.${ambiguitySuffix(evaluation)}`));
353
+ }
354
+ return result;
355
+ }
356
+ export function enforceLicensePolicy(inventory, options = {}) {
357
+ const issues = createLicensePolicyIssues(inventory);
358
+ if (issues.length === 0)
359
+ return;
360
+ const stderr = options.stderr ?? process.stderr;
361
+ const prefix = options.ignoreLicenseRules ? 'LICENSE WARNING' : 'LICENSE ERROR';
362
+ for (const policyIssue of issues)
363
+ stderr.write(`${prefix}: ${policyIssue.message}\n`);
364
+ if (options.ignoreLicenseRules) {
365
+ stderr.write(`License validation ignored ${issues.length} error${issues.length === 1 ? '' : 's'} because --ignore-license-rules was provided.\n`);
366
+ return;
367
+ }
368
+ stderr.write(`License validation failed with ${issues.length} error${issues.length === 1 ? '' : 's'}.\n`);
369
+ stderr.write(`${LICENSE_HELP_MESSAGE}\n`);
370
+ throw new LicensePolicyError(issues);
371
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@companion-module/tools",
3
- "version": "3.0.2",
3
+ "version": "3.1.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -8,7 +8,8 @@
8
8
  "url": "git+https://github.com/bitfocus/companion-module-tools.git"
9
9
  },
10
10
  "scripts": {
11
- "build": "rimraf dist && tsc -p tsconfig.json"
11
+ "build": "rimraf dist && tsc -p tsconfig.json",
12
+ "test": "yarn build && node --test test/*.test.mjs"
12
13
  },
13
14
  "bin": {
14
15
  "companion-module-build": "./dist/scripts/build-connection.js",
@@ -25,6 +26,7 @@
25
26
  "./scripts/*.js": "./dist/scripts/*.js",
26
27
  "./tsconfig/node22/recommended.json": "./tsconfig/node22/recommended.json",
27
28
  "./tsconfig/node22/recommended-esm.json": "./tsconfig/node22/recommended-esm.json",
29
+ "./tsconfig/node26/recommended.json": "./tsconfig/node26/recommended.json",
28
30
  "./.prettierrc.json": "./.prettierrc.json",
29
31
  "./build-config": "./dist/build-config.js"
30
32
  },
@@ -42,7 +44,8 @@
42
44
  "eslint-plugin-prettier": "^5.5.6",
43
45
  "find-up": "^8.0.0",
44
46
  "semver": "^7.8.4",
45
- "tar": "^7.5.16",
47
+ "spdx-expression-parse": "^5.0.0",
48
+ "tar": "^7.5.21",
46
49
  "zx": "^8.8.5"
47
50
  },
48
51
  "peerDependencies": {
@@ -76,6 +79,7 @@
76
79
  "@types/fs-extra": "^11.0.4",
77
80
  "@types/node": "^22.19.21",
78
81
  "@types/semver": "^7.7.1",
82
+ "@types/spdx-expression-parse": "^4.0.0",
79
83
  "eslint": "^10.5.0",
80
84
  "prettier": "^3.8.4",
81
85
  "rimraf": "^6.1.3",
@@ -1,26 +1,11 @@
1
1
  {
2
+ "extends": "../shared.json",
2
3
  "compilerOptions": {
3
4
  "module": "node20",
4
5
  "target": "es2024",
5
- "noImplicitAny": true,
6
6
  "moduleResolution": "node16",
7
- "sourceMap": true,
8
- "declaration": false,
9
- "importHelpers": false,
10
- "listFiles": false,
11
- "traceResolution": false,
12
- "pretty": true,
13
- "lib": ["es2024"],
14
- "types": ["node"],
15
- "strict": true,
16
- "forceConsistentCasingInFileNames": true,
17
- "noFallthroughCasesInSwitch": true,
18
- "noImplicitReturns": true,
19
- "noUnusedLocals": true,
20
- "noUnusedParameters": true,
21
- "skipLibCheck": true,
22
- "allowSyntheticDefaultImports": true,
23
- "esModuleInterop": true
24
- },
25
- "compileOnSave": false
7
+ "lib": [
8
+ "es2024"
9
+ ]
10
+ }
26
11
  }
@@ -1,26 +1,11 @@
1
1
  {
2
+ "extends": "../shared.json",
2
3
  "compilerOptions": {
3
4
  "module": "commonjs",
4
5
  "target": "es2022",
5
- "noImplicitAny": true,
6
6
  "moduleResolution": "node",
7
- "sourceMap": true,
8
- "declaration": false,
9
- "importHelpers": false,
10
- "listFiles": false,
11
- "traceResolution": false,
12
- "pretty": true,
13
- "lib": ["es2023"],
14
- "types": ["node"],
15
- "strict": true,
16
- "forceConsistentCasingInFileNames": true,
17
- "noFallthroughCasesInSwitch": true,
18
- "noImplicitReturns": true,
19
- "noUnusedLocals": true,
20
- "noUnusedParameters": true,
21
- "skipLibCheck": true,
22
- "allowSyntheticDefaultImports": true,
23
- "esModuleInterop": true
24
- },
25
- "compileOnSave": false
7
+ "lib": [
8
+ "es2023"
9
+ ]
10
+ }
26
11
  }
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "node20",
4
+ "target": "es2025",
5
+ "noImplicitAny": true,
6
+ "moduleResolution": "node16",
7
+ "sourceMap": true,
8
+ "declaration": false,
9
+ "importHelpers": false,
10
+ "listFiles": false,
11
+ "traceResolution": false,
12
+ "pretty": true,
13
+ "lib": ["es2025"],
14
+ "types": ["node"],
15
+ "strict": true,
16
+ "forceConsistentCasingInFileNames": true,
17
+ "noFallthroughCasesInSwitch": true,
18
+ "noImplicitReturns": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "skipLibCheck": true,
22
+ "allowSyntheticDefaultImports": true,
23
+ "esModuleInterop": true
24
+ },
25
+ "compileOnSave": false
26
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "noImplicitAny": true,
4
+ "sourceMap": true,
5
+ "declaration": false,
6
+ "importHelpers": false,
7
+ "listFiles": false,
8
+ "traceResolution": false,
9
+ "pretty": true,
10
+ "types": [
11
+ "node"
12
+ ],
13
+ "strict": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "noFallthroughCasesInSwitch": true,
16
+ "noImplicitReturns": true,
17
+ "noUnusedLocals": true,
18
+ "noUnusedParameters": true,
19
+ "skipLibCheck": true,
20
+ "allowSyntheticDefaultImports": true,
21
+ "esModuleInterop": true
22
+ },
23
+ "compileOnSave": false
24
+ }