Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(39)

Side by Side Diff: lib/base.ts

Issue 2225953002: Strip more unused features. (Closed) Base URL: git@github.com:dart-lang/js_facade_gen.git@master
Patch Set: Fix types Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gulpfile.js ('k') | lib/call.ts » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 import * as dartStyle from 'dart-style';
1 import * as ts from 'typescript'; 2 import * as ts from 'typescript';
2 import {Transpiler} from './main'; 3
4 import {OutputContext, Transpiler} from './main';
3 5
4 export type ClassLike = ts.ClassDeclaration | ts.InterfaceDeclaration; 6 export type ClassLike = ts.ClassDeclaration | ts.InterfaceDeclaration;
7 export type NamedDeclaration = ClassLike | ts.PropertyDeclaration | ts.VariableD eclaration |
8 ts.MethodDeclaration | ts.ModuleDeclaration | ts.FunctionDeclaration;
9
10 export type Set = {
11 [s: string]: boolean
12 };
5 13
6 export function ident(n: ts.Node): string { 14 export function ident(n: ts.Node): string {
7 if (n.kind === ts.SyntaxKind.Identifier) return (<ts.Identifier>n).text; 15 if (n.kind === ts.SyntaxKind.Identifier) return (<ts.Identifier>n).text;
8 if (n.kind === ts.SyntaxKind.QualifiedName) { 16 if (n.kind === ts.SyntaxKind.QualifiedName) {
9 let qname = (<ts.QualifiedName>n); 17 let qname = (<ts.QualifiedName>n);
10 let leftName = ident(qname.left); 18 let leftName = ident(qname.left);
11 if (leftName) return leftName + '.' + ident(qname.right); 19 if (leftName) return leftName + '.' + ident(qname.right);
12 } 20 }
13 return null; 21 return null;
14 } 22 }
15 23
24 export function isFunctionTypedefLikeInterface(ifDecl: ts.InterfaceDeclaration): boolean {
25 return ifDecl.members && ifDecl.members.length === 1 &&
26 ifDecl.members[0].kind === ts.SyntaxKind.CallSignature;
27 }
28
29 export function getDeclaration(type: ts.Type): ts.Declaration {
30 let symbol = type.getSymbol();
31 if (!symbol) return null;
32 if (symbol.valueDeclaration) return symbol.valueDeclaration;
33 return symbol.declarations && symbol.declarations.length > 0 ? symbol.declarat ions[0] : null;
34 }
35
36 export function isExtendsClause(heritageClause: ts.HeritageClause) {
37 return heritageClause.token === ts.SyntaxKind.ExtendsKeyword &&
38 heritageClause.parent.kind !== ts.SyntaxKind.InterfaceDeclaration;
39 }
40 export function isConstructor(n: ts.Node): boolean {
41 return n.kind === ts.SyntaxKind.Constructor || n.kind === ts.SyntaxKind.Constr uctSignature;
42 }
43
44 export function isStatic(n: ts.Node): boolean {
45 let hasStatic = false;
46 ts.forEachChild(n, (child) => {
47 if (child.kind === ts.SyntaxKind.StaticKeyword) {
48 hasStatic = true;
49 }
50 });
51 return hasStatic;
52 }
53
54 export function isCallableType(type: ts.TypeNode, tc: ts.TypeChecker): boolean {
55 if (isFunctionType(type, tc)) return true;
56 if (type.kind === ts.SyntaxKind.TypeReference) {
57 if (tc.getSignaturesOfType(tc.getTypeAtLocation(type), ts.SignatureKind.Call ).length > 0)
58 return true;
59 }
60 return false;
61 }
62
63 export function isFunctionType(type: ts.TypeNode, tc: ts.TypeChecker): boolean {
64 let kind = type.kind;
65 if (kind === ts.SyntaxKind.FunctionType) return true;
66 if (kind === ts.SyntaxKind.TypeReference) {
67 let t = tc.getTypeAtLocation(type);
68 if (t.symbol && t.symbol.flags & ts.SymbolFlags.Function) return true;
69 }
70
71 if (kind === ts.SyntaxKind.UnionType) {
72 let types = (<ts.UnionTypeNode>type).types;
73 for (let i = 0; i < types.length; ++i) {
74 if (!isFunctionType(types[i], tc)) {
75 return false;
76 }
77 }
78 return true;
79 }
80 // Warning: if the kind is a reference type and the reference is to an
81 // interface that only has a call member we will not return that it is a
82 // function type.
83 if (kind === ts.SyntaxKind.TypeLiteral) {
84 let members = (<ts.TypeLiteralNode>type).members;
85 for (let i = 0; i < members.length; ++i) {
86 if (members[i].kind !== ts.SyntaxKind.CallSignature) {
87 return false;
88 }
89 }
90 return true;
91 }
92 return false;
93 }
94
95 export function isTypeNode(node: ts.Node): boolean {
96 switch (node.kind) {
97 case ts.SyntaxKind.UnionType:
98 case ts.SyntaxKind.TypeReference:
99 case ts.SyntaxKind.TypeLiteral:
100 case ts.SyntaxKind.LastTypeNode:
101 case ts.SyntaxKind.ArrayType:
102 case ts.SyntaxKind.TypePredicate:
103 case ts.SyntaxKind.TypeQuery:
104 case ts.SyntaxKind.TupleType:
105 case ts.SyntaxKind.NumberKeyword:
106 case ts.SyntaxKind.StringKeyword:
107 case ts.SyntaxKind.VoidKeyword:
108 case ts.SyntaxKind.BooleanKeyword:
109 case ts.SyntaxKind.AnyKeyword:
110 case ts.SyntaxKind.FunctionType:
111 return true;
112 default:
113 return false;
114 }
115 }
116
117 export function isCallable(decl: ClassLike): boolean {
118 let members = decl.members as Array<ts.ClassElement>;
119 return members.some((member) => { return member.kind === ts.SyntaxKind.CallSig nature; });
120 }
121
122 export function copyLocation(src: ts.TextRange, dest: ts.TextRange) {
123 dest.pos = src.pos;
124 dest.end = src.end;
125 }
126
127 // Polyfill for ES6 Array.find.
128 export function arrayFindPolyfill<T>(
129 nodeArray: ts.NodeArray<T>, predicate: (node: T) => boolean): T {
130 for (let i = 0; i < nodeArray.length; ++i) {
131 if (predicate(nodeArray[i])) return nodeArray[i];
132 }
133 return null;
134 }
135
136 export function getAncestor(n: ts.Node, kind: ts.SyntaxKind): ts.Node {
137 for (let parent = n; parent; parent = parent.parent) {
138 if (parent.kind === kind) return parent;
139 }
140 return null;
141 }
142
143 export function getEnclosingClass(n: ts.Node): ClassLike {
144 for (let parent = n.parent; parent; parent = parent.parent) {
145 if (parent.kind === ts.SyntaxKind.ClassDeclaration ||
146 parent.kind === ts.SyntaxKind.InterfaceDeclaration) {
147 return <ClassLike>parent;
148 }
149 }
150 return null;
151 }
152
153 export function isConstCall(node: ts.CallExpression): boolean {
154 return node && ident(node.expression) === 'CONST_EXPR';
155 }
156
157 export function isInsideConstExpr(node: ts.Node): boolean {
158 return isConstCall(<ts.CallExpression>getAncestor(node, ts.SyntaxKind.CallExpr ession));
159 }
160
161 export function formatType(s: string, comment: string, insideCodeComment: boolea n): string {
162 if (!comment) {
163 return s;
164 } else if (insideCodeComment) {
165 // When inside a comment we only need to emit the comment version which
166 // is the syntax we would like to use if Dart supported all language
167 // features we would like to use for interop.
168 return comment;
169 } else {
170 let sb = s + '/*';
171 // Check if the comment is a valid type name in which case it is safe to use the Dart code
172 // written in comments syntax.
173 const stubToMakeTypeValidStatement = ' DUMMY_VARIABLE_NAME;';
174 comment = comment.trim();
175 let statement = comment + stubToMakeTypeValidStatement;
176 let result = dartStyle.formatCode(statement);
177
178 if (!result.error) {
179 result.code = result.code.trim();
180 let expectedStubIndex = result.code.length - stubToMakeTypeValidStatement. length;
181 if (result.code.lastIndexOf(stubToMakeTypeValidStatement) === expectedStub Index) {
182 comment = result.code.substring(0, expectedStubIndex).trim();
183 sb += '=';
184 }
185 }
186 sb += comment;
187 sb += '*/';
188 return sb;
189 }
190 }
191
16 export class TranspilerBase { 192 export class TranspilerBase {
17 private idCounter: number = 0; 193 private idCounter: number = 0;
18 constructor(private transpiler: Transpiler) {} 194 constructor(protected transpiler: Transpiler) {}
19 195
20 visit(n: ts.Node) { this.transpiler.visit(n); } 196 visit(n: ts.Node) { this.transpiler.visit(n); }
197 pushContext(context: OutputContext) { this.transpiler.pushContext(context); }
198 popContext() { this.transpiler.popContext(); }
21 emit(s: string) { this.transpiler.emit(s); } 199 emit(s: string) { this.transpiler.emit(s); }
22 emitNoSpace(s: string) { this.transpiler.emitNoSpace(s); } 200 emitNoSpace(s: string) { this.transpiler.emitNoSpace(s); }
201 emitType(s: string, comment: string) { this.transpiler.emitType(s, comment); }
202 maybeLineBreak() { return this.transpiler.maybeLineBreak(); }
203 enterCodeComment() { return this.transpiler.enterCodeComment(); }
204 exitCodeComment() { return this.transpiler.exitCodeComment(); }
205 get insideCodeComment() { return this.transpiler.insideCodeComment; }
206
207 emitImport(toEmit: string) {
208 if (!this.transpiler.importsEmitted[toEmit]) {
209 this.pushContext(OutputContext.Import);
210 this.emit(`import "${toEmit}";`);
211 this.transpiler.importsEmitted[toEmit] = true;
212 this.popContext();
213 }
214 }
215
23 reportError(n: ts.Node, message: string) { this.transpiler.reportError(n, mess age); } 216 reportError(n: ts.Node, message: string) { this.transpiler.reportError(n, mess age); }
24 217
25 visitNode(n: ts.Node): boolean { throw new Error('not implemented'); } 218 visitNode(n: ts.Node): boolean { throw new Error('not implemented'); }
26 219
27 visitEach(nodes: ts.Node[]) { nodes.forEach((n) => this.visit(n)); } 220 visitEach(nodes: ts.Node[]) { nodes.forEach((n) => this.visit(n)); }
28 221
29 visitEachIfPresent(nodes?: ts.Node[]) { 222 visitEachIfPresent(nodes?: ts.Node[]) {
30 if (nodes) this.visitEach(nodes); 223 if (nodes) this.visitEach(nodes);
31 } 224 }
32 225
33 visitList(nodes: ts.Node[], separator = ',') { 226 visitList(nodes: ts.Node[], separator = ',') {
34 for (let i = 0; i < nodes.length; i++) { 227 for (let i = 0; i < nodes.length; i++) {
35 this.visit(nodes[i]); 228 this.visit(nodes[i]);
36 if (i < nodes.length - 1) this.emit(separator); 229 if (i < nodes.length - 1) this.emitNoSpace(separator);
37 } 230 }
38 } 231 }
39 232
40 uniqueId(name: string): string { 233 uniqueId(name: string): string {
41 const id = this.idCounter++; 234 const id = this.idCounter++;
42 return `_${name}\$\$ts2dart\$${id}`; 235 return `_${name}\$\$js_facade_gen\$${id}`;
43 } 236 }
44 237
45 assert(c: ts.Node, condition: boolean, reason: string): void { 238 assert(c: ts.Node, condition: boolean, reason: string): void {
46 if (!condition) { 239 if (!condition) {
47 this.reportError(c, reason); 240 this.reportError(c, reason);
48 throw new Error(reason); 241 throw new Error(reason);
49 } 242 }
50 } 243 }
51 244
52 getAncestor(n: ts.Node, kind: ts.SyntaxKind): ts.Node { 245 getAncestor(n: ts.Node, kind: ts.SyntaxKind): ts.Node {
53 for (let parent = n; parent; parent = parent.parent) { 246 for (let parent = n; parent; parent = parent.parent) {
54 if (parent.kind === kind) return parent; 247 if (parent.kind === kind) return parent;
55 } 248 }
56 return null; 249 return null;
57 } 250 }
58 251
59 hasAncestor(n: ts.Node, kind: ts.SyntaxKind): boolean { return !!this.getAnces tor(n, kind); } 252 hasAncestor(n: ts.Node, kind: ts.SyntaxKind): boolean { return !!getAncestor(n , kind); }
60 253
61 hasAnnotation(decorators: ts.NodeArray<ts.Decorator>, name: string): boolean { 254 hasAnnotation(decorators: ts.NodeArray<ts.Decorator>, name: string): boolean {
62 if (!decorators) return false; 255 if (!decorators) return false;
63 return decorators.some((d) => { 256 return decorators.some((d) => {
64 let decName = ident(d.expression); 257 let decName = ident(d.expression);
65 if (decName === name) return true; 258 if (decName === name) return true;
66 if (d.expression.kind !== ts.SyntaxKind.CallExpression) return false; 259 if (d.expression.kind !== ts.SyntaxKind.CallExpression) return false;
67 let callExpr = (<ts.CallExpression>d.expression); 260 let callExpr = (<ts.CallExpression>d.expression);
68 decName = ident(callExpr.expression); 261 decName = ident(callExpr.expression);
69 return decName === name; 262 return decName === name;
70 }); 263 });
71 } 264 }
72 265
73 hasFlag(n: {flags: number}, flag: ts.NodeFlags): boolean { 266 hasFlag(n: {flags: number}, flag: ts.NodeFlags): boolean {
74 return n && (n.flags & flag) !== 0 || false; 267 return n && (n.flags & flag) !== 0 || false;
75 } 268 }
76 269
77 isConst(decl: ClassLike) {
78 return this.hasAnnotation(decl.decorators, 'CONST') ||
79 (<ts.NodeArray<ts.Declaration>>decl.members).some((m) => {
80 if (m.kind !== ts.SyntaxKind.Constructor) return false;
81 return this.hasAnnotation(m.decorators, 'CONST');
82 });
83 }
84
85 maybeDestructureIndexType(node: ts.TypeLiteralNode): [ts.TypeNode, ts.TypeNode ] {
86 let members = node.members;
87 if (members.length !== 1 || members[0].kind !== ts.SyntaxKind.IndexSignature ) {
88 return null;
89 }
90 let indexSig = <ts.IndexSignatureDeclaration>(members[0]);
91 if (indexSig.parameters.length > 1) {
92 this.reportError(indexSig, 'Expected an index signature to have a single p arameter');
93 }
94 return [indexSig.parameters[0].type, indexSig.type];
95 }
96
97
98 getRelativeFileName(fileName: string): string { 270 getRelativeFileName(fileName: string): string {
99 return this.transpiler.getRelativeFileName(fileName); 271 return this.transpiler.getRelativeFileName(fileName);
100 } 272 }
101 273
102 maybeVisitTypeArguments(n: {typeArguments?: ts.NodeArray<ts.TypeNode>}) { 274 maybeVisitTypeArguments(n: {typeArguments?: ts.NodeArray<ts.TypeNode>}) {
103 if (n.typeArguments) { 275 if (n.typeArguments) {
104 // If it's a single type argument `<void>`, ignore it and emit nothing. 276 // If it's a single type argument `<void>`, ignore it and emit nothing.
105 // This is particularly useful for `Promise<void>`, see 277 // This is particularly useful for `Promise<void>`, see
106 // https://github.com/dart-lang/sdk/issues/2231#issuecomment-108313639 278 // https://github.com/dart-lang/sdk/issues/2231#issuecomment-108313639
107 if (n.typeArguments.length === 1 && n.typeArguments[0].kind === ts.SyntaxK ind.VoidKeyword) { 279 if (n.typeArguments.length === 1 && n.typeArguments[0].kind === ts.SyntaxK ind.VoidKeyword) {
108 return; 280 return;
109 } 281 }
110 this.emitNoSpace('<'); 282 this.emitNoSpace('<');
111 this.visitList(n.typeArguments); 283 this.visitList(n.typeArguments);
112 this.emit('>'); 284 this.emitNoSpace('>');
113 } 285 }
114 } 286 }
287
288 visitParameters(parameters: ts.ParameterDeclaration[]) {
289 this.emitNoSpace('(');
290 let firstInitParamIdx = 0;
291 for (; firstInitParamIdx < parameters.length; firstInitParamIdx++) {
292 // ObjectBindingPatterns are handled within the parameter visit.
293 let isOpt = parameters[firstInitParamIdx].initializer ||
294 parameters[firstInitParamIdx].questionToken ||
295 parameters[firstInitParamIdx].dotDotDotToken;
296 if (isOpt && parameters[firstInitParamIdx].name.kind !== ts.SyntaxKind.Obj ectBindingPattern) {
297 break;
298 }
299 }
300
301 if (firstInitParamIdx !== 0) {
302 let requiredParams = parameters.slice(0, firstInitParamIdx);
303 this.visitList(requiredParams);
304 }
305
306 if (firstInitParamIdx !== parameters.length) {
307 if (firstInitParamIdx !== 0) this.emitNoSpace(',');
308 let positionalOptional = parameters.slice(firstInitParamIdx, parameters.le ngth);
309 this.emit('[');
310 this.visitList(positionalOptional);
311 this.emitNoSpace(']');
312 }
313
314 this.emitNoSpace(')');
315 }
115 } 316 }
OLDNEW
« no previous file with comments | « gulpfile.js ('k') | lib/call.ts » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698