UNPKG

@derivate/io-ts-deriver

Version:

156 lines (155 loc) 9.27 kB
"use strict"; 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]; }); })); } }); };