Skip to content

Instantly share code, notes, and snippets.

@reverofevil
Last active December 23, 2018 04:38
Show Gist options
  • Save reverofevil/255e0de2b2629145aa85e8f94e3e61b5 to your computer and use it in GitHub Desktop.
Save reverofevil/255e0de2b2629145aa85e8f94e3e61b5 to your computer and use it in GitHub Desktop.
Attempt at proper Mozilla AST typings for ES6
// if you've found this in Google, take a look into https://github.com/babel/babel/tree/master/packages/babel-types first
export type Node = AssignmentProperty
| CatchClause
| ClassBody
| ExportAllDeclaration
| ExportDefaultDeclaration
| ExportNamedDeclaration
| Expression
| Identifier
| ImportDeclaration
| Literal
| MethodDefinition
| Pattern
| Program
| Property
| SpreadElement
| Statement
| Super
| SwitchCase
| TemplateElement
| VariableDeclarator;
export type Statement = BlockStatement
| BreakStatement
| ContinueStatement
| DebuggerStatement
| Declaration
| DoWhileStatement
| EmptyStatement
| ExpressionStatement
| ForInStatement
| ForOfStatement
| ForStatement
| IfStatement
| LabeledStatement
| ReturnStatement
| SwitchStatement
| ThrowStatement
| TryStatement
| WhileStatement
| WithStatement;
export type Declaration = ClassDeclaration
| FunctionDeclaration
| VariableDeclaration;
export type Expression = ArrayExpression
| ArrowFunctionExpression
| AssignmentExpression
| BinaryExpression
| CallExpression
| ClassExpression
| ConditionalExpression
| FunctionExpression
| Identifier
| Literal
| LogicalExpression
| MemberExpression
| MetaProperty
| NewExpression
| ObjectExpression
| SequenceExpression
| TaggedTemplateExpression
| TemplateLiteral
| ThisExpression
| UnaryExpression
| UpdateExpression
| YieldExpression;
export type Pattern = ArrayPattern
| AssignmentPattern
| Identifier
| MemberExpression
| ObjectPattern
| RestElement;
export interface SourceLocation {
source: string | null;
start: Position;
end: Position;
}
export const mkSourceLocation = ({
source,
start,
end,
}: {
source: string | null,
start: Position,
end: Position,
}): SourceLocation => ({
source,
start,
end,
});
export interface Position {
line: number;
column: number;
}
export const mkPosition = ({
line,
column,
}: {
line: number,
column: number,
}): Position => ({
line,
column,
});
export interface Program {
type: "Program";
body: Statement[];
sourceType: "script" | "module";
}
export const mkProgram = ({
body,
sourceType,
}: {
body: Statement[],
sourceType: "script" | "module",
}): Program => ({
type: "Program",
body,
sourceType,
});
export interface EmptyStatement {
type: "EmptyStatement";
}
export const mkEmptyS = (): EmptyStatement => ({
type: "EmptyStatement",
});
export interface BlockStatement {
type: "BlockStatement";
body: Statement[];
}
export const mkBlockS = ({
body,
}: {
body: Statement[],
}): BlockStatement => ({
type: "BlockStatement",
body,
});
export interface ExpressionStatement {
type: "ExpressionStatement";
expression: Expression;
}
export const mkES = ({
expression,
}: {
expression: Expression,
}): ExpressionStatement => ({
type: "ExpressionStatement",
expression,
});
export interface IfStatement {
type: "IfStatement";
test: Expression;
consequent: Statement;
alternate: Statement | null;
}
export const mkIfS = ({
test,
consequent,
alternate,
}: {
test: Expression,
consequent: Statement,
alternate: Statement | null,
}): IfStatement => ({
type: "IfStatement",
test,
consequent,
alternate,
});
export interface LabeledStatement {
type: "LabeledStatement";
label: Identifier;
body: Statement;
}
export const mkLabeledS = ({
label,
body,
}: {
label: Identifier,
body: Statement,
}): LabeledStatement => ({
type: "LabeledStatement",
label,
body,
});
export interface BreakStatement {
type: "BreakStatement";
label: Identifier | null;
}
export const mkBreakS = ({
label,
}: {
label: Identifier | null,
}): BreakStatement => ({
type: "BreakStatement",
label,
});
export interface ContinueStatement {
type: "ContinueStatement";
label: Identifier | null;
}
export const mkContinueS = ({
label,
}: {
label: Identifier | null,
}): ContinueStatement => ({
type: "ContinueStatement",
label,
});
export interface WithStatement {
type: "WithStatement";
object: Expression;
body: Statement;
}
export const mkWithS = ({
object,
body,
}: {
object: Expression,
body: Statement,
}): WithStatement => ({
type: "WithStatement",
object,
body,
});
export interface SwitchStatement {
type: "SwitchStatement";
discriminant: Expression;
cases: SwitchCase[];
lexical: false;
}
export const mkSwitchS = ({
discriminant,
cases,
}: {
discriminant: Expression,
cases: SwitchCase[],
}): SwitchStatement => ({
type: "SwitchStatement",
discriminant,
cases,
lexical: false,
});
export interface ReturnStatement {
type: "ReturnStatement";
argument: Expression | null;
}
export const mkReturnS = ({
argument,
}: {
argument: Expression | null,
}): ReturnStatement => ({
type: "ReturnStatement",
argument,
});
export interface ThrowStatement {
type: "ThrowStatement";
argument: Expression;
}
export const mkThrowS = ({
argument,
}: {
argument: Expression,
}): ThrowStatement => ({
type: "ThrowStatement",
argument,
});
export interface TryStatement {
type: "TryStatement";
block: BlockStatement;
handler: CatchClause | null;
finalizer: BlockStatement | null;
}
export const mkTryS = ({
block,
handler,
finalizer,
}: {
block: BlockStatement,
handler: CatchClause | null,
finalizer: BlockStatement | null,
}): TryStatement => ({
type: "TryStatement",
block,
handler,
finalizer,
});
export interface WhileStatement {
type: "WhileStatement";
test: Expression;
body: Statement;
}
export const mkWhileS = ({
test,
body,
}: {
test: Expression,
body: Statement,
}): WhileStatement => ({
type: "WhileStatement",
test,
body,
});
export interface DoWhileStatement {
type: "DoWhileStatement";
body: Statement;
test: Expression;
}
export const mkDoWhileS = ({
body,
test,
}: {
body: Statement,
test: Expression,
}): DoWhileStatement => ({
type: "DoWhileStatement",
body,
test,
});
export interface ForStatement {
type: "ForStatement";
init: VariableDeclaration | Expression | null;
test: Expression | null;
update: Expression | null;
body: Statement;
}
export const mkForS = ({
init,
test,
update,
body,
}: {
init: VariableDeclaration | Expression | null,
test: Expression | null,
update: Expression | null,
body: Statement,
}): ForStatement => ({
type: "ForStatement",
init,
test,
update,
body,
});
export interface ForInStatement extends AbstractForStatement {
type: "ForInStatement";
}
export const mkForInS = ({
left,
right,
body,
}: {
left: VariableDeclaration | Expression,
right: Expression,
body: Statement,
}): ForInStatement => ({
left,
right,
body,
type: "ForInStatement",
});
export interface DebuggerStatement {
type: "DebuggerStatement";
}
export const mkDebuggerS = (): DebuggerStatement => ({
type: "DebuggerStatement",
});
export interface FunctionDeclaration extends AbstractFunction {
type: "FunctionDeclaration";
id: Identifier;
body: BlockStatement;
}
export const mkFunctionDeclaration = ({
id,
params,
generator,
body,
}: {
id: Identifier,
params: Pattern[],
generator: boolean,
body: BlockStatement,
}): FunctionDeclaration => ({
id,
params,
generator,
type: "FunctionDeclaration",
body,
});
export interface VariableDeclaration {
type: "VariableDeclaration";
declarations: VariableDeclarator[];
kind: "var" | "let" | "const";
}
export const mkVariableDeclaration = ({
declarations,
kind,
}: {
declarations: VariableDeclarator[],
kind: "var" | "let" | "const",
}): VariableDeclaration => ({
type: "VariableDeclaration",
declarations,
kind,
});
export interface VariableDeclarator {
type: "VariableDeclarator";
id: Pattern;
init: Expression | null;
}
export const mkVariableDeclarator = ({
id,
init,
}: {
id: Pattern,
init: Expression | null,
}): VariableDeclarator => ({
type: "VariableDeclarator",
id,
init,
});
export interface ThisExpression {
type: "ThisExpression";
}
export const mkThisE = (): ThisExpression => ({
type: "ThisExpression",
});
export interface ArrayExpression {
type: "ArrayExpression";
elements: (Expression | SpreadElement | null)[];
}
export const mkArrayE = ({
elements,
}: {
elements: (Expression | SpreadElement | null)[],
}): ArrayExpression => ({
type: "ArrayExpression",
elements,
});
export interface ObjectExpression {
type: "ObjectExpression";
properties: Property[];
}
export const mkObjectE = ({
properties,
}: {
properties: Property[],
}): ObjectExpression => ({
type: "ObjectExpression",
properties,
});
export interface Property extends AbstractProperty {
type: "Property";
value: Expression;
}
export const mkProperty = ({
key,
kind,
method,
shorthand,
computed,
value,
}: {
key: Expression,
kind: "init" | "get" | "set",
method: boolean,
shorthand: boolean,
computed: boolean,
value: Expression,
}): Property => ({
key,
kind,
method,
shorthand,
computed,
type: "Property",
value,
});
export interface FunctionExpression extends AbstractFunction {
type: "FunctionExpression";
body: BlockStatement;
}
export const mkFunctionE = ({
id,
params,
generator,
body,
}: {
id: Identifier | null,
params: Pattern[],
generator: boolean,
body: BlockStatement,
}): FunctionExpression => ({
id,
params,
generator,
type: "FunctionExpression",
body,
});
export interface SequenceExpression {
type: "SequenceExpression";
expressions: Expression[];
}
export const mkSequenceE = ({
expressions,
}: {
expressions: Expression[],
}): SequenceExpression => ({
type: "SequenceExpression",
expressions,
});
export interface UnaryExpression {
type: "UnaryExpression";
operator: UnaryOperator;
prefix: boolean;
argument: Expression;
}
export const mkUnaryE = ({
operator,
prefix,
argument,
}: {
operator: UnaryOperator,
prefix: boolean,
argument: Expression,
}): UnaryExpression => ({
type: "UnaryExpression",
operator,
prefix,
argument,
});
export interface BinaryExpression {
type: "BinaryExpression";
operator: BinaryOperator;
left: Expression;
right: Expression;
}
export const mkBinaryE = ({
operator,
left,
right,
}: {
operator: BinaryOperator,
left: Expression,
right: Expression,
}): BinaryExpression => ({
type: "BinaryExpression",
operator,
left,
right,
});
export interface AssignmentExpression {
type: "AssignmentExpression";
operator: AssignmentOperator;
left: Pattern | MemberExpression;
right: Expression;
}
export const mkAssignmentE = ({
operator,
left,
right,
}: {
operator: AssignmentOperator,
left: Pattern | MemberExpression,
right: Expression,
}): AssignmentExpression => ({
type: "AssignmentExpression",
operator,
left,
right,
});
export interface UpdateExpression {
type: "UpdateExpression";
operator: UpdateOperator;
argument: Expression;
prefix: boolean;
}
export const mkUpdateE = ({
operator,
argument,
prefix,
}: {
operator: UpdateOperator,
argument: Expression,
prefix: boolean,
}): UpdateExpression => ({
type: "UpdateExpression",
operator,
argument,
prefix,
});
export interface LogicalExpression {
type: "LogicalExpression";
operator: LogicalOperator;
left: Expression;
right: Expression;
}
export const mkLogicalE = ({
operator,
left,
right,
}: {
operator: LogicalOperator,
left: Expression,
right: Expression,
}): LogicalExpression => ({
type: "LogicalExpression",
operator,
left,
right,
});
export interface ConditionalExpression {
type: "ConditionalExpression";
test: Expression;
alternate: Expression;
consequent: Expression;
}
export const mkConditionalE = ({
test,
alternate,
consequent,
}: {
test: Expression,
alternate: Expression,
consequent: Expression,
}): ConditionalExpression => ({
type: "ConditionalExpression",
test,
alternate,
consequent,
});
export interface CallExpression extends AbstractCallExpression {
type: "CallExpression";
}
export const mkCallE = ({
callee,
args,
}: {
callee: Expression | Super,
args: (Expression | SpreadElement)[],
}): CallExpression => ({
callee,
"arguments": args,
type: "CallExpression",
});
export interface NewExpression extends AbstractCallExpression {
type: "NewExpression";
}
export const mkNewE = ({
callee,
args,
}: {
callee: Expression | Super,
args: (Expression | SpreadElement)[],
}): NewExpression => ({
callee,
"arguments": args,
type: "NewExpression",
});
export interface MemberExpression {
type: "MemberExpression";
object: Expression | Super;
property: Expression;
computed: boolean;
}
export const mkMemberE = ({
object,
property,
computed,
}: {
object: Expression | Super,
property: Expression,
computed: boolean,
}): MemberExpression => ({
type: "MemberExpression",
object,
property,
computed,
});
export interface SwitchCase {
type: "SwitchCase";
test: Expression | null;
consequent: Statement[];
}
export const mkSwitchCase = ({
test,
consequent,
}: {
test: Expression | null,
consequent: Statement[],
}): SwitchCase => ({
type: "SwitchCase",
test,
consequent,
});
export interface CatchClause {
type: "CatchClause";
param: Pattern;
guard: null;
body: BlockStatement;
}
export const mkCatchClause = ({
param,
body,
}: {
param: Pattern,
body: BlockStatement,
}): CatchClause => ({
type: "CatchClause",
param,
guard: null,
body,
});
export interface Identifier {
type: "Identifier";
name: string;
}
export const mkIdentifier = ({
name,
}: {
name: string,
}): Identifier => ({
type: "Identifier",
name,
});
export interface Literal {
type: "Literal";
value: string | boolean | null | number | RegExp;
}
export const mkLiteral = ({
value,
}: {
value: string | boolean | null | number | RegExp,
}): Literal => ({
type: "Literal",
value,
});
export interface RegexLiteral extends Literal {
regex: {
pattern: string;
flags: string;
};
}
export const mkRegexLiteral = ({
value,
regex,
}: {
value: string | boolean | null | number | RegExp,
regex: {
pattern: string;
flags: string;
},
}): RegexLiteral => ({
type: "Literal",
value,
regex,
});
export type UnaryOperator = "-" | "+" | "!" | "~" | "typeof" | "void" | "delete";
export type BinaryOperator = "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">=" | "<<" | ">>" | ">>>" | "+" | "-" | "*" | "/" | "%" | "|" | "^" | "&" | "in" | "instanceof";
export type LogicalOperator = "||" | "&&";
export type AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" | ">>>=" | "|=" | "^=" | "&=";
export type UpdateOperator = "++" | "--";
export interface ForOfStatement extends AbstractForStatement {
type: "ForOfStatement";
}
export const mkForOfS = ({
left,
right,
body,
}: {
left: VariableDeclaration | Expression,
right: Expression,
body: Statement,
}): ForOfStatement => ({
left,
right,
body,
type: "ForOfStatement",
});
export interface Super {
type: "Super";
}
export const mkSuper = (): Super => ({
type: "Super",
});
export interface SpreadElement {
type: "SpreadElement";
argument: Expression;
}
export const mkSpreadElement = ({
argument,
}: {
argument: Expression,
}): SpreadElement => ({
type: "SpreadElement",
argument,
});
export interface ArrowFunctionExpression extends AbstractFunction {
type: "ArrowFunctionExpression";
body: BlockStatement | Expression;
expression: boolean;
}
export const mkArrowFunctionE = ({
id,
params,
generator,
body,
expression,
}: {
id: Identifier | null,
params: Pattern[],
generator: boolean,
body: BlockStatement | Expression,
expression: boolean,
}): ArrowFunctionExpression => ({
id,
params,
generator,
type: "ArrowFunctionExpression",
body,
expression,
});
export interface YieldExpression {
type: "YieldExpression";
argument: Expression | null;
}
export const mkYieldE = ({
argument,
}: {
argument: Expression | null,
}): YieldExpression => ({
type: "YieldExpression",
argument,
});
export interface TemplateLiteral {
type: "TemplateLiteral";
quasis: TemplateElement[];
expressions: Expression[];
}
export const mkTemplateLiteral = ({
quasis,
expressions,
}: {
quasis: TemplateElement[],
expressions: Expression[],
}): TemplateLiteral => ({
type: "TemplateLiteral",
quasis,
expressions,
});
export interface TaggedTemplateExpression {
type: "TaggedTemplateExpression";
tag: Expression;
quasi: TemplateLiteral;
}
export const mkTaggedTemplateE = ({
tag,
quasi,
}: {
tag: Expression,
quasi: TemplateLiteral,
}): TaggedTemplateExpression => ({
type: "TaggedTemplateExpression",
tag,
quasi,
});
export interface TemplateElement {
type: "TemplateElement";
tail: boolean;
value: {
cooked: string;
value: string;
};
}
export const mkTemplateElement = ({
tail,
value,
}: {
tail: boolean,
value: {
cooked: string;
value: string;
},
}): TemplateElement => ({
type: "TemplateElement",
tail,
value,
});
export interface AssignmentProperty extends AbstractProperty {
type: "Property";
value: Pattern;
kind: "init";
method: false;
}
export const mkAssignmentProperty = ({
key,
shorthand,
computed,
value,
}: {
key: Expression,
shorthand: boolean,
computed: boolean,
value: Pattern,
}): AssignmentProperty => ({
key,
kind: "init",
method: false,
shorthand,
computed,
type: "Property",
value,
});
export interface ObjectPattern {
type: "ObjectPattern";
properties: AssignmentProperty[];
}
export const mkObjectPattern = ({
properties,
}: {
properties: AssignmentProperty[],
}): ObjectPattern => ({
type: "ObjectPattern",
properties,
});
export interface ArrayPattern {
type: "ArrayPattern";
elements: (Pattern | null)[];
}
export const mkArrayPattern = ({
elements,
}: {
elements: (Pattern | null)[],
}): ArrayPattern => ({
type: "ArrayPattern",
elements,
});
export interface RestElement {
type: "RestElement";
argument: Pattern;
}
export const mkRestElement = ({
argument,
}: {
argument: Pattern,
}): RestElement => ({
type: "RestElement",
argument,
});
export interface AssignmentPattern {
type: "AssignmentPattern";
left: Pattern;
right: Expression;
}
export const mkAssignmentPattern = ({
left,
right,
}: {
left: Pattern,
right: Expression,
}): AssignmentPattern => ({
type: "AssignmentPattern",
left,
right,
});
export interface ClassBody {
type: "ClassBody";
body: MethodDefinition[];
}
export const mkClassBody = ({
body,
}: {
body: MethodDefinition[],
}): ClassBody => ({
type: "ClassBody",
body,
});
export interface MethodDefinition {
type: "MethodDefinition";
key: Identifier;
value: FunctionExpression;
kind: "constructor" | "method" | "get" | "set";
computed: boolean;
static: boolean;
}
export const mkMethodDefinition = ({
key,
value,
kind,
computed,
isStatic,
}: {
key: Identifier,
value: FunctionExpression,
kind: "constructor" | "method" | "get" | "set",
computed: boolean,
isStatic: boolean,
}): MethodDefinition => ({
type: "MethodDefinition",
key,
value,
kind,
computed,
"static": isStatic,
});
export interface ClassDeclaration extends AbstractClass {
type: "ClassDeclaration";
id: Identifier;
}
export const mkClassDeclaration = ({
id,
superClass,
body,
}: {
id: Identifier,
superClass: Expression,
body: ClassBody,
}): ClassDeclaration => ({
id,
superClass,
body,
type: "ClassDeclaration",
});
export interface ClassExpression extends AbstractClass {
type: "ClassExpression";
}
export const mkClassE = ({
id,
superClass,
body,
}: {
id: Identifier | null,
superClass: Expression,
body: ClassBody,
}): ClassExpression => ({
id,
superClass,
body,
type: "ClassExpression",
});
export interface MetaProperty {
type: "MetaProperty";
meta: Identifier;
property: Identifier;
}
export const mkMetaProperty = ({
meta,
property,
}: {
meta: Identifier,
property: Identifier,
}): MetaProperty => ({
type: "MetaProperty",
meta,
property,
});
export interface ImportDeclaration {
type: "ImportDeclaration";
specifiers: (ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier)[];
source: Literal;
}
export const mkImportDeclaration = ({
specifiers,
source,
}: {
specifiers: (ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier)[],
source: Literal,
}): ImportDeclaration => ({
type: "ImportDeclaration",
specifiers,
source,
});
export interface ImportSpecifier {
type: "ImportSpecifier";
imported: Identifier;
local: Identifier;
}
export const mkImportSpecifier = ({
imported,
local,
}: {
imported: Identifier,
local: Identifier,
}): ImportSpecifier => ({
type: "ImportSpecifier",
imported,
local,
});
export interface ImportDefaultSpecifier {
type: "ImportDefaultSpecifier";
local: Identifier;
}
export const mkImportDefaultSpecifier = ({
local,
}: {
local: Identifier,
}): ImportDefaultSpecifier => ({
type: "ImportDefaultSpecifier",
local,
});
export interface ImportNamespaceSpecifier {
type: "ImportNamespaceSpecifier";
local: Identifier;
}
export const mkImportNamespaceSpecifier = ({
local,
}: {
local: Identifier,
}): ImportNamespaceSpecifier => ({
type: "ImportNamespaceSpecifier",
local,
});
export interface ExportNamedDeclaration {
type: "ExportNamedDeclaration";
declaration: Declaration | null;
specifiers: ExportSpecifier[];
source: Literal | null;
}
export const mkExportNamedDeclaration = ({
declaration,
specifiers,
source,
}: {
declaration: Declaration | null,
specifiers: ExportSpecifier[],
source: Literal | null,
}): ExportNamedDeclaration => ({
type: "ExportNamedDeclaration",
declaration,
specifiers,
source,
});
export interface ExportSpecifier {
type: "ExportSpecifier";
exported: Identifier;
local: Identifier;
}
export const mkExportSpecifier = ({
exported,
local,
}: {
exported: Identifier,
local: Identifier,
}): ExportSpecifier => ({
type: "ExportSpecifier",
exported,
local,
});
export interface ExportDefaultDeclaration {
type: "ExportDefaultDeclaration";
declaration: Declaration | Expression;
}
export const mkExportDefaultDeclaration = ({
declaration,
}: {
declaration: Declaration | Expression,
}): ExportDefaultDeclaration => ({
type: "ExportDefaultDeclaration",
declaration,
});
export interface ExportAllDeclaration {
type: "ExportAllDeclaration";
source: Literal;
}
export const mkExportAllDeclaration = ({
source,
}: {
source: Literal,
}): ExportAllDeclaration => ({
type: "ExportAllDeclaration",
source,
});
export interface AbstractClass {
id: Identifier | null;
superClass: Expression;
body: ClassBody;
}
export interface AbstractFunction {
id: Identifier | null;
params: Pattern[];
generator: boolean;
}
export interface AbstractForStatement {
left: VariableDeclaration | Expression;
right: Expression;
body: Statement;
}
export interface AbstractProperty {
key: Expression;
kind: "init" | "get" | "set";
method: boolean;
shorthand: boolean;
computed: boolean;
}
export interface AbstractCallExpression {
callee: Expression | Super;
arguments: (Expression | SpreadElement)[];
}
const esSchema = require('estree-formal/formal-data/es6.json');
const clone = o => JSON.parse(JSON.stringify(o));
const replace = (a, b, c) => {
a.forEach((x, i) => {
if (x === b) a[i] = c;
});
return a;
};
delete esSchema.Node.props.loc;
delete esSchema.Node.props.type;
const body = esSchema.Function.props.body;
delete esSchema.Function.props.body;
esSchema.AbstractClass = esSchema.Class;
esSchema.AbstractClass.base = [];
delete esSchema.Class;
esSchema.ClassExpression.base = ['Expression', 'AbstractClass'];
esSchema.ClassDeclaration.base = ['Declaration', 'AbstractClass'];
esSchema.AbstractFunction = clone(esSchema.Function);
esSchema.AbstractFunction.base = [];
delete esSchema.Function;
replace(esSchema.FunctionDeclaration.base, 'Function', 'AbstractFunction');
esSchema.FunctionDeclaration.props.body = body;
replace(esSchema.FunctionExpression.base, 'Function', 'AbstractFunction');
esSchema.FunctionExpression.props.body = body;
replace(esSchema.ArrowFunctionExpression.base, 'Function', 'AbstractFunction');
esSchema.AbstractForStatement = clone(esSchema.ForInStatement);
esSchema.AbstractForStatement.base = [];
delete esSchema.AbstractForStatement.props.type;
esSchema.ForInStatement.base = ['Statement', 'AbstractForStatement'];
esSchema.ForInStatement.props = {type: esSchema.ForInStatement.props.type};
esSchema.ForOfStatement.base = ['Statement', 'AbstractForStatement'];
esSchema.AbstractProperty = clone(esSchema.Property);
esSchema.AbstractProperty.base = [];
delete esSchema.AbstractProperty.props.type;
delete esSchema.AbstractProperty.props.value;
esSchema.AssignmentProperty.base = ['Node', 'AbstractProperty'];
esSchema.Property.base = ['Node', 'AbstractProperty'];
esSchema.Property.props = {
type: esSchema.Property.props.type,
value: esSchema.Property.props.value,
};
esSchema.AbstractCallExpression = clone(esSchema.CallExpression);
esSchema.AbstractCallExpression.base = [];
delete esSchema.AbstractCallExpression.props.type;
esSchema.NewExpression.base = ['Expression', 'AbstractCallExpression'];
esSchema.CallExpression.base = ['Expression', 'AbstractCallExpression'];
esSchema.CallExpression.props = {type: esSchema.CallExpression.props.type};
const badTypes = {
Node: ['Node'],
Statement: ['Statement'],
Declaration: ['Declaration'],
Expression: ['Expression'],
Pattern: ['Pattern'],
};
const withType = {
Node: {Statement: 1, Expression: 1, Pattern: 1},
Statement: {Declaration: 1},
Declaration: {},
Expression: {},
Pattern: {},
};
const resolveProps = ({kind, props, base}, ruleName) => {
if (kind !== 'interface') {
throw new Error('WUT2');
}
const baseProps = base.map(base => resolveProps(esSchema[base], base))
baseProps.push(props);
return baseProps.reduce((res, props) => {
const out = {...res, ...props};
return out;
}, {});
};
const printType = ({kind, name, value, types, base, items}, depth) => {
switch (kind) {
case 'reference':
return name;
case 'literal':
return JSON.stringify(value);
case 'union':
return types.map(type => printType(type, depth)).join(' | ');
case 'array':
return base.kind === 'reference'
? `${printType(base, depth)}[]`
: `(${printType(base, depth)})[]`;
case 'object':
return printObj(items, depth + 1);
default:
throw new Error();
}
};
const printObj = (props, depth) => {
const space = new Array(depth + 1).join('\t');
const space1 = new Array(depth).join('\t');
const propsStr = Object.keys(props).map(name => {
const type = printType(props[name], depth);
return `${space}${name}: ${type};\n`;
}).join('');
return `{\n${propsStr}${space1}}`;
};
const RENAMES = {
'arguments': 'args',
'static': 'isStatic',
};
const res = [];
for (const ruleName of Object.keys(esSchema)) {
const rule = esSchema[ruleName];
if (rule.kind === 'enum') {
const values = rule.values.map(value => JSON.stringify(value));
res.push(`export type ${ruleName} = ${values.join(' | ')};\n`);
} else if (rule.kind === 'interface') {
if (badTypes[ruleName])
continue;
rule.base.map(base => (badTypes[base] || []).map(base => {withType[base][ruleName] = true}));
rule.base = rule.base.filter(base => !badTypes[base]);
const allProps = resolveProps(rule, ruleName);
const props = clone(allProps);
Object.keys(props).forEach(key => {if (props[key].kind === 'literal') delete props[key] });
const extend = rule.base.length > 0 ? ` extends ${rule.base.join(', ')}` : '';
res.push(`export interface ${ruleName}${extend} ${printObj(rule.props, 1)}\n\n`);
if (!ruleName.startsWith('Abstract')) {
const argNames = Object.keys(props)
.map(name => `\t${RENAMES[name] || name},\n`)
.join('');
const propNames = Object.keys(allProps)
.map(name => {
const resName = allProps[name].kind === 'literal'
? `${name}: ${JSON.stringify(allProps[name].value)}`
: RENAMES[name]
? `"${name}": ${RENAMES[name]}`
: name;
return `\t${resName},\n`;
})
.join('');
const shortName = ruleName.replace('Statement', 'S').replace('Expression', 'E');
const propTypes = Object.keys(props)
.map(name => `\t${RENAMES[name] || name}: ${printType(props[name], 1)},\n`)
.join('');
const args = Object.keys(props).length > 0 ? `{\n${argNames}}: {\n${propTypes}}` : '';
res.push(`export const mk${shortName} = (${args}): ${ruleName} => ({\n${propNames}});\n\n`);
}
} else {
throw new Error('WUT');
}
}
for (const type of Object.keys(withType).reverse()) {
res.unshift(`export type ${type} = ${Object.keys(withType[type]).sort().join('\n\t| ')};\n\n`);
}
require('fs').writeFileSync('result.ts', res.join(''));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment