in pxtcompiler/emitter/service.ts [135:303]
function createSymbolInfo(typechecker: TypeChecker, qName: string, stmt: Node): SymbolInfo {
function typeOf(tn: TypeNode, n: Node, stripParams = false): string {
let t = typechecker.getTypeAtLocation(n)
if (!t) return "None"
if (stripParams) {
t = t.getCallSignatures()[0].getReturnType()
}
const readableName = typechecker.typeToString(t, undefined, TypeFormatFlags.UseFullyQualifiedType)
// TypeScript 2.0.0+ will assign constant variables numeric literal types which breaks the
// type checking we do in the blocks
// This can be a number literal '7' or a union type of them '0 | 1 | 2'
if (/^\d/.test(readableName)) {
return "number";
}
if (readableName == "this") {
return getFullName(typechecker, t.symbol);
}
return readableName;
}
let kind = getSymbolKind(stmt)
if (kind != SymbolKind.None) {
let decl: FunctionLikeDeclaration = stmt as any;
let attributes = parseComments(decl)
if (attributes.weight < 0)
return null;
let m = /^(.*)\.(.*)/.exec(qName)
let hasParams = kind == SymbolKind.Function || kind == SymbolKind.Method
let pkg: string = null
let pkgs: string[] = null
let src = getSourceFileOfNode(stmt)
if (src) {
let m = /^pxt_modules\/([^\/]+)/.exec(src.fileName)
if (m)
pkg = m[1]
}
let extendsTypes: string[] = undefined
if (kind == SymbolKind.Class || kind == SymbolKind.Interface) {
let cl = stmt as ClassLikeDeclaration
extendsTypes = []
if (cl.heritageClauses)
for (let h of cl.heritageClauses) {
if (h.types) {
for (let t of h.types) {
extendsTypes.push(typeOf(t, t))
}
}
}
}
if (kind == SymbolKind.Enum || kind === SymbolKind.EnumMember) {
(extendsTypes || (extendsTypes = [])).push("Number");
}
let r: SymbolInfo = {
kind,
qName,
namespace: m ? m[1] : "",
name: m ? m[2] : qName,
fileName: stmt.getSourceFile().fileName,
attributes,
pkg,
pkgs,
extendsTypes,
retType:
stmt.kind == SyntaxKind.Constructor ? "void" :
kind == SymbolKind.Module ? "" :
typeOf(decl.type, decl, hasParams),
parameters: !hasParams ? null : Util.toArray(decl.parameters).map((p, i) => {
let n = getName(p)
let desc = attributes.paramHelp[n] || ""
let minVal = attributes.paramMin && attributes.paramMin[n];
let maxVal = attributes.paramMax && attributes.paramMax[n];
let m = /\beg\.?:\s*(.+)/.exec(desc)
let props: PropertyDesc[];
let parameters: PropertyDesc[];
if (p.type && p.type.kind === SK.FunctionType) {
const callBackSignature = typechecker.getSignatureFromDeclaration(p.type as FunctionTypeNode);
const callbackParameters = callBackSignature.getParameters();
if (attributes.mutate === "objectdestructuring") {
assert(callbackParameters.length > 0);
props = typechecker.getTypeAtLocation(callbackParameters[0].valueDeclaration).getProperties().map(prop => {
return { name: prop.getName(), type: typechecker.typeToString(typechecker.getTypeOfSymbolAtLocation(prop, callbackParameters[0].valueDeclaration)) }
});
}
else {
parameters = callbackParameters.map((sym, i) => {
return {
name: sym.getName(),
type: typechecker.typeToString(typechecker.getTypeOfSymbolAtLocation(sym, p), undefined, TypeFormatFlags.UseFullyQualifiedType)
};
});
}
}
let options: pxt.Map<PropertyOption> = {};
const paramType = typechecker.getTypeAtLocation(p);
let isEnum = paramType && !!(paramType.flags & (TypeFlags.Enum | TypeFlags.EnumLiteral));
if (attributes.block && attributes.paramShadowOptions) {
const argNames: string[] = []
attributes.block.replace(/%(\w+)/g, (f, n) => {
argNames.push(n)
return ""
});
if (attributes.paramShadowOptions[argNames[i]]) {
options['fieldEditorOptions'] = { value: attributes.paramShadowOptions[argNames[i]] }
}
}
if (minVal) options['min'] = { value: minVal };
if (maxVal) options['max'] = { value: maxVal };
const pyTypeString = (p.type && emitPyTypeFromTypeNode(p.type))
|| (paramType && emitPyTypeFromTsType(paramType))
|| "unknown";
const initializer = p.initializer ? p.initializer.getText() :
getExplicitDefault(attributes, n) ||
(p.questionToken ? "undefined" : undefined)
return {
name: n,
description: desc,
type: typeOf(p.type, p),
pyTypeString,
initializer,
default: attributes.paramDefl[n],
properties: props,
handlerParameters: parameters,
options: options,
isEnum
}
}),
snippet: ts.isFunctionLike(stmt) ? null : undefined
}
switch (r.kind) {
case SymbolKind.EnumMember:
r.pyName = U.snakify(r.name).toUpperCase()
break
case SymbolKind.Variable:
case SymbolKind.Method:
case SymbolKind.Property:
case SymbolKind.Function:
r.pyName = U.snakify(r.name)
break
case SymbolKind.Enum:
case SymbolKind.Class:
case SymbolKind.Interface:
case SymbolKind.Module:
default:
r.pyName = r.name
break
}
if (stmt.kind === SK.GetAccessor ||
((stmt.kind === SK.PropertyDeclaration || stmt.kind === SK.PropertySignature) && isReadonly(stmt as Declaration))) {
r.isReadOnly = true
}
return r
}
return null;
}