Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

Commit

Permalink
[complete-doc]: add support for constuctor doc (#4861)
Browse files Browse the repository at this point in the history
* [complete-doc]: add support for constuctor doc

* [complete-docs]: add test for protected constructor, fix class name
  • Loading branch information
tanmoyopenroot authored and Josh Goldberg committed Oct 10, 2019
1 parent bfaf3e2 commit e493270
Show file tree
Hide file tree
Showing 11 changed files with 358 additions and 7 deletions.
53 changes: 53 additions & 0 deletions src/rules/completed-docs/constructorExclusion.ts
@@ -0,0 +1,53 @@
/**
* @license
* Copyright 2019 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { hasModifier } from "tsutils";
import * as ts from "typescript";

import {
ALL,
Privacy,
PRIVACY_PRIVATE,
PRIVACY_PROTECTED,
PRIVACY_PUBLIC,
} from "../completedDocsRule";

import { Exclusion } from "./exclusion";

export interface IConstructorExclusionDescriptor {
privacies?: Privacy[];
}

export class ConstructorExclusion extends Exclusion<IConstructorExclusionDescriptor> {
public readonly privacies: Set<Privacy> = this.createSet(this.descriptor.privacies);

public excludes(node: ts.Node) {
if (this.privacies.has(ALL)) {
return false;
}

if (hasModifier(node.modifiers, ts.SyntaxKind.PrivateKeyword)) {
return !this.privacies.has(PRIVACY_PRIVATE);
}

if (hasModifier(node.modifiers, ts.SyntaxKind.ProtectedKeyword)) {
return !this.privacies.has(PRIVACY_PROTECTED);
}

return !this.privacies.has(PRIVACY_PUBLIC);
}
}
17 changes: 13 additions & 4 deletions src/rules/completed-docs/exclusions.ts
Expand Up @@ -19,6 +19,7 @@ import { DESCRIPTOR_OVERLOADS, DocType } from "../completedDocsRule";

import { BlockExclusion, IBlockExclusionDescriptor } from "./blockExclusion";
import { ClassExclusion, IClassExclusionDescriptor } from "./classExclusion";
import { ConstructorExclusion, IConstructorExclusionDescriptor } from "./constructorExclusion";
import { Exclusion } from "./exclusion";
import { IInputExclusionDescriptors, InputExclusionDescriptor } from "./exclusionDescriptors";
import { ITagExclusionDescriptor, TagExclusion } from "./tagExclusion";
Expand Down Expand Up @@ -64,10 +65,18 @@ const createRequirementsForDocType = (docType: DocType, descriptor: InputExclusi
overloadsSeparateDocs = !!(descriptor as any)[DESCRIPTOR_OVERLOADS];
}

if (docType === "methods" || docType === "properties") {
requirements.push(new ClassExclusion(descriptor as IClassExclusionDescriptor));
} else {
requirements.push(new BlockExclusion(descriptor as IBlockExclusionDescriptor));
switch (docType) {
case "constructors":
requirements.push(
new ConstructorExclusion(descriptor as IConstructorExclusionDescriptor),
);
break;
case "methods":
case "properties":
requirements.push(new ClassExclusion(descriptor as IClassExclusionDescriptor));
break;
default:
requirements.push(new BlockExclusion(descriptor as IBlockExclusionDescriptor));
}

if ((descriptor as ITagExclusionDescriptor).tags !== undefined) {
Expand Down
54 changes: 51 additions & 3 deletions src/rules/completedDocsRule.ts
Expand Up @@ -26,6 +26,7 @@ import { constructExclusionsMap, ExclusionsMap } from "./completed-docs/exclusio
export const ALL = "all";

export const ARGUMENT_CLASSES = "classes";
export const ARGUMENT_CONSTRUCTORS = "constructors";
export const ARGUMENT_ENUMS = "enums";
export const ARGUMENT_ENUM_MEMBERS = "enum-members";
export const ARGUMENT_FUNCTIONS = "functions";
Expand Down Expand Up @@ -60,6 +61,7 @@ export type All = typeof ALL;
export type DocType =
| All
| typeof ARGUMENT_CLASSES
| typeof ARGUMENT_CONSTRUCTORS
| typeof ARGUMENT_ENUMS
| typeof ARGUMENT_ENUM_MEMBERS
| typeof ARGUMENT_FUNCTIONS
Expand Down Expand Up @@ -160,6 +162,35 @@ export class Rule extends Lint.Rules.AbstractRule {
type: "object",
};

public static ARGUMENT_DESCRIPTOR_CONSTRUCTOR = {
properties: {
[DESCRIPTOR_TAGS]: {
properties: {
[TAGS_FOR_CONTENT]: {
items: {
type: "string",
},
type: "object",
},
[TAGS_FOR_EXISTENCE]: {
items: {
type: "string",
},
type: "array",
},
},
},
[DESCRIPTOR_PRIVACIES]: {
enum: [ALL, PRIVACY_PRIVATE, PRIVACY_PROTECTED, PRIVACY_PUBLIC],
type: "string",
},
[DESCRIPTOR_OVERLOADS]: {
type: "boolean",
},
},
type: "object",
};

public static ARGUMENT_DESCRIPTOR_FUNCTION = {
properties: {
...Rule.ARGUMENT_DESCRIPTOR_BLOCK.properties,
Expand Down Expand Up @@ -214,6 +245,7 @@ export class Rule extends Lint.Rules.AbstractRule {
Types that may be enabled are:
* \`"${ARGUMENT_CLASSES}"\`
* \`"${ARGUMENT_CONSTRUCTORS}"\`
* \`"${ARGUMENT_ENUMS}"\`
* \`"${ARGUMENT_ENUM_MEMBERS}"\`
* \`"${ARGUMENT_FUNCTIONS}"\`
Expand Down Expand Up @@ -245,6 +277,7 @@ export class Rule extends Lint.Rules.AbstractRule {
type: "object",
properties: {
[ARGUMENT_CLASSES]: Rule.ARGUMENT_DESCRIPTOR_BLOCK,
[ARGUMENT_CONSTRUCTORS]: Rule.ARGUMENT_DESCRIPTOR_CONSTRUCTOR,
[ARGUMENT_ENUMS]: Rule.ARGUMENT_DESCRIPTOR_BLOCK,
[ARGUMENT_ENUM_MEMBERS]: Rule.ARGUMENT_DESCRIPTOR_BLOCK,
[ARGUMENT_FUNCTIONS]: Rule.ARGUMENT_DESCRIPTOR_FUNCTION,
Expand Down Expand Up @@ -326,6 +359,10 @@ function walk(context: Lint.WalkContext<ExclusionsMap>) {
checkNode(node as ts.ClassDeclaration, ARGUMENT_CLASSES);
break;

case ts.SyntaxKind.Constructor:
checkNode(node as ts.ClassDeclaration, ARGUMENT_CONSTRUCTORS);
break;

case ts.SyntaxKind.EnumDeclaration:
checkNode(node as ts.EnumDeclaration, ARGUMENT_ENUMS);
for (const member of (node as ts.EnumDeclaration).members) {
Expand Down Expand Up @@ -419,9 +456,12 @@ function walk(context: Lint.WalkContext<ExclusionsMap>) {
docType: DocType,
requirementNode: ts.Node,
): boolean {
const { name } = node;
if (name === undefined) {
return true;
if (docType !== ARGUMENT_CONSTRUCTORS) {
const { name } = node;

if (name === undefined) {
return true;
}
}

const exclusions = context.options.get(docType);
Expand Down Expand Up @@ -499,6 +539,14 @@ function walk(context: Lint.WalkContext<ExclusionsMap>) {
);
}

if (tsutils.isConstructorDeclaration(node)) {
const {
parent: { members },
} = node;

return members.filter(child => tsutils.isConstructorDeclaration(child));
}

if (
tsutils.isMethodDeclaration(node) &&
tsutils.isIdentifier(node.name) &&
Expand Down
@@ -0,0 +1,31 @@
class Foo {
constructor(i: number);

/**
* Exists in one place
*/
constructor(o: any) {}
}

