New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

dts-critic

Package Overview
Dependencies
Maintainers
1
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dts-critic - npm Package Compare versions

Comparing version 1.0.3 to 1.0.4

26

dt.js

@@ -6,3 +6,3 @@ const critic = require('./index')

/** @param {string} tslintPath */
async function hasDtHeaderLintRule(tslintPath) {
function hasDtHeaderLintRule(tslintPath) {
if (fs.existsSync(tslintPath)) {

@@ -18,9 +18,8 @@ const tslint = JSON.parse(stripJsonComments(fs.readFileSync(tslintPath, 'utf-8')))

async function main() {
function main() {
for (const item of fs.readdirSync('../DefinitelyTyped/types')) {
const entry = '../DefinitelyTyped/types/' + item
try {
if (await hasDtHeaderLintRule(entry + '/tslint.json')) {
await critic(entry + '/index.d.ts')
if (hasDtHeaderLintRule(entry + '/tslint.json')) {
critic(entry + '/index.d.ts')
}

@@ -37,6 +36,17 @@ }

console.log('trying to add ' + e.homepage + '...')
// const re = /\/\/ Project: (.+)/;
// const s = fs.readFileSync(entry + '/index.d.ts', 'utf-8')
// fs.writeFileSync(entry + '/index.d.ts', s.replace(re, '// Project: $1, ' + e.homepage), 'utf-8')
const re = /\/\/ Project: (.+)/;
const s = fs.readFileSync(entry + '/index.d.ts', 'utf-8')
fs.writeFileSync(entry + '/index.d.ts', s.replace(re, '// Project: $1, ' + e.homepage), 'utf-8')
}
else if (/but the source does not mention 'default'/.test(e.message)) {
console.log('converting', item, 'to export = ...')
const named = /export default function\s+(\w+\s*)\(/;
const anon = /export default function\s*\(/;
const id = /export default(\s+\w+);/;
let s = fs.readFileSync(entry + '/index.d.ts', 'utf-8')
s = s.replace(named, 'export = $1;\ndeclare function $1(')
s = s.replace(anon, 'export = _default;\ndeclare function _default(')
s = s.replace(id, 'export =$1;')
fs.writeFileSync(entry + '/index.d.ts', s, 'utf-8')
}
else {

@@ -43,0 +53,0 @@ console.log('*** ERROR for ' + item + ' ***')

@@ -1,2 +0,2 @@

declare function dtsCritic(dtsPath: string, sourcePath?: string): Promise<void>;
declare function dtsCritic(dtsPath: string, sourcePath?: string): void;
export = dtsCritic;

@@ -5,3 +5,3 @@ const yargs = require("yargs");

const path = require("path");
const request = require("request-promise-native");
const download = require("download-file-sync");

@@ -12,3 +12,3 @@ /**

*/
async function dtsCritic(dtsPath, sourcePath) {
function dtsCritic(dtsPath, sourcePath) {
const dts = fs.readFileSync(dtsPath, "utf-8");

@@ -22,3 +22,10 @@ let header;

}
check(await findNames(dtsPath, sourcePath, header), header);
const names = findNames(dtsPath, sourcePath, header)
const src = sourcePath ?
fs.readFileSync(require.resolve(sourcePath), "utf-8") :
download("https://unpkg.com/" + mangleScoped(names.src));
checkNames(names, header);
if (header && !header.nonNpm) {
checkSource(names.dts, dts, src);
}
}

@@ -28,3 +35,4 @@ dtsCritic.findDtsName = findDtsName;

dtsCritic.retrieveNpmHomepageOrFail = retrieveNpmHomepageOrFail;
dtsCritic.check = check;
dtsCritic.checkNames = checkNames;
dtsCritic.checkSource = checkSource;

@@ -34,3 +42,3 @@ module.exports = dtsCritic;

if (!module.parent) {
main().catch(e => { console.log(e); process.exit(1) });
main();
}

@@ -46,3 +54,3 @@

async function main() {
function main() {
const argv = yargs.

@@ -53,23 +61,16 @@ usage("$0 name.d.ts [source-folder]\n\nIf source-folder is not provided, I will look for a matching package on npm.", ).

if (argv._.length === 0) {
console.log('Please provide a path to a d.ts file for me to critique.');
console.log("Please provide a path to a d.ts file for me to critique.");
process.exit(1);
}
let header;
const dts = fs.readFileSync(argv._[0], "utf-8");
try {
header = headerParser.parseHeaderOrFail(dts);
}
catch(e) {
header = undefined;
}
check(await findNames(argv._[0], argv._[1], header), header);
return dtsCritic(argv._[0], argv._[1]);
}
/**
* Find package names of dts and source. Also finds the homepage from the DT header, if present.
* @param {string} dtsPath
* @param {string | undefined} sourcePath
* @param {headerParser.Header | undefined} header
* @return {Promise<Names>}
* @return {Names}
*/
async function findNames(dtsPath, sourcePath, header) {
function findNames(dtsPath, sourcePath, header) {
const dts = findDtsName(dtsPath);

@@ -85,3 +86,3 @@ let src;

try {
homepage = await retrieveNpmHomepageOrFail(dts);
homepage = retrieveNpmHomepageOrFail(dts);
nonNpmHasMatchingPackage = !!header && header.nonNpm && !isExistingSquatter(dts);

@@ -119,12 +120,20 @@ }

/** @param {string} dts */
function isExistingSquatter(dts) {
return dts === "atom" ||
dts === "ember__string" ||
dts === "fancybox" ||
dts === "jsqrcode" ||
dts === "node" ||
dts === "titanium";
/** @param {string} name */
function isExistingSquatter(name) {
return name === "atom" ||
name === "ember__string" ||
name === "fancybox" ||
name === "jsqrcode" ||
name === "node" ||
name === "geojson" ||
name === "titanium";
}
/** @param {string} name */
function isRealExportDefault(name) {
return name.indexOf("react-native") > -1 ||
name === "ember-feature-flags" ||
name === "material-ui-datatables";
}
/**

@@ -153,6 +162,10 @@ * If dtsName is 'index' (as with DT) then look to the parent directory for the name.

* @param {string} baseName
* @return {Promise<string>}
* @return {string}
*/
async function retrieveNpmHomepageOrFail(baseName) {
return JSON.parse(await request("https://registry.npmjs.org/" + mangleScoped(baseName))).homepage;
function retrieveNpmHomepageOrFail(baseName) {
const npm = JSON.parse(download("https://registry.npmjs.org/" + mangleScoped(baseName)));
if ("error" in npm) {
throw new Error(baseName + " " + npm.error);
}
return npm.homepage;
}

@@ -172,3 +185,3 @@

*/
function check(names, header) {
function checkNames(names, header) {
if (names.dts !== names.src) {

@@ -193,2 +206,20 @@ throw new Error(`d.ts name '${names.dts}' must match source name '${names.src}'.`);

/**
* A d.ts with 'export default' and no ambient modules should have source that contains
* either 'default' or '__esModule' or 'react-side-effect' or '@flow' somewhere.
* This function also skips any package named 'react-native'.
*
* Note that this function doesn't follow requires, but just tries to detect
* 'module.exports = require'
* @param {string} name
* @param {string} dts
* @param {string} src
*/
function checkSource(name, dts, src) {
if (dts.indexOf("export default") > -1 && !/declare module ['"]/.test(dts) &&
!isRealExportDefault(name) && src.indexOf("default") === -1 && src.indexOf("__esModule") === -1 && src.indexOf("react-side-effect") === -1 && src.indexOf("@flow") === -1 && src.indexOf("module.exports = require") === -1) {
throw new Error(`The types for ${name} specify 'export default' but the source does not mention 'default' anywhere.`);
}
}
/** @param {string} url */

@@ -195,0 +226,0 @@ function normalise(url) {

@@ -1,2 +0,2 @@

const { findDtsName, findNames, retrieveNpmHomepageOrFail, check } = require("./index");
const { findDtsName, findNames, retrieveNpmHomepageOrFail, checkNames, checkSource } = require("./index");
/**

@@ -31,4 +31,4 @@ * @param {string} description

suite("findNames", {
async absolutePathsBoth() {
expect(await findNames("jquery/index.d.ts", "~/dts-critic", undefined)).toEqual({
absolutePathsBoth() {
expect(findNames("jquery/index.d.ts", "~/dts-critic", undefined)).toEqual({
dts: "jquery",

@@ -40,4 +40,4 @@ src: "dts-critic",

},
async currentDirectorySource() {
expect(await findNames("jquery/index.d.ts", ".", undefined)).toEqual({
currentDirectorySource() {
expect(findNames("jquery/index.d.ts", ".", undefined)).toEqual({
dts: "jquery",

@@ -49,4 +49,4 @@ src: "dts-critic",

},
async mistakenFileNameSource() {
expect(await findNames("jquery/index.d.ts", "/home/lol/oops.index.js", undefined)).toEqual({
mistakenFileNameSource() {
expect(findNames("jquery/index.d.ts", "/home/lol/oops.index.js", undefined)).toEqual({
dts: "jquery",

@@ -58,4 +58,4 @@ src: "lol",

},
async trailingSlashSource() {
expect(await findNames("jquery/index.d.ts", "/home/lol/", undefined)).toEqual({
trailingSlashSource() {
expect(findNames("jquery/index.d.ts", "/home/lol/", undefined)).toEqual({
dts: "jquery",

@@ -67,13 +67,11 @@ src: "lol",

},
async mismatchPackageFailNoHeader() {
mismatchPackageFailNoHeader() {
// surely parseltongue will never exist
expect.assertions(1)
try {
await findNames("parseltongue.d.ts", undefined, undefined)
}
catch (e) {
expect(e.message).toEqual(`d.ts file must have a matching npm package.
expect(() => findNames("parseltongue.d.ts", undefined, undefined)).toThrow(
`d.ts file must have a matching npm package.
To resolve this error, either:
Add a Definitely Typed header with the first line
1. Change the name to match an npm package.
2. Add a Definitely Typed header with the first line
// Type definitions for non-npm package parseltongue-browser

@@ -85,10 +83,8 @@

Explicitly provide dts-critic with a source file. This is not allowed for submission to Definitely Typed.`)
}
3. Explicitly provide dts-critic with a source file. This is not allowed for submission to Definitely Typed.
`)
},
async mismatchPackageFailNpmHeader() {
mismatchPackageFailNpmHeader() {
// surely parseltongue will never exist
expect.assertions(1)
try {
await findNames("parseltongue.d.ts", undefined, {
expect(() => findNames("parseltongue.d.ts", undefined, {
nonNpm: false,

@@ -101,9 +97,9 @@ libraryName: "a",

projects: ["welcome-to-zombo.com", "this-is-zombo.com"]
})
}
catch (e) {
expect(e.message).toEqual(`d.ts file must have a matching npm package.
})).toThrow(
`d.ts file must have a matching npm package.
To resolve this error, either:
Add a Definitely Typed header with the first line
1. Change the name to match an npm package.
2. Add a Definitely Typed header with the first line
// Type definitions for non-npm package parseltongue-browser

@@ -115,10 +111,8 @@

Explicitly provide dts-critic with a source file. This is not allowed for submission to Definitely Typed.`)
}
3. Explicitly provide dts-critic with a source file. This is not allowed for submission to Definitely Typed.
`)
},
async mismatchPackageFailNonNpmHeader() {
mismatchPackageFailNonNpmHeader() {
// surely parseltongue will never exist
expect.assertions(1)
try {
await findNames("jquery.d.ts", undefined, {
expect(() => findNames("jquery.d.ts", undefined, {
nonNpm: true,

@@ -131,36 +125,28 @@ libraryName: "a",

projects: ["welcome-to-zombo.com", "this-is-zombo.com"]
})
}
catch (e) {
expect(e.message).toEqual(`Non-npm packages must not use names that conflict with existing npm packages.
})).toThrow(
`The non-npm package 'jquery' conflicts with the existing npm package 'jquery'.
Try adding -browser to the end of the name to get
jquery-browser`)
}
jquery-browser
`)
}
})
suite("retrieveNpmHomepageOrFail", {
async retrieveFailure() {
expect.assertions(1)
try {
// surely parseltongue will never exist
await retrieveNpmHomepageOrFail("parseltongue")
}
catch (e) {
expect(e.message).toEqual(`404 - "{\\"error\\":\\"Not found\\"}"`)
}
retrieveFailure() {
// surely parseltongue will never exist
expect(() => retrieveNpmHomepageOrFail("parseltongue")).toThrow(`parseltongue Not found`);
},
async retrieveShelljs() {
expect(await retrieveNpmHomepageOrFail("shelljs")).toBe("http://github.com/shelljs/shelljs")
retrieveShelljs() {
expect(retrieveNpmHomepageOrFail("shelljs")).toBe("http://github.com/shelljs/shelljs")
}
})
suite("check", {
suite("checkNames", {
standaloneFail() {
expect(() => check({ dts: "a", src: "b" }, undefined)).toThrow("d.ts name 'a' must match source name 'b'.")
expect(() => checkNames({ dts: "a", src: "b" }, undefined)).toThrow("d.ts name 'a' must match source name 'b'.")
},
okWithJustHomepage() {
expect(check({ dts: "a", src: "a", homepage: "zombo.com" }, undefined)).toBeUndefined()
expect(checkNames({ dts: "a", src: "a", homepage: "zombo.com" }, undefined)).toBeUndefined()
},
okWithJustHeader() {
expect(check({ dts: "a", src: "a" }, {
expect(checkNames({ dts: "a", src: "a" }, {
nonNpm: false,

@@ -176,3 +162,3 @@ libraryName: "a",

homepageFail() {
expect(() => check({ dts: "a", src: "a", homepage: "zombo.com" }, {
expect(() => checkNames({ dts: "a", src: "a", homepage: "zombo.com" }, {
nonNpm: false,

@@ -186,8 +172,18 @@ libraryName: "a",

})).toThrow(`At least one of the project urls listed in the header, ["welcome-to-zombo.com","this-is-zombo.com"], must match the homepage listed by npm, 'zombo.com'.
If your d.ts file is not for the npm package with zombo.com,
If your d.ts file is not for the npm package with URL zombo.com,
change the name by adding -browser to the end and change the first line
of the Definitely Typed header to
// Type definitions for npn-npm package a-browser`)
// Type definitions for non-npm package a-browser`)
}
});
suite("checkSource", {
badExportDefault() {
expect(() => checkSource(
"foo",
`function f() {}; export default f;`,
`module.exports = function () {};`)).toThrow(
"The types for foo specify 'export default' but the source does not mention 'default' anywhere.");
},
});
{
"name": "dts-critic",
"version": "1.0.3",
"version": "1.0.4",
"author": "Nathan Shively-Sanders",
"description": "Checks a new .d.ts against the Javascript source and tells you what problems it has",
"dependencies": {
"definitelytyped-header-parser": "^1.0.0",
"request-promise-native": "^1.0.5",
"definitelytyped-header-parser": "^1.0.1",
"download-file-sync": "^1.0.4",
"yargs": "^12.0.5"

@@ -36,3 +36,2 @@ },

"@types/node": "^10.12.21",
"@types/request-promise-native": "^1.0.15",
"@types/strip-json-comments": "0.0.30",

@@ -39,0 +38,0 @@ "@types/yargs": "^12.0.8",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc