could-be-class
Advanced tools
Comparing version 0.1.4 to 0.2.0
/** | ||
* Checks if an object could be an instantiable class. | ||
* @param strict If `true`, when testing ES5 class, will check if its name's | ||
* first character is upper-cased. | ||
*/ | ||
export function isClass(obj: any, strict?: boolean): boolean; | ||
export function isClass(obj: any): obj is new (...args: any[]) => any; | ||
export default isClass; |
57
index.js
@@ -0,33 +1,50 @@ | ||
"use strict"; | ||
/** | ||
* Checks if an object could be an instantiable class. | ||
* @param {any} obj | ||
* @param {boolean} strict | ||
* @returns {boolean} | ||
* @returns {obj is new (...args: any[]) => any} | ||
*/ | ||
function couldBeClass(obj, strict) { | ||
function couldBeClass(obj) { | ||
if (typeof obj != "function") return false; | ||
var str = obj.toString(); | ||
// async function or arrow function | ||
if (obj.prototype === undefined) return false; | ||
// generator function and malformed extends | ||
if (obj.prototype.constructor !== obj) return false; | ||
// ES6 class | ||
if (str.slice(0, 5) == "class") return true; | ||
if (obj.prototype === undefined) | ||
return false; | ||
// generator function and malformed inheritance | ||
if (obj.prototype.constructor !== obj) | ||
return false; | ||
// has own prototype properties | ||
if (Object.getOwnPropertyNames(obj.prototype).length >= 2) return true; | ||
if (Object.getOwnPropertyNames(obj.prototype).length >= 2) | ||
return true; | ||
var str = String(obj); | ||
// ES6 class | ||
if (str.slice(0, 5) == "class") | ||
return true; | ||
// anonymous function | ||
if (/^function\s+\(|^function\s+anonymous\(/.test(str)) return false; | ||
// ES5 class without `this` in the body and the name's first character | ||
// upper-cased. | ||
if (strict && /^function\s+[A-Z]/.test(str)) return true; | ||
// has `this` in the body | ||
if (/\b\(this\b|\bthis[\.\[]\b/.test(str)) { | ||
// not strict or ES5 class generated by babel | ||
if (!strict || /classCallCheck\(this/.test(str)) return true; | ||
if (/^function\s*\(|^function anonymous\(/.test(str)) | ||
return false; | ||
return /^function\sdefault_\d+\s*\(/.test(str); | ||
var hasThis = /(call|apply|_classCallCheck)\(this(, arguments)?\)|\bthis(.\S+|\[.+?\])\s*(=|\()|=\s*this[,;]/.test(str); | ||
// Upper-cased first char of the name and has `this` in the body, or it's | ||
// a native class in ES5 style. | ||
if (/^function\s+[A-Z]/.test(str) && (hasThis || | ||
(/\[native code\]/.test(str) && | ||
obj.name !== "BigInt" && // ES6 BigInt and Symbol is not class | ||
obj.name !== "Symbol" | ||
) | ||
)) { | ||
return true; | ||
} | ||
// TypeScript anonymous class to ES5 with default export | ||
if (hasThis && obj.name === "default_1") | ||
return true; | ||
return false; | ||
@@ -34,0 +51,0 @@ } |
{ | ||
"name": "could-be-class", | ||
"version": "0.1.4", | ||
"version": "0.2.0", | ||
"description": "Checks if an object could be an instantiable class.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -57,11 +57,6 @@ # couldBeClass | ||
function IsClass() { | ||
console.log("this is a class"); | ||
} | ||
assert.ok(couldBeClass(IsClass, true)); // strict mode | ||
function aMethod() { | ||
this.desc = "this is a method instead of a class"; | ||
} | ||
assert.ok(!couldBeClass(aMethod, true)); // strict mode | ||
assert.ok(!couldBeClass(aMethod)); | ||
@@ -72,3 +67,2 @@ function default_1() { | ||
assert.ok(couldBeClass(default_1)); | ||
assert.ok(couldBeClass(default_1, true)); // even in strict mode | ||
@@ -79,3 +73,2 @@ function default_2() { | ||
assert.ok(!couldBeClass(default_2)); | ||
assert.ok(!couldBeClass(default_2, true)); // even in strict mode | ||
@@ -106,9 +99,3 @@ function* GenFunc() { | ||
**Strict Mode**, you can pass the second argument `strict: boolean` to the | ||
function, if it is `true`, when testing ES5 class, will check if its name's | ||
first character is upper-cased, which is the common and recommended way to | ||
define a class. It always better to use the `strict` mode and code your classes | ||
in the recommended way. | ||
**WARN** This module only performs about 98% percent of accuracy when testing | ||
ES5 class. |
25
test.js
@@ -26,3 +26,3 @@ "use strict"; | ||
function D() { } | ||
D.prototype.show = function () { } | ||
D.prototype.show = function () { }; | ||
assert.ok(couldBeClass(D)); | ||
@@ -59,12 +59,23 @@ | ||
function aMethod() { | ||
this.desc = "this is a method instead of a class"; | ||
} | ||
assert.ok(!couldBeClass(aMethod)); | ||
function NotClass2() { | ||
// this. is nor a class. | ||
} | ||
assert.ok(!couldBeClass(NotClass2)); | ||
function IsClass() { | ||
console.log("this is a class"); | ||
this.doSomething(); | ||
} | ||
assert.ok(couldBeClass(IsClass, true)); // strict mode | ||
assert.ok(couldBeClass(IsClass)); | ||
function aMethod() { | ||
this.desc = "this is a method instead of a class"; | ||
function IsClass2() { | ||
this.doSomething = () => {}; | ||
} | ||
assert.ok(!couldBeClass(aMethod, true)); // strict mode | ||
assert.ok(couldBeClass(IsClass2)); | ||
function default_1() { | ||
@@ -74,3 +85,2 @@ this.dec = "this might be a class generated by typescript"; | ||
assert.ok(couldBeClass(default_1)); | ||
assert.ok(couldBeClass(default_1, true)); // even in strict mode | ||
@@ -81,3 +91,2 @@ function default_2() { | ||
assert.ok(!couldBeClass(default_2)); | ||
assert.ok(!couldBeClass(default_2, true)); // even in strict mode | ||
@@ -84,0 +93,0 @@ function* GenFunc() { |
Sorry, the diff of this file is not supported yet
136
8439
97