UNPKG

3.07 kBPlain TextView Raw
1/**
2 * @license
3 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
4 * This code may only be used under the BSD style license found at
5 * http://polymer.github.io/LICENSE.txt The complete set of authors may be found
6 * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may
7 * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by
8 * Google as part of the polymer project is also subject to an additional IP
9 * rights grant found at http://polymer.github.io/PATENTS.txt
10 */
11
12import {Declaration} from './declarations';
13import {formatComment} from './formatting';
14import {Export, Node} from './index';
15
16export interface TsLintDisable {
17 ruleName: string;
18 why: string;
19}
20
21export class Document {
22 readonly kind = 'document';
23 path: string;
24 members: Declaration[];
25 referencePaths: Set<string>;
26 header: string;
27 isEsModule: boolean;
28 tsLintDisables: TsLintDisable[];
29
30 constructor(data: {
31 path: string,
32 members?: Declaration[],
33 referencePaths?: Iterable<string>,
34 header?: string,
35 isEsModule?: boolean, tsLintDisables: TsLintDisable[],
36 }) {
37 this.path = data.path;
38 this.members = data.members || [];
39 this.referencePaths = new Set(Array.from(data.referencePaths || []));
40 this.header = data.header || '';
41 this.isEsModule = data.isEsModule || false;
42 this.tsLintDisables = data.tsLintDisables;
43 }
44
45 /**
46 * Iterate over all nodes in the document, depth first. Includes all
47 * recursive ancestors, and the document itself.
48 */
49 * traverse(): Iterable<Node> {
50 for (const m of this.members) {
51 yield* m.traverse();
52 }
53 yield this;
54 }
55
56 /**
57 * Clean up this AST.
58 */
59 simplify() {
60 for (const node of this.traverse()) {
61 if (node.kind === 'union') {
62 node.simplify();
63 }
64 }
65 }
66
67 serialize(): string {
68 let out = '';
69 if (this.header) {
70 out += formatComment(this.header, 0) + '\n';
71 }
72 const disables = this.tsLintDisables.slice();
73 for (const node of this.traverse()) {
74 if (node.kind === 'name' && node.name === 'any') {
75 // TODO: replace `any` with `unknown`
76 disables.push({
77 ruleName: 'no-any',
78 why: 'describes the API as best we are able today'
79 });
80 break;
81 }
82 }
83 out += '\n';
84 for (const disable of disables) {
85 out += `// tslint:disable:${disable.ruleName} ${disable.why}\n`;
86 }
87 out += '\n';
88 if (this.referencePaths.size > 0) {
89 for (const ref of this.referencePaths) {
90 out += `/// <reference path="${ref}" />\n`;
91 }
92 out += '\n';
93 }
94 out += this.members.map((m) => m.serialize()).join('\n');
95 // If these are typings for an ES module, we want to be sure that TypeScript
96 // will treat them as one too, which requires at least one import or export.
97 if (this.isEsModule === true &&
98 !this.members.some((m) => m.kind === 'import' || m.kind === 'export')) {
99 out += '\n' + (new Export({identifiers: []})).serialize();
100 }
101 return out;
102 }
103}