From 72c6eccc465ab2a8fb98228ddbac4e1319037c09 Mon Sep 17 00:00:00 2001 From: camilne Date: Wed, 9 Jan 2019 16:17:02 -0700 Subject: [PATCH 1/4] Add getter/setter gen from private ctor params --- src/getset.ts | 18 ++++++++++++++-- src/regexutil.ts | 29 ++++++++++++++++++++++++++ test/regexutil.test.ts | 47 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/regexutil.ts create mode 100644 test/regexutil.test.ts diff --git a/src/getset.ts b/src/getset.ts index a910318..feaade8 100644 --- a/src/getset.ts +++ b/src/getset.ts @@ -1,5 +1,7 @@ import * as vscode from 'vscode'; +import { findCtorPrivateParams } from './regexutil'; + export enum EType { GETTER, SETTER, BOTH, CONSTRUCTOR } @@ -130,11 +132,12 @@ export function generateClassesList(type: EType): IClass[] { let _class = getClass(classes, brackets.name); const matches = { privateDef: line.text.match(matchers.privateDef), + ctorMatches: findCtorPrivateParams(line.text), getMethod: line.text.match(matchers.getMethod), setMethod: line.text.match(matchers.setMethod) }; if (_class && - (matches.getMethod || matches.privateDef || matches.setMethod)) { + (matches.getMethod || matches.privateDef || matches.setMethod || matches.ctorMatches)) { // push the found items into the approriate containers if (matches.privateDef) { _class.vars.push({ @@ -143,6 +146,16 @@ export function generateClassesList(type: EType): IClass[] { typeName: matches.privateDef[2] }); } + // add the private constructor parameters + if (matches.ctorMatches.length !== 0) { + for (const match of matches.ctorMatches) { + _class.vars.push({ + name: match[2], + figure: publicName(match[2]), + typeName: match[3] + }); + } + } if (matches.getMethod) _class.getters.push(matches.getMethod[1]); if (matches.setMethod) _class.setters.push(matches.setMethod[1]); } @@ -172,7 +185,8 @@ export function generateClassesList(type: EType): IClass[] { break; } } - } else if (type == EType.SETTER || type == EType.BOTH) { + } + if (type == EType.SETTER || type == EType.BOTH) { for (let j = 0; j < _class.setters.length; j++) { if (_class.vars[i].figure.toLowerCase() === _class.setters[j].toLowerCase()) { _class.vars.splice(i, 1); diff --git a/src/regexutil.ts b/src/regexutil.ts new file mode 100644 index 0000000..1426571 --- /dev/null +++ b/src/regexutil.ts @@ -0,0 +1,29 @@ +const matchers = { + ctorDef: /\s*constructor\(\s*([^)]+?)\s*\)/, + ctorParam: /(?:public)?(private)?\s*([a-zA-Z_$][\w$]*)\s*:\s*([^\s,]+),?\s*/y, +}; + +/** + * Finds private constructor parameters and returns them as {@link RegExpMatchArray[]}. + * The groups of the returned matches is: + * 0: full match + * 1: private + * 2: name + * 3: type + * @param line The line of text in which to try to find private constructor parameters. + */ +export function findCtorPrivateParams(line: string): RegExpMatchArray[] { + const params: RegExpMatchArray[] = []; + let ctor: RegExpMatchArray; + // First match the constructor, then match each param + if (ctor = line.match(matchers.ctorDef)) { + let param: RegExpMatchArray; + while (param = ctor[1].match(matchers.ctorParam)) { + // Check if the param is private + if (param[1]) { + params.push(param); + } + } + } + return params; +} \ No newline at end of file diff --git a/test/regexutil.test.ts b/test/regexutil.test.ts new file mode 100644 index 0000000..5dfb9aa --- /dev/null +++ b/test/regexutil.test.ts @@ -0,0 +1,47 @@ +import * as assert from 'assert'; + +import * as regexutil from '../src/regexutil'; + +suite("Regex Util Constructor Tests", () => { + + test("Does match private params in constructor", () => { + const matches = regexutil.findCtorPrivateParams("constructor(private _name: string, private _age: number, _gender: string)"); + assert.equal(2, matches.length); + assert.equal("_name", matches[0][2]); + assert.equal("string", matches[0][3]); + assert.equal("_age", matches[1][2]); + assert.equal("number", matches[1][3]); + }); + + test("Does ignore public and default params", () => { + const matches = regexutil.findCtorPrivateParams("constructor(public _name: string, private _age: number, _gender: string)"); + assert.equal(1, matches.length); + assert.equal("_age", matches[0][2]); + assert.equal("number", matches[0][3]); + }); + + test("Does match private params after public and default params", () => { + const matches = regexutil.findCtorPrivateParams("constructor(public test: boolean, private _name: string, _gender: string, private _age: number)"); + assert.equal(2, matches.length); + assert.equal("_name", matches[0][2]); + assert.equal("string", matches[0][3]); + assert.equal("_age", matches[1][2]); + assert.equal("number", matches[1][3]); + }); + + test("Does not match if not constructor", () => { + const matches = regexutil.findCtorPrivateParams("myMethod(private _name: string, private _age: number)"); + assert.equal(0, matches.length); + }); + + test("Can match zero private params in constructor", () => { + const matches = regexutil.findCtorPrivateParams("constructor(name: string, age: number)"); + assert.equal(0, matches.length); + }); + + test("Does not match if empty constructor", () => { + const matches = regexutil.findCtorPrivateParams("constructor()"); + assert.equal(0, matches.length); + }); + +}); \ No newline at end of file From 3fea12733a4fc3f1ceae03c7c4fb3c5861524d09 Mon Sep 17 00:00:00 2001 From: camilne Date: Wed, 9 Jan 2019 17:07:43 -0700 Subject: [PATCH 2/4] Fix constructor get/set gen for generics with more than one type --- src/getset.ts | 15 ++++++++------- src/regexutil.ts | 15 +++++++++++---- src/variable.ts | 21 +++++++++++++++++++++ test/regexutil.test.ts | 29 +++++++++++++++++++---------- 4 files changed, 59 insertions(+), 21 deletions(-) create mode 100644 src/variable.ts diff --git a/src/getset.ts b/src/getset.ts index feaade8..f6fc25a 100644 --- a/src/getset.ts +++ b/src/getset.ts @@ -1,5 +1,6 @@ import * as vscode from 'vscode'; +import { Variable } from './variable'; import { findCtorPrivateParams } from './regexutil'; export enum EType { @@ -132,12 +133,12 @@ export function generateClassesList(type: EType): IClass[] { let _class = getClass(classes, brackets.name); const matches = { privateDef: line.text.match(matchers.privateDef), - ctorMatches: findCtorPrivateParams(line.text), + ctorParams: findCtorPrivateParams(line.text), getMethod: line.text.match(matchers.getMethod), setMethod: line.text.match(matchers.setMethod) }; if (_class && - (matches.getMethod || matches.privateDef || matches.setMethod || matches.ctorMatches)) { + (matches.getMethod || matches.privateDef || matches.setMethod || matches.ctorParams)) { // push the found items into the approriate containers if (matches.privateDef) { _class.vars.push({ @@ -147,12 +148,12 @@ export function generateClassesList(type: EType): IClass[] { }); } // add the private constructor parameters - if (matches.ctorMatches.length !== 0) { - for (const match of matches.ctorMatches) { + if (matches.ctorParams.length !== 0) { + for (const param of matches.ctorParams) { _class.vars.push({ - name: match[2], - figure: publicName(match[2]), - typeName: match[3] + name: param.name, + figure: publicName(param.name), + typeName: param.type }); } } diff --git a/src/regexutil.ts b/src/regexutil.ts index 1426571..e8a5ab8 100644 --- a/src/regexutil.ts +++ b/src/regexutil.ts @@ -1,6 +1,8 @@ +import { Variable } from './variable'; + const matchers = { ctorDef: /\s*constructor\(\s*([^)]+?)\s*\)/, - ctorParam: /(?:public)?(private)?\s*([a-zA-Z_$][\w$]*)\s*:\s*([^\s,]+),?\s*/y, + ctorParam: /(?:public)?(private)?\s*([a-zA-Z_$][\w$]+)\s*:\s*((?:[\.<\w$\s]+[,>])+|[\.\w$\s]+),?\s*/y, }; /** @@ -12,8 +14,8 @@ const matchers = { * 3: type * @param line The line of text in which to try to find private constructor parameters. */ -export function findCtorPrivateParams(line: string): RegExpMatchArray[] { - const params: RegExpMatchArray[] = []; +export function findCtorPrivateParams(line: string): Variable[] { + const params: Variable[] = []; let ctor: RegExpMatchArray; // First match the constructor, then match each param if (ctor = line.match(matchers.ctorDef)) { @@ -21,7 +23,12 @@ export function findCtorPrivateParams(line: string): RegExpMatchArray[] { while (param = ctor[1].match(matchers.ctorParam)) { // Check if the param is private if (param[1]) { - params.push(param); + // The regex is not great and leaves a trailing comma on non-generic types + let type = param[3]; + if (type.endsWith(',')) { + type = type.substr(0, type.length - 1); + } + params.push(new Variable(param[2], type)); } } } diff --git a/src/variable.ts b/src/variable.ts new file mode 100644 index 0000000..d8bc8d9 --- /dev/null +++ b/src/variable.ts @@ -0,0 +1,21 @@ +export class Variable { + constructor(private _name: string, private _type: string) { + + } + + public get name(): string { + return this._name; + } + + public set name(value: string) { + this._name = value; + } + + public get type(): string { + return this._type; + } + + public set type(value: string) { + this._type = value; + } +} \ No newline at end of file diff --git a/test/regexutil.test.ts b/test/regexutil.test.ts index 5dfb9aa..e13879b 100644 --- a/test/regexutil.test.ts +++ b/test/regexutil.test.ts @@ -7,26 +7,35 @@ suite("Regex Util Constructor Tests", () => { test("Does match private params in constructor", () => { const matches = regexutil.findCtorPrivateParams("constructor(private _name: string, private _age: number, _gender: string)"); assert.equal(2, matches.length); - assert.equal("_name", matches[0][2]); - assert.equal("string", matches[0][3]); - assert.equal("_age", matches[1][2]); - assert.equal("number", matches[1][3]); + assert.equal("_name", matches[0].name); + assert.equal("string", matches[0].type); + assert.equal("_age", matches[1].name); + assert.equal("number", matches[1].type); }); test("Does ignore public and default params", () => { const matches = regexutil.findCtorPrivateParams("constructor(public _name: string, private _age: number, _gender: string)"); assert.equal(1, matches.length); - assert.equal("_age", matches[0][2]); - assert.equal("number", matches[0][3]); + assert.equal("_age", matches[0].name); + assert.equal("number", matches[0].type); }); test("Does match private params after public and default params", () => { const matches = regexutil.findCtorPrivateParams("constructor(public test: boolean, private _name: string, _gender: string, private _age: number)"); assert.equal(2, matches.length); - assert.equal("_name", matches[0][2]); - assert.equal("string", matches[0][3]); - assert.equal("_age", matches[1][2]); - assert.equal("number", matches[1][3]); + assert.equal("_name", matches[0].name); + assert.equal("string", matches[0].type); + assert.equal("_age", matches[1].name); + assert.equal("number", matches[1].type); + }); + + test("Can match generic types with more than one argument", () => { + const matches = regexutil.findCtorPrivateParams("constructor(private _test1: Type, private _test2: Int)"); + assert.equal(2, matches.length); + assert.equal("_test1", matches[0].name); + assert.equal("Type", matches[0].type); + assert.equal("_test2", matches[1].name); + assert.equal("Int", matches[1].type); }); test("Does not match if not constructor", () => { From bc20c5bc1a1e223478b88ea2f14a618951d22b60 Mon Sep 17 00:00:00 2001 From: camilne Date: Wed, 9 Jan 2019 17:35:13 -0700 Subject: [PATCH 3/4] Fix constructor get/set gen for params with default value --- src/regexutil.ts | 16 +++------------- test/regexutil.test.ts | 9 +++++++++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/regexutil.ts b/src/regexutil.ts index e8a5ab8..4d998a1 100644 --- a/src/regexutil.ts +++ b/src/regexutil.ts @@ -2,16 +2,11 @@ import { Variable } from './variable'; const matchers = { ctorDef: /\s*constructor\(\s*([^)]+?)\s*\)/, - ctorParam: /(?:public)?(private)?\s*([a-zA-Z_$][\w$]+)\s*:\s*((?:[\.<\w$\s]+[,>])+|[\.\w$\s]+),?\s*/y, + ctorParam: /(?:public)?(private)?\s*([a-zA-Z_$][\w$]+)\s*\??:\s*([\.\w$]+<(?:[\.\w$\s]+,?)+>|[\.\[\]\w$]+)[^,]*,?\s*/y, }; /** - * Finds private constructor parameters and returns them as {@link RegExpMatchArray[]}. - * The groups of the returned matches is: - * 0: full match - * 1: private - * 2: name - * 3: type + * Finds private constructor parameters and returns them as {@link Variable[]}. * @param line The line of text in which to try to find private constructor parameters. */ export function findCtorPrivateParams(line: string): Variable[] { @@ -23,12 +18,7 @@ export function findCtorPrivateParams(line: string): Variable[] { while (param = ctor[1].match(matchers.ctorParam)) { // Check if the param is private if (param[1]) { - // The regex is not great and leaves a trailing comma on non-generic types - let type = param[3]; - if (type.endsWith(',')) { - type = type.substr(0, type.length - 1); - } - params.push(new Variable(param[2], type)); + params.push(new Variable(param[2], param[3])); } } } diff --git a/test/regexutil.test.ts b/test/regexutil.test.ts index e13879b..72ea7c7 100644 --- a/test/regexutil.test.ts +++ b/test/regexutil.test.ts @@ -38,6 +38,15 @@ suite("Regex Util Constructor Tests", () => { assert.equal("Int", matches[1].type); }); + test("Can match params with default value", () => { + const matches = regexutil.findCtorPrivateParams("constructor(private _test1: string = \"test1\", variable: string = 'abc', private _test2: number = 7)"); + assert.equal(2, matches.length); + assert.equal("_test1", matches[0].name); + assert.equal("string", matches[0].type); + assert.equal("_test2", matches[1].name); + assert.equal("number", matches[1].type); + }); + test("Does not match if not constructor", () => { const matches = regexutil.findCtorPrivateParams("myMethod(private _name: string, private _age: number)"); assert.equal(0, matches.length); From b027754fba0ec7f8f5dd802c31bfbc1f83bab6e7 Mon Sep 17 00:00:00 2001 From: camilne Date: Wed, 9 Jan 2019 17:40:41 -0700 Subject: [PATCH 4/4] Fix recognizing generic parameters with array type variable --- src/regexutil.ts | 2 +- test/regexutil.test.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/regexutil.ts b/src/regexutil.ts index 4d998a1..13085d5 100644 --- a/src/regexutil.ts +++ b/src/regexutil.ts @@ -2,7 +2,7 @@ import { Variable } from './variable'; const matchers = { ctorDef: /\s*constructor\(\s*([^)]+?)\s*\)/, - ctorParam: /(?:public)?(private)?\s*([a-zA-Z_$][\w$]+)\s*\??:\s*([\.\w$]+<(?:[\.\w$\s]+,?)+>|[\.\[\]\w$]+)[^,]*,?\s*/y, + ctorParam: /(?:public)?(private)?\s*([a-zA-Z_$][\w$]+)\s*\??:\s*([\.\w$]+<(?:[\.\[\]\w$\s]+,?)+>|[\.\[\]\w$]+)[^,]*,?\s*/y, }; /** diff --git a/test/regexutil.test.ts b/test/regexutil.test.ts index 72ea7c7..2d8e60a 100644 --- a/test/regexutil.test.ts +++ b/test/regexutil.test.ts @@ -30,12 +30,12 @@ suite("Regex Util Constructor Tests", () => { }); test("Can match generic types with more than one argument", () => { - const matches = regexutil.findCtorPrivateParams("constructor(private _test1: Type, private _test2: Int)"); + const matches = regexutil.findCtorPrivateParams("constructor(private _test1: Type, private _test2: Int)"); assert.equal(2, matches.length); assert.equal("_test1", matches[0].name); assert.equal("Type", matches[0].type); assert.equal("_test2", matches[1].name); - assert.equal("Int", matches[1].type); + assert.equal("Int", matches[1].type); }); test("Can match params with default value", () => {