class FooPublic {
public constructor(i: number);

/**
* Exists in one place
*/
public constructor(o: any) {}
}

class FooPrivate {
private constructor(i: number);

/**
* Exists in one place
*/
private constructor(o: any) {}
}

class FooProtected {
protected constructor(i: number);
protected constructor(o: any) {}
}
@@ -0,0 +1,9 @@
{
"rules": {
"completed-docs": [true, {
"constructors": {
"privacies": ["public", "private"]
}
}]
}
}
40 changes: 40 additions & 0 deletions test/rules/completed-docs/constructors/overloads/true/test.ts.lint
@@ -0,0 +1,40 @@
class Foo {
constructor(i: number);
~~~~~~~~~~~~~~~~~~~~~~~ [default]
/**
* Exists in one place
*/
constructor(o: any) {}
}

class FooPublic {
public constructor(i: number);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [public]
/**
* Exists in one place
*/
public constructor(o: any) {}
}

class FooPrivate {
private constructor(i: number);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [private]
/**
* Exists in one place
*/
private constructor(o: any) {}
}

class FooProtected {
protected constructor(i: number);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [protected]
/**
* Exists in one place
*/
protected constructor(o: any) {}
}

[default]: Documentation must exist for constructors.
[public]: Documentation must exist for public constructors.
[private]: Documentation must exist for private constructors.
[protected]: Documentation must exist for protected constructors.
10 changes: 10 additions & 0 deletions test/rules/completed-docs/constructors/overloads/true/tslint.json
@@ -0,0 +1,10 @@
{
"rules": {
"completed-docs": [true, {
"constructors": {
"overloads": true,
"privacies": ["public", "protected", "private"]
}
}]
}
}
99 changes: 99 additions & 0 deletions test/rules/completed-docs/constructors/privacies/test.ts.lint
@@ -0,0 +1,99 @@
class Foo {
constructor() {}
~~~~~~~~~~~~~~~~ [default]
}

