@definitelytyped/dts-critic 0.0.95-next.1
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 +21 -0
- package/README.md +88 -0
- package/develop.ts +446 -0
- package/dist/develop.d.ts +1 -0
- package/dist/develop.js +356 -0
- package/dist/develop.js.map +1 -0
- package/dist/dt.d.ts +1 -0
- package/dist/dt.js +79 -0
- package/dist/dt.js.map +1 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +852 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +196 -0
- package/dist/index.test.js.map +1 -0
- package/dist/jest.config.d.ts +2 -0
- package/dist/jest.config.js +11 -0
- package/dist/jest.config.js.map +1 -0
- package/dt.ts +76 -0
- package/index.test.ts +278 -0
- package/index.ts +1038 -0
- package/jest.config.js +9 -0
- package/package.json +60 -0
- package/testsource/dts-critic.d.ts +8 -0
- package/testsource/dts-critic.js +1 -0
- package/testsource/missingDefault.d.ts +1 -0
- package/testsource/missingDefault.js +1 -0
- package/testsource/missingDtsProperty.d.ts +3 -0
- package/testsource/missingDtsProperty.js +4 -0
- package/testsource/missingDtsSignature.d.ts +7 -0
- package/testsource/missingDtsSignature.js +3 -0
- package/testsource/missingExportEquals.d.ts +1 -0
- package/testsource/missingExportEquals.js +5 -0
- package/testsource/missingJsProperty.d.ts +2 -0
- package/testsource/missingJsProperty.js +5 -0
- package/testsource/missingJsSignatureExportEquals.d.ts +6 -0
- package/testsource/missingJsSignatureExportEquals.js +3 -0
- package/testsource/missingJsSignatureNoExportEquals.d.ts +1 -0
- package/testsource/missingJsSignatureNoExportEquals.js +1 -0
- package/testsource/noErrors.d.ts +2 -0
- package/testsource/noErrors.js +2 -0
- package/testsource/parseltongue.d.ts +0 -0
- package/testsource/tslib.d.ts +4 -0
- package/testsource/typescript.d.ts +4 -0
- package/testsource/webpackPropertyNames.d.ts +1 -0
- package/testsource/webpackPropertyNames.js +12 -0
- package/tsconfig.json +20 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,852 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
22
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.parseExportErrorKind = exports.dtToNpmName = exports.checkSource = exports.findDtsName = exports.getNpmInfo = exports.defaultErrors = exports.dtsCritic = exports.parseMode = exports.Mode = exports.ErrorKind = void 0;
|
|
26
|
+
const yargs = require("yargs");
|
|
27
|
+
const headerParser = require("@definitelytyped/header-parser");
|
|
28
|
+
const fs = require("fs");
|
|
29
|
+
const os = require("os");
|
|
30
|
+
const cp = require("child_process");
|
|
31
|
+
const path = require("path");
|
|
32
|
+
const semver = require("semver");
|
|
33
|
+
const rimraf = require("rimraf");
|
|
34
|
+
const command_exists_1 = require("command-exists");
|
|
35
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
36
|
+
const tmp = __importStar(require("tmp"));
|
|
37
|
+
var ErrorKind;
|
|
38
|
+
(function (ErrorKind) {
|
|
39
|
+
/** Declaration is marked as npm in header and has no matching npm package. */
|
|
40
|
+
ErrorKind["NoMatchingNpmPackage"] = "NoMatchingNpmPackage";
|
|
41
|
+
/** Declaration has no npm package matching specified version. */
|
|
42
|
+
ErrorKind["NoMatchingNpmVersion"] = "NoMatchingNpmVersion";
|
|
43
|
+
/** Declaration is not for an npm package, but has a name that conflicts with an existing npm package. */
|
|
44
|
+
ErrorKind["NonNpmHasMatchingPackage"] = "NonNpmHasMatchingPackage";
|
|
45
|
+
/** Declaration needs to use `export =` to match the JavaScript module's behavior. */
|
|
46
|
+
ErrorKind["NeedsExportEquals"] = "NeedsExportEquals";
|
|
47
|
+
/** Declaration has a default export, but JavaScript module does not have a default export. */
|
|
48
|
+
ErrorKind["NoDefaultExport"] = "NoDefaultExport";
|
|
49
|
+
/** JavaScript exports property not found in declaration exports. */
|
|
50
|
+
ErrorKind["JsPropertyNotInDts"] = "JsPropertyNotInDts";
|
|
51
|
+
/** Declaration exports property not found in JavaScript exports. */
|
|
52
|
+
ErrorKind["DtsPropertyNotInJs"] = "DtsPropertyNotInJs";
|
|
53
|
+
/** JavaScript module has signatures, but declaration module does not. */
|
|
54
|
+
ErrorKind["JsSignatureNotInDts"] = "JsSignatureNotInDts";
|
|
55
|
+
/** Declaration module has signatures, but JavaScript module does not. */
|
|
56
|
+
ErrorKind["DtsSignatureNotInJs"] = "DtsSignatureNotInJs";
|
|
57
|
+
})(ErrorKind = exports.ErrorKind || (exports.ErrorKind = {}));
|
|
58
|
+
var Mode;
|
|
59
|
+
(function (Mode) {
|
|
60
|
+
/** Checks based only on the package name and on the declaration's DefinitelyTyped header. */
|
|
61
|
+
Mode["NameOnly"] = "name-only";
|
|
62
|
+
/** Checks based on the source JavaScript code, in addition to the checks performed in name-only mode. */
|
|
63
|
+
Mode["Code"] = "code";
|
|
64
|
+
})(Mode = exports.Mode || (exports.Mode = {}));
|
|
65
|
+
function parseMode(mode) {
|
|
66
|
+
switch (mode) {
|
|
67
|
+
case Mode.NameOnly:
|
|
68
|
+
return Mode.NameOnly;
|
|
69
|
+
case Mode.Code:
|
|
70
|
+
return Mode.Code;
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
exports.parseMode = parseMode;
|
|
75
|
+
const defaultOpts = { mode: Mode.NameOnly };
|
|
76
|
+
function dtsCritic(dtsPath, sourcePath, options = defaultOpts, debug = false) {
|
|
77
|
+
if (!command_exists_1.sync("tar")) {
|
|
78
|
+
throw new Error("You need to have tar installed to run dts-critic, you can get it from https://www.gnu.org/software/tar");
|
|
79
|
+
}
|
|
80
|
+
if (!command_exists_1.sync("npm")) {
|
|
81
|
+
throw new Error("You need to have npm installed to run dts-critic, you can get it from https://www.npmjs.com/get-npm");
|
|
82
|
+
}
|
|
83
|
+
const dts = fs.readFileSync(dtsPath, "utf-8");
|
|
84
|
+
const header = parseDtHeader(dts);
|
|
85
|
+
const name = findDtsName(dtsPath);
|
|
86
|
+
const npmInfo = getNpmInfo(name);
|
|
87
|
+
if (isNonNpm(header)) {
|
|
88
|
+
const errors = [];
|
|
89
|
+
const nonNpmError = checkNonNpm(name, npmInfo);
|
|
90
|
+
if (nonNpmError) {
|
|
91
|
+
errors.push(nonNpmError);
|
|
92
|
+
}
|
|
93
|
+
if (sourcePath) {
|
|
94
|
+
if (options.mode === Mode.Code) {
|
|
95
|
+
errors.push(...checkSource(name, dtsPath, sourcePath, options.errors, debug));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (!module.parent) {
|
|
99
|
+
console.log(`Warning: declaration provided is for a non-npm package.
|
|
100
|
+
If you want to check the declaration against the JavaScript source code, you must provide a path to the source file.`);
|
|
101
|
+
}
|
|
102
|
+
return errors;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
const npmVersion = checkNpm(name, npmInfo, header);
|
|
106
|
+
if (typeof npmVersion !== "string") {
|
|
107
|
+
return [npmVersion];
|
|
108
|
+
}
|
|
109
|
+
if (options.mode === Mode.Code) {
|
|
110
|
+
let sourceEntry;
|
|
111
|
+
let packagePath;
|
|
112
|
+
if (sourcePath) {
|
|
113
|
+
sourceEntry = sourcePath;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const tempDirName = tmp.dirSync({ unsafeCleanup: true }).name;
|
|
117
|
+
packagePath = downloadNpmPackage(name, npmVersion, tempDirName);
|
|
118
|
+
sourceEntry = require.resolve(path.resolve(packagePath));
|
|
119
|
+
}
|
|
120
|
+
const errors = checkSource(name, dtsPath, sourceEntry, options.errors, debug);
|
|
121
|
+
if (packagePath) {
|
|
122
|
+
// Delete the source afterward to avoid running out of space
|
|
123
|
+
rimraf.sync(packagePath);
|
|
124
|
+
}
|
|
125
|
+
return errors;
|
|
126
|
+
}
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
exports.dtsCritic = dtsCritic;
|
|
131
|
+
function parseDtHeader(dts) {
|
|
132
|
+
try {
|
|
133
|
+
return headerParser.parseHeaderOrFail(dts);
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function isNonNpm(header) {
|
|
140
|
+
return !!header && header.nonNpm;
|
|
141
|
+
}
|
|
142
|
+
exports.defaultErrors = [ErrorKind.NeedsExportEquals, ErrorKind.NoDefaultExport];
|
|
143
|
+
function main() {
|
|
144
|
+
const argv = yargs
|
|
145
|
+
.usage("$0 --dts path-to-d.ts [--js path-to-source] [--mode mode] [--debug]\n\nIf source-folder is not provided, I will look for a matching package on npm.")
|
|
146
|
+
.option("dts", {
|
|
147
|
+
describe: "Path of declaration file to be critiqued.",
|
|
148
|
+
type: "string"
|
|
149
|
+
})
|
|
150
|
+
.demandOption("dts", "Please provide a path to a d.ts file for me to critique.")
|
|
151
|
+
.option("js", {
|
|
152
|
+
describe: "Path of JavaScript file to be used as source.",
|
|
153
|
+
type: "string"
|
|
154
|
+
})
|
|
155
|
+
.option("mode", {
|
|
156
|
+
describe: "Mode defines what checks will be performed.",
|
|
157
|
+
type: "string",
|
|
158
|
+
default: Mode.NameOnly,
|
|
159
|
+
choices: [Mode.NameOnly, Mode.Code]
|
|
160
|
+
})
|
|
161
|
+
.option("debug", {
|
|
162
|
+
describe: "Turn debug logging on.",
|
|
163
|
+
type: "boolean",
|
|
164
|
+
default: false
|
|
165
|
+
})
|
|
166
|
+
.help().argv;
|
|
167
|
+
let opts;
|
|
168
|
+
switch (argv.mode) {
|
|
169
|
+
case Mode.NameOnly:
|
|
170
|
+
opts = { mode: argv.mode };
|
|
171
|
+
break;
|
|
172
|
+
case Mode.Code:
|
|
173
|
+
opts = { mode: argv.mode, errors: new Map() };
|
|
174
|
+
}
|
|
175
|
+
const errors = dtsCritic(argv.dts, argv.js, opts, argv.debug);
|
|
176
|
+
if (errors.length === 0) {
|
|
177
|
+
console.log("No errors!");
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
for (const error of errors) {
|
|
181
|
+
console.log("Error: " + error.message);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const npmNotFound = "E404";
|
|
186
|
+
function getNpmInfo(name) {
|
|
187
|
+
const npmName = dtToNpmName(name);
|
|
188
|
+
const infoResult = cp.spawnSync("npm", ["info", npmName, "--json", "--silent", "versions", "dist-tags"], {
|
|
189
|
+
encoding: "utf8"
|
|
190
|
+
});
|
|
191
|
+
const info = JSON.parse(infoResult.stdout || infoResult.stderr);
|
|
192
|
+
if (info.error !== undefined) {
|
|
193
|
+
const error = info.error;
|
|
194
|
+
if (error.code === npmNotFound) {
|
|
195
|
+
return { isNpm: false };
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
throw new Error(`Command 'npm info' for package ${npmName} returned an error. Reason: ${error.summary}.`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else if (infoResult.status !== 0) {
|
|
202
|
+
throw new Error(`Command 'npm info' failed for package ${npmName} with status ${infoResult.status}.`);
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
isNpm: true,
|
|
206
|
+
versions: info.versions,
|
|
207
|
+
tags: info["dist-tags"]
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
exports.getNpmInfo = getNpmInfo;
|
|
211
|
+
/**
|
|
212
|
+
* Checks DefinitelyTyped non-npm package.
|
|
213
|
+
*/
|
|
214
|
+
function checkNonNpm(name, npmInfo) {
|
|
215
|
+
if (npmInfo.isNpm && !isExistingSquatter(name)) {
|
|
216
|
+
return {
|
|
217
|
+
kind: ErrorKind.NonNpmHasMatchingPackage,
|
|
218
|
+
message: `The non-npm package '${name}' conflicts with the existing npm package '${dtToNpmName(name)}'.
|
|
219
|
+
Try adding -browser to the end of the name to get
|
|
220
|
+
|
|
221
|
+
${name}-browser
|
|
222
|
+
`
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Checks DefinitelyTyped npm package.
|
|
229
|
+
* If all checks are successful, returns the npm version that matches the header.
|
|
230
|
+
*/
|
|
231
|
+
function checkNpm(name, npmInfo, header) {
|
|
232
|
+
if (!npmInfo.isNpm) {
|
|
233
|
+
return {
|
|
234
|
+
kind: ErrorKind.NoMatchingNpmPackage,
|
|
235
|
+
message: `Declaration file must have a matching npm package.
|
|
236
|
+
To resolve this error, either:
|
|
237
|
+
1. Change the name to match an npm package.
|
|
238
|
+
2. Add a Definitely Typed header with the first line
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
// Type definitions for non-npm package ${name}-browser
|
|
242
|
+
|
|
243
|
+
Add -browser to the end of your name to make sure it doesn't conflict with existing npm packages.`
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const target = getHeaderVersion(header);
|
|
247
|
+
const npmVersion = getMatchingVersion(target, npmInfo);
|
|
248
|
+
if (!npmVersion) {
|
|
249
|
+
const versions = npmInfo.versions;
|
|
250
|
+
const verstring = versions.join(", ");
|
|
251
|
+
const lateststring = versions[versions.length - 1];
|
|
252
|
+
const headerstring = target || "NO HEADER VERSION FOUND";
|
|
253
|
+
return {
|
|
254
|
+
kind: ErrorKind.NoMatchingNpmVersion,
|
|
255
|
+
message: `The types for '${name}' must match a version that exists on npm.
|
|
256
|
+
You should copy the major and minor version from the package on npm.
|
|
257
|
+
|
|
258
|
+
To resolve this error, change the version in the header, ${headerstring},
|
|
259
|
+
to match one on npm: ${verstring}.
|
|
260
|
+
|
|
261
|
+
For example, if you're trying to match the latest version, use ${lateststring}.`
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
return npmVersion;
|
|
265
|
+
}
|
|
266
|
+
function getHeaderVersion(header) {
|
|
267
|
+
if (!header) {
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
if (header.libraryMajorVersion === 0 && header.libraryMinorVersion === 0) {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
return `${header.libraryMajorVersion}.${header.libraryMinorVersion}`;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Finds an npm version that matches the target version specified, if it exists.
|
|
277
|
+
* If the target version is undefined, returns the latest version.
|
|
278
|
+
* The npm version returned might be a prerelease version.
|
|
279
|
+
*/
|
|
280
|
+
function getMatchingVersion(target, npmInfo) {
|
|
281
|
+
const versions = npmInfo.versions;
|
|
282
|
+
if (target) {
|
|
283
|
+
const matchingVersion = semver.maxSatisfying(versions, target, { includePrerelease: true });
|
|
284
|
+
return matchingVersion || undefined;
|
|
285
|
+
}
|
|
286
|
+
if (npmInfo.tags.latest) {
|
|
287
|
+
return npmInfo.tags.latest;
|
|
288
|
+
}
|
|
289
|
+
return versions[versions.length - 1];
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* If dtsName is 'index' (as with DT) then look to the parent directory for the name.
|
|
293
|
+
*/
|
|
294
|
+
function findDtsName(dtsPath) {
|
|
295
|
+
const resolved = path.resolve(dtsPath);
|
|
296
|
+
const baseName = path.basename(resolved, ".d.ts");
|
|
297
|
+
if (baseName && baseName !== "index") {
|
|
298
|
+
return baseName;
|
|
299
|
+
}
|
|
300
|
+
return path.basename(path.dirname(resolved));
|
|
301
|
+
}
|
|
302
|
+
exports.findDtsName = findDtsName;
|
|
303
|
+
/** Default path to store packages downloaded from npm. */
|
|
304
|
+
const sourceDir = path.resolve(path.join(__dirname, "..", "sources"));
|
|
305
|
+
/** Returns path of downloaded npm package. */
|
|
306
|
+
function downloadNpmPackage(name, version, outDir) {
|
|
307
|
+
const npmName = dtToNpmName(name);
|
|
308
|
+
const fullName = `${npmName}@${version}`;
|
|
309
|
+
const cpOpts = { encoding: "utf8", maxBuffer: 100 * 1024 * 1024 };
|
|
310
|
+
const npmPack = cp.execFileSync("npm", ["pack", fullName, "--json", "--silent"], cpOpts).trim();
|
|
311
|
+
const tarballName = npmPack.endsWith(".tgz") ? npmPack : JSON.parse(npmPack)[0].filename;
|
|
312
|
+
const outPath = path.join(outDir, name);
|
|
313
|
+
initDir(outPath);
|
|
314
|
+
const args = os.platform() === "darwin"
|
|
315
|
+
? ["-xz", "-f", tarballName, "-C", outPath]
|
|
316
|
+
: ["-xz", "-f", tarballName, "-C", outPath, "--warning=none"];
|
|
317
|
+
cp.execFileSync("tar", args, cpOpts);
|
|
318
|
+
fs.unlinkSync(tarballName);
|
|
319
|
+
return path.join(outPath, getPackageDir(outPath));
|
|
320
|
+
}
|
|
321
|
+
function getPackageDir(outPath) {
|
|
322
|
+
const dirs = fs.readdirSync(outPath, { encoding: "utf8", withFileTypes: true });
|
|
323
|
+
for (const dirent of dirs) {
|
|
324
|
+
if (dirent.isDirectory()) {
|
|
325
|
+
return dirent.name;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return "package";
|
|
329
|
+
}
|
|
330
|
+
function initDir(dirPath) {
|
|
331
|
+
if (!fs.existsSync(dirPath)) {
|
|
332
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function checkSource(name, dtsPath, srcPath, enabledErrors, debug) {
|
|
336
|
+
const diagnostics = checkExports(name, dtsPath, srcPath);
|
|
337
|
+
if (debug) {
|
|
338
|
+
console.log(formatDebug(name, diagnostics));
|
|
339
|
+
}
|
|
340
|
+
return diagnostics.errors.filter(err => { var _a; return (_a = enabledErrors.get(err.kind)) !== null && _a !== void 0 ? _a : exports.defaultErrors.includes(err.kind); });
|
|
341
|
+
}
|
|
342
|
+
exports.checkSource = checkSource;
|
|
343
|
+
function formatDebug(name, diagnostics) {
|
|
344
|
+
const lines = [];
|
|
345
|
+
lines.push(`\tDiagnostics for package ${name}.`);
|
|
346
|
+
lines.push("\tInferred source module structure:");
|
|
347
|
+
if (isSuccess(diagnostics.jsExportKind)) {
|
|
348
|
+
lines.push(diagnostics.jsExportKind.result);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
lines.push(`Could not infer type of JavaScript exports. Reason: ${diagnostics.jsExportKind.reason}`);
|
|
352
|
+
}
|
|
353
|
+
lines.push("\tInferred source export type:");
|
|
354
|
+
if (isSuccess(diagnostics.jsExportType)) {
|
|
355
|
+
lines.push(formatType(diagnostics.jsExportType.result));
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
lines.push(`Could not infer type of JavaScript exports. Reason: ${diagnostics.jsExportType.reason}`);
|
|
359
|
+
}
|
|
360
|
+
if (diagnostics.dtsExportKind) {
|
|
361
|
+
lines.push("\tInferred declaration module structure:");
|
|
362
|
+
if (isSuccess(diagnostics.dtsExportKind)) {
|
|
363
|
+
lines.push(diagnostics.dtsExportKind.result);
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
lines.push(`Could not infer type of declaration exports. Reason: ${diagnostics.dtsExportKind.reason}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (diagnostics.dtsExportType) {
|
|
370
|
+
lines.push("\tInferred declaration export type:");
|
|
371
|
+
if (isSuccess(diagnostics.dtsExportType)) {
|
|
372
|
+
lines.push(formatType(diagnostics.dtsExportType.result));
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
lines.push(`Could not infer type of declaration exports. Reason: ${diagnostics.dtsExportType.reason}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return lines.join("\n");
|
|
379
|
+
}
|
|
380
|
+
function formatType(type) {
|
|
381
|
+
const lines = [];
|
|
382
|
+
//@ts-ignore property `checker` of `ts.Type` is marked internal. The alternative is to have a TypeChecker parameter.
|
|
383
|
+
const checker = type.checker;
|
|
384
|
+
const properties = type.getProperties();
|
|
385
|
+
if (properties.length > 0) {
|
|
386
|
+
lines.push("Type's properties:");
|
|
387
|
+
lines.push(...properties.map(p => p.getName()));
|
|
388
|
+
}
|
|
389
|
+
const signatures = type.getConstructSignatures().concat(type.getCallSignatures());
|
|
390
|
+
if (signatures.length > 0) {
|
|
391
|
+
lines.push("Type's signatures:");
|
|
392
|
+
lines.push(...signatures.map(s => checker.signatureToString(s)));
|
|
393
|
+
}
|
|
394
|
+
lines.push(`Type string: ${checker.typeToString(type)}`);
|
|
395
|
+
return lines.join("\n");
|
|
396
|
+
}
|
|
397
|
+
const exportEqualsLink = "https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require";
|
|
398
|
+
/**
|
|
399
|
+
* Checks exports of a declaration file against its JavaScript source.
|
|
400
|
+
*/
|
|
401
|
+
function checkExports(name, dtsPath, sourcePath) {
|
|
402
|
+
const tscOpts = {
|
|
403
|
+
allowJs: true
|
|
404
|
+
};
|
|
405
|
+
const jsProgram = typescript_1.default.createProgram([sourcePath], tscOpts);
|
|
406
|
+
const jsFileNode = jsProgram.getSourceFile(sourcePath);
|
|
407
|
+
if (!jsFileNode) {
|
|
408
|
+
throw new Error(`TS compiler could not find source file ${sourcePath}.`);
|
|
409
|
+
}
|
|
410
|
+
const jsChecker = jsProgram.getTypeChecker();
|
|
411
|
+
const errors = [];
|
|
412
|
+
const sourceDiagnostics = inspectJs(jsFileNode, jsChecker, name);
|
|
413
|
+
const dtsDiagnostics = inspectDts(dtsPath, name);
|
|
414
|
+
if (isSuccess(sourceDiagnostics.exportEquals) &&
|
|
415
|
+
sourceDiagnostics.exportEquals.result.judgement === ExportEqualsJudgement.Required &&
|
|
416
|
+
isSuccess(dtsDiagnostics.exportKind) &&
|
|
417
|
+
dtsDiagnostics.exportKind.result !== DtsExportKind.ExportEquals) {
|
|
418
|
+
const error = {
|
|
419
|
+
kind: ErrorKind.NeedsExportEquals,
|
|
420
|
+
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
|
|
421
|
+
The declaration should use 'export =' syntax because the JavaScript source uses 'module.exports =' syntax and ${sourceDiagnostics.exportEquals.result.reason}.
|
|
422
|
+
|
|
423
|
+
To learn more about 'export =' syntax, see ${exportEqualsLink}.`
|
|
424
|
+
};
|
|
425
|
+
errors.push(error);
|
|
426
|
+
}
|
|
427
|
+
const compatibility = exportTypesCompatibility(name, sourceDiagnostics.exportType, dtsDiagnostics.exportType, dtsDiagnostics.exportKind);
|
|
428
|
+
if (isSuccess(compatibility)) {
|
|
429
|
+
errors.push(...compatibility.result);
|
|
430
|
+
}
|
|
431
|
+
if (dtsDiagnostics.defaultExport && !sourceDiagnostics.exportsDefault) {
|
|
432
|
+
errors.push({
|
|
433
|
+
kind: ErrorKind.NoDefaultExport,
|
|
434
|
+
position: dtsDiagnostics.defaultExport,
|
|
435
|
+
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
|
|
436
|
+
The declaration specifies 'export default' but the JavaScript source does not mention 'default' anywhere.
|
|
437
|
+
|
|
438
|
+
The most common way to resolve this error is to use 'export =' syntax instead of 'export default'.
|
|
439
|
+
To learn more about 'export =' syntax, see ${exportEqualsLink}.`
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
jsExportKind: sourceDiagnostics.exportKind,
|
|
444
|
+
jsExportType: sourceDiagnostics.exportType,
|
|
445
|
+
dtsExportKind: dtsDiagnostics.exportKind,
|
|
446
|
+
dtsExportType: dtsDiagnostics.exportType,
|
|
447
|
+
errors
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function inspectJs(sourceFile, checker, packageName) {
|
|
451
|
+
const exportKind = getJsExportKind(sourceFile);
|
|
452
|
+
const exportType = getJSExportType(sourceFile, checker, exportKind);
|
|
453
|
+
const exportsDefault = sourceExportsDefault(sourceFile, packageName);
|
|
454
|
+
let exportEquals;
|
|
455
|
+
if (isSuccess(exportType) && isSuccess(exportKind) && exportKind.result === JsExportKind.CommonJs) {
|
|
456
|
+
exportEquals = moduleTypeNeedsExportEquals(exportType.result, checker);
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
exportEquals = mergeErrors(exportType, exportKind);
|
|
460
|
+
}
|
|
461
|
+
return { exportKind, exportType, exportEquals, exportsDefault };
|
|
462
|
+
}
|
|
463
|
+
function getJsExportKind(sourceFile) {
|
|
464
|
+
// @ts-ignore property `commonJsModuleIndicator` of `ts.SourceFile` is marked internal.
|
|
465
|
+
if (sourceFile.commonJsModuleIndicator) {
|
|
466
|
+
return inferenceSuccess(JsExportKind.CommonJs);
|
|
467
|
+
}
|
|
468
|
+
// @ts-ignore property `externalModuleIndicator` of `ts.SourceFile` is marked internal.
|
|
469
|
+
if (sourceFile.externalModuleIndicator) {
|
|
470
|
+
return inferenceSuccess(JsExportKind.ES6);
|
|
471
|
+
}
|
|
472
|
+
return inferenceError("Could not infer export kind of source file.");
|
|
473
|
+
}
|
|
474
|
+
function getJSExportType(sourceFile, checker, exportKind) {
|
|
475
|
+
if (isSuccess(exportKind)) {
|
|
476
|
+
switch (exportKind.result) {
|
|
477
|
+
case JsExportKind.CommonJs: {
|
|
478
|
+
checker.getSymbolAtLocation(sourceFile); // TODO: get symbol in a safer way?
|
|
479
|
+
//@ts-ignore property `symbol` of `ts.Node` is marked internal.
|
|
480
|
+
const fileSymbol = sourceFile.symbol;
|
|
481
|
+
if (!fileSymbol) {
|
|
482
|
+
return inferenceError(`TS compiler could not find symbol for file node '${sourceFile.fileName}'.`);
|
|
483
|
+
}
|
|
484
|
+
const exportType = checker.getTypeOfSymbolAtLocation(fileSymbol, sourceFile);
|
|
485
|
+
return inferenceSuccess(exportType);
|
|
486
|
+
}
|
|
487
|
+
case JsExportKind.ES6: {
|
|
488
|
+
const fileSymbol = checker.getSymbolAtLocation(sourceFile);
|
|
489
|
+
if (!fileSymbol) {
|
|
490
|
+
return inferenceError(`TS compiler could not find symbol for file node '${sourceFile.fileName}'.`);
|
|
491
|
+
}
|
|
492
|
+
const exportType = checker.getTypeOfSymbolAtLocation(fileSymbol, sourceFile);
|
|
493
|
+
return inferenceSuccess(exportType);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return inferenceError(`Could not infer type of exports because exports kind is undefined.`);
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Decide if a JavaScript source module could have a default export.
|
|
501
|
+
*/
|
|
502
|
+
function sourceExportsDefault(sourceFile, name) {
|
|
503
|
+
const src = sourceFile.getFullText(sourceFile);
|
|
504
|
+
return (isRealExportDefault(name) ||
|
|
505
|
+
src.indexOf("default") > -1 ||
|
|
506
|
+
src.indexOf("__esModule") > -1 ||
|
|
507
|
+
src.indexOf("react-side-effect") > -1 ||
|
|
508
|
+
src.indexOf("@flow") > -1 ||
|
|
509
|
+
src.indexOf("module.exports = require") > -1);
|
|
510
|
+
}
|
|
511
|
+
function moduleTypeNeedsExportEquals(type, checker) {
|
|
512
|
+
if (isBadType(type)) {
|
|
513
|
+
return inferenceError(`Inferred type '${checker.typeToString(type)}' is not good enough to be analyzed.`);
|
|
514
|
+
}
|
|
515
|
+
const isObject = type.getFlags() & typescript_1.default.TypeFlags.Object;
|
|
516
|
+
// @ts-ignore property `isArrayLikeType` of `ts.TypeChecker` is marked internal.
|
|
517
|
+
if (isObject && !hasSignatures(type) && !checker.isArrayLikeType(type)) {
|
|
518
|
+
const judgement = ExportEqualsJudgement.NotRequired;
|
|
519
|
+
const reason = "'module.exports' is an object which is neither a function, class, or array";
|
|
520
|
+
return inferenceSuccess({ judgement, reason });
|
|
521
|
+
}
|
|
522
|
+
if (hasSignatures(type)) {
|
|
523
|
+
const judgement = ExportEqualsJudgement.Required;
|
|
524
|
+
const reason = "'module.exports' can be called or constructed";
|
|
525
|
+
return inferenceSuccess({ judgement, reason });
|
|
526
|
+
}
|
|
527
|
+
const primitive = typescript_1.default.TypeFlags.Boolean | typescript_1.default.TypeFlags.String | typescript_1.default.TypeFlags.Number;
|
|
528
|
+
if (type.getFlags() & primitive) {
|
|
529
|
+
const judgement = ExportEqualsJudgement.Required;
|
|
530
|
+
const reason = `'module.exports' has primitive type ${checker.typeToString(type)}`;
|
|
531
|
+
return inferenceSuccess({ judgement, reason });
|
|
532
|
+
}
|
|
533
|
+
// @ts-ignore property `isArrayLikeType` of `ts.TypeChecker` is marked internal.
|
|
534
|
+
if (checker.isArrayLikeType(type)) {
|
|
535
|
+
const judgement = ExportEqualsJudgement.Required;
|
|
536
|
+
const reason = `'module.exports' has array-like type ${checker.typeToString(type)}`;
|
|
537
|
+
return inferenceSuccess({ judgement, reason });
|
|
538
|
+
}
|
|
539
|
+
return inferenceError(`Could not analyze type '${checker.typeToString(type)}'.`);
|
|
540
|
+
}
|
|
541
|
+
function hasSignatures(type) {
|
|
542
|
+
return type.getCallSignatures().length > 0 || type.getConstructSignatures().length > 0;
|
|
543
|
+
}
|
|
544
|
+
function inspectDts(dtsPath, name) {
|
|
545
|
+
dtsPath = path.resolve(dtsPath);
|
|
546
|
+
const program = createDtProgram(dtsPath);
|
|
547
|
+
const sourceFile = program.getSourceFile(path.resolve(dtsPath));
|
|
548
|
+
if (!sourceFile) {
|
|
549
|
+
throw new Error(`TS compiler could not find source file '${dtsPath}'.`);
|
|
550
|
+
}
|
|
551
|
+
const checker = program.getTypeChecker();
|
|
552
|
+
const symbolResult = getDtsModuleSymbol(sourceFile, checker, name);
|
|
553
|
+
const exportKindResult = getDtsExportKind(sourceFile);
|
|
554
|
+
const exportType = getDtsExportType(sourceFile, checker, symbolResult, exportKindResult);
|
|
555
|
+
const defaultExport = getDtsDefaultExport(sourceFile, exportType);
|
|
556
|
+
return { exportKind: exportKindResult, exportType, defaultExport };
|
|
557
|
+
}
|
|
558
|
+
function createDtProgram(dtsPath) {
|
|
559
|
+
const dtsDir = path.dirname(dtsPath);
|
|
560
|
+
const configPath = path.join(dtsDir, "tsconfig.json");
|
|
561
|
+
const { config } = typescript_1.default.readConfigFile(configPath, p => fs.readFileSync(p, { encoding: "utf8" }));
|
|
562
|
+
const parseConfigHost = {
|
|
563
|
+
fileExists: fs.existsSync,
|
|
564
|
+
readDirectory: typescript_1.default.sys.readDirectory,
|
|
565
|
+
readFile: file => fs.readFileSync(file, { encoding: "utf8" }),
|
|
566
|
+
useCaseSensitiveFileNames: true
|
|
567
|
+
};
|
|
568
|
+
const parsed = typescript_1.default.parseJsonConfigFileContent(config, parseConfigHost, path.resolve(dtsDir));
|
|
569
|
+
const host = typescript_1.default.createCompilerHost(parsed.options, true);
|
|
570
|
+
return typescript_1.default.createProgram([path.resolve(dtsPath)], parsed.options, host);
|
|
571
|
+
}
|
|
572
|
+
function getDtsModuleSymbol(sourceFile, checker, name) {
|
|
573
|
+
if (matches(sourceFile, node => typescript_1.default.isModuleDeclaration(node))) {
|
|
574
|
+
const npmName = dtToNpmName(name);
|
|
575
|
+
const moduleSymbol = checker.getAmbientModules().find(symbol => symbol.getName() === `"${npmName}"`);
|
|
576
|
+
if (moduleSymbol) {
|
|
577
|
+
return inferenceSuccess(moduleSymbol);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
const fileSymbol = checker.getSymbolAtLocation(sourceFile);
|
|
581
|
+
if (fileSymbol && fileSymbol.getFlags() & typescript_1.default.SymbolFlags.ValueModule) {
|
|
582
|
+
return inferenceSuccess(fileSymbol);
|
|
583
|
+
}
|
|
584
|
+
return inferenceError(`Could not find module symbol for source file node.`);
|
|
585
|
+
}
|
|
586
|
+
function getDtsExportKind(sourceFile) {
|
|
587
|
+
if (matches(sourceFile, isExportEquals)) {
|
|
588
|
+
return inferenceSuccess(DtsExportKind.ExportEquals);
|
|
589
|
+
}
|
|
590
|
+
if (matches(sourceFile, isExportConstruct)) {
|
|
591
|
+
return inferenceSuccess(DtsExportKind.ES6Like);
|
|
592
|
+
}
|
|
593
|
+
return inferenceError("Could not infer export kind of declaration file.");
|
|
594
|
+
}
|
|
595
|
+
const exportEqualsSymbolName = "export=";
|
|
596
|
+
function getDtsExportType(sourceFile, checker, symbolResult, exportKindResult) {
|
|
597
|
+
if (isSuccess(symbolResult) && isSuccess(exportKindResult)) {
|
|
598
|
+
const symbol = symbolResult.result;
|
|
599
|
+
const exportKind = exportKindResult.result;
|
|
600
|
+
switch (exportKind) {
|
|
601
|
+
case DtsExportKind.ExportEquals: {
|
|
602
|
+
const exportSymbol = symbol.exports.get(exportEqualsSymbolName);
|
|
603
|
+
if (!exportSymbol) {
|
|
604
|
+
return inferenceError(`TS compiler could not find \`export=\` symbol.`);
|
|
605
|
+
}
|
|
606
|
+
const exportType = checker.getTypeOfSymbolAtLocation(exportSymbol, sourceFile);
|
|
607
|
+
return inferenceSuccess(exportType);
|
|
608
|
+
}
|
|
609
|
+
case DtsExportKind.ES6Like: {
|
|
610
|
+
const exportType = checker.getTypeOfSymbolAtLocation(symbol, sourceFile);
|
|
611
|
+
return inferenceSuccess(exportType);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
return mergeErrors(symbolResult, exportKindResult);
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Returns the position of the default export, if it exists.
|
|
619
|
+
*/
|
|
620
|
+
function getDtsDefaultExport(sourceFile, moduleType) {
|
|
621
|
+
if (isError(moduleType)) {
|
|
622
|
+
const src = sourceFile.getFullText(sourceFile);
|
|
623
|
+
const exportDefault = src.indexOf("export default");
|
|
624
|
+
if (exportDefault > -1 && src.indexOf("export =") === -1 && !/declare module ['"]/.test(src)) {
|
|
625
|
+
return {
|
|
626
|
+
start: exportDefault,
|
|
627
|
+
length: "export default".length
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
return undefined;
|
|
631
|
+
}
|
|
632
|
+
const exportDefault = moduleType.result.getProperty("default");
|
|
633
|
+
if (exportDefault === null || exportDefault === void 0 ? void 0 : exportDefault.declarations) {
|
|
634
|
+
return {
|
|
635
|
+
start: exportDefault.declarations[0].getStart(),
|
|
636
|
+
length: exportDefault.declarations[0].getWidth()
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
return undefined;
|
|
640
|
+
}
|
|
641
|
+
const ignoredProperties = ["__esModule", "prototype", "default", "F", "G", "S", "P", "B", "W", "U", "R"];
|
|
642
|
+
function ignoreProperty(property) {
|
|
643
|
+
const name = property.getName();
|
|
644
|
+
return name.startsWith("_") || ignoredProperties.includes(name);
|
|
645
|
+
}
|
|
646
|
+
/*
|
|
647
|
+
* Given the inferred type of the exports of both source and declaration, we make the following checks:
|
|
648
|
+
* 1. If source type has call or construct signatures, then declaration type should also have call or construct signatures.
|
|
649
|
+
* 2. If declaration type has call or construct signatures, then source type should also have call or construct signatures.
|
|
650
|
+
* 3. If source type has a property named "foo", then declaration type should also have a property named "foo".
|
|
651
|
+
* 4. If declaration type has a property named "foo", then source type should also have a property named "foo".
|
|
652
|
+
* Checks (2) and (4) don't work well in practice and should not be used for linting/verification purposes, because
|
|
653
|
+
* most of the times the error originates because the inferred type of the JavaScript source has missing information.
|
|
654
|
+
* Those checks are useful for finding examples where JavaScript type inference could be improved.
|
|
655
|
+
*/
|
|
656
|
+
function exportTypesCompatibility(name, sourceType, dtsType, dtsExportKind) {
|
|
657
|
+
if (isError(sourceType)) {
|
|
658
|
+
return inferenceError("Could not get type of exports of source module.");
|
|
659
|
+
}
|
|
660
|
+
if (isError(dtsType)) {
|
|
661
|
+
return inferenceError("Could not get type of exports of declaration module.");
|
|
662
|
+
}
|
|
663
|
+
if (isBadType(sourceType.result)) {
|
|
664
|
+
return inferenceError("Could not infer meaningful type of exports of source module.");
|
|
665
|
+
}
|
|
666
|
+
if (isBadType(dtsType.result)) {
|
|
667
|
+
return inferenceError("Could not infer meaningful type of exports of declaration module.");
|
|
668
|
+
}
|
|
669
|
+
const errors = [];
|
|
670
|
+
if (hasSignatures(sourceType.result) && !hasSignatures(dtsType.result)) {
|
|
671
|
+
if (isSuccess(dtsExportKind) && dtsExportKind.result === DtsExportKind.ExportEquals) {
|
|
672
|
+
errors.push({
|
|
673
|
+
kind: ErrorKind.JsSignatureNotInDts,
|
|
674
|
+
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
|
|
675
|
+
The JavaScript module can be called or constructed, but the declaration module cannot.`
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
errors.push({
|
|
680
|
+
kind: ErrorKind.JsSignatureNotInDts,
|
|
681
|
+
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
|
|
682
|
+
The JavaScript module can be called or constructed, but the declaration module cannot.
|
|
683
|
+
|
|
684
|
+
The most common way to resolve this error is to use 'export =' syntax.
|
|
685
|
+
To learn more about 'export =' syntax, see ${exportEqualsLink}.`
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
if (hasSignatures(dtsType.result) && !hasSignatures(sourceType.result)) {
|
|
690
|
+
errors.push({
|
|
691
|
+
kind: ErrorKind.DtsSignatureNotInJs,
|
|
692
|
+
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
|
|
693
|
+
The declaration module can be called or constructed, but the JavaScript module cannot.`
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
const sourceProperties = sourceType.result.getProperties();
|
|
697
|
+
const dtsProperties = dtsType.result.getProperties();
|
|
698
|
+
for (const sourceProperty of sourceProperties) {
|
|
699
|
+
// TODO: check `prototype` properties.
|
|
700
|
+
if (ignoreProperty(sourceProperty))
|
|
701
|
+
continue;
|
|
702
|
+
if (!dtsProperties.find(s => s.getName() === sourceProperty.getName())) {
|
|
703
|
+
errors.push({
|
|
704
|
+
kind: ErrorKind.JsPropertyNotInDts,
|
|
705
|
+
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
|
|
706
|
+
The JavaScript module exports a property named '${sourceProperty.getName()}', which is missing from the declaration module.`
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
for (const dtsProperty of dtsProperties) {
|
|
711
|
+
// TODO: check `prototype` properties.
|
|
712
|
+
if (ignoreProperty(dtsProperty))
|
|
713
|
+
continue;
|
|
714
|
+
if (!sourceProperties.find(s => s.getName() === dtsProperty.getName())) {
|
|
715
|
+
const error = {
|
|
716
|
+
kind: ErrorKind.DtsPropertyNotInJs,
|
|
717
|
+
message: `The declaration doesn't match the JavaScript module '${name}'. Reason:
|
|
718
|
+
The declaration module exports a property named '${dtsProperty.getName()}', which is missing from the JavaScript module.`
|
|
719
|
+
};
|
|
720
|
+
const declaration = dtsProperty.declarations && dtsProperty.declarations.length > 0 ? dtsProperty.declarations[0] : undefined;
|
|
721
|
+
if (declaration) {
|
|
722
|
+
error.position = {
|
|
723
|
+
start: declaration.getStart(),
|
|
724
|
+
length: declaration.getWidth()
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
errors.push(error);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return inferenceSuccess(errors);
|
|
731
|
+
}
|
|
732
|
+
function isBadType(type) {
|
|
733
|
+
return !!(type.getFlags() & (typescript_1.default.TypeFlags.Any | typescript_1.default.TypeFlags.Unknown | typescript_1.default.TypeFlags.Undefined | typescript_1.default.TypeFlags.Null));
|
|
734
|
+
}
|
|
735
|
+
function isExportEquals(node) {
|
|
736
|
+
return typescript_1.default.isExportAssignment(node) && !!node.isExportEquals;
|
|
737
|
+
}
|
|
738
|
+
function isExportConstruct(node) {
|
|
739
|
+
return typescript_1.default.isExportAssignment(node) || typescript_1.default.isExportDeclaration(node) || hasExportModifier(node);
|
|
740
|
+
}
|
|
741
|
+
function hasExportModifier(node) {
|
|
742
|
+
if (node.modifiers) {
|
|
743
|
+
return node.modifiers.some(modifier => modifier.kind === typescript_1.default.SyntaxKind.ExportKeyword);
|
|
744
|
+
}
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
function matches(srcFile, predicate) {
|
|
748
|
+
function matchesNode(node) {
|
|
749
|
+
if (predicate(node))
|
|
750
|
+
return true;
|
|
751
|
+
const children = node.getChildren(srcFile);
|
|
752
|
+
for (const child of children) {
|
|
753
|
+
if (matchesNode(child))
|
|
754
|
+
return true;
|
|
755
|
+
}
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
return matchesNode(srcFile);
|
|
759
|
+
}
|
|
760
|
+
function isExistingSquatter(name) {
|
|
761
|
+
return (name === "atom" ||
|
|
762
|
+
name === "ember__string" ||
|
|
763
|
+
name === "fancybox" ||
|
|
764
|
+
name === "jsqrcode" ||
|
|
765
|
+
name === "node" ||
|
|
766
|
+
name === "geojson" ||
|
|
767
|
+
name === "titanium");
|
|
768
|
+
}
|
|
769
|
+
function isRealExportDefault(name) {
|
|
770
|
+
return name.indexOf("react-native") > -1 || name === "ember-feature-flags" || name === "material-ui-datatables";
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Converts a package name from the name used in DT repository to the name used in npm.
|
|
774
|
+
* @param baseName DT name of a package
|
|
775
|
+
*/
|
|
776
|
+
function dtToNpmName(baseName) {
|
|
777
|
+
if (/__/.test(baseName)) {
|
|
778
|
+
return "@" + baseName.replace("__", "/");
|
|
779
|
+
}
|
|
780
|
+
return baseName;
|
|
781
|
+
}
|
|
782
|
+
exports.dtToNpmName = dtToNpmName;
|
|
783
|
+
/**
|
|
784
|
+
* @param error case-insensitive name of the error
|
|
785
|
+
*/
|
|
786
|
+
function parseExportErrorKind(error) {
|
|
787
|
+
error = error.toLowerCase();
|
|
788
|
+
switch (error) {
|
|
789
|
+
case "needsexportequals":
|
|
790
|
+
return ErrorKind.NeedsExportEquals;
|
|
791
|
+
case "nodefaultexport":
|
|
792
|
+
return ErrorKind.NoDefaultExport;
|
|
793
|
+
case "jspropertynotindts":
|
|
794
|
+
return ErrorKind.JsPropertyNotInDts;
|
|
795
|
+
case "dtspropertynotinjs":
|
|
796
|
+
return ErrorKind.DtsPropertyNotInJs;
|
|
797
|
+
case "jssignaturenotindts":
|
|
798
|
+
return ErrorKind.JsSignatureNotInDts;
|
|
799
|
+
case "dtssignaturenotinjs":
|
|
800
|
+
return ErrorKind.DtsSignatureNotInJs;
|
|
801
|
+
}
|
|
802
|
+
return undefined;
|
|
803
|
+
}
|
|
804
|
+
exports.parseExportErrorKind = parseExportErrorKind;
|
|
805
|
+
var JsExportKind;
|
|
806
|
+
(function (JsExportKind) {
|
|
807
|
+
JsExportKind["CommonJs"] = "CommonJs";
|
|
808
|
+
JsExportKind["ES6"] = "ES6";
|
|
809
|
+
})(JsExportKind || (JsExportKind = {}));
|
|
810
|
+
var ExportEqualsJudgement;
|
|
811
|
+
(function (ExportEqualsJudgement) {
|
|
812
|
+
ExportEqualsJudgement["Required"] = "Required";
|
|
813
|
+
ExportEqualsJudgement["NotRequired"] = "Not required";
|
|
814
|
+
})(ExportEqualsJudgement || (ExportEqualsJudgement = {}));
|
|
815
|
+
var DtsExportKind;
|
|
816
|
+
(function (DtsExportKind) {
|
|
817
|
+
DtsExportKind["ExportEquals"] = "export =";
|
|
818
|
+
DtsExportKind["ES6Like"] = "ES6-like";
|
|
819
|
+
})(DtsExportKind || (DtsExportKind = {}));
|
|
820
|
+
var InferenceResultKind;
|
|
821
|
+
(function (InferenceResultKind) {
|
|
822
|
+
InferenceResultKind[InferenceResultKind["Error"] = 0] = "Error";
|
|
823
|
+
InferenceResultKind[InferenceResultKind["Success"] = 1] = "Success";
|
|
824
|
+
})(InferenceResultKind || (InferenceResultKind = {}));
|
|
825
|
+
function inferenceError(reason) {
|
|
826
|
+
return { kind: InferenceResultKind.Error, reason };
|
|
827
|
+
}
|
|
828
|
+
function inferenceSuccess(result) {
|
|
829
|
+
return { kind: InferenceResultKind.Success, result };
|
|
830
|
+
}
|
|
831
|
+
function isSuccess(inference) {
|
|
832
|
+
return inference.kind === InferenceResultKind.Success;
|
|
833
|
+
}
|
|
834
|
+
function isError(inference) {
|
|
835
|
+
return inference.kind === InferenceResultKind.Error;
|
|
836
|
+
}
|
|
837
|
+
function mergeErrors(...results) {
|
|
838
|
+
const reasons = [];
|
|
839
|
+
for (const result of results) {
|
|
840
|
+
if (typeof result === "string") {
|
|
841
|
+
reasons.push(result);
|
|
842
|
+
}
|
|
843
|
+
else if (isError(result) && result.reason) {
|
|
844
|
+
reasons.push(result.reason);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
return inferenceError(reasons.join(" "));
|
|
848
|
+
}
|
|
849
|
+
if (!module.parent) {
|
|
850
|
+
main();
|
|
851
|
+
}
|
|
852
|
+
//# sourceMappingURL=index.js.map
|