UNPKG

flow-immutable-models

Version:

Generates model classes from Flow types using Immutable.js

162 lines (129 loc) 6.12 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = function (file, api, options) { var j = api.jscodeshift; var printOptions = options.printOptions || defaultPrintOptions; var root = j(file.source); var program = root.get().value.program; var body = program.body; var classes = []; function makeClass(className, type, defaultValues) { var classNameIdentifier = j.identifier(className); var staticMethods = [(0, _fromJS2.default)(j, className, defaultValues, type.properties)]; var instanceMethods = type.properties.reduce(function (methods, prop) { methods.push((0, _getter2.default)(j, prop), (0, _setter2.default)(j, prop)); return methods; }, [(0, _toJS2.default)(j, className, type.properties)]); var classDeclaration = j.exportNamedDeclaration(j.classDeclaration(classNameIdentifier, j.classBody(staticMethods.concat(instanceMethods)), j.identifier('ImmutableModel'))); var comments = [' /////////////////////////////////////////////////////////////////////////////', '', ' NOTE: THIS CLASS IS GENERATED. DO NOT MAKE CHANGES HERE.', '', ' If you need to update this class, update the corresponding flow type above', ' and re-run the flow-immutable-models codemod', '', ' /////////////////////////////////////////////////////////////////////////////']; classDeclaration.comments = comments.map(function (comment) { return j.commentLine(comment); }); return classDeclaration; } function parseType(td) { if (typeof td === 'string') { return td; } var typeDef = Object.assign({}, td); delete typeDef.start; delete typeDef.end; delete typeDef.loc; delete typeDef.extra; if (typeDef.id) { typeDef.id = parseType(typeDef.id); } if (typeDef.key) { typeDef.key = parseType(typeDef.key); } if (typeDef.value) { typeDef.value = parseType(typeDef.value); } if (typeDef.types) { typeDef.types = typeDef.types.map(parseType); } if (typeDef.properties) { typeDef.properties = typeDef.properties.map(parseType); } return typeDef; } root.find(j.ExportNamedDeclaration).filter(function (p) { if (p.node.exportKind === 'type') { var identifier = p.node.declaration.id.name; return (0, _withoutModelTypeSuffix.endsWithModelType)(identifier); } return false; }).forEach(function (p) { var identifier = p.node.declaration.id.name; var className = (0, _withoutModelTypeSuffix.withoutModelTypeSuffix)(identifier); var parsedType = parseType(p.node.declaration.right); if (parsedType.type !== 'ObjectTypeAnnotation') { throw new Error('Expected ' + identifier + ' to be of type ObjectTypeAnnotation. Instead it was of type ' + parsedType.type + '.\n\nAll types ending with "ModelType" are expected to be defined as object literals with properties.\nPerhaps you didn\'t mean for ' + identifier + ' to be a ModelType.\n'); } var defaultValuesName = 'default' + (0, _capitalize2.default)(className) + 'Values'; var defaultValues = null; root.find(j.VariableDeclaration).filter(function (path) { return path.node.declarations.forEach(function (dec) { if (dec.id.name === defaultValuesName) { defaultValues = dec; } }); }); classes.push({ className: className, classDef: makeClass(className, parsedType, defaultValues), optionalType: (0, _getDefaultValueTypeStatements.getOptionalTypeStatement)(j, className, defaultValues), requiredType: (0, _getDefaultValueTypeStatements.getRequiredTypeStatement)(j, className, defaultValues, parsedType.properties), fromJSType: (0, _getDefaultValueTypeStatements.getFromJSTypeStatement)(j, className, defaultValues), fullType: (0, _getDefaultValueTypeStatements.getFullTypeStatement)(j, className, defaultValues) }); }); var replaceOrAddStatement = function replaceOrAddStatement(tokenType, filterFn, statement) { var existingStatement = root.find(tokenType).filter(filterFn); if (existingStatement.size() === 1) { existingStatement.replaceWith(statement); } else { body.push(statement); } }; classes.forEach(function (_ref) { var className = _ref.className, classDef = _ref.classDef, fromJSType = _ref.fromJSType, fullType = _ref.fullType, optionalType = _ref.optionalType, requiredType = _ref.requiredType; replaceOrAddStatement(j.ExportNamedDeclaration, function (path) { return path.node.declaration.type === 'ClassDeclaration' && path.node.declaration.id.name === className; }, classDef); replaceOrAddStatement(j.TypeAlias, function (path) { return path.node.id.name === className + 'OptionalArguments'; }, optionalType); replaceOrAddStatement(j.TypeAlias, function (path) { return path.node.id.name === className + 'RequiredArguments'; }, requiredType); replaceOrAddStatement(j.TypeAlias, function (path) { return path.node.id.name === className + 'FullType'; }, fullType); replaceOrAddStatement(j.TypeAlias, function (path) { return path.node.id.name === className + 'FromJSType'; }, fromJSType); }); return root.toSource(printOptions); }; var _capitalize = require('./helpers/capitalize'); var _capitalize2 = _interopRequireDefault(_capitalize); var _fromJS = require('./helpers/fromJS'); var _fromJS2 = _interopRequireDefault(_fromJS); var _getDefaultValueTypeStatements = require('./helpers/getDefaultValueTypeStatements'); var _getter = require('./helpers/getter'); var _getter2 = _interopRequireDefault(_getter); var _setter = require('./helpers/setter'); var _setter2 = _interopRequireDefault(_setter); var _toJS = require('./helpers/toJS'); var _toJS2 = _interopRequireDefault(_toJS); var _withoutModelTypeSuffix = require('./helpers/withoutModelTypeSuffix'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var defaultPrintOptions = { quote: 'single', trailingComma: true };