This repository has been archived by the owner on Dec 12, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
282 additions
and
200 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,129 @@ | ||
import { parse, Node } from "acorn" | ||
import { Class, DECORATOR_KEY, Decorator, DecoratorIterator, DecoratorTargetType, ParamDecorator, DecoratorOption, ArrayDecorator, TypeDecorator, PrivateDecorator } from "./types" | ||
import { Node, parse } from "acorn" | ||
import { ArrayDecorator, Class, Decorator, DECORATOR_KEY, TypeDecorator } from "./types" | ||
|
||
|
||
/* ---------------------------------------------------------------- */ | ||
/* --------------------------- HELPERS ---------------------------- */ | ||
/* ---------------------------------------------------------------- */ | ||
|
||
function useCache<K, P extends any[], R>(cache: Map<K, R>, fn: (...args: P) => R, getKey: (...args: P) => K) { | ||
return (...args: P) => { | ||
const key = getKey(...args) | ||
const result = cache.get(key) | ||
if (!!result) return result | ||
else { | ||
const newResult = fn(...args) | ||
cache.set(key, newResult) | ||
return newResult | ||
} | ||
} | ||
} | ||
|
||
namespace metadata { | ||
|
||
function isConstructor(value: Function) { | ||
return ("" + value).indexOf("class") == 0 | ||
} | ||
function getNode(node: Node, criteria: (x: any) => boolean): Node | undefined { | ||
if (criteria(node)) return node | ||
if (!(node as any).body) return | ||
if (Array.isArray((node as any).body)) { | ||
for (const child of (node as any).body) { | ||
const result = getNode(child, criteria) | ||
if (result) return result | ||
} | ||
} | ||
return getNode((node as any).body, criteria) | ||
} | ||
|
||
function getNamesFromAst(nodes: any[]) { | ||
const getName = (node: any): undefined | string | { [key: string]: string[] } => { | ||
if (node.type === "Identifier") return node.name | ||
if (node.type === "AssignmentPattern") return node.left.name | ||
if (node.type === "RestElement") return node.argument.name | ||
if (node.type === "Property") { | ||
if (node.value.type === "Identifier") return node.value.name | ||
else { | ||
const result: { [key: string]: any } = {} | ||
result[node.key.name] = getName(node.value) | ||
return result | ||
} | ||
} | ||
//if (node.type === "ObjectPattern") { | ||
return node.properties.map((x: any) => getName(x)) | ||
//} | ||
} | ||
return nodes.map(x => getName(x)).filter((x): x is string | { [key: string]: string[] } => !!x) | ||
} | ||
|
||
function isCustomClass(type: Function | Function[]) { | ||
switch (type) { | ||
case Boolean: | ||
case String: | ||
case Array: | ||
case Number: | ||
case Object: | ||
case Date: | ||
return false | ||
default: | ||
return true | ||
export function getMethodParameters(fn: Class, method: string) { | ||
const body = fn.toString() | ||
const ast = parse(body) | ||
const ctor = getNode(ast, x => x.type === "MethodDefinition" && x.kind === "method" && x.key.name === method) | ||
return getNamesFromAst(ctor ? (ctor as any).value.params : []) | ||
} | ||
} | ||
|
||
export function getConstructorParameters(fn: Class) { | ||
const body = fn.toString() | ||
const ast = parse(body) | ||
const ctor = getNode(ast, x => x.type === "MethodDefinition" && x.kind === "constructor") | ||
return getNamesFromAst(ctor ? (ctor as any).value.params : []) | ||
} | ||
|
||
export function getParameterNames(fn: Function) { | ||
try { | ||
const body = fn.toString() | ||
const ast = parse(body) | ||
return getNamesFromAst((ast as any).body[0].params) | ||
} | ||
catch { | ||
return [] | ||
} | ||
} | ||
|
||
function addDecorator<T extends Decorator>(target: any, decorator: T) { | ||
const decorators: Decorator[] = Reflect.getOwnMetadata(DECORATOR_KEY, target) || [] | ||
decorators.push(decorator) | ||
Reflect.defineMetadata(DECORATOR_KEY, decorators, target) | ||
} | ||
export function getClassMembers(fun: Function) { | ||
const isGetter = (name: string) => Object.getOwnPropertyDescriptor(fun.prototype, name)!.get | ||
const isSetter = (name: string) => Object.getOwnPropertyDescriptor(fun.prototype, name)!.set | ||
const isFunction = (name: string) => typeof fun.prototype[name] === "function"; | ||
const members = Object.getOwnPropertyNames(fun.prototype) | ||
.filter(name => isGetter(name) || isSetter(name) || isFunction(name)) | ||
const properties = (Reflect.getOwnMetadata(DECORATOR_KEY, fun) || []) | ||
.filter((x: Decorator) => x.targetType === "Property") | ||
.map((x: Decorator) => x.target) | ||
const names = members.concat(properties) | ||
.filter(name => name !== "constructor" && !~name.indexOf("__")) | ||
return [...new Set(names)] | ||
} | ||
|
||
export function getType(decorators: any[], type: any) { | ||
const array = decorators.find((x: ArrayDecorator): x is ArrayDecorator => x.kind === "Array") | ||
const override = decorators.find((x: TypeDecorator): x is TypeDecorator => x.kind === "Override") | ||
if (override) | ||
return override.type | ||
else if (array) | ||
return [array.type] | ||
else if (type === Array) | ||
return [Object] | ||
else | ||
return type | ||
} | ||
|
||
export function isConstructor(value: Function) { | ||
return ("" + value).indexOf("class") == 0 | ||
} | ||
|
||
function useCache<K, P extends any[], R>(cache: Map<K, R>, fn: (...args: P) => R, getKey: (...args: P) => K) { | ||
return (...args: P) => { | ||
const key = getKey(...args) | ||
const result = cache.get(key) | ||
if (!!result) return result | ||
else { | ||
const newResult = fn(...args) | ||
cache.set(key, newResult) | ||
return newResult | ||
export function isCustomClass(type: Function | Function[]) { | ||
switch (type) { | ||
case Boolean: | ||
case String: | ||
case Array: | ||
case Number: | ||
case Object: | ||
case Date: | ||
return false | ||
default: | ||
return true | ||
} | ||
} | ||
} | ||
|
||
|
||
|
||
export { isConstructor, addDecorator, isCustomClass, useCache } | ||
export { useCache, metadata } |
Oops, something went wrong.