mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-15 02:41:30 -05:00
Cleanup of processTypes script and various transformations. Added JSX
This commit is contained in:
555
scripts/processTypes/discovery.ts
Normal file
555
scripts/processTypes/discovery.ts
Normal file
@@ -0,0 +1,555 @@
|
||||
import { SyntaxKind, Symbol, SymbolFlags, Map, } from "./typescript-internal";
|
||||
import { hasProperty, getProperty } from "./utilities";
|
||||
import { getType, getTypes, makeArrayType, resolveQualifiedName, annotation, EnumValue, Annotation, TypeInfo, PropertyInfo } from "./types";
|
||||
|
||||
export interface DiscoveryResult {
|
||||
createableNodes: SyntaxNode[];
|
||||
updateableNodes: SyntaxNode[];
|
||||
testableNodes: SyntaxNode[];
|
||||
testableTypes: SyntaxType[];
|
||||
}
|
||||
|
||||
export interface SyntaxType {
|
||||
type: TypeInfo;
|
||||
typeName: string;
|
||||
superTypes: SyntaxType[];
|
||||
directSyntaxNodes: SyntaxNode[];
|
||||
syntaxNodes?: SyntaxNode[];
|
||||
testFunctionName?: string;
|
||||
}
|
||||
|
||||
export interface SyntaxNode {
|
||||
kind: SyntaxKind;
|
||||
kindName: string;
|
||||
typeName: string;
|
||||
createFunctionName: string;
|
||||
createParameters: SyntaxMember[];
|
||||
updateFunctionName: string;
|
||||
updateParameters: SyntaxMember[];
|
||||
testFunctionName: string;
|
||||
}
|
||||
|
||||
export interface SyntaxMember {
|
||||
propertyName?: string;
|
||||
parameterName?: string;
|
||||
parameterTypeName: string;
|
||||
isFactoryParameter?: boolean;
|
||||
isNodeArray?: boolean;
|
||||
isModifiersArray?: boolean;
|
||||
testFunctionName?: string;
|
||||
visitorFunctionName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers type information and symbols for various SyntaxNodes
|
||||
*/
|
||||
export function discover(): DiscoveryResult {
|
||||
const typesReferencedByProperties: boolean[] = [];
|
||||
const syntaxTypeForTypeInfo: SyntaxType[] = [];
|
||||
const createableNodes: SyntaxNode[] = [];
|
||||
const updateableNodes: SyntaxNode[] = [];
|
||||
const testableNodes: SyntaxNode[] = [];
|
||||
const syntaxTypes: SyntaxType[] = [];
|
||||
const testableTypes: SyntaxType[] = [];
|
||||
const localNames: Map<string> = {};
|
||||
|
||||
let types = getTypes("ts");
|
||||
let nodeType = getType("ts.Node");
|
||||
let modifierType = getType("ts.Modifier");
|
||||
let statementType = getType("ts.Statement");
|
||||
let conciseBodyType = getType("ts.ConciseBody");
|
||||
let functionBodyType = getType("ts.FunctionBody");
|
||||
let moduleBodyType = getType("ts.ModuleBody");
|
||||
let sourceFileType = getType("ts.SourceFile");
|
||||
let nodeArrayType = getType("ts.NodeArray");
|
||||
let modifiersArrayType = getType("ts.ModifiersArray");
|
||||
|
||||
for (let type of types) {
|
||||
discoverType(type);
|
||||
}
|
||||
|
||||
for (let type of syntaxTypes) {
|
||||
discoverTestableType(type);
|
||||
}
|
||||
|
||||
createableNodes.sort((a, b) => a.kind - b.kind);
|
||||
updateableNodes.sort((a, b) => a.kind - b.kind);
|
||||
testableNodes.sort((a, b) => a.kind - b.kind);
|
||||
testableTypes.sort((a, b) => a.toString().localeCompare(b.toString()));
|
||||
|
||||
return { createableNodes, updateableNodes, testableNodes, testableTypes };
|
||||
|
||||
function discoverType(type: TypeInfo) {
|
||||
let syntaxType = syntaxTypeForTypeInfo[type.id];
|
||||
if (!syntaxType) {
|
||||
if (nodeType.isAssignableFrom(type)) {
|
||||
let superTypes: SyntaxType[] = [];
|
||||
let directSyntaxNodes: SyntaxNode[] = [];
|
||||
let typeName = type.toString();
|
||||
|
||||
syntaxType = {
|
||||
type,
|
||||
typeName,
|
||||
superTypes,
|
||||
directSyntaxNodes
|
||||
};
|
||||
|
||||
syntaxTypes.push(syntaxType);
|
||||
syntaxTypeForTypeInfo[type.id] = syntaxType;
|
||||
|
||||
for (let superType of type.getSuperTypes()) {
|
||||
let superSyntaxType = discoverType(superType);
|
||||
if (superSyntaxType) {
|
||||
superTypes.push(superSyntaxType);
|
||||
}
|
||||
}
|
||||
|
||||
for (let kind of type.findAllAnnotations(/*inherited*/ false, KindAnnotation.match)) {
|
||||
directSyntaxNodes.push(discoverKind(type, kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
return syntaxType;
|
||||
}
|
||||
|
||||
function discoverKind(type: TypeInfo, kind: KindAnnotation) {
|
||||
let kindName = kind.kindSymbol.name;
|
||||
let typeName = type.toString();
|
||||
let createFunctionName = discoverFunctionName(kindName, "create", kind.create);
|
||||
let createParameters: SyntaxMember[] = createFunctionName ? [] : undefined;
|
||||
let updateFunctionName = discoverFunctionName(kindName, "update", kind.update);
|
||||
let updateParameters: SyntaxMember[] = updateFunctionName ? [] : undefined;
|
||||
let testFunctionName = discoverFunctionName(kindName, "is", kind.test);
|
||||
if (type.name === "StringLiteral") {
|
||||
debugger;
|
||||
}
|
||||
for (let property of type.getProperties(/*inherited*/ true)) {
|
||||
if (FactoryHiddenAnnotation.getState(type, property.name) === FactoryHiddenState.Hidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let isFactoryParameter = property.findFirstAnnotation(/*inherited*/ true, FactoryParamAnnotation.match) !== undefined;
|
||||
let isNode = nodeType.isAssignableFrom(property.propertyType);
|
||||
let isModifiersArray = modifiersArrayType.isAssignableFrom(property.propertyType);
|
||||
let isNodeArray = !isModifiersArray && nodeArrayType.isAssignableFrom(property.propertyType);
|
||||
if (isFactoryParameter || isNode || isNodeArray || isModifiersArray) {
|
||||
let propertyName = property.name;
|
||||
let parameterName = property.name === "arguments" ? "_arguments" : property.name;
|
||||
let parameterType: TypeInfo;
|
||||
let nodeType: TypeInfo;
|
||||
if (isModifiersArray) {
|
||||
nodeType = modifierType;
|
||||
parameterType = makeArrayType(nodeType);
|
||||
}
|
||||
else if (isNodeArray) {
|
||||
nodeType = property.propertyType.getGenericTypeArguments()[0];
|
||||
parameterType = makeArrayType(nodeType);
|
||||
}
|
||||
else if (isNode) {
|
||||
nodeType = property.propertyType;
|
||||
parameterType = nodeType;
|
||||
}
|
||||
else {
|
||||
parameterType = property.propertyType;
|
||||
}
|
||||
|
||||
if (nodeType) {
|
||||
typesReferencedByProperties[nodeType.id] = true;
|
||||
discoverType(nodeType);
|
||||
}
|
||||
|
||||
let parameterTypeName = parameterType.toString();
|
||||
let testFunctionName: string;
|
||||
let visitorFunctionName: string;
|
||||
if (!isFactoryParameter) {
|
||||
switch (property.propertyType) {
|
||||
case nodeType: break;
|
||||
case statementType: visitorFunctionName = "transformer.visitStatement"; break;
|
||||
case conciseBodyType: visitorFunctionName = "transformer.visitConciseBody"; break;
|
||||
case functionBodyType: visitorFunctionName = "transformer.visitFunctionBody"; break;
|
||||
case moduleBodyType: visitorFunctionName = "transformer.visitModuleBody"; break;
|
||||
case sourceFileType: visitorFunctionName = "transformer.visitSourceFile"; break;
|
||||
default:
|
||||
if (isModifiersArray || isNodeArray) {
|
||||
visitorFunctionName = "transformer.visitNodes";
|
||||
visitorFunctionName = "transformer.visitNodes";
|
||||
}
|
||||
else if (isNode) {
|
||||
visitorFunctionName = "transformer.visitNode";
|
||||
}
|
||||
|
||||
if (isModifiersArray) {
|
||||
testFunctionName = "isModifier";
|
||||
}
|
||||
else if (isNodeArray || isNode) {
|
||||
testFunctionName = getIsAnyNodeFunctionName(nodeType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let syntaxMember = {
|
||||
propertyName,
|
||||
parameterName,
|
||||
parameterTypeName,
|
||||
isFactoryParameter,
|
||||
isNodeArray,
|
||||
isModifiersArray,
|
||||
testFunctionName,
|
||||
visitorFunctionName
|
||||
};
|
||||
|
||||
if (createFunctionName) {
|
||||
createParameters.push(syntaxMember);
|
||||
}
|
||||
|
||||
if (updateFunctionName && !isFactoryParameter) {
|
||||
updateParameters.push(syntaxMember);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let factoryOrder = type.findFirstAnnotation(/*inherited*/ true, FactoryOrderAnnotation.match);
|
||||
if (factoryOrder) {
|
||||
if (createFunctionName) {
|
||||
createParameters = sortMembers(createParameters, factoryOrder.propertyNames);
|
||||
}
|
||||
|
||||
if (updateFunctionName) {
|
||||
updateParameters = sortMembers(updateParameters, factoryOrder.propertyNames);
|
||||
}
|
||||
}
|
||||
|
||||
let syntaxNode = {
|
||||
kind: kind.kind,
|
||||
kindName,
|
||||
typeName,
|
||||
createFunctionName,
|
||||
createParameters,
|
||||
updateFunctionName,
|
||||
updateParameters,
|
||||
testFunctionName
|
||||
};
|
||||
|
||||
if (createFunctionName) {
|
||||
createableNodes.push(syntaxNode);
|
||||
localNames[createFunctionName] = createFunctionName;
|
||||
}
|
||||
|
||||
if (updateFunctionName && updateParameters.length > 0) {
|
||||
updateableNodes.push(syntaxNode);
|
||||
localNames[updateFunctionName] = updateFunctionName;
|
||||
}
|
||||
|
||||
if (testFunctionName) {
|
||||
testableNodes.push(syntaxNode);
|
||||
localNames[testFunctionName] = testFunctionName;
|
||||
}
|
||||
|
||||
return syntaxNode;
|
||||
}
|
||||
|
||||
function sortMembers(members: SyntaxMember[], order: string[]) {
|
||||
let indices = members.map((_, i) => i);
|
||||
indices.sort((a, b) => {
|
||||
let aOverride = order.indexOf(members[a].propertyName);
|
||||
let bOverride = order.indexOf(members[b].propertyName);
|
||||
if (aOverride >= 0) {
|
||||
if (bOverride >= 0) {
|
||||
return aOverride - bOverride;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
else if (bOverride >= 0) {
|
||||
return +1;
|
||||
}
|
||||
|
||||
return a - b;
|
||||
});
|
||||
|
||||
return indices.map(i => members[i]);
|
||||
}
|
||||
|
||||
function discoverFunctionName(kindName: string, prefix: string, option: boolean | string) {
|
||||
if (typeof option === "string") {
|
||||
return option;
|
||||
}
|
||||
else if (option) {
|
||||
let functionName = prefix + kindName;
|
||||
if (!hasProperty(localNames, functionName)) {
|
||||
let symbol = resolveQualifiedName("ts." + functionName, SymbolFlags.Function);
|
||||
if (!symbol) {
|
||||
return functionName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getIsAnyNodeFunctionName(type: TypeInfo) {
|
||||
if (type !== nodeType) {
|
||||
let functionName: string;
|
||||
let nodeTest = type.findFirstAnnotation(/*inherited*/ false, NodeTestAnnotation.match);
|
||||
if (nodeTest) {
|
||||
return nodeTest.functionName;
|
||||
}
|
||||
else if (type.isTypeAlias || type.isInterface) {
|
||||
return "is" + getKindOrTypeNameForType(type);
|
||||
}
|
||||
else if (type.isUnionType) {
|
||||
return "is" + type.getConstituentTypes().map(getKindOrTypeNameForType).join("Or");
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function discoverTestableType(syntaxType: SyntaxType) {
|
||||
if (syntaxType.type !== nodeType && !syntaxType.syntaxNodes) {
|
||||
syntaxType.syntaxNodes = [];
|
||||
if (syntaxType.type.findFirstAnnotation(/*inherited*/ false, KindAnnotation.match)) {
|
||||
copySyntaxNodes(syntaxType.type, syntaxType.syntaxNodes, []);
|
||||
}
|
||||
else {
|
||||
discoverSyntaxNodes(syntaxType.type, syntaxType.syntaxNodes, []);
|
||||
}
|
||||
|
||||
if (syntaxType.syntaxNodes.length > 0) {
|
||||
let testFunctionName = discoverIsAnyNodeFunctionName(syntaxType.type);
|
||||
if (testFunctionName) {
|
||||
syntaxType.testFunctionName = testFunctionName;
|
||||
testableTypes.push(syntaxType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function discoverSyntaxNodes(type: TypeInfo, syntaxNodes: SyntaxNode[], seen: boolean[]) {
|
||||
copySyntaxNodes(type, syntaxNodes, seen);
|
||||
|
||||
for (let aliasType of type.getAliases()) {
|
||||
copySyntaxNodes(aliasType, syntaxNodes, seen);
|
||||
}
|
||||
|
||||
if (type.isInterface) {
|
||||
for (let subType of type.getSubTypes()) {
|
||||
discoverSyntaxNodes(subType, syntaxNodes, seen);
|
||||
}
|
||||
}
|
||||
|
||||
if (type.isTypeAlias) {
|
||||
discoverSyntaxNodes(type.getAliasedType(), syntaxNodes, seen);
|
||||
}
|
||||
|
||||
if (type.isUnionType) {
|
||||
for (let constituentType of type.getConstituentTypes()) {
|
||||
discoverSyntaxNodes(constituentType, syntaxNodes, seen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function copySyntaxNodes(type: TypeInfo, syntaxNodes: SyntaxNode[], seen: boolean[]) {
|
||||
let syntaxType = syntaxTypeForTypeInfo[type.id];
|
||||
if (syntaxType) {
|
||||
for (let syntaxNode of syntaxType.directSyntaxNodes) {
|
||||
if (!seen[syntaxNode.kind]) {
|
||||
seen[syntaxNode.kind] = true;
|
||||
syntaxNodes.push(syntaxNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function discoverIsAnyNodeFunctionName(type: TypeInfo) {
|
||||
if (typesReferencedByProperties[type.id]) {
|
||||
let functionName = getIsAnyNodeFunctionName(type);
|
||||
if (functionName && !hasProperty(localNames, functionName)) {
|
||||
let symbol = resolveQualifiedName("ts." + functionName, SymbolFlags.Function);
|
||||
if (!symbol) {
|
||||
localNames[functionName] = functionName;
|
||||
return functionName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getKindOrTypeNameForType(type: TypeInfo) {
|
||||
let kinds = type.findAllAnnotations(/*inherited*/ false, KindAnnotation.match);
|
||||
if (kinds.length === 1) {
|
||||
return kinds[0].kindSymbol.name;
|
||||
}
|
||||
|
||||
return type.name;
|
||||
}
|
||||
}
|
||||
|
||||
export interface KindOptions {
|
||||
create: boolean | string;
|
||||
update: boolean | string;
|
||||
test: boolean | string;
|
||||
}
|
||||
|
||||
@annotation("kind", { inherited: false })
|
||||
export class KindAnnotation extends Annotation {
|
||||
public kind: SyntaxKind;
|
||||
public kindSymbol: Symbol;
|
||||
public create: boolean | string;
|
||||
public update: boolean | string;
|
||||
public test: boolean | string;
|
||||
|
||||
constructor([{ value, symbol }, { create = true, update = true, test = true } = <KindOptions>{}, ..._arguments]: [EnumValue<SyntaxKind>, KindOptions, any]) {
|
||||
super(_arguments);
|
||||
this.kind = value;
|
||||
this.kindSymbol = symbol;
|
||||
this.create = create;
|
||||
this.update = update;
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
public static match(annotation: Annotation): annotation is KindAnnotation {
|
||||
return annotation instanceof KindAnnotation;
|
||||
}
|
||||
}
|
||||
|
||||
export const enum FactoryHiddenState {
|
||||
None,
|
||||
Hidden,
|
||||
Visible
|
||||
}
|
||||
|
||||
@annotation("factoryhidden", { inherited: true, allowMultiple: true })
|
||||
export class FactoryHiddenAnnotation extends Annotation {
|
||||
public propertyName: string;
|
||||
public hidden: boolean;
|
||||
constructor([ propertyName, hidden, ..._arguments]: [string | boolean, boolean, any]) {
|
||||
super(_arguments);
|
||||
if (typeof propertyName === "boolean") {
|
||||
this.hidden = propertyName;
|
||||
}
|
||||
else if (typeof propertyName === "string") {
|
||||
this.propertyName = propertyName;
|
||||
if (typeof hidden === "boolean") {
|
||||
this.hidden = hidden;
|
||||
}
|
||||
else {
|
||||
this.hidden = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static getState(type: TypeInfo, propertyName?: string) {
|
||||
if (propertyName) {
|
||||
return this.getStateForProperty(type, propertyName);
|
||||
}
|
||||
else {
|
||||
return this.getStateForType(type);
|
||||
}
|
||||
}
|
||||
|
||||
private static getStateForProperty(type: TypeInfo, propertyName: string) {
|
||||
let factoryHiddenState = FactoryHiddenState.None;
|
||||
let inheritedTypes: TypeInfo[] = [type];
|
||||
while (factoryHiddenState === FactoryHiddenState.None && inheritedTypes.length) {
|
||||
[factoryHiddenState, inheritedTypes] = this.getStateForPropertyBreadthFirst(inheritedTypes, propertyName);
|
||||
}
|
||||
return factoryHiddenState;
|
||||
}
|
||||
|
||||
private static getStateForPropertyBreadthFirst(types: TypeInfo[], propertyName: string): [FactoryHiddenState, TypeInfo[]] {
|
||||
let inheritedTypes: TypeInfo[] = [];
|
||||
let factoryHidden: FactoryHiddenAnnotation;
|
||||
let factoryHiddenState: FactoryHiddenState = FactoryHiddenState.None;
|
||||
for (let type of types) {
|
||||
let property = type.getProperty(propertyName, /*inherited*/ false);
|
||||
if (property) {
|
||||
if (factoryHidden = property.findFirstAnnotation(/*inherited*/ false, FactoryHiddenAnnotation.match)) {
|
||||
factoryHiddenState = factoryHidden.hidden ? FactoryHiddenState.Hidden : FactoryHiddenState.Visible;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (factoryHidden = type.findFirstAnnotation(/*inherited*/ false, FactoryHiddenAnnotation.matchProperty(propertyName))) {
|
||||
factoryHiddenState = factoryHidden.hidden ? FactoryHiddenState.Hidden : FactoryHiddenState.Visible;
|
||||
break;
|
||||
}
|
||||
|
||||
if (property) {
|
||||
factoryHiddenState = FactoryHiddenState.Visible;
|
||||
break;
|
||||
}
|
||||
|
||||
if (type.isInterface) {
|
||||
inheritedTypes = inheritedTypes.concat(type.getSuperTypes());
|
||||
}
|
||||
else if (type.isTypeAlias) {
|
||||
inheritedTypes.push(type.getAliasedType());
|
||||
}
|
||||
else if (type.isUnionType) {
|
||||
inheritedTypes = inheritedTypes.concat(type.getConstituentTypes());
|
||||
}
|
||||
}
|
||||
|
||||
return [factoryHiddenState, inheritedTypes];
|
||||
}
|
||||
|
||||
private static getStateForType(type: TypeInfo) {
|
||||
let annotation = type.findFirstAnnotation(/*inherited*/ false, this.matchProperty(undefined));
|
||||
return annotation ? annotation.hidden ? FactoryHiddenState.Hidden : FactoryHiddenState.Visible : FactoryHiddenState.None;
|
||||
}
|
||||
|
||||
public static matchProperty(propertyName: string): (annotation: Annotation) => annotation is FactoryHiddenAnnotation {
|
||||
return (annotation): annotation is FactoryHiddenAnnotation => this.match(annotation) && annotation.propertyName === propertyName;
|
||||
}
|
||||
|
||||
public static match(annotation: Annotation): annotation is FactoryHiddenAnnotation {
|
||||
return annotation instanceof FactoryHiddenAnnotation;
|
||||
}
|
||||
}
|
||||
|
||||
@annotation("factoryorder", { inherited: true })
|
||||
export class FactoryOrderAnnotation extends Annotation {
|
||||
public propertyNames: string[];
|
||||
constructor(propertyNames: string[]) {
|
||||
super([]);
|
||||
this.propertyNames = propertyNames;
|
||||
}
|
||||
|
||||
public static match(annotation: Annotation): annotation is FactoryOrderAnnotation {
|
||||
return annotation instanceof FactoryOrderAnnotation;
|
||||
}
|
||||
}
|
||||
|
||||
@annotation("factoryparam", { inherited: true, allowMultiple: true })
|
||||
export class FactoryParamAnnotation extends Annotation {
|
||||
public propertyName: string;
|
||||
constructor([propertyName, ..._arguments]: [string, any]) {
|
||||
super(_arguments);
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
public static matchProperty(propertyName: string): (annotation: Annotation) => annotation is FactoryParamAnnotation {
|
||||
return (annotation): annotation is FactoryParamAnnotation => this.match(annotation) && annotation.propertyName === propertyName;
|
||||
}
|
||||
|
||||
public static match(annotation: Annotation): annotation is FactoryParamAnnotation {
|
||||
return annotation instanceof FactoryParamAnnotation;
|
||||
}
|
||||
}
|
||||
|
||||
@annotation("nodetest", { inherited: false, allowMultiple: false })
|
||||
export class NodeTestAnnotation extends Annotation {
|
||||
public functionName: string;
|
||||
constructor([functionName, ..._arguments]: [string, any]) {
|
||||
super(_arguments);
|
||||
this.functionName = functionName
|
||||
}
|
||||
|
||||
public static match(annotation: Annotation): annotation is NodeTestAnnotation {
|
||||
return annotation instanceof NodeTestAnnotation;
|
||||
}
|
||||
}
|
||||
105
scripts/processTypes/processTypes.ts
Normal file
105
scripts/processTypes/processTypes.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { sys, getDefaultCompilerOptions, createProgram, createCompilerHost } from "./typescript-internal";
|
||||
import { loadSourceFiles } from "./types";
|
||||
import { discover, DiscoveryResult } from "./discovery";
|
||||
import { combinePaths } from "./utilities";
|
||||
|
||||
main();
|
||||
|
||||
function main() {
|
||||
if (sys.args.length < 3) {
|
||||
sys.write("Usage:" + sys.newLine)
|
||||
sys.write("\tnode processTypes.js <types-ts-input-file> <factory-ts-input-file> <utilities-ts-input-file>" + sys.newLine);
|
||||
return;
|
||||
}
|
||||
|
||||
const typesTsFileName = sys.resolvePath(sys.args[0]);
|
||||
const factoryTsFileName = sys.resolvePath(sys.args[1]);
|
||||
const utilitiesTsFileName = sys.resolvePath(sys.args[2]);
|
||||
|
||||
loadSourceFiles([
|
||||
/*typesTsFileName*/ sys.resolvePath(sys.args[0]),
|
||||
/*factoryTsFileName*/ sys.resolvePath(sys.args[1]),
|
||||
/*utilitiesTsFileName*/ sys.resolvePath(sys.args[2])
|
||||
]);
|
||||
|
||||
// Discover syntax nodes
|
||||
const discovery = discover();
|
||||
|
||||
// Emit the generated factory output file
|
||||
const factoryDirectory = sys.resolvePath(combinePaths(factoryTsFileName, ".."));
|
||||
const factoryOutputFile = combinePaths(factoryDirectory, "factory.generated.ts");
|
||||
const factoryOutput = generateFactory(discovery);
|
||||
sys.writeFile(factoryOutputFile, factoryOutput);
|
||||
}
|
||||
|
||||
export function generateFactory(discovery: DiscoveryResult) {
|
||||
return `
|
||||
// <auto-generated />
|
||||
/// <reference path="factory.ts" />
|
||||
namespace ts {${each(discovery.createableNodes, syntaxNode => `
|
||||
export function ${syntaxNode.createFunctionName}(${each(syntaxNode.createParameters, member => `${member.parameterName}?: ${member.parameterTypeName}, `)}location?: TextRange, flags?: NodeFlags): ${syntaxNode.typeName} {
|
||||
let node = createNode<${syntaxNode.typeName}>(SyntaxKind.${syntaxNode.kindName}, location, flags); ${each(syntaxNode.createParameters, member => `
|
||||
if (${member.parameterName}) ${
|
||||
member.isModifiersArray
|
||||
? `setModifiers(node, ${member.parameterName});`
|
||||
: member.isNodeArray
|
||||
? `node.${member.propertyName} = createNodeArray(${member.parameterName});`
|
||||
: `node.${member.propertyName} = ${member.parameterName};`
|
||||
}`)}
|
||||
return node;
|
||||
}`)}${each(discovery.updateableNodes, syntaxNode => `
|
||||
export function ${syntaxNode.updateFunctionName}(node: ${syntaxNode.typeName}${each(syntaxNode.updateParameters, member => `, ${member.parameterName}: ${member.parameterTypeName}`)}): ${syntaxNode.typeName} {
|
||||
if (${each(syntaxNode.updateParameters, member => `${member.parameterName} !== node.${member.propertyName}`, ` || `)}) {
|
||||
let newNode = ${syntaxNode.createFunctionName}(${each(syntaxNode.createParameters, member =>
|
||||
member.isFactoryParameter
|
||||
? `node.${member.propertyName}`
|
||||
: member.parameterName, `, `)});
|
||||
return updateFrom(node, newNode);
|
||||
}
|
||||
return node;
|
||||
}`)}${each(discovery.testableNodes, syntaxNode => `
|
||||
export function ${syntaxNode.testFunctionName}(node: Node): node is ${syntaxNode.typeName} {
|
||||
return node && node.kind === SyntaxKind.${syntaxNode.kindName};
|
||||
}`)}${each(discovery.testableTypes, syntaxType => `
|
||||
export function ${syntaxType.testFunctionName}(node: Node): node is ${syntaxType.typeName} {
|
||||
if (node) {
|
||||
switch (node.kind) {${each(syntaxType.syntaxNodes, syntaxNode => `
|
||||
case SyntaxKind.${syntaxNode.kindName}:`)}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}`)}
|
||||
export function cloneNode<TNode extends Node>(node: TNode, location?: TextRange, flags?: NodeFlags): TNode;
|
||||
export function cloneNode(node: Node, location?: TextRange, flags: NodeFlags = node.flags): Node {
|
||||
if (node) {
|
||||
switch (node.kind) {${each(discovery.createableNodes, syntaxNode => `
|
||||
case SyntaxKind.${syntaxNode.kindName}:
|
||||
return ${syntaxNode.createFunctionName}(${each(syntaxNode.createParameters, member =>
|
||||
`(<${syntaxNode.typeName}>node).${member.propertyName}, `
|
||||
)}location, flags);`)}
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
export function acceptTransformer(transformer: Transformer, node: Node, visitor: (node: Node, write: (node: Node) => void) => void): Node {
|
||||
if (node) {
|
||||
switch (node.kind) {${each(discovery.updateableNodes, syntaxNode => `
|
||||
case SyntaxKind.${syntaxNode.kindName}:
|
||||
return ${syntaxNode.updateFunctionName}(<${syntaxNode.typeName}>node${each(syntaxNode.updateParameters, member =>
|
||||
member.visitorFunctionName && member.testFunctionName
|
||||
? `, ${member.visitorFunctionName}((<${syntaxNode.typeName}>node).${member.propertyName}, visitor, ${member.testFunctionName})`
|
||||
: member.visitorFunctionName
|
||||
? `, ${member.visitorFunctionName}((<${syntaxNode.typeName}>node).${member.propertyName}, visitor)`
|
||||
: `, (<${syntaxNode.typeName}>node).${member.propertyName}`
|
||||
)});`)}
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}`;
|
||||
|
||||
function each<T>(items: T[], callbackfn: (item: T) => string, separator = ``) {
|
||||
return items.map(callbackfn).join(separator);
|
||||
}
|
||||
}
|
||||
12
scripts/processTypes/tsconfig.json
Normal file
12
scripts/processTypes/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES5",
|
||||
"module": "commonjs",
|
||||
"outDir": "../../built/scripts/processTypes/",
|
||||
"experimentalDecorators": true,
|
||||
"noImplicitAny": true,
|
||||
"removeComments": true,
|
||||
"preserveConstEnums": true,
|
||||
"sourceMap": true
|
||||
}
|
||||
}
|
||||
1222
scripts/processTypes/types.ts
Normal file
1222
scripts/processTypes/types.ts
Normal file
File diff suppressed because it is too large
Load Diff
4
scripts/processTypes/typescript-internal.d.ts
vendored
Normal file
4
scripts/processTypes/typescript-internal.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/// <reference path="../../lib/typescript_standalone.d.ts" />
|
||||
import { Symbol } from "typescript";
|
||||
export * from "typescript";
|
||||
export declare function getSymbolId(symbol: Symbol): number;
|
||||
1
scripts/processTypes/typescript-internal.js
Normal file
1
scripts/processTypes/typescript-internal.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("../../../lib/typescript");
|
||||
49
scripts/processTypes/utilities.ts
Normal file
49
scripts/processTypes/utilities.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Map } from "./typescript-internal";
|
||||
|
||||
let hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
export function hasProperty<T>(map: Map<T>, key: string): boolean {
|
||||
return hasOwnProperty.call(map, key);
|
||||
}
|
||||
|
||||
export function getProperty<T>(map: Map<T>, key: string): T {
|
||||
return hasOwnProperty.call(map, key) ? map[key] : undefined;
|
||||
}
|
||||
|
||||
export let directorySeparator = "/";
|
||||
|
||||
export function getRootLength(path: string): number {
|
||||
if (path.charAt(0) === directorySeparator) {
|
||||
if (path.charAt(1) !== directorySeparator) return 1;
|
||||
let p1 = path.indexOf("/", 2);
|
||||
if (p1 < 0) return 2;
|
||||
let p2 = path.indexOf("/", p1 + 1);
|
||||
if (p2 < 0) return p1 + 1;
|
||||
return p2 + 1;
|
||||
}
|
||||
if (path.charAt(1) === ":") {
|
||||
if (path.charAt(2) === directorySeparator) return 3;
|
||||
return 2;
|
||||
}
|
||||
// Per RFC 1738 'file' URI schema has the shape file://<host>/<path>
|
||||
// if <host> is omitted then it is assumed that host value is 'localhost',
|
||||
// however slash after the omitted <host> is not removed.
|
||||
// file:///folder1/file1 - this is a correct URI
|
||||
// file://folder2/file2 - this is an incorrect URI
|
||||
if (path.lastIndexOf("file:///", 0) === 0) {
|
||||
return "file:///".length;
|
||||
}
|
||||
let idx = path.indexOf("://");
|
||||
if (idx !== -1) {
|
||||
return idx + "://".length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function combinePaths(path1: string, path2: string) {
|
||||
if (!(path1 && path1.length)) return path2;
|
||||
if (!(path2 && path2.length)) return path1;
|
||||
if (getRootLength(path2) !== 0) return path2;
|
||||
if (path1.charAt(path1.length - 1) === directorySeparator) return path1 + path2;
|
||||
return path1 + directorySeparator + path2;
|
||||
}
|
||||
Reference in New Issue
Block a user