Skip to content

Commit

Permalink
Merge b4ba327 into d780dc5
Browse files Browse the repository at this point in the history
  • Loading branch information
ktutnik committed Dec 28, 2022
2 parents d780dc5 + b4ba327 commit 9f957fc
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 14 deletions.
37 changes: 23 additions & 14 deletions packages/reflect/src/parser.ts
Expand Up @@ -58,37 +58,46 @@ function getNamesFromAst(nodes: any[]) {
return nodes.map(x => getName(x)).filter((x): x is RootNode => !!x)
}

function getCode(fn: Class | Function) {
const syntaxReplacement = [
{ pattern: /^class(\s*)extends\s*BaseClass\s*{\s*}/gm, replacement: "class DynamicClass extends Parent {}" },
{ pattern: /^class(\s*){\s*}/gm, replacement: "class DynamicClass {}" },
]
function refineCode(fn: Class | Function, functionOnly = false) {
// some code may detected as invalid code, so its need to be fixed before parsed by acorn
const code = fn.toString()
const exclude = syntaxReplacement.find(x => code.search(x.pattern) > -1)
if (exclude) {
return exclude.replacement
}
else
return code.replace("[native code]", "")

// for class created dynamically using reflect.create()
if(code.search(/^class(\s*)extends\s*BaseClass\s*{\s*}/gm) > -1)
return "class DynamicClass extends Parent {}"

// for class created using reflect.class() but without base class
if(code.search(/^class(\s*){\s*}/gm) > -1)
return "class DynamicClass {}"

// in case function inside object, it will cause error
// example
// const obj = { fn(par1) {} }
// reflect(obj.fn)
if(functionOnly && code.search(/^([A-z0-9]+)\s*\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\)/gm) > -1)
return `function ${code}`;

// for the rest code, sometime its contain [native code], just remove it
return code.replace("[native code]", "")
}

function getMethodParameters(fn: Class, method: string) {
const body = getCode(fn)
const body = refineCode(fn)
const ast = parse(body, { ecmaVersion: 2020 })
const ctor = getNode(ast, x => x.type === "MethodDefinition" && x.kind === "method" && x.key.name === method)
return getNamesFromAst(ctor ? (ctor as any).value.params : [])
}

function getConstructorParameters(fn: Class) {
const body = getCode(fn)
const body = refineCode(fn)
const ast = parse(body, { ecmaVersion: 2020 })
const ctor = getNode(ast, x => x.type === "MethodDefinition" && x.kind === "constructor")
return getNamesFromAst(ctor ? (ctor as any).value.params : [])
}

function getFunctionParameters(fn: Function) {
try {
const body = getCode(fn)
const body = refineCode(fn, true)
const ast: any = parse(body, { ecmaVersion: 2020 })
const expBody = ast.body[0]
if (expBody.type === "FunctionDeclaration")
Expand Down
19 changes: 19 additions & 0 deletions tests/behavior/reflect/__snapshots__/function.spec.ts.snap
Expand Up @@ -22,6 +22,25 @@ Object {
}
`;

exports[`Reflect function Should able to reflect function inside object 1`] = `
Object {
"kind": "Function",
"name": "fn",
"parameters": Array [
Object {
"decorators": Array [],
"fields": "par1",
"index": 0,
"kind": "Parameter",
"name": "par1",
"type": undefined,
"typeClassification": undefined,
},
],
"returnType": undefined,
}
`;

exports[`Reflect function Should able to reflect function parameter names 1`] = `
Object {
"kind": "Function",
Expand Down
9 changes: 9 additions & 0 deletions tests/behavior/reflect/function.spec.ts
Expand Up @@ -26,6 +26,14 @@ describe("Reflect function", () => {
const meta = reflect(myFunction)
expect(meta).toMatchSnapshot()
})

it("Should able to reflect function inside object", () => {
const obj = {
fn(par1:string) {}
}
const meta = reflect(obj.fn)
expect(meta).toMatchSnapshot()
})
})

describe("Reflect lambda function", () => {
Expand Down Expand Up @@ -53,4 +61,5 @@ describe("Reflect lambda function", () => {
const meta = reflect(myFunction)
expect(meta).toMatchSnapshot()
})

})

0 comments on commit 9f957fc

Please sign in to comment.