UNPKG

views-morph

Version:
1,789 lines (1,406 loc) 94.2 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var path = require('path'); var buble = _interopDefault(require('buble')); var toCamelCase = _interopDefault(require('to-camel-case')); var toSlugCase = _interopDefault(require('to-slug-case')); var list = _interopDefault(require('google-fonts-complete/api-response.json')); var toPascalCase = _interopDefault(require('to-pascal-case')); var sort = _interopDefault(require('bubblesort')); var prettier = _interopDefault(require('prettier')); var Levenshtein = _interopDefault(require('levenshtein')); var sortBy = _interopDefault(require('lodash.sortby')); var wrap = (function (s) { return "{" + s + "}"; }); var safe = (function (value) { return typeof value === 'string' && !isSlot(value) ? JSON.stringify(value) : wrap(value); }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var defineProperty = function (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; }; var objectWithoutProperties = function (obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }; var slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var toArray = function (arr) { return Array.isArray(arr) ? arr : Array.from(arr); }; var toConsumableArray = function (arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; var safeScope = function safeScope(value) { return typeof value === 'string' && !isSlot(value) ? JSON.stringify(value) : value; }; var checkParentStem = function checkParentStem(node, styleKey) { if (styleKey !== 'hover' || styleKey !== 'disabled' || !node.parent) return false; var matchingParentStem = node.parent.scopes.some(function (scope) { return scope.value === styleKey; }); return matchingParentStem && (node.parent.is || node.parent.name); }; var INTERPOLATION = /\${(.+)}/; var isInterpolation = function isInterpolation(str) { return INTERPOLATION.test(str); }; var deinterpolate = function deinterpolate(str) { var match = str.match(INTERPOLATION); return match ? match[1] : str; }; var getObjectAsString = function getObjectAsString(obj) { return wrap(Object.keys(obj).map(function (k) { var v = _typeof(obj[k]) === 'object' && hasKeys(obj[k]) ? getObjectAsString(obj[k]) : obj[k]; return JSON.stringify(k) + ': ' + v; }).join(',')); }; var getPropertiesAsObject = function getPropertiesAsObject(list$$1) { var obj = {}; list$$1.forEach(function (prop) { obj[prop.name] = safeScope(prop.value); }); return getObjectAsString(obj); }; var getProp = function getProp(node, key) { var finder = typeof key === 'string' ? function (p) { return p.name === key; } : function (p) { return key.test(p.name); }; return node.properties && node.properties.find(finder); }; var maybeSafe = function maybeSafe(node) { return node.tags.slot ? node.value : typeof node.value === 'string' ? safe(node.value) : node.value; }; var getScopedProps = function getScopedProps(propNode, blockNode) { var scopes = blockNode.scopes.filter(function (scope) { return !scope.isSystem; }).map(function (scope) { var prop = scope.properties.find(function (prop) { return prop.name === propNode.name; }); return prop && { prop: prop, when: scope.value }; }).filter(Boolean).reverse(); if (isEmpty(scopes)) return false; return scopes; }; var getScopedCondition = function getScopedCondition(propNode, blockNode) { var conditional = maybeSafe(propNode); if (!getScopedProps(propNode, blockNode)) return false; getScopedProps(propNode, blockNode).forEach(function (scope) { conditional = scope.when + ' ? ' + maybeSafe(scope.prop) + ' : ' + conditional; }); return conditional; }; var getScopedImageCondition = function getScopedImageCondition(scopes, scopedNames, defaultName) { var conditional = defaultName; scopes.forEach(function (scope, index) { conditional = scope.when + ' ? ' + scopedNames[index] + ' : ' + conditional; }); return conditional; }; var getScopedRequireCondition = function getScopedRequireCondition(scopes, paths, defaultName) { var conditional = 'requireImage(\'' + defaultName + '\')'; scopes.forEach(function (scope, index) { conditional = scope.when + ' ? requireImage(\'' + paths[index] + '\') : ' + conditional; }); return conditional; }; var styleStems = ['hover', 'focus', 'placeholder', 'disabled', 'print']; var getStyleType = function getStyleType(node) { return styleStems.find(function (tag) { return isTag(node, tag); }) || 'base'; }; var hasKeys = function hasKeys(obj) { return Object.keys(obj).length > 0; }; var hasKeysInChildren = function hasKeysInChildren(obj) { return Object.keys(obj).some(function (k) { return hasKeys(obj[k]); }); }; var hasProp = function hasProp(node, key, match) { var prop = getProp(node, key); if (!prop) return false; return typeof match === 'function' ? match(prop.value) : true; }; var isSlot = function isSlot(node) { return typeof node === 'string' ? /props/.test(node) : isTag(node, 'slot'); }; var isStyle = function isStyle(node) { return isTag(node, 'style'); }; var isTag = function isTag(node, tag) { return node && node.tags[tag]; }; var getActionableParent = function getActionableParent(node) { if (!node.parent) return false; if (node.parent.action) return node.parent; return getActionableParent(node.parent); }; var getAllowedStyleKeys = function getAllowedStyleKeys(node) { if (node.isCapture) { return ['base', 'focus', 'hover', 'disabled', 'placeholder', 'print']; } else if (node.action || getActionableParent(node)) { return ['base', 'focus', 'hover', 'disabled', 'print']; } return ['base', 'focus', 'print']; }; var isList = function isList(node) { return node && node.type === 'Block' && node.name === 'List'; }; var isEmpty = function isEmpty(list$$1) { return list$$1.length === 0; }; var isValidImgSrc = function isValidImgSrc(node, parent) { return node.name === 'source' && parent.name === 'Image' && parent.isBasic; }; var pushImageToState = function pushImageToState(state, scopedNames, paths) { return scopedNames.forEach(function (name) { var path$$1 = paths[scopedNames.findIndex(function (item) { return item === name; })]; if (!state.images.includes(path$$1)) { state.images.push({ name: name, file: path$$1 }); } }); }; var getScopes = function getScopes(node, parent) { var scopedProps = getScopedProps(node, parent); if (!scopedProps) return false; var paths = scopedProps.map(function (scope) { return scope.prop.value; }); var scopedNames = paths.map(function (path$$1) { return toCamelCase(path$$1); }); return { scopedProps: scopedProps, paths: paths, scopedNames: scopedNames }; }; var isSvg = function isSvg(node) { return (/^Svg/.test(node.name) && node.isBasic ); }; var getScopeDescription = function getScopeDescription(scope) { var dictionary = {}; var re = /(?:^|\W)props.(\w+)(?!\w)/g; var match = re.exec(scope); while (match) { dictionary[match[1]] = toSlugCase(match[1]); match = re.exec(scope); } for (var key in dictionary) { scope = scope.replace(new RegExp(key, 'g'), dictionary[key]); } return toCamelCase(scope.replace(/\|\|/g, '-or-').replace(/!/g, 'not-').replace(/&&/g, '-and-').replace(/props\./g, '').replace(/\s/g, '')); }; var makeOnClickTracker = function makeOnClickTracker(node, state) { var block = node.testId ? '"' + state.name + '.' + node.testId + '"' : 'props["' + state.testIdKey + '"] || "' + state.name + '"'; state.isTracking = true; return 'event => context.track({ block: ' + block + ', action: "click", callback: ' + node.value + ', event })'; }; var enter$1 = function enter(node, parent, state) { if (node.name === 'Proxy') return; var scopes = node.scopes.filter(function (scope) { return !scope.isSystem; }).map(function (scope) { return scope.value; }).filter(Boolean).reverse(); var conditional = scopes.reduce(function (prev, scope) { return scope + ' ? \'' + getScopeDescription(scope) + '|\' : ' + prev; }, "''"); conditional = scopes.length > 0 ? '${' + conditional + '}' : ''; var value = void 0; if (parent) { value = '{`' + state.name + '.' + node.testId + '|' + conditional + '`}'; } else { value = '{`${props[\'' + state.testIdKey + '\'] || \'' + node.testId + '\'}|' + conditional + '`}'; } state.render.push(' ' + state.testIdKey + '=' + value); }; var typesMap = { CaptureEmail: 'email', CaptureText: 'text', CaptureNumber: 'number', CapturePhone: 'tel', CaptureSecure: 'password' }; var enter$2 = function enter(node, parent, state) { var blockType = node.name; if (!/Capture/.test(blockType)) return; node.isCapture = true; var name = toCamelCase(node.is || blockType); state.captures.push(name); if (typesMap[blockType]) { state.render.push(' type=\'' + typesMap[blockType] + '\''); } // if you specify a value, then you're supposed to manage the input from // outside the view if (getProp(node, 'value')) return; state.render.push(' onChange={event => this.setState({ ' + name + ': event.target.value })}'); state.render.push(' value={state.' + name + '}'); if (state.debug) { state.render.push(' tabIndex={-1}'); } }; function leave$1(node, parent, state) { if (node.explicitChildren) { state.render.push('>'); state.render.push(node.explicitChildren); } } var enter$3 = function enter(node, parent, state) { if (node.goTo) { var goTo = getProp(node, 'goTo'); state.render.push(' href=' + safe(goTo.value, goTo) + ' rel=\'noopener noreferrer\' target=\'_blank\''); } }; function enter$4(node, parent, state) { if (node.isGroup && node.children.length > 0) { state.render.push('>'); } } function enter$5(node, parent, state) { if (isList(parent)) { state.render.push(' {...item} key={item.id || index}'); } } function enter$6(node, parent, state) { if (isList(node)) { var from = getProp(node, 'from'); if (!from) return; state.render.push('{Array.isArray(' + from.value + ') && ' + from.value + '.map((item, index) => '); } } function leave$2(node, parent, state) { if (isList(node)) { state.render.push(')}'); } } function leave$3(node, parent, state) { if (!parent && node.isGroup || node.explicitChildren || node.isGroup && node.children.length > 0) { if (!parent && node.isGroup) { if (node.children.length === 0) { state.render.push('>'); } if (!node.usesProxy) { state.render.push('{props.children}'); } } state.render.push('</' + node.nameFinal + '>'); } else { state.render.push('/>'); } } var getBlockName = (function (node, parent, state) { var name = node.name; switch (node.name) { case 'CaptureEmail': case 'CaptureFile': case 'CaptureNumber': case 'CapturePhone': case 'CaptureSecure': case 'CaptureText': name = 'input'; break; case 'CaptureTextArea': name = 'textarea'; break; case 'Horizontal': case 'Vertical': name = getGroupBlockName(node, parent, state); break; case 'Image': name = 'img'; break; case 'Text': return 'span'; case 'List': name = 'div'; break; case 'Proxy': return null; case 'Svg': name = 'svg'; break; case 'SvgGroup': name = 'g'; break; case 'SvgCircle': case 'SvgEllipse': case 'SvgLinearGradient': case 'SvgRadialGradient': case 'SvgLine': case 'SvgText': case 'SvgPath': case 'SvgPolygon': case 'SvgPolyline': case 'SvgRect': case 'SvgSymbol': case 'SvgUse': case 'SvgDefs': case 'SvgStop': name = toCamelCase(node.name.replace('Svg', '')); break; default: break; } return name; }); var getGroupBlockName = function getGroupBlockName(node, parent, state) { var name = 'div'; if (hasProp(node, 'teleportTo')) { name = 'Link'; node.teleport = true; } else if (hasProp(node, 'goTo')) { name = 'a'; node.goTo = true; } else if (hasProp(node, 'onClick')) { var propNode = getProp(node, 'onClick'); var prevParent = parent; var canBeButton = true; while (prevParent && canBeButton) { if (prevParent.type === 'Block') { canBeButton = !hasProp(prevParent, 'onClick'); } prevParent = prevParent.parent; } if (canBeButton) { name = 'button'; node.action = propNode.value; } } else if (hasProp(node, 'overflowY', function (v) { return v === 'auto' || v === 'scroll'; })) { name = 'div'; } else if (hasProp(node, 'onSubmit')) { name = 'form'; } return name; }; function enter$7(node, parent, state) { var name = getBlockName(node, parent, state); if (name === null) return true; node.nameFinal = name; node.nameTag = name; state.use(name); if (node.isBasic) { var hasDynamicStyles = node.properties.some(function (prop) { return prop.tags.style && prop.tags.slot; }); var hasDynamicScopedStyles = node.scopes.some(function (scope) { return scope.isSystem ? scope.properties.some(function (prop) { return prop.tags.style && prop.tags.slot; }) : scope.properties.some(function (prop) { return prop.tags.style; }); }); // TODO expand to active, focus, etc var hasHoverStem = node.scopes.some(function (scope) { return scope.value === 'hover'; }); var hasMatchingParentWithHover = hasHoverStem && checkParentStem(node, 'hover'); node.isDynamic = hasDynamicStyles || hasDynamicScopedStyles || hasMatchingParentWithHover; if (node.isDynamic) { // we need to reset it to the block's name or value var finalValue = node.is || node.name; // count repeatead ones if (state.usedBlockNames[finalValue]) { finalValue = '' + finalValue + state.usedBlockNames[finalValue]++; } else { state.usedBlockNames[finalValue] = 1; } node.nameFinal = finalValue; } } state.render.push('<' + node.nameFinal); } function enter$8(node, parent, state) { // onWhen lets you show/hide blocks depending on props var onWhen = getProp(node, 'onWhen'); if (onWhen) { node.onWhen = true; if (parent && !isList(parent)) state.render.push('{'); state.render.push(onWhen.value + ' ? '); } } function leave$4(node, parent, state) { if (node.onWhen) { state.render.push(' : null'); if (parent && !isList(parent)) state.render.push('}'); } } function leave$5(node, parent, state) { if (node.childrenProxyMap) { state.render.push(' childrenProxyMap={' + getObjectAsString(node.childrenProxyMap) + '}'); } } var enter$10 = function enter(node, parent, state) { node.className = ['views-block']; var className = getProp(node, 'className'); if (className) { node.className.push(className.tags.slot ? '${' + className.value + '}' : className.value); } if (state.debug && node.isCapture) { node.className.push('mousetrap'); } }; var leave$6 = function leave(node, parent, state) { if (node.className.length === 1) { var className = node.className[0]; var shouldWrap = true; if (isInterpolation(className)) { className = deinterpolate(className); } else if (!isSlot(className)) { className = '"' + className + '"'; shouldWrap = false; } state.render.push(' className=' + (shouldWrap ? wrap(className) : className)); } else if (node.className.length > 1) { var _className = '`' + node.className.join(' ') + '`'; state.render.push(' className=' + wrap(_className)); } }; var enter$11 = function enter(node, parent, state) { // TODO caption if (node.name === 'Image') { state.render.push(' alt={""}'); } }; function leave$7(node, parent, state) { if (node.isRoute) { state.render.push(' {...routeProps}'); } } function enter$12(node, parent, state) { node.style = { dynamic: { base: {}, hover: {}, focus: {}, disabled: {}, placeholder: {}, print: {} }, static: { base: {}, hover: {}, focus: {}, disabled: {}, placeholder: {}, print: {} } // TODO use this directly in styles without having to go through this };node.scopes.filter(function (scope) { return scope.isSystem; }).forEach(function (scope) { scope.properties.forEach(function (propNode) { if (propNode.name === 'when') return; var _state$getStyleForPro = state.getStyleForProperty(propNode, node, isSlot(propNode)), _isProp = _state$getStyleForPro._isProp, styleForProperty = objectWithoutProperties(_state$getStyleForPro, ['_isProp']); if (_isProp) { Object.keys(styleForProperty).forEach(function (k) { return state.render.push(' ' + k + '=' + safe(styleForProperty[k], node)); }); } else { var hasMatchingParent = parent && node.isDynamic ? checkParentStem(node, scope.value) : false; var target = isSlot(propNode) || hasMatchingParent ? node.style.dynamic : node.style.static; Object.assign(target[scope.value], styleForProperty); } }); }); // ensure flex-direction in Horizontals if (node.isGroup && node.name === 'Horizontal') { node.style.static.base.flexDirection = 'row'; } } // https://raw.githubusercontent.com/threepointone/glam/master/src/hash.js // murmurhash2 via https://gist.github.com/raycmorgan/588423 var hash = (function (arr) { return 'h' + hash$1(arr); }); function hash$1(arr) { var str = (Array.isArray(arr) ? arr : Object.keys(arr).map(function (k) { return k + ':' + JSON.stringify(arr[k]); })).join(','); return murmur2(str, str.length).toString(36); } function murmur2(str, seed) { var m = 0x5bd1e995; var r = 24; var h = seed ^ str.length; var length = str.length; var currentIndex = 0; while (length >= 4) { var k = UInt32(str, currentIndex); k = Umul32(k, m); k ^= k >>> r; k = Umul32(k, m); h = Umul32(h, m); h ^= k; currentIndex += 4; length -= 4; } switch (length) { case 3: h ^= UInt16(str, currentIndex); h ^= str.charCodeAt(currentIndex + 2) << 16; h = Umul32(h, m); break; case 2: h ^= UInt16(str, currentIndex); h = Umul32(h, m); break; case 1: h ^= str.charCodeAt(currentIndex); h = Umul32(h, m); break; } h ^= h >>> 13; h = Umul32(h, m); h ^= h >>> 15; return h >>> 0; } function UInt32(str, pos) { return str.charCodeAt(pos++) + (str.charCodeAt(pos++) << 8) + (str.charCodeAt(pos++) << 16) + (str.charCodeAt(pos) << 24); } function UInt16(str, pos) { return str.charCodeAt(pos++) + (str.charCodeAt(pos++) << 8); } function Umul32(n, m) { n = n | 0; m = m | 0; var nlo = n & 0xffff; var nhi = n >>> 16; var res = nlo * m + ((nhi * m & 0xffff) << 16) | 0; return res; } function leave$8(node, parent, state) { var _node$style = node.style, dynamic = _node$style.dynamic, staticStyle = _node$style.static; var allowedStyleKeys = getAllowedStyleKeys(node); var scopedUnderParent = !node.isCapture && !node.action && getActionableParent(node); if (scopedUnderParent) { scopedUnderParent = scopedUnderParent.styleName; } // dynamic merges static styles if (hasKeysInChildren(dynamic)) { state.cssDynamic = true; node.styleName = node.nameFinal; var cssStatic = Object.keys(staticStyle).filter(function (key) { return allowedStyleKeys.includes(key) && hasKeys(staticStyle[key]); }).map(function (key) { return asCss(asStaticCss(staticStyle[key], Object.keys(dynamic[key])), key, scopedUnderParent).join('\n'); }).join(',\n'); var cssDynamic = ['({ props }) => ({']; cssDynamic = cssDynamic.concat(Object.keys(dynamic).filter(function (key) { return allowedStyleKeys.includes(key) && hasKeys(dynamic[key]); }).map(function (key) { return asCss(asDynamicCss(dynamic[key]), key, scopedUnderParent).join('\n'); }).join(',\n')); cssDynamic.push('})'); cssDynamic = cssDynamic.join('\n'); if (cssStatic || cssDynamic) { state.styles[node.nameFinal] = 'const ' + node.nameFinal + ' = styled(\'' + node.nameTag + '\')(' + (cssStatic ? '{' + cssStatic + '}, ' : '') + cssDynamic + ')'; // TODO we may want to be smarter here and only pass what's needed state.render.push(' props={props}'); } } else if (hasKeysInChildren(staticStyle)) { state.cssStatic = true; var id = (node.is || node.name) + '_' + hash(staticStyle); node.styleName = id; node.className.push('${' + id + '}'); var css = Object.keys(staticStyle).filter(function (key) { return allowedStyleKeys.includes(key) && hasKeys(staticStyle[key]); }).map(function (key) { return asCss(asStaticCss(staticStyle[key]), key, scopedUnderParent).join('\n'); }).join(',\n'); if (css) { state.styles[id] = 'const ' + id + ' = css({' + css + '})'; } } } var asDynamicCss = function asDynamicCss(styles) { return Object.keys(styles).map(function (prop) { return prop + ': ' + styles[prop]; }); }; var safe$1 = function safe(str) { return typeof str === 'string' ? '"' + str.replace(/"/g, "'") + '"' : str; }; var asStaticCss = function asStaticCss(styles) { var dynamicStyles = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; return Object.keys(styles).filter(function (prop) { return !dynamicStyles.includes(prop); }).map(function (prop) { return prop + ': ' + safe$1(styles[prop]); }); }; var asCss = function asCss(styles, key, scopedUnderParent) { var css = []; if (key !== 'base') { if (scopedUnderParent) { var parent = '${' + scopedUnderParent + '}'; if (/_/.test(scopedUnderParent)) { parent = '.' + parent; } css.push('[`' + parent + ':' + key + ' &, ' + parent + '.' + key + ' &`]: {'); } else if (key === 'hover' || key === 'disabled' || key === 'focus' || key === 'placeholder') { css.push('"&:' + key + ', &.' + key + '": {'); } else if (key === 'print') { // TODO can we use this to support all media queries? css.push('"@media print": {'); } } css.push(styles.join(',\n')); if (key !== 'base') css.push('}'); return css; }; function enter$13(node, parent, state) { if (node.name === 'ref') { state.render.push(' ' + (parent.isDynamic ? 'innerRef' : 'ref') + '=' + wrap(node.value)); return true; } } function enter$14(node, parent, state) { var value = state.getValueForProperty(node, parent, state); if (value) { Object.keys(value).forEach(function (k) { return state.render.push(" " + k + "=" + value[k]); }); } } function enter$15(node, parent, state) { if (!isStyle(node) || !parent.isBasic || isSvg(parent) && state.isReactNative || parent.name === 'SvgGroup') return; var styleForProperty = void 0, isScopedVal = void 0, _isProp = void 0; var code = isSlot(node); // TODO refactor if (getScopedCondition(node, parent)) { isScopedVal = true; styleForProperty = defineProperty({}, node.name, getScopedCondition(node, parent)); } else { var _state$getStyleForPro = state.getStyleForProperty(node, parent, code); _isProp = _state$getStyleForPro._isProp; styleForProperty = objectWithoutProperties(_state$getStyleForPro, ['_isProp']); } if (_isProp) { Object.keys(styleForProperty).forEach(function (k) { return state.render.push(' ' + k + '=' + safe(styleForProperty[k], node)); }); } else { var hasMatchingParent = parent && node.isDynamic ? checkParentStem(node, getStyleType(node)) : false; var target = code || isScopedVal || hasMatchingParent ? parent.style.dynamic : parent.style.static; Object.assign(target[getStyleType(node)], styleForProperty); } return true; } function enter$16(node, parent, state) { if (node.name === 'text' && parent.name === 'Text') { if (getScopedCondition(node, parent)) { parent.explicitChildren = wrap(getScopedCondition(node, parent)); } else { parent.explicitChildren = isSlot(node) ? wrap(node.value) : node.value; } return true; } } var blacklist = ['classname', 'teleportto', 'goto']; var blacklistDebug = ['autofocus', 'tabindex']; var isValidPropertyForBlock = (function (node, parent, state) { var name = node.name.toLowerCase(); return !(blacklist.includes(name) || state.debug && blacklistDebug.includes(name)); }); function enter$9(node, parent, state) { enter$12(node, parent, state); enter$10(node, parent, state); enter$11(node, parent, state); node.properties.forEach(function (propNode) { if (propNode.name === 'at' || propNode.name === 'when' || propNode.name === 'onWhen' || propNode.name === 'ref' && state.debug || propNode.tags.unsupportedShorthand || !isValidPropertyForBlock(propNode, node, state) && node.isBasic || propNode.name === 'from' && node.name === 'List') return; !enter$13(propNode, node, state) && !enter$15(propNode, node, state) && !enter$16(propNode, node, state) && enter$14(propNode, node, state); }); leave$8(node, parent, state); leave$7(node, parent, state); leave$5(node, parent, state); leave$6(node, parent, state); } function enter$17(node, parent, state) { if (node.name !== 'Proxy') return; var prevParent = parent; while (prevParent) { if (prevParent.type === 'Block' && !prevParent.parent) { prevParent.usesProxy = true; } prevParent = prevParent.parent; } var proxied = node.properties.find(function (p) { return p.name === 'from'; }); if (!proxied) return; proxied = proxied.value; var otherProperties = node.properties.filter(function (p) { return p.name !== 'from' && p.name !== 'onWhen' && p.name !== 'when'; }); if (!node.onWhen) { state.render.push('{'); } if (proxied === 'all') { var childContent = otherProperties.length > 0 ? 'React.Children.map(props.children, child => React.cloneElement(child, ' + getPropertiesAsObject(otherProperties) + '))' : 'props.children'; state.render.push(childContent); } else { if (!node.onWhen) { state.render.push('props.childrenProxyMap && '); } var child = 'childrenArray[props.childrenProxyMap[\'' + proxied + '\']]'; if (otherProperties.length > 0) { if (node.onWhen) { if (state.render[state.render.length - 1].endsWith(' ? ')) { state.render[state.render.length - 1] = state.render[state.render.length - 1].replace(' ? ', ' && '); } } state.render.push(' ' + child + ' ? React.cloneElement(' + child + ', ' + getPropertiesAsObject(otherProperties) + ') : null'); } else { state.render.push(child); } state.usesChildrenArray = true; } state.render.push('}'); // skip next return true; } function enter$18(node, parent, state) { var at = getProp(node, 'at'); if (at) { var _at$value$split = at.value.split(' '), _at$value$split2 = slicedToArray(_at$value$split, 2), path$$1 = _at$value$split2[0], _at$value$split2$ = _at$value$split2[1], isExact = _at$value$split2$ === undefined ? false : _at$value$split2$; state.use('Route'); if (path$$1 === '/') state.use('Router'); if (!path$$1.startsWith('/')) { path$$1 = isSlot(path$$1) ? '`${' + path$$1 + '}`' : path$$1; // path = `\`\${props.match.url}/${to}\`` } node.isRoute = true; state.render.push('<Route path=' + safe(path$$1) + ' ' + (isExact ? 'exact' : '') + ' render={routeProps => '); } } function leave$9(node, parent, state) { if (node.isRoute) { state.render.push('} />'); } } var enter$19 = function enter(node, parent, state) { if (node.name === 'Proxy') return; var blockName = node.is || node.name; if (typeof state.testIds[blockName] === 'number') { state.testIds[blockName]++; blockName = blockName + ':' + state.testIds[blockName]; } else { state.testIds[blockName] = 0; } node.testId = blockName; }; var enter$20 = function enter(node, parent, state) { if (node.teleport) { var to = getProp(node, 'teleportTo').value; state.render.push(' to=' + safe(to)); } }; var enter = [enter$19, enter$8, enter$17, enter$18, enter$7, enter$2, enter$20, enter$3, enter$5, enter$1, enter$9, enter$4, enter$6]; var leave = [leave$2, leave$1, leave$3, leave$9, leave$4]; var visitor = Object.freeze({ enter: enter, leave: leave }); var getWeights = function getWeights(variants) { return variants.filter(function (v) { return !v.includes('italic'); }).map(function (v) { return v === 'regular' ? 400 : v; }); }; var all = list.map(function (font) { return { category: font.category, value: font.family, weights: getWeights(font.variants) }; }); var byName = {}; all.forEach(function (f) { return byName[f.value] = f; }); var fontFamily = all.map(function (f) { return f.value; }); var isGoogleFont = function isGoogleFont(family) { return !!byName[family]; }; var maybeAddFallbackFont = function maybeAddFallbackFont(f) { var font = byName[f]; return font && font.category ? f + ', ' + font.category : f; }; var getStyleForProperty = (function (node, parent, code) { switch (node.name) { case 'appRegion': return { WebkitAppRegion: node.value }; case 'backgroundImage': return { backgroundImage: code ? '`url(${' + node.value + '})`' : 'url("' + node.value + '")' }; case 'fontFamily': return { fontFamily: code ? node.value : maybeAddFallbackFont(node.value) }; case 'shadowColor': case 'shadowRadius': case 'shadowOffsetX': case 'shadowOffsetY': case 'shadowSpread': return getShadow(node, parent); case 'userSelect': return { WebkitUserSelect: node.value }; case 'zIndex': return { zIndex: code ? node.value : parseInt(node.value, 10) }; default: return defineProperty({}, node.name, node.value); } }); var getPropValue = function getPropValue(prop) { var unit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; if (!prop) return false; if (prop.tags.slot) { return '${' + prop.value + '}' + unit; } return '' + prop.value + unit; }; var getShadow = function getShadow(node, parent) { var isText = parent.name === 'Text'; var shadowColor = getProp(parent, 'shadowColor'); var shadowRadius = getProp(parent, 'shadowRadius'); var shadowOffsetX = getProp(parent, 'shadowOffsetX'); var shadowOffsetY = getProp(parent, 'shadowOffsetY'); var shadowSpread = getProp(parent, 'shadowSpread'); var value = [getPropValue(shadowOffsetX, 'px'), getPropValue(shadowOffsetY, 'px'), getPropValue(shadowRadius, 'px'), !isText && getPropValue(shadowSpread, 'px'), getPropValue(shadowColor)].filter(Boolean).join(' '); if (isSlot(shadowColor) || isSlot(shadowRadius) || isSlot(shadowOffsetY) || isSlot(shadowOffsetX) || isSlot(shadowSpread)) { value = '`' + value + '`'; } return defineProperty({}, isText ? 'textShadow' : 'boxShadow', value); }; var getStyles = (function (_ref) { var styles = _ref.styles; return '\n' + Object.keys(styles).map(function (k) { return styles[k]; }).join('\n'); }); var isUrl = function isUrl(str) { return (/^https?:\/\//.test(str) ); }; var getImageSource = function getImageSource(node, state, parent) { var scopes = getScopes(node, parent); if (scopes && (isUrl(node.value) || node.tags.slot)) { return wrap(getScopedCondition(node, parent)); } else if (isUrl(node.value) || node.tags.slot) { return safe(node.value); } else { if (scopes && state.debug) { return wrap(getScopedRequireCondition(scopes.scopedProps, scopes.paths, node.value)); } else if (state.debug) { return '{requireImage("' + node.value + '")}'; } else { if (scopes) { pushImageToState(state, scopes.scopedNames, scopes.paths); } var name = toCamelCase(node.value); if (!state.images.includes(node.value)) { state.images.push({ name: name, file: node.value }); } return scopes ? wrap(getScopedImageCondition(scopes.scopedProps, scopes.scopedNames, name)) : '{' + name + '}'; } } }; var getValueForProperty = (function (node, parent, state) { if (isValidImgSrc(node, parent)) { return { src: getImageSource(node, state, parent) }; } else if (parent.isBasic && node.name === 'isDisabled') { return { disabled: safe(node.value, node) }; } else if (getScopedCondition(node, parent)) { return defineProperty({}, node.name, safe(getScopedCondition(node, parent))); } else if (parent.isBasic && node.name === 'onClick' && state.track && !state.debug) { return { onClick: wrap(makeOnClickTracker(node, state)) }; } else { return defineProperty({}, node.name, safe(node.value, node)); } }); var maybeUsesRouter = (function (state) { if (state.uses.includes('Router')) { state.render = ['<Router>'].concat(toConsumableArray(state.render), ['</Router>']); } }); var reactNative = ['CaptureEmail', 'CaptureFile', 'CaptureInput', 'CaptureNumber', 'CapturePhone', 'CaptureSecure', 'CaptureText', 'Horizontal', 'Vertical', 'Image', 'Text', 'List', 'Proxy', 'SvgText', 'Svg', 'SvgCircle', 'SvgEllipse', 'SvgGroup', 'SvgLinearGradient', 'SvgRadialGradient', 'SvgLine', 'SvgPath', 'SvgPolygon', 'SvgPolyline', 'SvgRect', 'SvgSymbol', 'SvgUse', 'SvgDefs', 'SvgStop', 'Router', 'Route', 'Link']; var getBody = (function (_ref) { var state = _ref.state, name = _ref.name; var render = state.render.join(''); var maybeChildrenArray = state.usesChildrenArray ? 'const childrenArray = React.Children.toArray(props.children)' : ''; var maybeState = state.captures.length > 0 ? 'constructor(props) {\n super(props)\n this.state = {}\n }' : ''; var block = 'this.props["' + state.testIdKey + '"] || "' + state.name + '"'; var maybeTracking = state.track && !state.debug ? 'componentDidMount() {\n this.context.track({ block: ' + block + ', action: "enter" })\n}\n\ncomponentWillUnmount() {\n this.context.track({ block: ' + block + ', action: "leave" })\n}' : ''; if (maybeState || maybeTracking) { return 'class ' + name + ' extends React.Component {\n ' + maybeState + '\n ' + maybeTracking + '\n\n render() {\n const { ' + (maybeTracking ? 'context,' : '') + ' props, ' + (maybeState ? 'state' : '') + ' } = this\n ' + maybeChildrenArray + '\n return (' + render + ')\n }\n}'; } else { return 'const ' + name + ' = (props ' + (maybeTracking ? ', context' : '') + ') => {\n ' + maybeChildrenArray + '\n return (' + render + ')\n}'; } }); var getContext = (function (_ref) { var state = _ref.state, name = _ref.name; if (state.track && !state.debug) { return name + '.contextTypes = {\n track: PropTypes.func.isRequired\n}'; } return ''; }); var stringify = function stringify(slot) { return (/^[0-9]+$/.test(slot.defaultValue) ? slot.defaultValue : JSON.stringify(slot.defaultValue) ); }; var getDefaultProps = (function (_ref) { var state = _ref.state, name = _ref.name; var slots = state.slots.filter(function (slot) { return slot.defaultValue !== false; }).map(function (slot) { return slot.name + ': ' + stringify(slot); }); return slots.length === 0 ? '' : name + '.defaultProps = {' + slots.join(',\n') + '}'; }); var SVG = ['Svg', 'SvgCircle', 'SvgEllipse', 'SvgDefs', 'SvgGroup', 'SvgLinearGradient', 'SvgRadialGradient', 'SvgLine', 'SvgPath', 'SvgPolygon', 'SvgPolyline', 'SvgRect', 'SvgSymbol', 'SvgText', 'SvgUse', 'SvgDefs', 'SvgStop']; var NATIVE = ['Animated', 'Image', 'KeyboardAvoidingView', 'ScrollView', 'StyleSheet', 'Text', 'TextInput', 'TouchableWithoutFeedback', 'TouchableHighlight', 'View']; var getDependencies = (function (state, getImport) { var usesNative = []; var usesSvg = []; var useNative = function useNative(d) { if (!usesNative.includes(d)) { usesNative.push(d); } }; var useSvg = function useSvg(d) { if (!usesSvg.includes(d)) { usesSvg.push(d); } }; var dependencies = []; state.uses.sort().forEach(function (d) { if (state.isReactNative && NATIVE.includes(d)) { useNative(d); } else if (state.isReactNative && SVG.includes(d)) { useSvg(d === 'Svg' ? d : d === 'SvgGroup' ? 'G as SvgGroup' : d.replace('Svg', '') + ' as ' + d); } else if (d.endsWith('SvgInline')) { dependencies.push('import ' + d + ' from "./' + d + '.view.js"'); } else if (/^[A-Z]/.test(d)) { dependencies.push(getImport(d)); } }); // TODO native if (!state.isReactNative) { dependencies.push(getImport('ViewsBaseCss')); state.fonts.forEach(function (usedFont) { var font = state.getFont(usedFont); if (font) { dependencies.push('import "' + font + '"'); } }); } // TODO we probably want to check that the file exists and do something if it // doesn;t, like warn the user at least? state.images.forEach(function (img) { return dependencies.push('import ' + img.name + ' from "' + img.file + '"'); }); if (state.cssDynamic && state.cssStatic) { dependencies.push('import styled, { css } from "react-emotion"'); } else if (state.cssStatic) { dependencies.push('import { css } from "react-emotion"'); } else if (state.cssDynamic) { dependencies.push('import styled from "react-emotion"'); } if (usesSvg.length > 0) { var svg = usesSvg.filter(function (m) { return m !== 'Svg'; }).join(', '); dependencies.push('import Svg, { ' + svg + ' } from \'react-native-svg\''); } if (usesNative.length > 0) { dependencies.push('import { ' + usesNative.join(', ') + ' } from \'react-native\''); } if (state.track && !state.debug) { dependencies.push('import PropTypes from "prop-types"'); } return dependencies.join('\n'); }); var toComponent = (function (_ref) { var getImport = _ref.getImport, getStyles = _ref.getStyles, name = _ref.name, state = _ref.state; // TODO Emojis should be wrapped in <span>, have role="img", and have an accessible description // with aria-label or aria-labelledby jsx-a11y/accessible-emoji return '/* eslint-disable jsx-a11y/accessible-emoji, no-unused-vars */\nimport React from \'react\'\n' + getDependencies(state, getImport) + '\n' + getStyles(state, name) + '\n\n' + getBody({ state: state, name: name }) + '\n' + getContext({ state: state, name: name }) + '\n' + getDefaultProps({ state: state, name: name }) + '\nexport default ' + name; }); function walk(ast, _ref, state) { var enter = _ref.enter, leave = _ref.leave; visit(ast, null, enter, leave, state); } function visit(node, parent, enter, leave, state) { if (!node) return; if (enter) { if (enter.some(function (fn) { return fn(node, parent, state); })) return; } if (Array.isArray(node.children)) { node.children.forEach(function (child) { child.parent = node; visit(child, node, enter, leave, state); }); } if (leave) { leave.forEach(function (fn) { return fn(node, parent, state); }); } } var imports = { Animated: "import Animated from 'react-dom-animated'", Link: "import { Link } from 'react-router-dom'", Route: "import { Route } from 'react-router-dom'", Router: "import { BrowserRouter as Router } from 'react-router-dom'" }; var reactDom = (function (_ref) { var debug = _ref.debug, _ref$enableAnimated = _ref.enableAnimated, enableAnimated = _ref$enableAnimated === undefined ? true : _ref$enableAnimated, file = _ref.file, _ref$getFont = _ref.getFont, getFont = _ref$getFont === undefined ? function () { return false; } : _ref$getFont, getImport = _ref.getImport, name = _ref.name, _ref$track = _ref.track, track = _ref$track === undefined ? true : _ref$track, views = _ref.views; var finalName = reactNative.includes(name) ? name + '1' : name; if (name !== finalName) { console.warn('// "' + name + '" is a Views reserved name.\n We\'ve renamed it to "' + finalName + '", so your view should work but this isn\'t ideal.\n To fix this, change its file name to something else.'); } var state = { captures: [], cssDynamic: false, cssStatic: false, enableAnimated: enableAnimated, debug: debug, file: file, getFont: getFont, getStyleForProperty: getStyleForProperty, getValueForProperty: getValueForProperty, images: [], isDynamic: false, isReactNative: false, name: finalName, render: [], styles: {}, svgs: [], usedBlockNames: defineProperty({}, finalName, 1), uses: [], testIdKey: 'data-test-id', testIds: {}, track: track, use: function use(block) { if (state.uses.includes(block) || /props/.test(block) || block === finalName) return; state.uses.push(block); } }; if (name !== finalName) { console.warn('// ' + name + ' is a Views reserved name. To fix this, change its file name to something else.'); } var parsed = views[name]; state.fonts = parsed.fonts; state.slots = parsed.slots; walk(parsed.views[0], visitor, state); maybeUsesRouter(state); var finalGetImport = function finalGetImport(name) { return imports[name] || getImport(name); }; return { code: toComponent({ getImport: finalGetImport, getStyles: getStyles, name: finalName, state: state }), fonts: parsed.fonts, slots: parsed.slots, svgs: state.svgs }; }); var BORDER_RADIUS = ['borderRadius', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomLeftRadius', 'borderBottomRightRadius']; var enter$22 = function enter(node, parent, state) { if (node.backgroundImage) { var source = getObjectAsString({ uri: node.backgroundImage }); var resizeMode = getProp(node, 'backgroundSize'); resizeMode = safe(resizeMode ? resizeMode.value.value : 'cover'); state.render.push(' resizeMode=' + resizeMode + ' source={' + source + '}'); // hack until https://github.com/facebook/react-native/issues/8885 // is fixed BORDER_RADIUS.forEach(function (prop) { if (hasProp(node, prop)) { var propNode = getProp(node, prop); state.render.push(' ' + prop + '={' + propNode.value.value + '}'); } }); } }; var keyboardType = { CaptureEmail: 'email-address', CaptureText: 'default', CaptureTextArea: 'default', CaptureNumber: 'numeric', CapturePhone: 'phone-pad' }; var enter$23 = function enter(node, parent, state) { var blockType = node.name; if (!/Capture/.test(node.name)) return; node.isCapture = true; var name = toCamelCase(node.is || blockType); state.captures.push(name); var captureNext = node.captureNext; var onSubmit = getProp(node, 'onSubmit') || null; if (onSubmit) onSubmit = onSubmit.value.value; if (captureNext) { state.render.push(' blurOnSubmit={false}'); state.render.push(' onSubmitEditing={this.$' + captureNext + '? () => this.$' + captureNext + '.focus() : ' + onSubmit + '}'); state.render.push(' returnKeyType = {this.$' + captureNext + '? \'next\' : \'go\'}'); } else { if (onSubmit) { state.render.push(' onSubmitEditing={' + onSubmit + '}'); state.render.push(' returnKeyType="go"'); } else { state.render.push(' returnKeyType="done"'); } } state.render.push(' onChangeText = {' + name + ' => this.setState({ ' + name + ' })}'); state.render.push(' ref={$e => this.$' + name + ' = $e}'); state.render.push(' value={state.' + name + '}'); if (node.name === 'CaptureSecure') { state.render.push(' secureTextEntry'); } else { state.render.push(' keyboardType=\'' + keyboardType[blockType] + '\''); } if (node.name === 'CaptureTextArea') { state.render.push(' multiline={true}'); } // TODO rest of props var onBlur = getProp(node, 'onBlur'); if (onBlur) { state.render.push(' onBlur=' + safe(onBlur.value.value)); } var onFocus = getProp(node, 'onFocus'); if (onFocus) { state.render.push(' onFocus=' + safe(onFocus.value.value)); } var autoCorrect = getProp(node, 'autoCorrect'); state.render.push(' autoCorrect=' + (autoCorrect ? safe(autoCorrect.value.value) : '{false}')); var placeholder = getProp(node, 'placeholder'); if (placeholder) { state.render.push(' placeholder=' + safe(placeholder.value.value)); } var defaultValue = getProp(node, 'defaultValue'); if (defaultValue) { state.render.push(' defaultValue=' + safe(defaultValue.value.value)); } var underlineColorAndroid = getProp(node, 'underlineColorAndroid'); var underlineColorAndroidValue = underlineColorAndroid ? underlineColorAndroid.value.value : 'transparent'; state.render.push(' underlineColorAndroid=' + safe(underlineColorAndroidValue)); }; var getBlockName$1 = (function (node, parent, state) { switch (node.name) { case 'CaptureEmail': // case 'CaptureFile': case 'CaptureNumber': case 'CapturePhone': case 'CaptureSecure': case 'CaptureText': case 'CaptureTextArea': return 'TextInput'; case 'Horizontal': case 'Vertical': return getGroupBlockName$1(node, state); case 'Image': return getImageName(node, state); case 'List': return getListBlockName(node); case 'Proxy': return null; case 'Text': return node.maybeAnimated ? 'Animated.Text' : 'Text'; default: return node.name; } }); var getGroupBlockName$1 = function getGroupBlockName(node, state) { var name = 'View'; if (hasProp(node, 'teleportTo')) { node.teleport = true; } else if (hasProp(node, 'goTo')) { node.goTo = true; } else if (hasProp(node, 'onClick')) { var propNode = getProp(node, 'onClick'); node.action = propNode.value; } if (hasProp(node, 'backgroundImage')) { var _propNode = getProp(node, 'backgroundImage'); node.backgroundImage = isSlot(_propNode) ? _propNode.value : JSON.stringify(_propNode.value); name = 'Image'; } else if (hasProp(node, 'overflowY', function (v) { return v === 'auto' || v === 'scroll'; })) { name = 'ScrollView'; } if (node.maybeAnimated && name !== 'Link') { name = 'Animated.' + name; } return name; }; var getListBlockName = function getListBlockName(node) { var base = hasProp(node, /^overflow/, function (v) { return v === 'auto' || v === 'scroll'; }) ? 'ScrollView' : 'View'; return node.maybeAnimated ? 'Animated.' + base : base; }; var isSvg$1 = function isSvg$$1(str) { return (/\.svg$/.test(str) ); }; var getImageName = function getImageName(node, state) { if (hasProp(node, 'source')) { var source = getProp(node, 'source'); var value = source.value.value; if (isSvg$1(value)) { var name = toPascalCase(value) + 'Inline'; node.isSvg = true; if (!state.svgs.some(function (svg) { return svg.source === value; })) { state.svgs.push({ source: value, view: name }); } return name; } } return 'Image'; }; function enter$24(node, parent, state) { var name = getBlockName$1(node, parent, state); if (name === null) return true; state.use(/Animated/.test(name) ? 'Animated' : name); node.nameFinal = name; state.render.push('<' + name); } var leave$11 = function leave(node, parent, state) { var style = null; if (node.ensureBackgroundColor && (!('backgroundColor' in node.style.static.base) || !('backgroundColor' in node.style.dynamic.base))) { node.style.static.base.backgroundColor = 'transparent'; } if (hasKeys(node.style.static.base)) { var id = hash(node.style.static.base); state.styles[id] = node.style.static.base; node.styleId = id; style = 'styles.' + id; } if (hasKeys(node.style.dynamic.base)) { var dynamic = getObjectAsString(node.styl