class Foo {
public constructor() {}
~~~~~~~~~~~~~~~~~~~~~~~ [public]
}

class Foo {
private constructor() {}
~~~~~~~~~~~~~~~~~~~~~~~~ [private]
}

class Foo {
protected constructor() {}
}

class Foo {
/** ... */
constructor() {}
}

class Foo {
/** content */
constructor() {}
}

class Foo {
/** */
constructor() {}
~~~~~~~~~~~~~~~~ [default]
}

class Foo {
/** ... */
public constructor() {}
}

class Foo {
/** content */
public constructor() {}
}

class Foo {
/** */
public constructor() {}
~~~~~~~~~~~~~~~~~~~~~~~ [public]
}

class Foo {
/** ... */
private constructor() {}
}

class Foo {
/** content */
private constructor() {}
}

class Foo {
/** */
private constructor() {}
~~~~~~~~~~~~~~~~~~~~~~~~ [private]
}


class Foo {
/**
* ...
*/
constructor() {}
}

class Foo {
/**
* ...
*/
public constructor() {}
}

class Foo {
/**
* ...
*/
private constructor() {}
}

class Foo {
/**
* ...
*/
protected constructor() {}
}

[default]: Documentation must exist for constructors.
[public]: Documentation must exist for public constructors.
[private]: Documentation must exist for private constructors.
9 changes: 9 additions & 0 deletions test/rules/completed-docs/constructors/privacies/tslint.json
@@ -0,0 +1,9 @@
{
"rules": {
"completed-docs": [true, {
"constructors": {
"privacies": ["public", "private"]
}
}]
}
}

0 comments on commit e493270

Please sign in to comment.