@derivate/io-ts-deriver
Version:
156 lines (155 loc) • 9.27 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var Do_1 = require("fp-ts-contrib/lib/Do");
var A = require("fp-ts/lib/Array");
var Array_1 = require("fp-ts/lib/Array");
var function_1 = require("fp-ts/lib/function");
var O = require("fp-ts/lib/Option");
var pipeable_1 = require("fp-ts/lib/pipeable");
var ts = require("typescript");
var D = require("@derivate/core/lib/derivate");
var helpers_1 = require("@derivate/core/lib/utils/helpers");
var hood_1 = require("@derivate/core/lib/utils/hood");
var compilerUtils_1 = require("@derivate/core/lib/utils/compilerUtils");
var JSDocTagName = "implied";
var FuncName = "__deriveIO";
// const ModuleName = "derivate/lib/io-ts-type";
// const ModuleName = "../src/io-ts-type";
var accessT = function (id, s) {
return D.of(ts.createPropertyAccess(ts.createPropertyAccess(id, ts.createIdentifier(tImport)), ts.createIdentifier(s)));
};
var callT = function (importId, s) { return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return pipeable_1.pipe(accessT(importId, s), D.map(function (str) { return ts.createCall(str, undefined, args); }));
}; };
var tImport = "t";
exports.IoTsDeriver = function (moduleName) {
if (moduleName === void 0) { moduleName = "@derivate/io-ts-deriver/lib/io-ts-type"; }
return ({
expressionBuilder: function (type, id, advance, currentPath) {
return helpers_1.matchType({
stringLiteral: function (str) { return callT(id, "literal")(ts.createStringLiteral(str.value)); },
string: function () { return accessT(id, "string"); },
numberLiteral: function (num) { return callT(id, "literal")(ts.createLiteral(num.value)); },
number: function () { return accessT(id, "number"); },
void: function () { return accessT(id, "void"); },
unknown: function () { return accessT(id, "unknown"); },
any: function () { return accessT(id, "any"); },
booleanLiteral: function (bool) { return callT(id, "literal")(ts.createLiteral(bool.value)); },
boolean: function () { return accessT(id, "boolean"); },
union: function (u) {
return pipeable_1.pipe(hood_1.splay(u.types), function (hoods) {
return Array_1.array.traverse(D.derivate)(hoods, function (hood) {
return advance(hood.focus, {
_type: "union",
hood: hood
});
});
}, D.map(ts.createArrayLiteral), D.chain(callT(id, "union")));
},
intersection: function (i) {
return pipeable_1.pipe(hood_1.splay(i.types), function (hoods) {
return Array_1.array.traverse(D.derivate)(hoods, function (hood) {
return advance(hood.focus, {
_type: "intersection",
hood: hood
});
});
}, D.map(ts.createArrayLiteral), D.chain(callT(id, "union")));
},
class: function (t) {
return D.error(D.unsupportedType(t.type, "classes ain't supported", currentPath));
},
interface: function (t) {
return D.error(D.unsupportedType(t.type, "interfaces ain't supported", currentPath));
},
// todo: hmm
// generic: { type: ts.Type, parameters: ts.Type[] },
function: function () { return accessT(id, "Function"); },
struct: function (_a) {
var extract = _a.extract;
return D.askM(function (_a) {
var checker = _a.checker, source = _a.source;
return pipeable_1.pipe(extract(checker, source), function (_a) {
var props = _a.props;
return Array_1.array.traverse(D.derivate)(props, helpers_1.propFold({
method: function (name) {
return pipeable_1.pipe(accessT(id, "function"), D.map(function (acc) { return ts.createPropertyAssignment(name, acc); }));
},
property: function (name, t) {
return pipeable_1.pipe(advance(t, { _type: "prop", name: name, type: t }), D.map(function (acc) { return ts.createPropertyAssignment(name, acc); }));
}
}));
}, D.map(ts.createObjectLiteral), D.chain(callT(id, "type")));
});
},
default: function () {
return D.error({ _type: "Exception", message: 'sent to "default" matcher' });
}
})(type);
},
symbolRepresentsTcForType: function (symbol, type) {
return Do_1.Do(D.derivate)
.bind("checker", D.ask(function (a) { return a.checker; }))
.bind("rootNode", D.ask(function (a) { return a.deriveNode; }))
.bindL("represents", function (_a) {
var checker = _a.checker, rootNode = _a.rootNode;
var typ = pipeable_1.pipe(O.tryCatch(function () { return checker.getTypeOfSymbolAtLocation(symbol, rootNode); }));
var matches = pipeable_1.pipe(typ, O.chain(function (t) { return O.fromNullable(t.symbol); }), O.chain(function (s) { return O.fromNullable(s.declarations); }), O.chain(A.head), O.chain(O.fromNullable), O.map(compilerUtils_1.access("parent")), O.chain(compilerUtils_1.extract(ts.isSourceFile)), O.map(function (a) { return a.fileName.endsWith("io-ts/lib/index.d.ts"); }), O.map(function (matches) {
return matches &&
pipeable_1.pipe(
// todo: should this be handle by derivate?
symbol.getJsDocTags(), A.findFirst(function (tag) { return tag.name === JSDocTagName; }), O.isSome);
}), O.getOrElse(function () { return false; }));
if (matches) {
// get jsdoc annotations
// console.log('MATCHED', symbol.name)
return pipeable_1.pipe(typ, O.chain(function (t) {
return O.tryCatch(function () {
return checker.getTypeArguments(t);
});
}), O.chain(A.head), O.map(function (t) { return compilerUtils_1.typeEq(checker).equals(t, type); }), O.getOrElse(function () { return false; }), D.of);
}
else {
return D.of(false);
}
})
.return(function (p) { return p.represents; });
},
extractor: function (node) {
return pipeable_1.pipe(D.deriver, D.map(function (_a) {
var checker = _a.context.checker;
return Do_1.Do(O.option)
.bind("ce", compilerUtils_1.extract(ts.isCallExpression)(node))
// .bindL("ceName", ({ce}) => extract(ts.isIdentifier)(ce.expression))
.bindL("propAccess", function (_a) {
var ce = _a.ce;
return compilerUtils_1.extract(ts.isPropertyAccessExpression)(ce.expression);
})
.bindL("leftExpression", function (_a) {
var propAccess = _a.propAccess;
return compilerUtils_1.extract(ts.isIdentifier)(propAccess.expression);
})
.bindL("identifier", function (_a) {
var propAccess = _a.propAccess, leftExpression = _a.leftExpression;
return pipeable_1.pipe(O.fromNullable(checker.getSymbolAtLocation(leftExpression)), O.map(compilerUtils_1.symbolMatches(FuncName, moduleName)), O.chain(function (matches) { return (matches && propAccess.name.text === 'derive' ? O.some(leftExpression) : O.none); }));
})
.bindL("type", function_1.flow(compilerUtils_1.access("ce"), compilerUtils_1.access("typeArguments"), O.fromNullable, O.map(function (args) { return args[0]; }), O.chain(O.fromNullable), O.map(checker.getTypeFromTypeNode)))
.return(function (_a) {
// console.log("found!");
// console.log(" call expression:", ce.getText());
var ce = _a.ce, identifier = _a.identifier, type = _a.type;
// console.log(' children:');
// ce.getChildren().forEach(n => {
// console.log(' :', syntaxKindtoName(n.kind), `(${n.getText()})`)
// })
// console.log(" extracted type :", type.symbol.escapedName);
return [type, identifier];
});
}));
}
});
};