@polymer/gen-typescript-declarations
Version:
Generate TypeScript type declarations for Polymer components.
268 lines • 7.73 kB
JavaScript
"use strict";
/**
* @license
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at
* http://polymer.github.io/LICENSE.txt The complete set of authors may be found
* at http://polymer.github.io/AUTHORS.txt The complete set of contributors may
* be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by
* Google as part of the polymer project is also subject to an additional IP
* rights grant found at http://polymer.github.io/PATENTS.txt
*/
Object.defineProperty(exports, "__esModule", { value: true });
// string, MyClass, null, undefined, any
class NameType {
constructor(name) {
this.kind = 'name';
this.name = name;
}
*traverse() {
yield this;
}
serialize() {
return this.name;
}
}
exports.NameType = NameType;
// foo|bar
class UnionType {
constructor(members) {
this.kind = 'union';
this.members = members;
}
*traverse() {
for (const m of this.members) {
yield* m.traverse();
}
yield this;
}
/**
* Simplify this union type:
*
* 1) Flatten nested unions (`foo|(bar|baz)` -> `foo|bar|baz`).
* 2) De-duplicate identical members (`foo|bar|foo` -> `foo|bar`).
*/
simplify() {
const flattened = [];
for (const m of this.members) {
if (m.kind === 'union') {
// Note we are not recursing here, because we assume we're being called
// via a depth-first walk, so any union members have already been
// simplified.
flattened.push(...m.members);
}
else {
flattened.push(m);
}
}
// TODO This only de-dupes Name types. We should de-dupe Arrays and
// Functions too.
const deduped = [];
const names = new Set();
let hasNull = false;
let hasUndefined = false;
for (const m of flattened) {
if (m.kind === 'name') {
if (m.name === 'null') {
hasNull = true;
}
else if (m.name === 'undefined') {
hasUndefined = true;
}
else if (!names.has(m.name)) {
deduped.push(m);
names.add(m.name);
}
}
else {
deduped.push(m);
}
}
// Always put `null` and `undefined` at the end because it's more readable.
// Preserve declared order for everything else.
if (hasNull) {
deduped.push(exports.nullType);
}
if (hasUndefined) {
deduped.push(exports.undefinedType);
}
this.members = deduped;
}
serialize() {
return this.members
.map((member) => {
let s = member.serialize();
if (member.kind === 'function') {
// The function syntax is ambiguous when part of a union, so add
// parens (e.g. `() => string|null` vs `(() => string)|null`).
s = '(' + s + ')';
}
return s;
})
.join('|');
}
}
exports.UnionType = UnionType;
// Array<foo>
class ArrayType {
constructor(itemType) {
this.kind = 'array';
this.itemType = itemType;
}
*traverse() {
yield* this.itemType.traverse();
yield this;
}
serialize() {
if (this.itemType.kind === 'name') {
// Use the concise `foo[]` syntax when the item type is simple.
return `${this.itemType.serialize()}[]`;
}
else {
// Otherwise use the `Array<foo>` syntax which is easier to read with
// complex types (e.g. arrays of arrays).
return `Array<${this.itemType.serialize()}>`;
}
}
}
exports.ArrayType = ArrayType;
// Foo<Bar>
class ParameterizedType {
constructor(name, itemTypes) {
this.kind = 'parameterized';
this.name = name;
this.itemTypes = itemTypes;
}
*traverse() {
for (const itemType of this.itemTypes) {
yield* itemType.traverse();
}
yield this;
}
serialize() {
const types = this.itemTypes.map((t) => t.serialize());
return `${this.name}<${types.join(', ')}>`;
}
}
exports.ParameterizedType = ParameterizedType;
// (foo: bar) => baz
class FunctionType {
constructor(params, returns) {
this.kind = 'function';
this.params = params;
this.returns = returns;
}
*traverse() {
for (const p of this.params) {
yield* p.traverse();
}
yield* this.returns.traverse();
yield this;
}
serialize() {
const params = this.params.map((param) => param.serialize());
return `(${params.join(', ')}) => ${this.returns.serialize()}`;
}
}
exports.FunctionType = FunctionType;
// {new(foo): bar}
class ConstructorType {
constructor(params, returns) {
this.kind = 'constructor';
this.params = params;
this.returns = returns;
}
*traverse() {
for (const p of this.params) {
yield* p.traverse();
}
yield* this.returns.traverse();
yield this;
}
serialize() {
const params = this.params.map((param) => param.serialize());
return `{new(${params.join(', ')}): ${this.returns.serialize()}}`;
}
}
exports.ConstructorType = ConstructorType;
// foo: bar
class ParamType {
constructor(data) {
this.kind = 'param';
this.name = data.name;
this.type = data.type || exports.anyType;
this.optional = data.optional || false;
this.rest = data.rest || false;
this.description = data.description || '';
}
*traverse() {
yield* this.type.traverse();
yield this;
}
serialize() {
let out = '';
if (this.rest) {
out += '...';
}
out += this.name;
if (this.optional) {
out += '?';
}
out += ': ' + this.type.serialize();
return out;
}
}
exports.ParamType = ParamType;
class RecordType {
constructor(fields) {
this.kind = 'record';
this.fields = fields;
}
*traverse() {
for (const f of this.fields) {
yield* f.traverse();
}
yield this;
}
serialize() {
const fields = this.fields.map((field) => field.serialize());
return `{${fields.join(', ')}}`;
}
}
exports.RecordType = RecordType;
class IntersectionType {
constructor(types) {
this.kind = 'intersection';
this.types = types;
}
*traverse() {
for (const t of this.types) {
yield* t.traverse();
}
yield this;
}
serialize() {
return this.types.map((t) => t.serialize()).join(' & ');
}
}
exports.IntersectionType = IntersectionType;
class IndexableObjectType {
constructor(keyType, valueType) {
this.kind = 'indexableObject';
this.keyType = keyType;
this.valueType = valueType;
}
*traverse() {
yield* this.keyType.traverse();
yield* this.valueType.traverse();
yield this;
}
serialize() {
return `{[key: ${this.keyType.serialize()}]: ${this.valueType.serialize()}}`;
}
}
exports.IndexableObjectType = IndexableObjectType;
exports.anyType = new NameType('any');
exports.nullType = new NameType('null');
exports.undefinedType = new NameType('undefined');
//# sourceMappingURL=types.js.map