From e550f7c7c55e1e678803171a50548be572fb890d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BChler?= Date: Tue, 31 Jul 2018 07:55:47 +0200 Subject: [PATCH] feat: add isOptional to methods as well (#84) Add tests for isOptional properties and methods (#80) and the same flag to methods. --- jest.json | 1 + .../propertyDeclaration.ts | 2 +- src/declarations/Declaration.ts | 17 ++ src/declarations/MethodDeclaration.ts | 17 +- src/declarations/PropertyDeclaration.ts | 6 +- src/node-parser/class-parser.ts | 1 + src/node-parser/interface-parser.ts | 1 + test/TypescriptParser.spec.ts | 22 ++- .../TypescriptParser.spec.ts.snap | 153 +++++++++++++++++- test/_workspace/typescript-parser/class.ts | 6 + .../_workspace/typescript-parser/interface.ts | 14 ++ .../DeclarationIndex.spec.ts.snap | 26 +++ ...dex-with-global-module-export.spec.ts.snap | 1 + 13 files changed, 251 insertions(+), 16 deletions(-) diff --git a/jest.json b/jest.json index 6cda8fa..ca4916a 100644 --- a/jest.json +++ b/jest.json @@ -3,6 +3,7 @@ "transform": { "^.+\\.tsx?$": "/node_modules/ts-jest/preprocessor.js" }, + "testURL": "http://localhost/", "testMatch": [ "**/test/**/*.spec.ts" ], diff --git a/src/code-generators/typescript-generators/propertyDeclaration.ts b/src/code-generators/typescript-generators/propertyDeclaration.ts index 2e1e4f1..8a847c4 100644 --- a/src/code-generators/typescript-generators/propertyDeclaration.ts +++ b/src/code-generators/typescript-generators/propertyDeclaration.ts @@ -16,5 +16,5 @@ export function generatePropertyDeclaration( ): string { return `${Array(tabSize + 1).join(' ')}` + `${property.visibility !== undefined ? getVisibilityText(property.visibility) + ' ' : ''}` + - `${property.name}${property.optional ? '?' : ''}${property.type ? `: ${property.type}` : ''};\n`; + `${property.name}${property.isOptional ? '?' : ''}${property.type ? `: ${property.type}` : ''};\n`; } diff --git a/src/declarations/Declaration.ts b/src/declarations/Declaration.ts index 7094642..8e14214 100644 --- a/src/declarations/Declaration.ts +++ b/src/declarations/Declaration.ts @@ -175,3 +175,20 @@ export interface AbstractDeclaration extends Declaration { */ isAbstract: boolean; } + +/** + * Interface for possible optional declarations. Contains information if the element is optional or not. + * + * @export + * @interface OptionalDeclaration + * @extends {Declaration} + */ +export interface OptionalDeclaration extends Declaration { + /** + * Defines if the declaration is optional or not. + * + * @type {boolean} + * @memberof OptionalDeclaration + */ + isOptional: boolean; +} diff --git a/src/declarations/MethodDeclaration.ts b/src/declarations/MethodDeclaration.ts index 70a29c7..60e093d 100644 --- a/src/declarations/MethodDeclaration.ts +++ b/src/declarations/MethodDeclaration.ts @@ -1,4 +1,10 @@ -import { AbstractDeclaration, CallableDeclaration, ScopedDeclaration, TypedDeclaration } from './Declaration'; +import { + AbstractDeclaration, + CallableDeclaration, + OptionalDeclaration, + ScopedDeclaration, + TypedDeclaration, +} from './Declaration'; import { DeclarationVisibility } from './DeclarationVisibility'; import { ParameterDeclaration } from './ParameterDeclaration'; import { VariableDeclaration } from './VariableDeclaration'; @@ -13,7 +19,13 @@ import { VariableDeclaration } from './VariableDeclaration'; * @implements {ScopedDeclaration} * @implements {TypedDeclaration} */ -export class MethodDeclaration implements AbstractDeclaration, CallableDeclaration, ScopedDeclaration, TypedDeclaration { +export class MethodDeclaration implements + AbstractDeclaration, + CallableDeclaration, + OptionalDeclaration, + ScopedDeclaration, + TypedDeclaration { + public parameters: ParameterDeclaration[] = []; public variables: VariableDeclaration[] = []; @@ -22,6 +34,7 @@ export class MethodDeclaration implements AbstractDeclaration, CallableDeclarati public isAbstract: boolean, public visibility: DeclarationVisibility | undefined, public type: string | undefined, + public isOptional: boolean, public start?: number, public end?: number, ) { } diff --git a/src/declarations/PropertyDeclaration.ts b/src/declarations/PropertyDeclaration.ts index a6ee61c..e7769d9 100644 --- a/src/declarations/PropertyDeclaration.ts +++ b/src/declarations/PropertyDeclaration.ts @@ -1,4 +1,4 @@ -import { ScopedDeclaration, TypedDeclaration } from './Declaration'; +import { OptionalDeclaration, ScopedDeclaration, TypedDeclaration } from './Declaration'; import { DeclarationVisibility } from './DeclarationVisibility'; /** @@ -9,12 +9,12 @@ import { DeclarationVisibility } from './DeclarationVisibility'; * @implements {ScopedDeclaration} * @implements {TypedDeclaration} */ -export class PropertyDeclaration implements ScopedDeclaration, TypedDeclaration { +export class PropertyDeclaration implements OptionalDeclaration, ScopedDeclaration, TypedDeclaration { constructor( public name: string, public visibility: DeclarationVisibility | undefined, public type: string | undefined, - public optional: boolean, + public isOptional: boolean, public start?: number, public end?: number, ) { } diff --git a/src/node-parser/class-parser.ts b/src/node-parser/class-parser.ts index 3ad405c..a1f3c93 100644 --- a/src/node-parser/class-parser.ts +++ b/src/node-parser/class-parser.ts @@ -196,6 +196,7 @@ export function parseClass(tsResource: Resource, node: ClassDeclaration): void { o.modifiers !== undefined && o.modifiers.some(m => m.kind === SyntaxKind.AbstractKeyword), getNodeVisibility(o), getNodeType(o.type), + !!o.questionToken, o.getStart(), o.getEnd(), ); diff --git a/src/node-parser/interface-parser.ts b/src/node-parser/interface-parser.ts index ac02189..90b70b5 100644 --- a/src/node-parser/interface-parser.ts +++ b/src/node-parser/interface-parser.ts @@ -48,6 +48,7 @@ export function parseInterface(resource: Resource, node: InterfaceDeclaration): true, DeclarationVisibility.Public, getNodeType(o.type), + !!o.questionToken, o.getStart(), o.getEnd(), ); diff --git a/test/TypescriptParser.spec.ts b/test/TypescriptParser.spec.ts index c552d6d..c1ef37d 100644 --- a/test/TypescriptParser.spec.ts +++ b/test/TypescriptParser.spec.ts @@ -395,7 +395,7 @@ describe('TypescriptParser', () => { }); it('should parse a file', () => { - expect(parsed.declarations).toHaveLength(4); + expect(parsed.declarations).toHaveLength(6); }); it('should parse a non exported interface', () => { @@ -436,6 +436,18 @@ describe('TypescriptParser', () => { expect(parsedInterface.typeParameters).toContain('TError'); }); + it('should parse optional properties', () => { + const parsedInterface = parsed.declarations[4] as InterfaceDeclaration; + + expect(parsedInterface.properties).toMatchSnapshot(); + }); + + it('should parse optional functions', () => { + const parsedInterface = parsed.declarations[5] as InterfaceDeclaration; + + expect(parsedInterface).toMatchSnapshot(); + }); + }); describe('Classes', () => { @@ -448,7 +460,7 @@ describe('TypescriptParser', () => { }); it('should parse a file', () => { - expect(parsed.declarations).toHaveLength(8); + expect(parsed.declarations).toHaveLength(9); }); it('should parse an abstract class', () => { @@ -529,6 +541,12 @@ describe('TypescriptParser', () => { expect(parsedClass.ctor).toMatchSnapshot(); }); + it('should parse optional class properties', () => { + const parsedClass = parsed.declarations[8] as ClassDeclaration; + + expect(parsedClass.properties).toMatchSnapshot(); + }); + }); describe('Modules', () => { diff --git a/test/__snapshots__/TypescriptParser.spec.ts.snap b/test/__snapshots__/TypescriptParser.spec.ts.snap index 0a5b8d2..421bd3e 100644 --- a/test/__snapshots__/TypescriptParser.spec.ts.snap +++ b/test/__snapshots__/TypescriptParser.spec.ts.snap @@ -23,6 +23,7 @@ ClassDeclaration { MethodDeclaration { "end": 203, "isAbstract": false, + "isOptional": false, "name": "method1", "parameters": Array [], "start": 177, @@ -33,6 +34,7 @@ ClassDeclaration { MethodDeclaration { "end": 237, "isAbstract": false, + "isOptional": false, "name": "method2", "parameters": Array [], "start": 208, @@ -43,6 +45,7 @@ ClassDeclaration { MethodDeclaration { "end": 300, "isAbstract": false, + "isOptional": false, "name": "method3", "parameters": Array [], "start": 242, @@ -64,8 +67,8 @@ ClassDeclaration { "properties": Array [ PropertyDeclaration { "end": 166, + "isOptional": false, "name": "param1", - "optional": false, "start": 145, "type": "string", "visibility": 2, @@ -121,6 +124,7 @@ ClassDeclaration { MethodDeclaration { "end": 55, "isAbstract": false, + "isOptional": false, "name": "method1", "parameters": Array [], "start": 35, @@ -131,6 +135,7 @@ ClassDeclaration { MethodDeclaration { "end": 100, "isAbstract": true, + "isOptional": false, "name": "abstractMethod", "parameters": Array [], "start": 61, @@ -172,24 +177,24 @@ ClassDeclaration { "properties": Array [ PropertyDeclaration { "end": 363, + "isOptional": false, "name": "_property", - "optional": false, "start": 337, "type": "string", "visibility": 0, }, PropertyDeclaration { "end": 394, + "isOptional": false, "name": "protect", - "optional": false, "start": 368, "type": "string", "visibility": 1, }, PropertyDeclaration { "end": 418, + "isOptional": false, "name": "pub", - "optional": false, "start": 399, "type": "string", "visibility": 2, @@ -239,6 +244,7 @@ Array [ MethodDeclaration { "end": 1251, "isAbstract": false, + "isOptional": false, "name": "objMethod", "parameters": Array [ ObjectBoundParameterDeclaration { @@ -276,6 +282,7 @@ Array [ MethodDeclaration { "end": 1307, "isAbstract": false, + "isOptional": false, "name": "arrMethod", "parameters": Array [ ArrayBoundParameterDeclaration { @@ -313,6 +320,7 @@ Array [ MethodDeclaration { "end": 1386, "isAbstract": false, + "isOptional": false, "name": "objAndArrMethod", "parameters": Array [ ArrayBoundParameterDeclaration { @@ -370,6 +378,35 @@ Array [ ] `; +exports[`TypescriptParser Declaration parsing Classes should parse optional class properties 1`] = ` +Array [ + PropertyDeclaration { + "end": 1448, + "isOptional": false, + "name": "nonOptional", + "start": 1421, + "type": "string", + "visibility": 2, + }, + PropertyDeclaration { + "end": 1498, + "isOptional": false, + "name": "nonOptionalAsWell", + "start": 1453, + "type": "string | undefined", + "visibility": 2, + }, + PropertyDeclaration { + "end": 1528, + "isOptional": true, + "name": "optional", + "start": 1503, + "type": "string", + "visibility": 2, + }, +] +`; + exports[`TypescriptParser Declaration parsing Classes should parse property accessors 1`] = ` Array [ GetterDeclaration { @@ -627,6 +664,7 @@ InterfaceDeclaration { MethodDeclaration { "end": 93, "isAbstract": true, + "isOptional": false, "name": "method1", "parameters": Array [], "start": 83, @@ -637,6 +675,7 @@ InterfaceDeclaration { MethodDeclaration { "end": 128, "isAbstract": true, + "isOptional": false, "name": "method2", "parameters": Array [ ParameterDeclaration { @@ -656,16 +695,16 @@ InterfaceDeclaration { "properties": Array [ PropertyDeclaration { "end": 55, + "isOptional": false, "name": "property1", - "optional": false, "start": 37, "type": "string", "visibility": 2, }, PropertyDeclaration { "end": 78, + "isOptional": false, "name": "property2", - "optional": false, "start": 60, "type": "number", "visibility": 2, @@ -684,6 +723,7 @@ InterfaceDeclaration { MethodDeclaration { "end": 247, "isAbstract": true, + "isOptional": false, "name": "method1", "parameters": Array [ ObjectBoundParameterDeclaration { @@ -715,6 +755,7 @@ InterfaceDeclaration { MethodDeclaration { "end": 284, "isAbstract": true, + "isOptional": false, "name": "method2", "parameters": Array [ ArrayBoundParameterDeclaration { @@ -748,16 +789,16 @@ InterfaceDeclaration { "properties": Array [ PropertyDeclaration { "end": 191, + "isOptional": false, "name": "property1", - "optional": false, "start": 173, "type": "string", "visibility": 2, }, PropertyDeclaration { "end": 214, + "isOptional": false, "name": "property2", - "optional": false, "start": 196, "type": "number", "visibility": 2, @@ -767,6 +808,95 @@ InterfaceDeclaration { } `; +exports[`TypescriptParser Declaration parsing Interfaces should parse optional functions 1`] = ` +InterfaceDeclaration { + "accessors": Array [], + "end": 714, + "isExported": false, + "methods": Array [ + MethodDeclaration { + "end": 680, + "isAbstract": true, + "isOptional": false, + "name": "nonOptionalFunction2", + "parameters": Array [], + "start": 651, + "type": "void", + "variables": Array [], + "visibility": 2, + }, + MethodDeclaration { + "end": 712, + "isAbstract": true, + "isOptional": true, + "name": "optionalFunction3", + "parameters": Array [], + "start": 685, + "type": "void", + "variables": Array [], + "visibility": 2, + }, + ], + "name": "OptionalFunctionInterface", + "properties": Array [ + PropertyDeclaration { + "end": 572, + "isOptional": false, + "name": "nonOptionalFunction1", + "start": 539, + "type": "() => void", + "visibility": 2, + }, + PropertyDeclaration { + "end": 610, + "isOptional": true, + "name": "optionalFunction1", + "start": 577, + "type": "{ (): void }", + "visibility": 2, + }, + PropertyDeclaration { + "end": 646, + "isOptional": true, + "name": "optionalFunction2", + "start": 615, + "type": "() => void", + "visibility": 2, + }, + ], + "start": 497, +} +`; + +exports[`TypescriptParser Declaration parsing Interfaces should parse optional properties 1`] = ` +Array [ + PropertyDeclaration { + "end": 422, + "isOptional": false, + "name": "nonOptional", + "start": 402, + "type": "string", + "visibility": 2, + }, + PropertyDeclaration { + "end": 470, + "isOptional": false, + "name": "alsoNonOptional", + "start": 427, + "type": "string | null | undefined", + "visibility": 2, + }, + PropertyDeclaration { + "end": 493, + "isOptional": true, + "name": "optional", + "start": 475, + "type": "string", + "visibility": 2, + }, +] +`; + exports[`TypescriptParser Declaration parsing Modules should parse a module 1`] = ` Module { "declarations": Array [ @@ -1628,6 +1758,7 @@ File { MethodDeclaration { "end": 304, "isAbstract": false, + "isOptional": false, "name": "render", "parameters": Array [], "start": 80, @@ -1692,6 +1823,7 @@ Array [ MethodDeclaration { "end": 304, "isAbstract": false, + "isOptional": false, "name": "render", "parameters": Array [], "start": 80, @@ -1756,6 +1888,7 @@ File { MethodDeclaration { "end": 304, "isAbstract": false, + "isOptional": false, "name": "render", "parameters": Array [], "start": 80, @@ -1828,6 +1961,7 @@ File { MethodDeclaration { "end": 93, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 76, @@ -1886,6 +2020,7 @@ Array [ MethodDeclaration { "end": 93, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 76, @@ -1944,6 +2079,7 @@ File { MethodDeclaration { "end": 93, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 76, @@ -2043,6 +2179,7 @@ File { MethodDeclaration { "end": 142, "isAbstract": false, + "isOptional": false, "name": "test", "parameters": Array [], "start": 45, diff --git a/test/_workspace/typescript-parser/class.ts b/test/_workspace/typescript-parser/class.ts index 6046dfa..64f783d 100644 --- a/test/_workspace/typescript-parser/class.ts +++ b/test/_workspace/typescript-parser/class.ts @@ -64,3 +64,9 @@ class ObjAndArrDestruct { public objAndArrMethod([p1, p2, p3]: string[], { p4, p5 }: any): void { } } + +class OptionalProperties { + public nonOptional: string; + public nonOptionalAsWell: string | undefined; + public optional?: string; +} diff --git a/test/_workspace/typescript-parser/interface.ts b/test/_workspace/typescript-parser/interface.ts index 5a0c8b4..d6b383e 100644 --- a/test/_workspace/typescript-parser/interface.ts +++ b/test/_workspace/typescript-parser/interface.ts @@ -14,3 +14,17 @@ export interface ExportedInterface { interface Generic { } interface MultiGeneric { } + +interface OptionalPropertyInterface { + nonOptional: string; + alsoNonOptional: string | null | undefined; + optional?: string; +} + +interface OptionalFunctionInterface { + nonOptionalFunction1: () => void; + optionalFunction1?: { (): void }; + optionalFunction2?: () => void; + nonOptionalFunction2(): void; + optionalFunction3?(): void; +} diff --git a/test/declaration-index/__snapshots__/DeclarationIndex.spec.ts.snap b/test/declaration-index/__snapshots__/DeclarationIndex.spec.ts.snap index 10b2074..bf156b1 100644 --- a/test/declaration-index/__snapshots__/DeclarationIndex.spec.ts.snap +++ b/test/declaration-index/__snapshots__/DeclarationIndex.spec.ts.snap @@ -964,6 +964,7 @@ Object { MethodDeclaration { "end": 329, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 292, @@ -989,6 +990,7 @@ Object { MethodDeclaration { "end": 105, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 75, @@ -1019,6 +1021,7 @@ Object { MethodDeclaration { "end": 329, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 292, @@ -1058,6 +1061,7 @@ Object { MethodDeclaration { "end": 105, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 75, @@ -1214,6 +1218,7 @@ Object { MethodDeclaration { "end": 137, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 100, @@ -1239,6 +1244,7 @@ Object { MethodDeclaration { "end": 57, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 27, @@ -1395,6 +1401,7 @@ Object { MethodDeclaration { "end": 137, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 100, @@ -1420,6 +1427,7 @@ Object { MethodDeclaration { "end": 57, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 27, @@ -1492,6 +1500,7 @@ Object { MethodDeclaration { "end": 329, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 292, @@ -1517,6 +1526,7 @@ Object { MethodDeclaration { "end": 105, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 75, @@ -1547,6 +1557,7 @@ Object { MethodDeclaration { "end": 329, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 292, @@ -1572,6 +1583,7 @@ Object { MethodDeclaration { "end": 105, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 75, @@ -1728,6 +1740,7 @@ Object { MethodDeclaration { "end": 137, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 100, @@ -1753,6 +1766,7 @@ Object { MethodDeclaration { "end": 57, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 27, @@ -1785,6 +1799,7 @@ Object { MethodDeclaration { "end": 329, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 292, @@ -1824,6 +1839,7 @@ Object { MethodDeclaration { "end": 105, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 75, @@ -1854,6 +1870,7 @@ Object { MethodDeclaration { "end": 329, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 292, @@ -1879,6 +1896,7 @@ Object { MethodDeclaration { "end": 105, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 75, @@ -1909,6 +1927,7 @@ Object { MethodDeclaration { "end": 329, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 292, @@ -1948,6 +1967,7 @@ Object { MethodDeclaration { "end": 105, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 75, @@ -1992,6 +2012,7 @@ Object { MethodDeclaration { "end": 329, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 292, @@ -2031,6 +2052,7 @@ Object { MethodDeclaration { "end": 105, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 75, @@ -2187,6 +2209,7 @@ Object { MethodDeclaration { "end": 137, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 100, @@ -2212,6 +2235,7 @@ Object { MethodDeclaration { "end": 57, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 27, @@ -2242,6 +2266,7 @@ Object { MethodDeclaration { "end": 329, "isAbstract": false, + "isOptional": false, "name": "doSomethingAwesome", "parameters": Array [], "start": 292, @@ -2267,6 +2292,7 @@ Object { MethodDeclaration { "end": 105, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 75, diff --git a/test/declaration-index/specific-cases/reindex-with-global-module/__snapshots__/DeclarationIndex.reindex-with-global-module-export.spec.ts.snap b/test/declaration-index/specific-cases/reindex-with-global-module/__snapshots__/DeclarationIndex.reindex-with-global-module-export.spec.ts.snap index e41dd8d..649cbc6 100644 --- a/test/declaration-index/specific-cases/reindex-with-global-module/__snapshots__/DeclarationIndex.reindex-with-global-module-export.spec.ts.snap +++ b/test/declaration-index/specific-cases/reindex-with-global-module/__snapshots__/DeclarationIndex.reindex-with-global-module-export.spec.ts.snap @@ -41,6 +41,7 @@ Array [ MethodDeclaration { "end": 59, "isAbstract": false, + "isOptional": false, "name": "doSomething", "parameters": Array [], "start": 29,