The extraction is interruptible now
parent
8ce9bc35f4
commit
fa0f96ebea
141
lib/extractor.js
141
lib/extractor.js
|
@ -4,81 +4,116 @@ const assert = require('assert');
|
|||
|
||||
const {partition, log} = require('./utils');
|
||||
|
||||
function extract(node) {
|
||||
if (!extractors[node.type]) {
|
||||
const provide = (schema) => ({command: 'provide', schema});
|
||||
|
||||
function extract(node, schemas) {
|
||||
const extractor = extractors[node.type];
|
||||
|
||||
if (!extractor) {
|
||||
log(node);
|
||||
return null;
|
||||
}
|
||||
|
||||
return extractors[node.type](node);
|
||||
const iter = extractor(node);
|
||||
|
||||
let result = null;
|
||||
|
||||
while (true) {
|
||||
const {done, value} = iter.next(result);
|
||||
|
||||
if (done) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
result = null;
|
||||
} else if (value.command === 'provide') {
|
||||
const {schema} = value;
|
||||
|
||||
schemas[schema.name] = schema;
|
||||
} else if (Array.isArray(value)) {
|
||||
result = value.map(val => extract(val, schemas));
|
||||
} else {
|
||||
result = extract(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const extractors = {
|
||||
TypeAlias(node) {
|
||||
return extract(node.right);
|
||||
* TypeAlias(node) {
|
||||
const schema = yield node.right;
|
||||
schema.name = yield node.id;
|
||||
|
||||
yield provide(schema);
|
||||
},
|
||||
|
||||
InterfaceDeclaration(node) {
|
||||
return extract(node.body);
|
||||
* InterfaceDeclaration(node) {
|
||||
const schema = yield node.body;
|
||||
schema.name = yield node.id;
|
||||
|
||||
yield provide(schema);
|
||||
},
|
||||
|
||||
ClassDeclaration(node) {
|
||||
return extract(node.body);
|
||||
* ClassDeclaration(node) {
|
||||
const schema = yield node.body;
|
||||
schema.name = yield node.id;
|
||||
|
||||
yield provide(schema);
|
||||
},
|
||||
|
||||
ClassBody(node) {
|
||||
* ClassBody(node) {
|
||||
return {
|
||||
type: 'record',
|
||||
fields: node.body.map(extract).filter(Boolean),
|
||||
fields: (yield node.body).filter(Boolean),
|
||||
};
|
||||
},
|
||||
|
||||
ClassProperty(node) {
|
||||
* ClassProperty(node) {
|
||||
if (node.static) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let type = node.leadingComments && extractLastPragma(node.leadingComments);
|
||||
let type = node.leadingComments && (yield* extractLastPragma(node.leadingComments));
|
||||
|
||||
return {
|
||||
name: extract(node.key),
|
||||
type: type || extract(node.typeAnnotation),
|
||||
name: yield node.key,
|
||||
type: type || (yield node.typeAnnotation),
|
||||
};
|
||||
},
|
||||
|
||||
ClassMethod(node) {
|
||||
* ClassMethod(node) {
|
||||
return null;
|
||||
},
|
||||
|
||||
ObjectTypeAnnotation(node) {
|
||||
* ObjectTypeAnnotation(node) {
|
||||
if (node.indexers.length > 0) {
|
||||
// Allow functions, getters and setters.
|
||||
const properties = node.properties.map(extract).filter(Boolean);
|
||||
const properties = (yield node.properties).filter(Boolean);
|
||||
|
||||
assert.equal(properties.length, 0);
|
||||
assert.equal(node.indexers.length, 1);
|
||||
|
||||
return {
|
||||
type: 'map',
|
||||
values: extract(node.indexers[0]),
|
||||
values: yield node.indexers[0],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'record',
|
||||
fields: node.properties.map(extract).filter(Boolean),
|
||||
fields: (yield node.properties).filter(Boolean),
|
||||
};
|
||||
},
|
||||
|
||||
ObjectTypeProperty(node) {
|
||||
* ObjectTypeProperty(node) {
|
||||
let type = null;
|
||||
|
||||
if (node.leadingComments) {
|
||||
type = extractLastPragma(node.leadingComments);
|
||||
type = yield* extractLastPragma(node.leadingComments);
|
||||
}
|
||||
|
||||
if (!type) {
|
||||
type = extract(node.value);
|
||||
type = yield node.value;
|
||||
}
|
||||
|
||||
if (!type) {
|
||||
|
@ -86,49 +121,49 @@ const extractors = {
|
|||
}
|
||||
|
||||
return {
|
||||
name: extract(node.key),
|
||||
name: yield node.key,
|
||||
type,
|
||||
};
|
||||
},
|
||||
|
||||
ObjectTypeIndexer(node) {
|
||||
const key = extract(node.key);
|
||||
* ObjectTypeIndexer(node) {
|
||||
const key = yield node.key;
|
||||
|
||||
assert.equal(key, 'string');
|
||||
|
||||
return extract(node.value);
|
||||
return yield node.value;
|
||||
},
|
||||
|
||||
TypeAnnotation(node) {
|
||||
return extract(node.typeAnnotation);
|
||||
* TypeAnnotation(node) {
|
||||
return yield node.typeAnnotation;
|
||||
},
|
||||
|
||||
NumberTypeAnnotation(node) {
|
||||
* NumberTypeAnnotation(node) {
|
||||
return 'double';
|
||||
},
|
||||
|
||||
StringTypeAnnotation(node) {
|
||||
* StringTypeAnnotation(node) {
|
||||
return 'string';
|
||||
},
|
||||
|
||||
BooleanTypeAnnotation(node) {
|
||||
* BooleanTypeAnnotation(node) {
|
||||
return 'boolean';
|
||||
},
|
||||
|
||||
ArrayTypeAnnotation(node) {
|
||||
* ArrayTypeAnnotation(node) {
|
||||
return {
|
||||
type: 'array',
|
||||
items: extract(node.elementType),
|
||||
items: yield node.elementType,
|
||||
};
|
||||
},
|
||||
|
||||
UnionTypeAnnotation(node) {
|
||||
* UnionTypeAnnotation(node) {
|
||||
// TODO: flatten variants.
|
||||
|
||||
let [symbols, variants] = partition(node.types, isEnumSymbol);
|
||||
|
||||
symbols = symbols.map(unwrapEnumSymbol);
|
||||
variants = variants.map(extract);
|
||||
variants = yield variants;
|
||||
|
||||
if (symbols.length > 0) {
|
||||
const enumeration = {
|
||||
|
@ -146,23 +181,23 @@ const extractors = {
|
|||
return variants;
|
||||
},
|
||||
|
||||
NullableTypeAnnotation(node) {
|
||||
return ['null', extract(node.typeAnnotation)];
|
||||
* NullableTypeAnnotation(node) {
|
||||
return ['null', yield node.typeAnnotation];
|
||||
},
|
||||
|
||||
NullLiteralTypeAnnotation(node) {
|
||||
* NullLiteralTypeAnnotation(node) {
|
||||
return 'null';
|
||||
},
|
||||
|
||||
StringLiteralTypeAnnotation(node) {
|
||||
* StringLiteralTypeAnnotation(node) {
|
||||
return {
|
||||
type: 'enum',
|
||||
symbols: [node.value],
|
||||
};
|
||||
},
|
||||
|
||||
GenericTypeAnnotation(node) {
|
||||
const name = extract(node.id);
|
||||
* GenericTypeAnnotation(node) {
|
||||
const name = yield node.id;
|
||||
|
||||
// TODO: shadowing?
|
||||
if (name === 'Buffer') {
|
||||
|
@ -172,23 +207,29 @@ const extractors = {
|
|||
return name;
|
||||
},
|
||||
|
||||
FunctionTypeAnnotation(node) {
|
||||
* FunctionTypeAnnotation(node) {
|
||||
return null;
|
||||
},
|
||||
|
||||
Identifier(node) {
|
||||
* Identifier(node) {
|
||||
return node.name;
|
||||
},
|
||||
|
||||
CommentLine(node) {
|
||||
* CommentLine(node) {
|
||||
return extractPragma(node.value);
|
||||
},
|
||||
|
||||
CommentBlock(node) {
|
||||
* CommentBlock(node) {
|
||||
return extractPragma(node.value);
|
||||
},
|
||||
};
|
||||
|
||||
function* extractLastPragma(comments) {
|
||||
const pragmas = (yield comments).filter(Boolean);
|
||||
|
||||
return pragmas.length > 0 ? pragmas[pragmas.length - 1] : null;
|
||||
}
|
||||
|
||||
function parsePragma(pragma) {
|
||||
let [type, arg] = pragma.split(/\s+/);
|
||||
|
||||
|
@ -221,14 +262,6 @@ function parsePragma(pragma) {
|
|||
return [type, arg];
|
||||
}
|
||||
|
||||
function extractLastPragma(comments) {
|
||||
const pragmas = comments
|
||||
.map(extract)
|
||||
.filter(Boolean);
|
||||
|
||||
return pragmas.length > 0 ? pragmas[pragmas.length - 1] : null;
|
||||
}
|
||||
|
||||
function extractPragma(text) {
|
||||
const marker = '$avro ';
|
||||
|
||||
|
|
20
lib/index.js
20
lib/index.js
|
@ -1,21 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
const parse = require('./parser');
|
||||
const visit = require('./visitor');
|
||||
const extract = require('./extractor');
|
||||
|
||||
function collect(node, schemes) {
|
||||
const scheme = extract(node);
|
||||
|
||||
const name = node.id.name;
|
||||
|
||||
assert(!schemes[name]);
|
||||
|
||||
scheme.name = name;
|
||||
|
||||
schemes[name] = scheme;
|
||||
function collect(node, schemas) {
|
||||
extract(node, schemas);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -29,11 +19,11 @@ const visitor = {
|
|||
function generate(code) {
|
||||
const ast = parse(code);
|
||||
|
||||
const schemes = Object.create({});
|
||||
const schemas = Object.create({});
|
||||
|
||||
visit(ast, visitor, schemes);
|
||||
visit(ast, visitor, schemas);
|
||||
|
||||
return schemes;
|
||||
return schemas;
|
||||
}
|
||||
|
||||
module.exports = generate;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
function partition(iter, predicate) {
|
||||
const left = [];
|
||||
const right = [];
|
||||
|
|
Loading…
Reference in New Issue