UNPKG

@airtasker/form-schema-compiler

Version:
343 lines (264 loc) 13.4 kB
"use strict"; exports.__esModule = true; exports.compileProps = undefined; exports.compileComponents = compileComponents; var _curryRight = require("lodash/curryRight"); var _curryRight2 = _interopRequireDefault(_curryRight); var _curry = require("lodash/curry"); var _curry2 = _interopRequireDefault(_curry); var _mapValues = require("lodash/mapValues"); var _mapValues2 = _interopRequireDefault(_mapValues); var _mapKeys = require("lodash/mapKeys"); var _mapKeys2 = _interopRequireDefault(_mapKeys); var _findKey = require("lodash/findKey"); var _findKey2 = _interopRequireDefault(_findKey); var _flowRight = require("lodash/flowRight"); var _flowRight2 = _interopRequireDefault(_flowRight); var _const = require("./const"); var _parsers = require("./parsers"); var _typeCompiler = require("./typeCompiler"); var _typeCompiler2 = _interopRequireDefault(_typeCompiler); var _utils = require("./utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); } function isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } function _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } var mapValuesFp = (0, _curryRight2["default"])(_mapValues2["default"]); var mapKeysFp = (0, _curryRight2["default"])(_mapKeys2["default"]); /** * convert json value * "string" to {type: string, value: "string"} * 1 to {type: numeric, value: 1} * true to {type: boolean, value: 1} * null to {type: Null, value: null} * other types to {type: Raw, value} * @param obj * @returns {*} */ var toValueObject = function toValueObject(value) { if (value === null) { return { type: _const.TYPES.Null, value: value }; } switch (_typeof(value)) { case "string": return { type: _const.TYPES.String, value: value }; case "number": return { type: _const.TYPES.Numeric, value: value }; case "boolean": return { type: _const.TYPES.Boolean, value: value }; default: return { type: _const.TYPES.Raw, value: value }; } }; /** * get annotation * @param key string * * e.g. * '[value]' return '[]' * '<value>' return '<>' * '#value#' return '##' * '{value}' return '{}' * '(value)' return '()' */ var getAnnotationType = function getAnnotationType(key) { return (0, _findKey2["default"])(_const.ANNOTATIONS, { 0: key[0], 1: key.substr(-1) }); }; /** * strip annotation * @param key string * * e.g. * '[value]' return 'value' * '<value>' return 'value' * '#value#' return 'value' * '{value}' return 'value' * '(value)' return 'value' */ var stripAnnotation = function stripAnnotation(value, key) { var strippedKey = key.substring(1, key.length - 1); switch (getAnnotationType(key)) { case _const.ANNOTATION_TYPES.TwoWayBinding: case _const.ANNOTATION_TYPES.PropertyBinding: case _const.ANNOTATION_TYPES.Template: case _const.ANNOTATION_TYPES.Components: // only strip annotation when there is one // convert [value] to value return strippedKey; case _const.ANNOTATION_TYPES.EventBinding: // convert (click) to onClick return "on".concat(strippedKey[0].toUpperCase()).concat(strippedKey.substr(1)); default: return key; } }; var ErrorPathTrace = /*#__PURE__*/ function (_Error) { _inherits(ErrorPathTrace, _Error); function ErrorPathTrace(key, value, error) { var _this; _classCallCheck(this, ErrorPathTrace); _this = _possibleConstructorReturn(this, _getPrototypeOf(ErrorPathTrace).call(this)); if (error.kind === 'ErrorPathTrace') { _this.path = "".concat(key, ".").concat(error.path); _this.originMessage = error.originMessage; } else { _this.path = "".concat(key, ":\"").concat(value, "\""); _this.originMessage = error.message; } _this.kind = 'ErrorPathTrace'; _this.message = "Found an error in ".concat(_this.path, ". Error details: ").concat(_this.originMessage); return _this; } return ErrorPathTrace; }(_wrapNativeSuper(Error)); /** * compile value to ast expression, * examples see expression parsers and tests * @param {*} options * @param {*} value * @param {*} key */ var compileValue = (0, _curry2["default"])(function (options, value, key) { try { switch (getAnnotationType(key)) { case _const.ANNOTATION_TYPES.EventBinding: return { type: _const.ANNOTATION_TYPES.EventBinding, value: (0, _parsers.parseExpressionString)(value) }; case _const.ANNOTATION_TYPES.PropertyBinding: if (_typeof(value) === "object") { return { type: _const.ANNOTATION_TYPES.PropertyBinding, nested: true, value: compileProps(value, options) }; } return { type: _const.ANNOTATION_TYPES.PropertyBinding, nested: false, value: (0, _parsers.parseExpressionString)(value) }; case _const.ANNOTATION_TYPES.TwoWayBinding: throw new Error("Should use compile to convert TwoWayBinding to EventBinding and PropertyBinding"); case _const.ANNOTATION_TYPES.Template: return { type: _const.ANNOTATION_TYPES.PropertyBinding, value: (0, _parsers.parseTemplateString)(value) }; case _const.ANNOTATION_TYPES.Components: // recursively compile nested component // eslint-disable-next-line no-use-before-define return compileComponents(value, options); default: return toValueObject(value); } } catch (error) { throw new ErrorPathTrace(key, value, error); } }); /** * compile values but not keys, compile values to ast expression. * e.g. * {'{value}': 'expression'} return {'{value}': 'compiled expression'} */ var createCompileValues = function createCompileValues(options) { return mapValuesFp(compileValue(options)); }; /** * compile keys but not value, compile keys to non-annotation key. * e.g. * {'{value}': 'expression', '<component>': 'expression' } return {'value': 'expression', 'component': 'expression'} */ var compileKeys = mapKeysFp(stripAnnotation); /** * compile keys and values. */ var compileProps = exports.compileProps = function compileProps(props, options) { return (0, _flowRight2["default"])(compileKeys, createCompileValues(options))(props); }; var compilePropsFp = (0, _curryRight2["default"])(compileProps); /** * Take component schema return AST, * examples see expression parsers and tests * @param {*} componentSchema * @param {{typeCompilers: *}} options * @returns {{type: *}} */ var compileComponent = function compileComponent(_ref) { var type = _ref.type, props = _objectWithoutProperties(_ref, ["type"]); var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (!type) { throw new Error("type is a mandatory field in component"); } var typeCompiler = (0, _typeCompiler2["default"])(type, options.typeCompilers); var composed = (0, _flowRight2["default"])(typeCompiler.after, compilePropsFp(options), typeCompiler.before); return _objectSpread({ type: type }, composed(props)); }; /** * compile components schema * @param {*} components if components is an object convert to [components] * @param {{typeCompilers: *}} options * @returns {{type: string, components: Array}} */ function compileComponents(components, options) { if (_typeof(components) !== "object") { throw new Error("components must be a object or array"); } var componentArray = Array.isArray(components) ? components : [components]; return { type: _const.TYPES.Components, components: componentArray.map(function (component) { return compileComponent(component, options); }) }; } var compile = function compile(_ref2, options) { var schemaVersion = _ref2.schemaVersion, rest = _objectWithoutProperties(_ref2, ["schemaVersion"]); if (!schemaVersion || !(0, _utils.isVersionCompatible)(schemaVersion)) { throw new Error("incompatible version, you may use wrong version form-schema"); } var component = rest["<component>"]; return _objectSpread({}, rest, { schemaVersion: schemaVersion, component: compileComponents(component, options) }); }; exports["default"] = compile;