views-morph
Version:
Views language morpher
997 lines (875 loc) • 30.5 kB
JavaScript
;
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var Levenshtein = _interopDefault(require('levenshtein'));
var sortBy = _interopDefault(require('lodash.sortby'));
var STYLE = ['alignContent', 'alignItems', 'alignSelf', 'appRegion', 'background', 'backgroundColor', 'backgroundImage', 'backgroundSize', 'borderBottomColor', 'borderBottomLeftRadius', 'borderBottomRightRadius', 'borderBottomStyle', 'borderBottomWidth', 'borderColor', 'borderLeftColor', 'borderLeftStyle', 'borderLeftWidth', 'borderRightColor', 'borderRightStyle', 'borderRightWidth', 'borderStyle', 'borderTopColor', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderTopStyle', 'borderTopWidth', 'borderWidth', 'bottom', 'clipPath', 'color', 'cursor', 'fill', 'filter', 'flex', 'flex-grow', 'flexBasis', 'flexDirection', 'flexFlow', 'flexShrink', 'flexWrap', 'fontFamily', 'fontSize', 'fontStyle', 'fontWeight', 'height', 'hyphens', 'justifyContent', 'left', 'letterSpacing', 'lineHeight', 'marginBottom', 'marginLeft', 'marginRight', 'marginTop', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'opacity', 'outlineColor', 'outlineOffset', 'outlineStyle', 'outlineWidth', 'overflowWrap', 'overflowX', 'overflowY', 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'pointerEvents', 'position', 'resize', 'right', 'shadowColor', 'shadowOffsetX', 'shadowOffsetY', 'shadowRadius', 'shadowSpread', 'stroke', 'textAlign', 'textDecoration', 'top', 'transform', 'transformOrigin', 'transition', 'userSelect', 'whiteSpace', 'width', 'wordBreak', 'wordSpacing', 'wordWrap', 'zIndex'];
var isStyle = function isStyle(name) {
return STYLE.includes(name);
};
/**
* Creates a fuzzy matcher.
*
* Usage:
*
* ```
* var m = new Matcher({
* values: 'init install update upgrade',
* threshold: 4
* });
*
* m.list('udpate') // [ { value: 'update', distance: 2 }, { value: 'upgrade', distance: 4 } ]
* m.get('udpate') // { value: 'update', distance: 2 }
* ```
*
* You can also initialize with an array or with a string directly:
*
* ```
* new Matcher('init install update upgrade');
* new Matcher(['init', 'install', 'update', 'upgrade']);
* ```
*
* @param options {Object} may contain:
*
* * `threshold` (number, default `2`) — maximum search distance, increase
* for more relaxed search
*
* * `values` (array or string, default `[]`) — an array of words to match from;
* if a string is given, values can be separated with comma or whitespace
*
* * `caseSensitive` (boolean, default `false`) — ignore case when matching
*/
var Matcher = function Matcher(options) {
options = options || {};
if (typeof options == 'string' || Array.isArray(options)) options = { values: options };
this.values = [];
this.threshold = options.threshold || 2;
// Try to initialize via `options.values`
if (Array.isArray(options.values)) this.values = options.values;else if (typeof options.values == 'string') this.values = options.values.split(/[, ]\s*/g);
this.caseSensitive = options.caseSensitive || false;
};
/**
* Adds values to the dictionary.
*
* Usage:
*
* ```
* new Matcher().add('update', 'upgrade', 'delete').get('deete')
* ```
*
* @returns {Matcher} this for chaining
*/
Matcher.prototype.add = function () {
[].push.apply(this.values, arguments);
return this;
};
/**
* Chainable helper for settings `this.caseSensitive = false`.
*
* @returns {Matcher} this for chaining
*/
Matcher.prototype.ignoreCase = function () {
this.caseSensitive = false;
return this;
};
/**
* Chainable helper for settings `this.caseSensitive = true`.
*
* @returns {Matcher} this for chaining
*/
Matcher.prototype.matchCase = function () {
this.caseSensitive = true;
return this;
};
/**
* Chainable helper for settings `this.threshold`.
*
* @param num {Number} new threshold
* @returns {Matcher} this for chaining
*/
Matcher.prototype.setThreshold = function (num) {
this.threshold = num;
return this;
};
/**
* Calculate distance (how much difference) between two strings
*
* @param word1 {String} a string input
* @param word2 {String} the other string input
* @returns {Number} Levenshtein distance between word1 and word2
*/
Matcher.prototype.distance = function (word1, word2) {
return new Levenshtein(word1, word2).distance;
};
/**
* Lists all results from dictionary which are similar to `q`.
*
* ```
* new Matcher({
* values: 'init install update upgrade',
* threshold: 4
* }).list('udpdate');
* // [ { value: 'update', distance: 2 }, { value: 'upgrade', distance: 4 } ]
* ```
*
* The results are sorted by their distance (similarity). The distance of `0` means
* a strict match.
*
* You can increase `threshold` for more relaxed search, or decrease it to shorten the results.
*
* @param q {String} — search string
* @returns {Array} — an array of objects `{ value: String, distance: Number }`
*/
Matcher.prototype.list = function (q) {
var m = this;
q = q.trim();
if (!m.caseSensitive) q = q.toLowerCase();
var matches = this.values.reduce(function (results, word) {
var d = m.distance(q, m.caseSensitive ? word : word.toLowerCase());
if (d > m.threshold) return results;
return results.concat({
value: word,
distance: d
});
}, []);
return sortBy(matches, 'distance');
};
/**
* Returns a single closest match (or `null` if no values from the dictionary
* are similar to `q`).
*
* @param q {String} — search string
* @returns {String} — closest match or `null`
*/
Matcher.prototype.get = function (q) {
var closest = this.list(q)[0];
return closest ? closest.value : null;
};
var isNumber = {
width: true,
maxWidth: true,
minWidth: true,
height: true,
maxHeight: true,
minHeight: true,
margin: true,
marginBottom: true,
marginLeft: true,
marginRight: true,
marginTop: true,
padding: true,
paddingBottom: true,
paddingLeft: true,
paddingRight: true,
paddingTop: true,
bottom: true,
left: true,
right: true,
top: true,
outline: true,
opacity: true,
zIndex: true,
scale: true,
translateX: true,
translateY: true,
borderBottomLeftRadius: true,
borderBottomRightRadius: true,
borderBottomWidth: true,
borderLeftWidth: true,
borderRadius: true,
borderRightWidth: true,
borderTopLeftRadius: true,
borderTopRightRadius: true,
borderTopWidth: true,
borderWidth: true,
fontSize: true,
fontWeight: true,
letterSpacing: true,
lineHeight: true,
wordSpacing: true
};
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 dymBlockMatcher = new Matcher('CaptureEmail|CaptureFile|CaptureNumber|CapturePhone|CaptureSecure|CaptureText|CaptureTextArea|G|Horizontal|Image|List|Svg|SvgCircle|SvgEllipse|SvgDefs|SvgGroup|SvgLinearGradient|SvgRadialGradient|SvgLine|SvgPath|SvgPolygon|SvgPolyline|SvgRect|SvgSymbol|SvgText|SvgUse|SvgStop|Text|Vertical'.split('|'));
var dymPropMatcher = new Matcher([].concat(toConsumableArray(STYLE), ['defaultValue', 'fill', 'stroke', 'from', 'viewBox', 'stroke', 'strokeWidth', 'strokeLinecap', 'strokeMiterlimit', 'at', 'd', 'x', 'x1', 'y1', 'y', 'x2', 'y2', 'strokeLinejoin', 'onBlur', 'onChange', 'onClick', 'onDrag', 'onDragEnd', 'onDragOver', 'onDragStart', 'onFocus', 'onMouseDown', 'onMouseMove', 'onMouseOver', 'onMouseUp', 'onWheel', 'onWhen', 'ref', 'tabIndex', 'text', 'value', 'when']));
var didYouMeanBlock = function didYouMeanBlock(block) {
return dymBlockMatcher.get(block);
};
var didYouMeanProp = function didYouMeanProp(prop) {
return dymPropMatcher.get(prop);
};
var BASIC = /^(CaptureEmail|CaptureFile|CaptureNumber|CapturePhone|CaptureSecure|CaptureText|CaptureTextArea|Horizontal|Image|List|Svg|SvgCircle|SvgEllipse|SvgDefs|SvgGroup|SvgLinearGradient|SvgRadialGradient|SvgLine|SvgPath|SvgPolygon|SvgPolyline|SvgRect|SvgSymbol|SvgText|SvgUse|SvgStop|Text|Vertical)$/i;
var BLOCK = /^([A-Z][a-zA-Z0-9]*)(\s+([A-Z][a-zA-Z0-9]*))?$/;
var BOOL = /^(false|true)$/i;
var CAPTURE = /^(CaptureEmail|CaptureFile|CaptureNumber|CapturePhone|CaptureSecure|CaptureText|CaptureTextArea)$/i;
var COMMENT = /^#(.+)$/;
var FLOAT = /^-?[0-9]+\.[0-9]+$/;
var FONTABLE = /^(CaptureEmail|CaptureNumber|CapturePhone|CaptureSecure|CaptureText|CaptureTextArea|Text)$/;
var INT = /^-?[0-9]+$/;
var NOT_GROUP = /^(Image|Text|Proxy|SvgCircle|SvgEllipse|SvgLine|SvgPath|SvgPolygon|SvgPolyline|SvgRect|SvgText|SvgStop)$/i;
var PROP = /^([a-z][a-zA-Z0-9]*)(\s+(.+))?$/;
var UNSUPPORTED_SHORTHAND = {
border: ['borderWidth', 'borderStyle', 'borderColor'],
borderBottom: ['borderBottomWidth', 'borderBottomStyle', 'borderBottomColor'],
borderTop: ['borderTopWidth', 'borderTopStyle', 'borderTopColor'],
borderRight: ['borderRightWidth', 'borderRightStyle', 'borderRightColor'],
borderLeft: ['borderLeftWidth', 'borderLeftStyle', 'borderLeftColor'],
borderRadius: ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomLeftRadius', 'borderBottomRightRadius'],
boxShadow: ['shadowOffsetX', 'shadowOffsetY', 'shadowRadius', 'shadowSpread', 'shadowColor'],
margin: ['marginTop', 'marginRight', 'marginBottom', 'marginLeft'],
padding: ['paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft'],
textShadow: ['shadowOffsetX', 'shadowOffsetY', 'shadowRadius', 'shadowColor'],
outline: ['outlineWidth', 'outlineStyle', 'outlineColor'],
overflow: ['overflowX', 'overflowY']
};
var TRUE = /^true$/i;
var USER_COMMENT = /^##(.*)$/;
// TODO slot can't start with a number
var SLOT = /^<((!)?([a-zA-Z0-9]+))?(\s+(.+))?$/;
var is = function is(thing, line) {
return thing.test(line);
};
var isBasic = function isBasic(line) {
return is(BASIC, line);
};
var isBlock = function isBlock(line) {
return is(BLOCK, line);
};
var isBool = function isBool(line) {
return is(BOOL, line);
};
var isCapture = function isCapture(line) {
return is(CAPTURE, line);
};
var isComment = function isComment(line) {
return is(COMMENT, line);
};
var isEmptyText = function isEmptyText(line) {
return line === '';
};
var isEnd = function isEnd(line) {
return line === '';
};
var isFloat = function isFloat(line) {
return is(FLOAT, line);
};
var isFontable = function isFontable(line) {
return is(FONTABLE, line);
};
var isGroup = function isGroup(line) {
return !is(NOT_GROUP, line) && !isCapture(line);
};
var isList = function isList(line) {
return line === 'List';
};
var isInt = function isInt(line) {
return is(INT, line);
};
var isProp = function isProp(line) {
return is(PROP, line);
};
var isUnsupportedShorthand = function isUnsupportedShorthand(name) {
return name in UNSUPPORTED_SHORTHAND;
};
var isTrue = function isTrue(line) {
return is(TRUE, line);
};
var isUserComment = function isUserComment(line) {
return is(USER_COMMENT, line);
};
var get = function get(regex, line) {
return line.match(regex);
};
var getBlock = function getBlock(line) {
// eslint-disable-next-line
var _get = get(BLOCK, line),
_get2 = slicedToArray(_get, 4),
_ = _get2[0],
is = _get2[1],
_1 = _get2[2],
block = _get2[3];
return {
block: block || is,
is: block ? is : null
};
};
var getComment = function getComment(line) {
try {
return get(COMMENT, line).slice(1);
} catch (err) {
return '';
}
};
var getProp = function getProp(line) {
// eslint-disable-next-line
var _get3 = get(PROP, line),
_get4 = slicedToArray(_get3, 4),
_ = _get4[0],
name = _get4[1],
_1 = _get4[2],
_get4$ = _get4[3],
value = _get4$ === undefined ? '' : _get4$;
var prop = { name: name, isSlot: false, value: value };
if (is(SLOT, value)) {
var _getSlot = getSlot(value),
_getSlot2 = slicedToArray(_getSlot, 5),
// eslint-disable-next-line
_2 = _getSlot2[0],
_getSlot2$ = _getSlot2[1],
slotIsNot = _getSlot2$ === undefined ? false : _getSlot2$,
_getSlot2$2 = _getSlot2[2],
slotName = _getSlot2$2 === undefined ? '' : _getSlot2$2,
// eslint-disable-next-line
_3 = _getSlot2[3],
_getSlot2$3 = _getSlot2[4],
defaultValue = _getSlot2$3 === undefined ? '' : _getSlot2$3;
prop.isSlot = true;
prop.slotIsNot = slotIsNot === '!';
prop.slotName = slotName;
prop.value = defaultValue || value;
}
return prop;
};
var getSlot = function getSlot(line) {
return get(SLOT, line).slice(1);
};
var getUnsupportedShorthandExpanded = function getUnsupportedShorthandExpanded(name, value) {
var props = UNSUPPORTED_SHORTHAND[name];
if (name === 'borderRadius') {
var theValue = value.replace('px', '');
return [props[0] + ' ' + theValue, props[1] + ' ' + theValue, props[2] + ' ' + theValue, props[3] + ' ' + theValue];
} else if (name.startsWith('border') || name === 'outline') {
var _value$split = value.split(' '),
_value$split2 = toArray(_value$split),
width = _value$split2[0],
style = _value$split2[1],
color = _value$split2.slice(2);
return [props[0] + ' ' + width.replace('px', ''), props[1] + ' ' + style, props[2] + ' ' + color.join(' ')];
} else if (name === 'boxShadow') {
var _value$split3 = value.split(' '),
_value$split4 = toArray(_value$split3),
offsetX = _value$split4[0],
offsetY = _value$split4[1],
blurRadius = _value$split4[2],
spreadRadius = _value$split4[3],
_color = _value$split4.slice(4);
return [props[0] + ' ' + offsetX.replace('px', ''), props[1] + ' ' + offsetY.replace('px', ''), props[2] + ' ' + blurRadius.replace('px', ''), props[3] + ' ' + spreadRadius.replace('px', ''), props[4] + ' ' + _color.join(' ')];
} else if (name === 'textShadow') {
var _value$split5 = value.split(' '),
_value$split6 = toArray(_value$split5),
_offsetX = _value$split6[0],
_offsetY = _value$split6[1],
_blurRadius = _value$split6[2],
_color2 = _value$split6.slice(3);
return [props[0] + ' ' + _offsetX.replace('px', ''), props[1] + ' ' + _offsetY.replace('px', ''), props[2] + ' ' + _blurRadius.replace('px', ''), props[3] + ' ' + _color2.join(' ')];
} else if (name === 'overflow') {
return [props[0] + ' ' + value, props[1] + ' ' + value];
} else if (name === 'padding' || name === 'margin') {
var _value$split7 = value.split(' '),
_value$split8 = slicedToArray(_value$split7, 4),
top = _value$split8[0],
right = _value$split8[1],
bottom = _value$split8[2],
left = _value$split8[3];
top = top.replace('px', '');
right = right ? right.replace('px', '') : top;
bottom = bottom ? bottom.replace('px', '') : top;
left = left ? left.replace('px', '') : right || top;
return [props[0] + ' ' + top, props[1] + ' ' + right, props[2] + ' ' + bottom, props[3] + ' ' + left];
}
};
var getValue = function getValue(value) {
if (isFloat(value)) {
return parseFloat(value, 10);
} else if (isInt(value)) {
return parseInt(value, 10);
} else if (isEmptyText(value)) {
return '';
} else if (isBool(value)) {
return isTrue(value);
} else {
return value;
}
};
var SYSTEM_SCOPES = ['active',
// TODO disabled should be a prop instead I think
'disabled', 'focus', 'hover', 'placeholder', 'print'];
var isSystemScope = function isSystemScope(name) {
return SYSTEM_SCOPES.includes(name);
};
var isActionable = function isActionable(name) {
return name !== 'onWhen' && /^on[A-Z]/.test(name);
};
var getPropType = function getPropType(block, name, defaultValue) {
return block.isList && name === 'from' ? 'array' : isActionable(name) ? 'function' : isNumber[name] ? 'number' : 'string';
};
var getLoc = (function (line, scolumn, ecolumn) {
return {
start: {
line: line,
column: scolumn
},
end: {
line: line,
column: ecolumn
}
};
});
var SLOT_PROPS = ['from', 'when', 'onClick', 'onFocus', 'onWhen'];
var shouldBeSlot = function shouldBeSlot(prop) {
return SLOT_PROPS.includes(prop) || /^on[A-Z]/.test(prop);
};
var getTags = (function (_ref) {
var name = _ref.name,
isSlot$$1 = _ref.isSlot,
slotName = _ref.slotName,
slotIsNot = _ref.slotIsNot,
value = _ref.value,
block = _ref.block;
var tags = {};
if (isStyle(name)) tags.style = true;
if (isUnsupportedShorthand(name) && block.isBasic) {
tags.unsupportedShorthand = true;
}
if (shouldBeSlot(name)) tags.shouldBeSlot = true;
if (isSlot$$1) tags.slot = true;
if (slotIsNot) tags.slotIsNot = true;
tags.validSlot = tags.slot || tags.shouldBeSlot && tags.slot || null;
return tags;
});
var index = (function () {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$convertSlotToPro = _ref.convertSlotToProps,
convertSlotToProps = _ref$convertSlotToPro === undefined ? true : _ref$convertSlotToPro,
_ref$skipComments = _ref.skipComments,
skipComments = _ref$skipComments === undefined ? true : _ref$skipComments,
source = _ref.source;
// convert crlf to lf
var text = source.replace(/\r\n/g, '\n');
var rlines = text.split('\n');
var lines = rlines.map(function (line) {
return line.trim();
});
var fonts = [];
var stack = [];
var slots = [];
var views = [];
var warnings = [];
var lastCapture = void 0;
var getChildrenProxyMap = function getChildrenProxyMap(block) {
var childrenProxyMap = {};
block.children.forEach(function (child, i) {
var maybeName = child.is || child.name;
var name = maybeName;
var next = 1;
while (name in childrenProxyMap) {
name = '' + maybeName + next;
next++;
}
childrenProxyMap[name] = i;
});
return Object.keys(childrenProxyMap).length === 0 ? null : childrenProxyMap;
};
var lookForFonts = function lookForFonts(block) {
if (block.properties && (isFontable(block.name) || !block.isBasic)) {
var fontFamilyProp = block.properties.find(function (p) {
return p.name === 'fontFamily';
});
if (fontFamilyProp) {
var fontFamily = fontFamilyProp.value;
var fontWeightProp = block.properties.find(function (p) {
return p.name === 'fontWeight';
});
var fontStyleProp = block.properties.find(function (p) {
return p.name === 'fontStyle';
});
var fontWeight = fontWeightProp ? fontWeightProp.value.toString() : '400';
var fontStyle = fontStyleProp ? fontStyleProp.value.toString() : 'normal';
if (!fonts.find(function (font) {
return font.family === fontFamily && font.weight === fontWeight && font.style === fontStyle;
})) {
fonts.push({
id: fontFamily + '-' + fontWeight + (fontStyle === 'italic' ? '-italic' : ''),
family: fontFamily,
weight: fontWeight,
style: fontStyle
});
}
}
}
};
var end = function end(block, endLine) {
block.loc.end = {
line: endLine,
column: Math.max(0, lines[endLine].length - 1)
};
if (block.isGroup && !block.isBasic) {
block.childrenProxyMap = getChildrenProxyMap(block);
}
if (!block.properties) {
block.properties = [];
}
if (block.name === 'List' && !block.properties.some(function (prop) {
return prop.name === 'from';
})) {
warnings.push({
loc: block.loc,
type: 'A List needs "from <" to work',
line: lines[block.loc.start.line]
});
}
if (stack.length === 0) {
// if we're the last block on the stack, then this is the view!
views.push(block);
return true;
}
return false;
};
var parseBlock = function parseBlock(line, i) {
var _getBlock = getBlock(line),
name = _getBlock.block,
is$$1 = _getBlock.is;
var shouldPushToStack = false;
var block = {
type: 'Block',
name: name,
isBasic: isBasic(name),
isGroup: false,
loc: getLoc(i, 0),
properties: [],
scopes: []
};
if (is$$1 && !block.isBasic) {
var meant = didYouMeanBlock(name);
if (meant && meant !== name) {
warnings.push({
loc: block.loc,
type: 'Did you mean "' + meant + '" instead of "' + name + '"?',
line: line
});
}
}
if (is$$1) {
block.is = is$$1;
if (isCapture(name)) {
if (lastCapture) {
lastCapture.captureNext = is$$1;
}
lastCapture = block;
}
}
var last = stack[stack.length - 1];
if (last) {
shouldPushToStack = true;
if (last.isGroup) {
if (last.isList) {
if (block.isBasic) {
warnings.push({
loc: block.loc,
type: 'A basic block "' + block.name + '" can\'t be inside a List. Use a view you made instead.',
line: line,
blocker: true
});
} else if (last.children.length > 0) {
warnings.push({
loc: block.loc,
type: 'A List can only have one view inside. "' + block.name + '" is outside of it. Put 1 empty line before.',
line: line
});
} else {
last.children.push(block);
}
} else {
last.children.push(block);
}
} else {
// the block is inside a block that isn't a group
end(stack.pop(), i);
if (last.isBasic) {
warnings.push({
loc: block.loc,
type: 'An empty line is required after every block. Put 1 empty line before',
line: line
});
} else if (views[0] && views[0].isGroup) {
warnings.push({
loc: block.loc,
type: lines[i - 1] === '' ? 'Put 1 empty line before' : 'Put 2 empty lines before',
line: line
});
} else {
warnings.push({
loc: block.loc,
type: 'Add Vertical at the top',
line: line
});
}
}
} else if (views.length > 0) {
// the block is outside the top level block
var newLinesBeforePreviousBlock = 1;
while (isEnd(lines[i - newLinesBeforePreviousBlock])) {
newLinesBeforePreviousBlock++;
}
var help = [];
if (!views[0].isGroup) {
help.push('Add Vertical at the top');
}
if (newLinesBeforePreviousBlock > 2) {
var linesToRemove = newLinesBeforePreviousBlock - 2;
help.push('remove ' + linesToRemove + ' empty line' + (linesToRemove > 1 ? 's' : '') + ' before');
}
warnings.push({
loc: block.loc,
type: help.join(', '),
line: line
});
}
if (isGroup(name)) {
block.isGroup = true;
block.isList = isList(name);
block.children = [];
}
if (shouldPushToStack || stack.length === 0) {
stack.push(block);
}
parseProps(i, block);
lookForFonts(block);
};
var parseProps = function parseProps(i, block) {
var endOfBlockIndex = i;
while (endOfBlockIndex < lines.length - 1 && !isBlock(lines[endOfBlockIndex + 1])) {
endOfBlockIndex++;
}
var properties = [];
var scopes = [];
var scope = void 0;
var inScope = false;
var _loop = function _loop(j) {
var line = lines[j];
var propNode = null;
if (isProp(line)) {
var _getProp = getProp(line),
name = _getProp.name,
isSlot$$1 = _getProp.isSlot,
slotName = _getProp.slotName,
slotIsNot = _getProp.slotIsNot,
value = _getProp.value;
var loc = getLoc(j, line.indexOf(name), line.length - 1);
var tags = getTags({
name: name,
isSlot: isSlot$$1,
slotIsNot: slotIsNot,
slotName: slotName,
value: value,
block: block
});
if (block.isBasic) {
if (tags.unsupportedShorthand) {
warnings.push({
loc: loc,
type: 'The shorthand ' + name + ' isn\'t supported. You need to expand it like:\n' + getUnsupportedShorthandExpanded(name, value).join('\n'),
line: line
});
} else {
var meant = didYouMeanProp(name);
if (meant && meant !== name) {
warnings.push({
loc: loc,
type: 'Did you mean "' + meant + '" instead of "' + name + '"?',
line: line
});
}
}
}
if (name === 'when') {
var isSystem = isSystemScope(value);
if (value === '' || value === '<' || value === '<!') {
warnings.push({
loc: loc,
type: 'This when has no condition assigned to it. Add one like: when <isCondition',
line: line
});
} else if (!isSystem && !tags.validSlot) {
warnings.push({
loc: loc,
type: 'The value you used in the slot "' + name + '" is invalid',
line: line
});
}
tags.scope = value;
inScope = true;
scope = {
isSystem: isSystem,
value: value,
name: name,
properties: []
};
if (!isSystem) {
if (convertSlotToProps) {
scope.value = (slotIsNot ? '!' : '') + 'props.' + (slotName || name);
}
scope.slotIsNot = slotIsNot;
scope.slotName = slotName;
}
scopes.push(scope);
} else if ((tags.slot || tags.shouldBeSlot) && !tags.validSlot) {
warnings.push({
loc: loc,
type: 'The value you used in the slot "' + name + '" is invalid',
line: line
});
}
if (name === 'onWhen' && properties.length > 0) {
warnings.push({
type: 'Put onWhen at the top of the block. It\'s easier to see it that way!',
line: line,
loc: loc
});
}
propNode = {
type: 'Property',
loc: loc,
name: name,
tags: tags,
value: getValue(value)
};
if (tags.slot) {
var needsDefaultValue = block.isBasic && !tags.shouldBeSlot && /</.test(propNode.value);
propNode.defaultValue = propNode.value;
propNode.slotName = slotName;
if (convertSlotToProps) {
propNode.value = (slotIsNot ? '!' : '') + 'props.' + (slotName || name);
}
if (needsDefaultValue) {
if (name === 'text' && block.name === 'Text') {
propNode.defaultValue = '';
} else {
propNode.defaultValue = false;
warnings.push({
loc: loc,
type: 'Add a default value to "' + name + '" like: "' + name + ' <' + slotName + ' default value"',
line: line
});
}
}
if (!inScope && !slots.some(function (vp) {
return vp.name === name;
})) {
slots.push({
name: slotName || name,
type: getPropType(block, name, value),
defaultValue: tags.shouldBeSlot || !block.isBasic ? false : propNode.defaultValue
});
}
}
} else if (isComment(line) && !skipComments) {
var _getComment = getComment(line),
_getComment2 = slicedToArray(_getComment, 1),
_value = _getComment2[0];
var userComment = isUserComment(line);
if (userComment) {
_value = getComment(_value);
}
propNode = {
type: 'Property',
loc: getLoc(j, 0, line.length - 1),
value: _value,
tags: { comment: true, userComment: userComment }
};
}
if (propNode) {
block.loc.end = propNode.loc.end;
if (inScope) {
if (propNode.name !== 'when' && !propNode.tags.comment && !properties.some(function (baseProp) {
return baseProp.name === propNode.name;
})) {
warnings.push({
loc: propNode.loc,
type: 'You\'re missing a base prop for ' + propNode.name + '. Add it before all whens on the block.',
line: line
});
}
scope.properties.push(propNode);
} else {
properties.push(propNode);
}
}
};
for (var j = i; j <= endOfBlockIndex; j++) {
_loop(j);
}
block.properties = properties;
block.scopes = scopes;
};
lines.forEach(function (line, i) {
if (line !== rlines[i]) {
warnings.push({
type: 'You have some spaces before or after this line. Clean them up.',
loc: {
start: {
line: i
}
},
line: rlines[i]
});
}
if (isBlock(line)) {
parseBlock(line, i);
} else if (isEnd(line) && stack.length > 0) {
end(stack.pop(), i);
}
});
if (stack.length > 0) {
while (!end(stack.pop(), lines.length - 1)) {}
}
return {
fonts: fonts,
slots: slots,
views: views,
warnings: warnings
};
});
module.exports = index;
//# sourceMappingURL=parse.js.map