From 73614974b1f7b72b951beaa9694d0fbc2748624c Mon Sep 17 00:00:00 2001 From: Jon Hardy Date: Fri, 21 Dec 2018 15:36:12 -0500 Subject: [PATCH 1/4] Improve flexibility of categories --- src/lib/converter/plugins/CategoryPlugin.ts | 154 ++++++++++++++------ src/lib/models/ReflectionGroup.ts | 15 ++ 2 files changed, 126 insertions(+), 43 deletions(-) diff --git a/src/lib/converter/plugins/CategoryPlugin.ts b/src/lib/converter/plugins/CategoryPlugin.ts index 77f18fe8e..15777dcf1 100644 --- a/src/lib/converter/plugins/CategoryPlugin.ts +++ b/src/lib/converter/plugins/CategoryPlugin.ts @@ -1,10 +1,10 @@ -import { Reflection, ContainerReflection } from '../../models/reflections/index'; +import { Reflection, ContainerReflection, SourceDirectory, SourceFile } from '../../models'; import { ReflectionCategory } from '../../models/ReflectionCategory'; -import { SourceDirectory } from '../../models/sources/directory'; import { Component, ConverterComponent } from '../components'; import { Converter } from '../converter'; import { Context } from '../context'; -import { GroupPlugin } from './GroupPlugin'; +import { Option } from '../../utils/component'; +import { ParameterType } from '../../utils/options/declaration'; /** * A handler that sorts and categorizes the found reflections in the resolving phase. @@ -13,9 +13,31 @@ import { GroupPlugin } from './GroupPlugin'; */ @Component({name: 'category'}) export class CategoryPlugin extends ConverterComponent { - /** - * Define the sort order of categories. By default, sort alphabetically. - */ + @Option({ + name: 'defaultCategory', + help: 'Specifies the default category for reflections without a category.', + type: ParameterType.String, + defaultValue: 'Other' + }) + defaultCategory!: string; + + @Option({ + name: 'categoryOrder', + help: 'Specifies the order in which categories appear. * indicates the relative order for categories not in the list.', + type: ParameterType.Array + }) + categoryOrder!: string[]; + + @Option({ + name: 'categorizeByGroup', + help: 'Specifies whether categorization will be done at the group level.', + type: ParameterType.Boolean, + defaultValue: true + }) + categorizeByGroup!: boolean; + + // For use in static methods + static defaultCategory = 'Other'; static WEIGHTS: string[] = []; /** @@ -23,9 +45,25 @@ export class CategoryPlugin extends ConverterComponent { */ initialize() { this.listenTo(this.owner, { + [Converter.EVENT_BEGIN]: this.onBegin, [Converter.EVENT_RESOLVE]: this.onResolve, [Converter.EVENT_RESOLVE_END]: this.onEndResolve - }); + }, undefined, -200); + } + + /** + * Triggered when the converter begins converting a project. + * + * @param context The context object describing the current state the converter is in. + */ + private onBegin(context: Context) { + // Set up static properties + if (this.defaultCategory) { + CategoryPlugin.defaultCategory = this.defaultCategory; + } + if (this.categoryOrder) { + CategoryPlugin.WEIGHTS = this.categoryOrder; + } } /** @@ -36,13 +74,7 @@ export class CategoryPlugin extends ConverterComponent { */ private onResolve(context: Context, reflection: Reflection) { if (reflection instanceof ContainerReflection) { - if (reflection.children && reflection.children.length > 0) { - reflection.children.sort(GroupPlugin.sortCallback); - reflection.categories = CategoryPlugin.getReflectionCategories(reflection.children); - } - if (reflection.categories && reflection.categories.length > 1) { - reflection.categories.sort(CategoryPlugin.sortCatCallback); - } + this.categorize(reflection); } } @@ -52,32 +84,65 @@ export class CategoryPlugin extends ConverterComponent { * @param context The context object describing the current state the converter is in. */ private onEndResolve(context: Context) { - function walkDirectory(directory: SourceDirectory) { - directory.categories = CategoryPlugin.getReflectionCategories(directory.getAllReflections()); + // const self = this; + // function walkDirectory(directory: SourceDirectory) { + // self.categorize(directory); - for (let key in directory.directories) { - if (!directory.directories.hasOwnProperty(key)) { - continue; - } - walkDirectory(directory.directories[key]); - } - } + // for (let key in directory.directories) { + // if (!directory.directories.hasOwnProperty(key)) { + // continue; + // } + // walkDirectory(directory.directories[key]); + // } + // } const project = context.project; - if (project.children && project.children.length > 0) { - project.children.sort(GroupPlugin.sortCallback); - project.categories = CategoryPlugin.getReflectionCategories(project.children); - } - if (project.categories && project.categories.length > 1) { - project.categories.sort(CategoryPlugin.sortCatCallback); + this.categorize(project); + + // walkDirectory(project.directory); + // project.files.forEach((file) => { + // this.categorize(file); + // }); + } + + private categorize(obj: ContainerReflection | SourceDirectory | SourceFile) { + if (this.categorizeByGroup) { + this.groupCategorize(obj); + } else { + this.lumpCategorize(obj); } + } - walkDirectory(project.directory); - project.files.forEach((file) => { - file.categories = CategoryPlugin.getReflectionCategories(file.reflections); + private groupCategorize(obj: ContainerReflection | SourceDirectory | SourceFile) { + if (!obj.groups || obj.groups.length === 0) { + return; + } + obj.groups.forEach((group) => { + group.categories = CategoryPlugin.getReflectionCategories(group.children); + if (group.categories && group.categories.length > 1) { + group.categories.sort(CategoryPlugin.sortCatCallback); + } else if (group.categories.length === 1 && group.categories[0].title === CategoryPlugin.defaultCategory) { + // no categories if everything is uncategorized + group.categories = undefined; + } }); } + private lumpCategorize(obj: ContainerReflection | SourceDirectory | SourceFile) { + if (obj instanceof ContainerReflection) { + if (obj.children && obj.children.length > 0) { + obj.categories = CategoryPlugin.getReflectionCategories(obj.children); + } + if (obj.categories && obj.categories.length > 1) { + obj.categories.sort(CategoryPlugin.sortCatCallback); + } + } else if (obj instanceof SourceDirectory) { + obj.categories = CategoryPlugin.getReflectionCategories(obj.getAllReflections()); + } else { + obj.categories = CategoryPlugin.getReflectionCategories(obj.reflections); + } + } + /** * Create a categorized representation of the given list of reflections. * @@ -86,23 +151,26 @@ export class CategoryPlugin extends ConverterComponent { */ static getReflectionCategories(reflections: Reflection[]): ReflectionCategory[] { const categories: ReflectionCategory[] = []; + let defaultCat: ReflectionCategory | undefined; reflections.forEach((child) => { const childCat = CategoryPlugin.getCategory(child); if (childCat === '') { - return; - } - for (let i = 0; i < categories.length; i++) { - const category = categories[i]; - - if (category.title !== childCat) { - continue; + if (!defaultCat) { + defaultCat = categories.find(category => category.title === CategoryPlugin.defaultCategory); + if (!defaultCat) { + defaultCat = new ReflectionCategory(CategoryPlugin.defaultCategory); + categories.push(defaultCat); + } } - + defaultCat.children.push(child); + return; + } + let category = categories.find(cat => cat.title === childCat); + if (category) { category.children.push(child); return; } - - const category = new ReflectionCategory(childCat); + category = new ReflectionCategory(childCat); category.children.push(child); categories.push(category); }); @@ -122,7 +190,7 @@ export class CategoryPlugin extends ConverterComponent { for (let i = 0; i < tags.length; i++) { if (tags[i].tagName === 'category') { let tag = tags[i].text; - return (tag.charAt(0).toUpperCase() + tag.slice(1).toLowerCase()).trim(); + return tag.trim(); } } } diff --git a/src/lib/models/ReflectionGroup.ts b/src/lib/models/ReflectionGroup.ts index 88dbc9d26..97da1ae7c 100644 --- a/src/lib/models/ReflectionGroup.ts +++ b/src/lib/models/ReflectionGroup.ts @@ -1,4 +1,5 @@ import { Reflection, ReflectionKind } from './reflections/abstract'; +import { ReflectionCategory } from './ReflectionCategory'; /** * A group of reflections. All reflections in a group are of the same kind. @@ -62,6 +63,11 @@ export class ReflectionGroup { */ someChildrenAreExported?: boolean; + /** + * Categories contained within this group. + */ + categories?: ReflectionCategory[]; + /** * Create a new ReflectionGroup instance. * @@ -106,6 +112,15 @@ export class ReflectionGroup { result['children'] = children; } + if (this.categories) { + const categories: any[] = []; + this.categories.forEach((category) => { + categories.push(category.toObject()); + }); + + result['categories'] = categories; + } + return result; } } From be9c6cfa870db8648b3f9be8feb0c90c40cdc731 Mon Sep 17 00:00:00 2001 From: Jon Hardy Date: Fri, 4 Jan 2019 15:55:15 -0500 Subject: [PATCH 2/4] Category improvements, test Improve categories to work at the group level or the container level, add category options for flexibility, add test for categories --- src/lib/converter/plugins/CategoryPlugin.ts | 76 +- src/test/converter/category/category.ts | 115 ++ src/test/converter/category/specs.json | 1231 +++++++++++++++++++ 3 files changed, 1375 insertions(+), 47 deletions(-) create mode 100644 src/test/converter/category/category.ts create mode 100644 src/test/converter/category/specs.json diff --git a/src/lib/converter/plugins/CategoryPlugin.ts b/src/lib/converter/plugins/CategoryPlugin.ts index 15777dcf1..9a7454ed5 100644 --- a/src/lib/converter/plugins/CategoryPlugin.ts +++ b/src/lib/converter/plugins/CategoryPlugin.ts @@ -1,10 +1,11 @@ -import { Reflection, ContainerReflection, SourceDirectory, SourceFile } from '../../models'; +import { Reflection, ContainerReflection, DeclarationReflection } from '../../models'; import { ReflectionCategory } from '../../models/ReflectionCategory'; import { Component, ConverterComponent } from '../components'; import { Converter } from '../converter'; import { Context } from '../context'; import { Option } from '../../utils/component'; import { ParameterType } from '../../utils/options/declaration'; +import { Comment } from '../../models/comments/index'; /** * A handler that sorts and categorizes the found reflections in the resolving phase. @@ -84,28 +85,11 @@ export class CategoryPlugin extends ConverterComponent { * @param context The context object describing the current state the converter is in. */ private onEndResolve(context: Context) { - // const self = this; - // function walkDirectory(directory: SourceDirectory) { - // self.categorize(directory); - - // for (let key in directory.directories) { - // if (!directory.directories.hasOwnProperty(key)) { - // continue; - // } - // walkDirectory(directory.directories[key]); - // } - // } - const project = context.project; this.categorize(project); - - // walkDirectory(project.directory); - // project.files.forEach((file) => { - // this.categorize(file); - // }); } - private categorize(obj: ContainerReflection | SourceDirectory | SourceFile) { + private categorize(obj: ContainerReflection) { if (this.categorizeByGroup) { this.groupCategorize(obj); } else { @@ -113,7 +97,7 @@ export class CategoryPlugin extends ConverterComponent { } } - private groupCategorize(obj: ContainerReflection | SourceDirectory | SourceFile) { + private groupCategorize(obj: ContainerReflection) { if (!obj.groups || obj.groups.length === 0) { return; } @@ -128,7 +112,7 @@ export class CategoryPlugin extends ConverterComponent { }); } - private lumpCategorize(obj: ContainerReflection | SourceDirectory | SourceFile) { + private lumpCategorize(obj: ContainerReflection) { if (obj instanceof ContainerReflection) { if (obj.children && obj.children.length > 0) { obj.categories = CategoryPlugin.getReflectionCategories(obj.children); @@ -136,10 +120,6 @@ export class CategoryPlugin extends ConverterComponent { if (obj.categories && obj.categories.length > 1) { obj.categories.sort(CategoryPlugin.sortCatCallback); } - } else if (obj instanceof SourceDirectory) { - obj.categories = CategoryPlugin.getReflectionCategories(obj.getAllReflections()); - } else { - obj.categories = CategoryPlugin.getReflectionCategories(obj.reflections); } } @@ -184,8 +164,8 @@ export class CategoryPlugin extends ConverterComponent { * @returns The category the reflection belongs to */ static getCategory(reflection: Reflection): string { - if (reflection.comment) { - const tags = reflection.comment.tags; + function extractCategoryTag(comment: Comment) { + const tags = comment.tags; if (tags) { for (let i = 0; i < tags.length; i++) { if (tags[i].tagName === 'category') { @@ -194,19 +174,21 @@ export class CategoryPlugin extends ConverterComponent { } } } + return ''; } - return ''; - } - /** - * Callback used to sort reflections by name. - * - * @param a The left reflection to sort. - * @param b The right reflection to sort. - * @returns The sorting weight. - */ - static sortCallback(a: Reflection, b: Reflection): number { - return a.name > b.name ? 1 : -1; + let category = ''; + if (reflection.comment) { + category = extractCategoryTag(reflection.comment); + } else if (reflection instanceof DeclarationReflection && reflection.signatures) { + // If a reflection has signatures, use the first category tag amongst them + reflection.signatures.forEach(sig => { + if (sig.comment && category === '') { + category = extractCategoryTag(sig.comment); + } + }); + } + return category; } /** @@ -217,16 +199,16 @@ export class CategoryPlugin extends ConverterComponent { * @returns The sorting weight. */ static sortCatCallback(a: ReflectionCategory, b: ReflectionCategory): number { - const aWeight = CategoryPlugin.WEIGHTS.indexOf(a.title); - const bWeight = CategoryPlugin.WEIGHTS.indexOf(b.title); - if (aWeight < 0 && bWeight < 0) { - return a.title > b.title ? 1 : -1; + let aWeight = CategoryPlugin.WEIGHTS.indexOf(a.title); + let bWeight = CategoryPlugin.WEIGHTS.indexOf(b.title); + if (aWeight === -1 || bWeight === -1) { + let asteriskIndex = CategoryPlugin.WEIGHTS.indexOf('*'); + if (asteriskIndex === -1) { asteriskIndex = CategoryPlugin.WEIGHTS.length; } + if (aWeight === -1) { aWeight = asteriskIndex; } + if (bWeight === -1) { bWeight = asteriskIndex; } } - if (aWeight < 0) { - return 1; - } - if (bWeight < 0) { - return -1; + if (aWeight === bWeight) { + return a.title > b.title ? 1 : -1; } return aWeight - bWeight; } diff --git a/src/test/converter/category/category.ts b/src/test/converter/category/category.ts new file mode 100644 index 000000000..bc3e43d01 --- /dev/null +++ b/src/test/converter/category/category.ts @@ -0,0 +1,115 @@ +/** + * TestClass comment short text. + * + * TestClass comment text. + * + * @see [[TestClass]] @ fixtures + * @category Test + */ +export class TestClass { + + /** + * publicProperty short text. + * @category Test + */ + public publicProperty: string; + + /** + * privateProperty short text. + */ + private privateProperty: number[]; + + /** + * privateProperty short text. + */ + static staticProperty: TestClass; + + /** + * Constructor short text. + */ + constructor() { } + + /** + * publicMethod short text. + * @category Test + */ + public publicMethod() {} + + /** + * protectedMethod short text. + * @category Test + */ + protected protectedMethod() {} + + /** + * privateMethod short text. + */ + private privateMethod() {} + + /** + * staticMethod short text. + */ + static staticMethod() {} +} + +export class TestSubClass extends TestClass { + /** + * publicMethod short text. + */ + public publicMethod() {} + + /** + * protectedMethod short text. + */ + protected protectedMethod() {} + + /** + * Constructor short text. + * + * @param p1 Constructor param + * @param p2 Private string property + * @param p3 Public number property + * @param p4 Public implicit any property + */ + constructor(p1, private p2: string, public p3: number, public p4) { + super(); + } +} + +export abstract class TestAbstractClass { + abstract myAbstractProperty: string; + + protected abstract myAbstractMethod(): void; +} + +export class TestAbstractClassImplementation extends TestAbstractClass { + myAbstractProperty: string; + + protected myAbstractMethod(): void { } +} + +export interface TestSubClass { + /** + * mergedMethod short text. + */ + mergedMethod(); +} + +export module TestSubClass { + /** + * staticMergedMethod short text. + */ + export function staticMergedMethod() { } +} + +/** + * This class will not appear when `excludeNotExported=true` + */ +abstract class NotExportedClass { + /** + * Adds two numbers + */ + add(a: number, b: number) { + a + b; + } +} diff --git a/src/test/converter/category/specs.json b/src/test/converter/category/specs.json new file mode 100644 index 000000000..7df7dd958 --- /dev/null +++ b/src/test/converter/category/specs.json @@ -0,0 +1,1231 @@ +{ + "id": 0, + "name": "typedoc", + "kind": 0, + "flags": {}, + "children": [ + { + "id": 1, + "name": "\"category\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "%BASE%/category/category.ts", + "children": [ + { + "id": 44, + "name": "NotExportedClass", + "kind": 128, + "kindString": "Class", + "flags": { + "isAbstract": true + }, + "comment": { + "shortText": "This class will not appear when `excludeNotExported=true`" + }, + "children": [ + { + "id": 45, + "name": "add", + "kind": 2048, + "kindString": "Method", + "flags": {}, + "signatures": [ + { + "id": 46, + "name": "add", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Adds two numbers" + }, + "parameters": [ + { + "id": 47, + "name": "a", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 48, + "name": "b", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 112, + "character": 7 + } + ] + } + ], + "groups": [ + { + "title": "Methods", + "kind": 2048, + "children": [ + 45 + ] + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 108, + "character": 31 + } + ] + }, + { + "id": 34, + "name": "TestAbstractClass", + "kind": 128, + "kindString": "Class", + "flags": { + "isExported": true, + "isAbstract": true + }, + "children": [ + { + "id": 35, + "name": "myAbstractProperty", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isAbstract": true + }, + "sources": [ + { + "fileName": "category.ts", + "line": 80, + "character": 31 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 36, + "name": "myAbstractMethod", + "kind": 2048, + "kindString": "Method", + "flags": { + "isProtected": true, + "isExported": true, + "isAbstract": true + }, + "signatures": [ + { + "id": 37, + "name": "myAbstractMethod", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 82, + "character": 39 + } + ] + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 35 + ] + }, + { + "title": "Methods", + "kind": 2048, + "children": [ + 36 + ] + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 79, + "character": 39 + } + ], + "extendedBy": [ + { + "type": "reference", + "name": "TestAbstractClassImplementation", + "id": 38 + } + ] + }, + { + "id": 38, + "name": "TestAbstractClassImplementation", + "kind": 128, + "kindString": "Class", + "flags": { + "isExported": true + }, + "children": [ + { + "id": 39, + "name": "myAbstractProperty", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "category.ts", + "line": 86, + "character": 22 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "overwrites": { + "type": "reference", + "name": "TestAbstractClass.myAbstractProperty", + "id": 35 + } + }, + { + "id": 40, + "name": "myAbstractMethod", + "kind": 2048, + "kindString": "Method", + "flags": { + "isProtected": true, + "isExported": true + }, + "signatures": [ + { + "id": 41, + "name": "myAbstractMethod", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "void" + }, + "overwrites": { + "type": "reference", + "name": "TestAbstractClass.myAbstractMethod", + "id": 36 + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 88, + "character": 30 + } + ], + "overwrites": { + "type": "reference", + "name": "TestAbstractClass.myAbstractMethod", + "id": 36 + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 39 + ] + }, + { + "title": "Methods", + "kind": 2048, + "children": [ + 40 + ] + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 85, + "character": 44 + } + ], + "extendedTypes": [ + { + "type": "reference", + "name": "TestAbstractClass", + "id": 34 + } + ] + }, + { + "id": 2, + "name": "TestClass", + "kind": 128, + "kindString": "Class", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "TestClass comment short text.", + "text": "TestClass comment text.\n", + "tags": [ + { + "tag": "see", + "text": "[[TestClass]] @ fixtures" + }, + { + "tag": "category", + "text": "Test\n" + } + ] + }, + "children": [ + { + "id": 6, + "name": "constructor", + "kind": 512, + "kindString": "Constructor", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "Constructor short text." + }, + "signatures": [ + { + "id": 7, + "name": "new TestClass", + "kind": 16384, + "kindString": "Constructor signature", + "flags": {}, + "comment": { + "shortText": "Constructor short text." + }, + "type": { + "type": "reference", + "name": "TestClass", + "id": 2 + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 25, + "character": 37 + } + ] + }, + { + "id": 4, + "name": "privateProperty", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "comment": { + "shortText": "privateProperty short text." + }, + "sources": [ + { + "fileName": "category.ts", + "line": 20, + "character": 27 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "number" + } + } + }, + { + "id": 3, + "name": "publicProperty", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPublic": true, + "isExported": true + }, + "comment": { + "shortText": "publicProperty short text.", + "tags": [ + { + "tag": "category", + "text": "Test\n" + } + ] + }, + "sources": [ + { + "fileName": "category.ts", + "line": 15, + "character": 25 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 5, + "name": "staticProperty", + "kind": 1024, + "kindString": "Property", + "flags": { + "isStatic": true, + "isExported": true + }, + "comment": { + "shortText": "privateProperty short text." + }, + "sources": [ + { + "fileName": "category.ts", + "line": 25, + "character": 25 + } + ], + "type": { + "type": "reference", + "name": "TestClass", + "id": 2 + } + }, + { + "id": 12, + "name": "privateMethod", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 13, + "name": "privateMethod", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "privateMethod short text." + }, + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 47, + "character": 25 + } + ] + }, + { + "id": 10, + "name": "protectedMethod", + "kind": 2048, + "kindString": "Method", + "flags": { + "isProtected": true, + "isExported": true + }, + "signatures": [ + { + "id": 11, + "name": "protectedMethod", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "protectedMethod short text.", + "tags": [ + { + "tag": "category", + "text": "Test\n" + } + ] + }, + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 42, + "character": 29 + } + ] + }, + { + "id": 8, + "name": "publicMethod", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPublic": true, + "isExported": true + }, + "signatures": [ + { + "id": 9, + "name": "publicMethod", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "publicMethod short text.", + "tags": [ + { + "tag": "category", + "text": "Test\n" + } + ] + }, + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 36, + "character": 23 + } + ] + }, + { + "id": 14, + "name": "staticMethod", + "kind": 2048, + "kindString": "Method", + "flags": { + "isStatic": true, + "isExported": true + }, + "signatures": [ + { + "id": 15, + "name": "staticMethod", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "staticMethod short text." + }, + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 52, + "character": 23 + } + ] + } + ], + "groups": [ + { + "title": "Constructors", + "kind": 512, + "children": [ + 6 + ] + }, + { + "title": "Properties", + "kind": 1024, + "children": [ + 4, + 3, + 5 + ], + "categories": [ + { + "title": "Other", + "children": [ + 4, + 5 + ] + }, + { + "title": "Test", + "children": [ + 3 + ] + } + ] + }, + { + "title": "Methods", + "kind": 2048, + "children": [ + 12, + 10, + 8, + 14 + ], + "categories": [ + { + "title": "Other", + "children": [ + 12, + 14 + ] + }, + { + "title": "Test", + "children": [ + 10, + 8 + ] + } + ] + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 9, + "character": 22 + } + ], + "extendedBy": [ + { + "type": "reference", + "name": "TestSubClass", + "id": 16 + } + ] + }, + { + "id": 16, + "name": "TestSubClass", + "kind": 128, + "kindString": "Class", + "flags": { + "isExported": true + }, + "children": [ + { + "id": 21, + "name": "constructor", + "kind": 512, + "kindString": "Constructor", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "Constructor short text." + }, + "signatures": [ + { + "id": 25, + "name": "new TestSubClass", + "kind": 16384, + "kindString": "Constructor signature", + "flags": {}, + "comment": { + "shortText": "Constructor short text." + }, + "parameters": [ + { + "id": 26, + "name": "p1", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "shortText": "Constructor param" + }, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 27, + "name": "p2", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "shortText": "Private string property" + }, + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 28, + "name": "p3", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "shortText": "Public number property" + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 29, + "name": "p4", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "shortText": "Public implicit any property\n" + }, + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "type": { + "type": "reference", + "name": "TestSubClass", + "id": 16 + }, + "overwrites": { + "type": "reference", + "name": "TestClass.__constructor", + "id": 6 + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 64, + "character": 34 + } + ], + "overwrites": { + "type": "reference", + "name": "TestClass.__constructor", + "id": 6 + } + }, + { + "id": 22, + "name": "p2", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true, + "isConstructorProperty": true + }, + "comment": { + "shortText": "Private string property" + }, + "sources": [ + { + "fileName": "category.ts", + "line": 74, + "character": 30 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 23, + "name": "p3", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPublic": true, + "isExported": true, + "isConstructorProperty": true + }, + "comment": { + "shortText": "Public number property" + }, + "sources": [ + { + "fileName": "category.ts", + "line": 74, + "character": 49 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 24, + "name": "p4", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPublic": true, + "isExported": true, + "isConstructorProperty": true + }, + "comment": { + "shortText": "Public implicit any property\n" + }, + "sources": [ + { + "fileName": "category.ts", + "line": 74, + "character": 68 + } + ], + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 30, + "name": "publicProperty", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPublic": true, + "isExported": true + }, + "comment": { + "shortText": "publicProperty short text.", + "tags": [ + { + "tag": "category", + "text": "Test\n" + } + ] + }, + "sources": [ + { + "fileName": "category.ts", + "line": 15, + "character": 25 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "inheritedFrom": { + "type": "reference", + "name": "TestClass.publicProperty", + "id": 3 + } + }, + { + "id": 31, + "name": "staticProperty", + "kind": 1024, + "kindString": "Property", + "flags": { + "isStatic": true, + "isExported": true + }, + "comment": { + "shortText": "privateProperty short text." + }, + "sources": [ + { + "fileName": "category.ts", + "line": 25, + "character": 25 + } + ], + "type": { + "type": "reference", + "name": "TestClass", + "id": 2 + }, + "inheritedFrom": { + "type": "reference", + "name": "TestClass.staticProperty", + "id": 5 + } + }, + { + "id": 42, + "name": "mergedMethod", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true + }, + "signatures": [ + { + "id": 43, + "name": "mergedMethod", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "mergedMethod short text." + }, + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 95, + "character": 16 + } + ] + }, + { + "id": 19, + "name": "protectedMethod", + "kind": 2048, + "kindString": "Method", + "flags": { + "isProtected": true, + "isExported": true + }, + "signatures": [ + { + "id": 20, + "name": "protectedMethod", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "protectedMethod short text." + }, + "type": { + "type": "intrinsic", + "name": "void" + }, + "overwrites": { + "type": "reference", + "name": "TestClass.protectedMethod", + "id": 10 + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 64, + "character": 29 + } + ], + "overwrites": { + "type": "reference", + "name": "TestClass.protectedMethod", + "id": 10 + } + }, + { + "id": 17, + "name": "publicMethod", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPublic": true, + "isExported": true + }, + "signatures": [ + { + "id": 18, + "name": "publicMethod", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "publicMethod short text." + }, + "type": { + "type": "intrinsic", + "name": "void" + }, + "overwrites": { + "type": "reference", + "name": "TestClass.publicMethod", + "id": 8 + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 59, + "character": 23 + } + ], + "overwrites": { + "type": "reference", + "name": "TestClass.publicMethod", + "id": 8 + } + }, + { + "id": 49, + "name": "staticMergedMethod", + "kind": 2048, + "kindString": "Method", + "flags": { + "isStatic": true, + "isExported": true + }, + "signatures": [ + { + "id": 50, + "name": "staticMergedMethod", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "staticMergedMethod short text." + }, + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 102, + "character": 38 + } + ] + }, + { + "id": 32, + "name": "staticMethod", + "kind": 2048, + "kindString": "Method", + "flags": { + "isStatic": true, + "isExported": true + }, + "signatures": [ + { + "id": 33, + "name": "staticMethod", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "staticMethod short text." + }, + "type": { + "type": "intrinsic", + "name": "void" + }, + "inheritedFrom": { + "type": "reference", + "name": "TestClass.staticMethod", + "id": 14 + } + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 52, + "character": 23 + } + ], + "inheritedFrom": { + "type": "reference", + "name": "TestClass.staticMethod", + "id": 14 + } + } + ], + "groups": [ + { + "title": "Constructors", + "kind": 512, + "children": [ + 21 + ] + }, + { + "title": "Properties", + "kind": 1024, + "children": [ + 22, + 23, + 24, + 30, + 31 + ], + "categories": [ + { + "title": "Other", + "children": [ + 22, + 23, + 24, + 31 + ] + }, + { + "title": "Test", + "children": [ + 30 + ] + } + ] + }, + { + "title": "Methods", + "kind": 2048, + "children": [ + 42, + 19, + 17, + 49, + 32 + ] + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 55, + "character": 25 + }, + { + "fileName": "category.ts", + "line": 91, + "character": 29 + }, + { + "fileName": "category.ts", + "line": 98, + "character": 26 + } + ], + "extendedTypes": [ + { + "type": "reference", + "name": "TestClass", + "id": 2 + } + ] + } + ], + "groups": [ + { + "title": "Classes", + "kind": 128, + "children": [ + 44, + 34, + 38, + 2, + 16 + ], + "categories": [ + { + "title": "Other", + "children": [ + 44, + 34, + 38, + 16 + ] + }, + { + "title": "Test", + "children": [ + 2 + ] + } + ] + } + ], + "sources": [ + { + "fileName": "category.ts", + "line": 1, + "character": 0 + } + ] + } + ], + "groups": [ + { + "title": "External modules", + "kind": 1, + "children": [ + 1 + ] + } + ] +} \ No newline at end of file From d9412025fe07a4f160ccff8c60070d60780d5b57 Mon Sep 17 00:00:00 2001 From: Jon Hardy Date: Mon, 14 Jan 2019 15:18:43 -0500 Subject: [PATCH 3/4] Serialization Make some changes for serialization and remove some unused code --- src/lib/models/reflections/project.ts | 27 ------------ src/lib/models/sources/directory.ts | 3 -- src/lib/models/sources/file.ts | 6 --- src/lib/serialization/browser.ts | 22 ++++++++++ src/lib/serialization/index.ts | 1 + src/lib/serialization/serializers/index.ts | 1 + .../serializers/reflection-category.ts | 42 +++++++++++++++++++ .../serializers/reflection-group.ts | 4 ++ .../serializers/reflections/container.ts | 4 ++ 9 files changed, 74 insertions(+), 36 deletions(-) create mode 100644 src/lib/serialization/serializers/reflection-category.ts diff --git a/src/lib/models/reflections/project.ts b/src/lib/models/reflections/project.ts index 17394207f..6e4fbd9c1 100644 --- a/src/lib/models/reflections/project.ts +++ b/src/lib/models/reflections/project.ts @@ -1,7 +1,6 @@ import { SourceFile, SourceDirectory } from '../sources/index'; import { Reflection, ReflectionKind } from './abstract'; import { ContainerReflection } from './container'; -import { ReflectionCategory } from '../ReflectionCategory'; /** * A reflection that represents the root of the project. @@ -27,11 +26,6 @@ export class ProjectReflection extends ContainerReflection { */ files: SourceFile[] = []; - /** - * All reflections categorized. - */ - categories?: ReflectionCategory[]; - /** * The name of the project. * @@ -123,25 +117,4 @@ export class ProjectReflection extends ContainerReflection { return undefined; } - - /** - * Return a raw object representation of this reflection. - * @deprecated Use serializers instead - */ - toObject(): any { - const result = super.toObject(); - - if (this.categories) { - const categories: any[] = []; - this.categories.forEach((category) => { - categories.push(category.toObject()); - }); - - if (categories.length > 0) { - result['categories'] = categories; - } - } - - return result; - } } diff --git a/src/lib/models/sources/directory.ts b/src/lib/models/sources/directory.ts index 8b7152996..71377031c 100644 --- a/src/lib/models/sources/directory.ts +++ b/src/lib/models/sources/directory.ts @@ -1,5 +1,4 @@ import { Reflection } from '../reflections/abstract'; -import { ReflectionCategory } from '../ReflectionCategory'; import { ReflectionGroup } from '../ReflectionGroup'; import { SourceFile } from './file'; @@ -23,8 +22,6 @@ export class SourceDirectory { groups?: ReflectionGroup[]; - categories?: ReflectionCategory[]; - /** * A list of all files in this directory. */ diff --git a/src/lib/models/sources/file.ts b/src/lib/models/sources/file.ts index 1cb131c10..97dc18363 100644 --- a/src/lib/models/sources/file.ts +++ b/src/lib/models/sources/file.ts @@ -1,7 +1,6 @@ import * as Path from 'path'; import { Reflection } from '../reflections/abstract'; -import { ReflectionCategory } from '../ReflectionCategory'; import { ReflectionGroup } from '../ReflectionGroup'; import { SourceDirectory } from './directory'; @@ -81,11 +80,6 @@ export class SourceFile { */ groups?: ReflectionGroup[]; - /** - * A categorized list of the reflections declared in this file. - */ - categories?: ReflectionCategory[]; - /** * Create a new SourceFile instance. * diff --git a/src/lib/serialization/browser.ts b/src/lib/serialization/browser.ts index c7f345dae..180c56599 100644 --- a/src/lib/serialization/browser.ts +++ b/src/lib/serialization/browser.ts @@ -56,6 +56,10 @@ export interface GroupsContainer { groups: T[]; } +export interface CategoriesContainer { + categories: T[]; +} + export interface ContainerReflectionContainer { children: TChildren[]; } @@ -147,6 +151,7 @@ export interface ParameterReflectionObject extends ReflectionObject, export interface ContainerReflectionObject extends ReflectionObject, Partial>, Partial>, + Partial>, ContainerReflectionContainer {} export interface DeclarationReflectionObject extends ContainerReflectionObject, @@ -285,6 +290,23 @@ export interface ReflectionGroupObject { * A list of reflection id's for this group. */ children?: number[]; + + /** + * A list of categories for this group. + */ + categories?: ReflectionCategoryObject[]; +} + +export interface ReflectionCategoryObject { + /** + * The title, a string representation of the typescript kind, of this category. + */ + title: string; + + /** + * A list of reflection id's for this category. + */ + children?: number[]; } export interface ReflectionFlagsObject { diff --git a/src/lib/serialization/index.ts b/src/lib/serialization/index.ts index 37ec1c249..e284a0f88 100644 --- a/src/lib/serialization/index.ts +++ b/src/lib/serialization/index.ts @@ -22,6 +22,7 @@ export { ParameterReflectionSerializer, ProjectReflectionSerializer, ReferenceTypeSerializer, + ReflectionCategorySerializer, ReflectionGroupSerializer, ReflectionSerializer, ReflectionTypeSerializer, diff --git a/src/lib/serialization/serializers/index.ts b/src/lib/serialization/serializers/index.ts index abd4a09df..b16cecabb 100644 --- a/src/lib/serialization/serializers/index.ts +++ b/src/lib/serialization/serializers/index.ts @@ -4,4 +4,5 @@ export * from './comments'; export * from './sources'; export * from './decorator'; export * from './reflection-group'; +export * from './reflection-category'; export * from './models'; diff --git a/src/lib/serialization/serializers/reflection-category.ts b/src/lib/serialization/serializers/reflection-category.ts new file mode 100644 index 000000000..5cc9a59e3 --- /dev/null +++ b/src/lib/serialization/serializers/reflection-category.ts @@ -0,0 +1,42 @@ +import { Component } from '../../utils/component'; +import { ReflectionCategory } from '../../models/ReflectionCategory'; + +import { SerializerComponent } from '../components'; + +@Component({name: 'serializer:reflection-category'}) +export class ReflectionCategorySerializer extends SerializerComponent { + + static PRIORITY = 1000; + + /** + * Filter for instances of [[ReflectionCategory]] + */ + serializeGroup(instance: any): boolean { + return instance instanceof ReflectionCategory; + } + + serializeGroupSymbol = ReflectionCategory; + + initialize(): void { + super.initialize(); + } + + supports(r: unknown) { + return r instanceof ReflectionCategory; + } + + toObject(category: ReflectionCategory, obj?: any): any { + obj = obj || {}; + + Object.assign(obj, { + title: category.title + }); + + if (category.children && category.children.length > 0) { + obj.children = category.children.map( child => child.id ); + } + + return obj; + } + +} diff --git a/src/lib/serialization/serializers/reflection-group.ts b/src/lib/serialization/serializers/reflection-group.ts index b9ab40a61..f52701213 100644 --- a/src/lib/serialization/serializers/reflection-group.ts +++ b/src/lib/serialization/serializers/reflection-group.ts @@ -37,6 +37,10 @@ export class ReflectionGroupSerializer extends SerializerComponent child.id ); } + if (group.categories && group.categories.length > 0) { + obj.categories = group.categories.map( category => this.owner.toObject(category) ); + } + return obj; } diff --git a/src/lib/serialization/serializers/reflections/container.ts b/src/lib/serialization/serializers/reflections/container.ts index c7caec21a..d60b695d1 100644 --- a/src/lib/serialization/serializers/reflections/container.ts +++ b/src/lib/serialization/serializers/reflections/container.ts @@ -18,6 +18,10 @@ export class ContainerReflectionSerializer extends ReflectionSerializerComponent obj.groups = container.groups.map( group => this.owner.toObject(group) ); } + if (container.categories && container.categories.length > 0) { + obj.categroies = container.categories.map( category => this.owner.toObject(category) ); + } + if (container.sources && container.sources.length > 0) { obj.sources = container.sources .map( source => this.owner From e80dee181c49e3b3868ad827e5e91cda82a43a82 Mon Sep 17 00:00:00 2001 From: Jon Hardy Date: Mon, 14 Jan 2019 15:24:34 -0500 Subject: [PATCH 4/4] Typo --- src/lib/serialization/serializers/reflections/container.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/serialization/serializers/reflections/container.ts b/src/lib/serialization/serializers/reflections/container.ts index d60b695d1..9ac6b5b34 100644 --- a/src/lib/serialization/serializers/reflections/container.ts +++ b/src/lib/serialization/serializers/reflections/container.ts @@ -19,7 +19,7 @@ export class ContainerReflectionSerializer extends ReflectionSerializerComponent } if (container.categories && container.categories.length > 0) { - obj.categroies = container.categories.map( category => this.owner.toObject(category) ); + obj.categories = container.categories.map( category => this.owner.toObject(category) ); } if (container.sources && container.sources.length > 0) {