@evadata/react-scripts 5.0.2
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/LICENSE +22 -0
- package/README.md +9 -0
- package/bin/react-scripts.js +58 -0
- package/config/env.js +112 -0
- package/config/getHttpsConfig.js +74 -0
- package/config/jest/babelTransform.js +37 -0
- package/config/jest/cssTransform.js +22 -0
- package/config/jest/fileTransform.js +40 -0
- package/config/modules.js +142 -0
- package/config/paths.js +153 -0
- package/config/webpack/persistentCache/createEnvironmentHash.js +9 -0
- package/config/webpack.config.js +771 -0
- package/config/webpackDevServer.config.js +137 -0
- package/lib/react-app.d.ts +71 -0
- package/package.json +100 -0
- package/scripts/build.js +225 -0
- package/scripts/eject.js +340 -0
- package/scripts/init.js +416 -0
- package/scripts/start.js +162 -0
- package/scripts/test.js +129 -0
- package/scripts/utils/createJestConfig.js +152 -0
- package/scripts/utils/verifyTypeScriptSetup.js +298 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// @remove-file-on-eject
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2015-present, Facebook, Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const chalk = require('react-dev-utils/chalk');
|
|
12
|
+
const paths = require('../../config/paths');
|
|
13
|
+
const modules = require('../../config/modules');
|
|
14
|
+
|
|
15
|
+
module.exports = (resolve, rootDir, isEjecting) => {
|
|
16
|
+
// Use this instead of `paths.testsSetup` to avoid putting
|
|
17
|
+
// an absolute filename into configuration after ejecting.
|
|
18
|
+
const setupTestsMatches = paths.testsSetup.match(/src[/\\]setupTests\.(.+)/);
|
|
19
|
+
const setupTestsFileExtension =
|
|
20
|
+
(setupTestsMatches && setupTestsMatches[1]) || 'js';
|
|
21
|
+
const setupTestsFile = fs.existsSync(paths.testsSetup)
|
|
22
|
+
? `<rootDir>/src/setupTests.${setupTestsFileExtension}`
|
|
23
|
+
: undefined;
|
|
24
|
+
|
|
25
|
+
const config = {
|
|
26
|
+
roots: ['<rootDir>/src'],
|
|
27
|
+
|
|
28
|
+
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.d.ts'],
|
|
29
|
+
|
|
30
|
+
setupFiles: [
|
|
31
|
+
isEjecting
|
|
32
|
+
? 'react-app-polyfill/jsdom'
|
|
33
|
+
: require.resolve('react-app-polyfill/jsdom')
|
|
34
|
+
],
|
|
35
|
+
|
|
36
|
+
setupFilesAfterEnv: setupTestsFile ? [setupTestsFile] : [],
|
|
37
|
+
testMatch: [
|
|
38
|
+
'<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}',
|
|
39
|
+
'<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}'
|
|
40
|
+
],
|
|
41
|
+
testEnvironment: 'jsdom',
|
|
42
|
+
transform: {
|
|
43
|
+
'^.+\\.(js|jsx|mjs|cjs|ts|tsx)$': resolve(
|
|
44
|
+
'config/jest/babelTransform.js'
|
|
45
|
+
),
|
|
46
|
+
'^.+\\.css$': resolve('config/jest/cssTransform.js'),
|
|
47
|
+
'^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': resolve(
|
|
48
|
+
'config/jest/fileTransform.js'
|
|
49
|
+
)
|
|
50
|
+
},
|
|
51
|
+
transformIgnorePatterns: [
|
|
52
|
+
'[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$',
|
|
53
|
+
'^.+\\.module\\.(css|sass|scss)$'
|
|
54
|
+
],
|
|
55
|
+
modulePaths: modules.additionalModulePaths || [],
|
|
56
|
+
moduleNameMapper: {
|
|
57
|
+
'^react-native$': 'react-native-web',
|
|
58
|
+
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
|
|
59
|
+
...(modules.jestAliases || {})
|
|
60
|
+
},
|
|
61
|
+
moduleFileExtensions: [...paths.moduleFileExtensions, 'node'].filter(
|
|
62
|
+
ext => !ext.includes('mjs')
|
|
63
|
+
),
|
|
64
|
+
watchPlugins: [
|
|
65
|
+
'jest-watch-typeahead/filename',
|
|
66
|
+
'jest-watch-typeahead/testname'
|
|
67
|
+
],
|
|
68
|
+
resetMocks: true
|
|
69
|
+
};
|
|
70
|
+
if (rootDir) {
|
|
71
|
+
config.rootDir = rootDir;
|
|
72
|
+
}
|
|
73
|
+
const overrides = Object.assign({}, require(paths.appPackageJson).jest);
|
|
74
|
+
const supportedKeys = [
|
|
75
|
+
'clearMocks',
|
|
76
|
+
'collectCoverageFrom',
|
|
77
|
+
'coveragePathIgnorePatterns',
|
|
78
|
+
'coverageReporters',
|
|
79
|
+
'coverageThreshold',
|
|
80
|
+
'displayName',
|
|
81
|
+
'extraGlobals',
|
|
82
|
+
'globalSetup',
|
|
83
|
+
'globalTeardown',
|
|
84
|
+
'moduleNameMapper',
|
|
85
|
+
'resetMocks',
|
|
86
|
+
'resetModules',
|
|
87
|
+
'restoreMocks',
|
|
88
|
+
'snapshotSerializers',
|
|
89
|
+
'testMatch',
|
|
90
|
+
'transform',
|
|
91
|
+
'transformIgnorePatterns',
|
|
92
|
+
'watchPathIgnorePatterns'
|
|
93
|
+
];
|
|
94
|
+
if (overrides) {
|
|
95
|
+
supportedKeys.forEach(key => {
|
|
96
|
+
if (Object.prototype.hasOwnProperty.call(overrides, key)) {
|
|
97
|
+
if (Array.isArray(config[key]) || typeof config[key] !== 'object') {
|
|
98
|
+
// for arrays or primitive types, directly override the config key
|
|
99
|
+
config[key] = overrides[key];
|
|
100
|
+
} else {
|
|
101
|
+
// for object types, extend gracefully
|
|
102
|
+
config[key] = Object.assign({}, config[key], overrides[key]);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
delete overrides[key];
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
const unsupportedKeys = Object.keys(overrides);
|
|
109
|
+
if (unsupportedKeys.length) {
|
|
110
|
+
const isOverridingSetupFile =
|
|
111
|
+
unsupportedKeys.indexOf('setupFilesAfterEnv') > -1;
|
|
112
|
+
|
|
113
|
+
if (isOverridingSetupFile) {
|
|
114
|
+
console.error(
|
|
115
|
+
chalk.red(
|
|
116
|
+
'We detected ' +
|
|
117
|
+
chalk.bold('setupFilesAfterEnv') +
|
|
118
|
+
' in your package.json.\n\n' +
|
|
119
|
+
'Remove it from Jest configuration, and put the initialization code in ' +
|
|
120
|
+
chalk.bold('src/setupTests.js') +
|
|
121
|
+
'.\nThis file will be loaded automatically.\n'
|
|
122
|
+
)
|
|
123
|
+
);
|
|
124
|
+
} else {
|
|
125
|
+
console.error(
|
|
126
|
+
chalk.red(
|
|
127
|
+
'\nOut of the box, Create React App only supports overriding ' +
|
|
128
|
+
'these Jest options:\n\n' +
|
|
129
|
+
supportedKeys
|
|
130
|
+
.map(key => chalk.bold(' \u2022 ' + key))
|
|
131
|
+
.join('\n') +
|
|
132
|
+
'.\n\n' +
|
|
133
|
+
'These options in your package.json Jest configuration ' +
|
|
134
|
+
'are not currently supported by Create React App:\n\n' +
|
|
135
|
+
unsupportedKeys
|
|
136
|
+
.map(key => chalk.bold(' \u2022 ' + key))
|
|
137
|
+
.join('\n') +
|
|
138
|
+
'\n\nIf you wish to override other Jest options, you need to ' +
|
|
139
|
+
'eject from the default setup. You can do so by running ' +
|
|
140
|
+
chalk.bold('npm run eject') +
|
|
141
|
+
' but remember that this is a one-way operation. ' +
|
|
142
|
+
'You may also file an issue with Create React App to discuss ' +
|
|
143
|
+
'supporting more options out of the box.\n'
|
|
144
|
+
)
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return config;
|
|
152
|
+
};
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
// @remove-file-on-eject
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2015-present, Facebook, Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const chalk = require('react-dev-utils/chalk');
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const resolve = require('resolve');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const paths = require('../../config/paths');
|
|
16
|
+
const os = require('os');
|
|
17
|
+
const semver = require('semver');
|
|
18
|
+
const immer = require('react-dev-utils/immer').produce;
|
|
19
|
+
const globby = require('react-dev-utils/globby').sync;
|
|
20
|
+
|
|
21
|
+
const hasJsxRuntime = (() => {
|
|
22
|
+
if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
require.resolve('react/jsx-runtime', { paths: [paths.appPath] });
|
|
28
|
+
return true;
|
|
29
|
+
} catch (e) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
})();
|
|
33
|
+
|
|
34
|
+
function writeJson(fileName, object) {
|
|
35
|
+
fs.writeFileSync(
|
|
36
|
+
fileName,
|
|
37
|
+
JSON.stringify(object, null, 2).replace(/\n/g, os.EOL) + os.EOL
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function verifyNoTypeScript() {
|
|
42
|
+
const typescriptFiles = globby(
|
|
43
|
+
['**/*.(ts|tsx)', '!**/node_modules', '!**/*.d.ts'],
|
|
44
|
+
{ cwd: paths.appSrc }
|
|
45
|
+
);
|
|
46
|
+
if (typescriptFiles.length > 0) {
|
|
47
|
+
console.warn(
|
|
48
|
+
chalk.yellow(
|
|
49
|
+
`We detected TypeScript in your project (${chalk.bold(
|
|
50
|
+
`src${path.sep}${typescriptFiles[0]}`
|
|
51
|
+
)}) and created a ${chalk.bold('tsconfig.json')} file for you.`
|
|
52
|
+
)
|
|
53
|
+
);
|
|
54
|
+
console.warn();
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function verifyTypeScriptSetup() {
|
|
61
|
+
let firstTimeSetup = false;
|
|
62
|
+
|
|
63
|
+
if (!fs.existsSync(paths.appTsConfig)) {
|
|
64
|
+
if (verifyNoTypeScript()) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
writeJson(paths.appTsConfig, {});
|
|
68
|
+
firstTimeSetup = true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const isYarn = fs.existsSync(paths.yarnLockFile);
|
|
72
|
+
|
|
73
|
+
// Ensure typescript is installed
|
|
74
|
+
let ts;
|
|
75
|
+
try {
|
|
76
|
+
// TODO: Remove this hack once `globalThis` issue is resolved
|
|
77
|
+
// https://github.com/jsdom/jsdom/issues/2961
|
|
78
|
+
const globalThisWasDefined = !!global.globalThis;
|
|
79
|
+
|
|
80
|
+
ts = require(resolve.sync('typescript', {
|
|
81
|
+
basedir: paths.appNodeModules
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
if (!globalThisWasDefined && !!global.globalThis) {
|
|
85
|
+
delete global.globalThis;
|
|
86
|
+
}
|
|
87
|
+
} catch (_) {
|
|
88
|
+
console.error(
|
|
89
|
+
chalk.bold.red(
|
|
90
|
+
`It looks like you're trying to use TypeScript but do not have ${chalk.bold(
|
|
91
|
+
'typescript'
|
|
92
|
+
)} installed.`
|
|
93
|
+
)
|
|
94
|
+
);
|
|
95
|
+
console.error(
|
|
96
|
+
chalk.bold(
|
|
97
|
+
'Please install',
|
|
98
|
+
chalk.cyan.bold('typescript'),
|
|
99
|
+
'by running',
|
|
100
|
+
chalk.cyan.bold(
|
|
101
|
+
isYarn ? 'yarn add typescript' : 'npm install typescript'
|
|
102
|
+
) + '.'
|
|
103
|
+
)
|
|
104
|
+
);
|
|
105
|
+
console.error(
|
|
106
|
+
chalk.bold(
|
|
107
|
+
'If you are not trying to use TypeScript, please remove the ' +
|
|
108
|
+
chalk.cyan('tsconfig.json') +
|
|
109
|
+
' file from your package root (and any TypeScript files).'
|
|
110
|
+
)
|
|
111
|
+
);
|
|
112
|
+
console.error();
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const compilerOptions = {
|
|
117
|
+
// These are suggested values and will be set when not present in the
|
|
118
|
+
// tsconfig.json
|
|
119
|
+
// 'parsedValue' matches the output value from ts.parseJsonConfigFileContent()
|
|
120
|
+
target: {
|
|
121
|
+
parsedValue: ts.ScriptTarget.ES5,
|
|
122
|
+
suggested: 'es5'
|
|
123
|
+
},
|
|
124
|
+
lib: { suggested: ['dom', 'dom.iterable', 'esnext'] },
|
|
125
|
+
allowJs: { suggested: true },
|
|
126
|
+
skipLibCheck: { suggested: true },
|
|
127
|
+
esModuleInterop: { suggested: true },
|
|
128
|
+
allowSyntheticDefaultImports: { suggested: true },
|
|
129
|
+
strict: { suggested: true },
|
|
130
|
+
forceConsistentCasingInFileNames: { suggested: true },
|
|
131
|
+
noFallthroughCasesInSwitch: { suggested: true },
|
|
132
|
+
|
|
133
|
+
// These values are required and cannot be changed by the user
|
|
134
|
+
// Keep this in sync with the webpack config
|
|
135
|
+
module: {
|
|
136
|
+
parsedValue: ts.ModuleKind.ESNext,
|
|
137
|
+
value: 'esnext',
|
|
138
|
+
reason: 'for import() and import/export'
|
|
139
|
+
},
|
|
140
|
+
moduleResolution: {
|
|
141
|
+
parsedValue: ts.ModuleResolutionKind.NodeJs,
|
|
142
|
+
value: 'node',
|
|
143
|
+
reason: 'to match webpack resolution'
|
|
144
|
+
},
|
|
145
|
+
resolveJsonModule: { value: true, reason: 'to match webpack loader' },
|
|
146
|
+
isolatedModules: { value: true, reason: 'implementation limitation' },
|
|
147
|
+
noEmit: { value: true },
|
|
148
|
+
jsx: {
|
|
149
|
+
parsedValue:
|
|
150
|
+
hasJsxRuntime && semver.gte(ts.version, '4.1.0-beta')
|
|
151
|
+
? ts.JsxEmit.ReactJSX
|
|
152
|
+
: ts.JsxEmit.React,
|
|
153
|
+
value:
|
|
154
|
+
hasJsxRuntime && semver.gte(ts.version, '4.1.0-beta')
|
|
155
|
+
? 'react-jsx'
|
|
156
|
+
: 'react',
|
|
157
|
+
reason: 'to support the new JSX transform in React 17'
|
|
158
|
+
},
|
|
159
|
+
paths: { value: undefined, reason: 'aliased imports are not supported' }
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const formatDiagnosticHost = {
|
|
163
|
+
getCanonicalFileName: fileName => fileName,
|
|
164
|
+
getCurrentDirectory: ts.sys.getCurrentDirectory,
|
|
165
|
+
getNewLine: () => os.EOL
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const messages = [];
|
|
169
|
+
let appTsConfig;
|
|
170
|
+
let parsedTsConfig;
|
|
171
|
+
let parsedCompilerOptions;
|
|
172
|
+
try {
|
|
173
|
+
const { config: readTsConfig, error } = ts.readConfigFile(
|
|
174
|
+
paths.appTsConfig,
|
|
175
|
+
ts.sys.readFile
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
if (error) {
|
|
179
|
+
throw new Error(ts.formatDiagnostic(error, formatDiagnosticHost));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
appTsConfig = readTsConfig;
|
|
183
|
+
|
|
184
|
+
// Get TS to parse and resolve any "extends"
|
|
185
|
+
// Calling this function also mutates the tsconfig above,
|
|
186
|
+
// adding in "include" and "exclude", but the compilerOptions remain untouched
|
|
187
|
+
let result;
|
|
188
|
+
parsedTsConfig = immer(readTsConfig, config => {
|
|
189
|
+
result = ts.parseJsonConfigFileContent(
|
|
190
|
+
config,
|
|
191
|
+
ts.sys,
|
|
192
|
+
path.dirname(paths.appTsConfig)
|
|
193
|
+
);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
if (result.errors && result.errors.length) {
|
|
197
|
+
throw new Error(
|
|
198
|
+
ts.formatDiagnostic(result.errors[0], formatDiagnosticHost)
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
parsedCompilerOptions = result.options;
|
|
203
|
+
} catch (e) {
|
|
204
|
+
if (e && e.name === 'SyntaxError') {
|
|
205
|
+
console.error(
|
|
206
|
+
chalk.red.bold(
|
|
207
|
+
'Could not parse',
|
|
208
|
+
chalk.cyan('tsconfig.json') + '.',
|
|
209
|
+
'Please make sure it contains syntactically correct JSON.'
|
|
210
|
+
)
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
console.log(e && e.message ? `${e.message}` : '');
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (appTsConfig.compilerOptions == null) {
|
|
219
|
+
appTsConfig.compilerOptions = {};
|
|
220
|
+
firstTimeSetup = true;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
for (const option of Object.keys(compilerOptions)) {
|
|
224
|
+
const { parsedValue, value, suggested, reason } = compilerOptions[option];
|
|
225
|
+
|
|
226
|
+
const valueToCheck = parsedValue === undefined ? value : parsedValue;
|
|
227
|
+
const coloredOption = chalk.cyan('compilerOptions.' + option);
|
|
228
|
+
|
|
229
|
+
if (suggested != null) {
|
|
230
|
+
if (parsedCompilerOptions[option] === undefined) {
|
|
231
|
+
appTsConfig = immer(appTsConfig, config => {
|
|
232
|
+
config.compilerOptions[option] = suggested;
|
|
233
|
+
});
|
|
234
|
+
messages.push(
|
|
235
|
+
`${coloredOption} to be ${chalk.bold(
|
|
236
|
+
'suggested'
|
|
237
|
+
)} value: ${chalk.cyan.bold(suggested)} (this can be changed)`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
} else if (parsedCompilerOptions[option] !== valueToCheck) {
|
|
241
|
+
appTsConfig = immer(appTsConfig, config => {
|
|
242
|
+
config.compilerOptions[option] = value;
|
|
243
|
+
});
|
|
244
|
+
messages.push(
|
|
245
|
+
`${coloredOption} ${chalk.bold(
|
|
246
|
+
valueToCheck == null ? 'must not' : 'must'
|
|
247
|
+
)} be ${valueToCheck == null ? 'set' : chalk.cyan.bold(value)}` +
|
|
248
|
+
(reason != null ? ` (${reason})` : '')
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// tsconfig will have the merged "include" and "exclude" by this point
|
|
254
|
+
if (parsedTsConfig.include == null) {
|
|
255
|
+
appTsConfig = immer(appTsConfig, config => {
|
|
256
|
+
config.include = ['src'];
|
|
257
|
+
});
|
|
258
|
+
messages.push(
|
|
259
|
+
`${chalk.cyan('include')} should be ${chalk.cyan.bold('src')}`
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (messages.length > 0) {
|
|
264
|
+
if (firstTimeSetup) {
|
|
265
|
+
console.log(
|
|
266
|
+
chalk.bold(
|
|
267
|
+
'Your',
|
|
268
|
+
chalk.cyan('tsconfig.json'),
|
|
269
|
+
'has been populated with default values.'
|
|
270
|
+
)
|
|
271
|
+
);
|
|
272
|
+
console.log();
|
|
273
|
+
} else {
|
|
274
|
+
console.warn(
|
|
275
|
+
chalk.bold(
|
|
276
|
+
'The following changes are being made to your',
|
|
277
|
+
chalk.cyan('tsconfig.json'),
|
|
278
|
+
'file:'
|
|
279
|
+
)
|
|
280
|
+
);
|
|
281
|
+
messages.forEach(message => {
|
|
282
|
+
console.warn(' - ' + message);
|
|
283
|
+
});
|
|
284
|
+
console.warn();
|
|
285
|
+
}
|
|
286
|
+
writeJson(paths.appTsConfig, appTsConfig);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Reference `react-scripts` types
|
|
290
|
+
if (!fs.existsSync(paths.appTypeDeclarations)) {
|
|
291
|
+
fs.writeFileSync(
|
|
292
|
+
paths.appTypeDeclarations,
|
|
293
|
+
`/// <reference types="react-scripts" />${os.EOL}`
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
module.exports = verifyTypeScriptSetup;
|