Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Juno Suárez committed Oct 5, 2020
1 parent 7d1e7e0 commit 3e10a90
Show file tree
Hide file tree
Showing 33 changed files with 1,326 additions and 1 deletion.
1 change: 0 additions & 1 deletion .gitignore
@@ -1,6 +1,5 @@
.DS_Store
coverage
lib
node_modules
npm-debug.log
package-lock.json
Expand Down
44 changes: 44 additions & 0 deletions lib/elementType.js
@@ -0,0 +1,44 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = elementType;
function resolveMemberExpressions() {
var object = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var property = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

if (object.type === 'JSXMemberExpression') {
return resolveMemberExpressions(object.object, object.property) + '.' + property.name;
}

return object.name + '.' + property.name;
}

/**
* Returns the tagName associated with a JSXElement.
*/
function elementType() {
var node = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var name = node.name;


if (!name) {
throw new Error('The argument provided is not a JSXElement node.');
}

if (name.type === 'JSXMemberExpression') {
var _name$object = name.object,
object = _name$object === undefined ? {} : _name$object,
_name$property = name.property,
property = _name$property === undefined ? {} : _name$property;

return resolveMemberExpressions(object, property);
}

if (name.type === 'JSXNamespacedName') {
return name.namespace.name + ':' + name.name.name;
}

return node.name.name;
}
32 changes: 32 additions & 0 deletions lib/eventHandlers.js
@@ -0,0 +1,32 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});
/**
* Common event handlers for JSX element event binding.
*/

var eventHandlersByType = {
clipboard: ['onCopy', 'onCut', 'onPaste'],
composition: ['onCompositionEnd', 'onCompositionStart', 'onCompositionUpdate'],
keyboard: ['onKeyDown', 'onKeyPress', 'onKeyUp'],
focus: ['onFocus', 'onBlur'],
form: ['onChange', 'onInput', 'onSubmit'],
mouse: ['onClick', 'onContextMenu', 'onDblClick', 'onDoubleClick', 'onDrag', 'onDragEnd', 'onDragEnter', 'onDragExit', 'onDragLeave', 'onDragOver', 'onDragStart', 'onDrop', 'onMouseDown', 'onMouseEnter', 'onMouseLeave', 'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp'],
selection: ['onSelect'],
touch: ['onTouchCancel', 'onTouchEnd', 'onTouchMove', 'onTouchStart'],
ui: ['onScroll'],
wheel: ['onWheel'],
media: ['onAbort', 'onCanPlay', 'onCanPlayThrough', 'onDurationChange', 'onEmptied', 'onEncrypted', 'onEnded', 'onError', 'onLoadedData', 'onLoadedMetadata', 'onLoadStart', 'onPause', 'onPlay', 'onPlaying', 'onProgress', 'onRateChange', 'onSeeked', 'onSeeking', 'onStalled', 'onSuspend', 'onTimeUpdate', 'onVolumeChange', 'onWaiting'],
image: ['onLoad', 'onError'],
animation: ['onAnimationStart', 'onAnimationEnd', 'onAnimationIteration'],
transition: ['onTransitionEnd']
};

var eventHandlers = Object.keys(eventHandlersByType).reduce(function (accumulator, type) {
return accumulator.concat(eventHandlersByType[type]);
}, []);

exports.default = eventHandlers;
exports.eventHandlersByType = eventHandlersByType;
122 changes: 122 additions & 0 deletions lib/getProp.js
@@ -0,0 +1,122 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: 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 _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

exports.default = getProp;

var _propName = require('./propName');

var _propName2 = _interopRequireDefault(_propName);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _objectWithoutProperties(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 DEFAULT_OPTIONS = {
ignoreCase: true
};

/**
* Returns the JSXAttribute itself or undefined, indicating the prop
* is not present on the JSXOpeningElement.
*
*/
function getProp() {
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var prop = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_OPTIONS;

function getName(name) {
return options.ignoreCase ? name.toUpperCase() : name;
}
var propToFind = getName(prop);
function isPropToFind(property) {
return property.type === 'Property' && property.key.type === 'Identifier' && propToFind === getName(property.key.name);
}

var foundAttribute = props.find(function (attribute) {
// If the props contain a spread prop, try to find the property in the object expression.
if (attribute.type === 'JSXSpreadAttribute') {
return attribute.argument.type === 'ObjectExpression' && propToFind !== getName('key') // https://github.com/reactjs/rfcs/pull/107
&& attribute.argument.properties.some(isPropToFind);
}

return propToFind === getName((0, _propName2.default)(attribute));
});

if (foundAttribute && foundAttribute.type === 'JSXSpreadAttribute') {
return propertyToJSXAttribute(foundAttribute.argument.properties.find(isPropToFind));
}

return foundAttribute;
}

function propertyToJSXAttribute(node) {
var key = node.key,
value = node.value;

return _extends({
type: 'JSXAttribute',
name: _extends({ type: 'JSXIdentifier', name: key.name }, getBaseProps(key)),
value: value.type === 'Literal' ? adjustRangeStartAndEndOfNode(value) : _extends({
type: 'JSXExpressionContainer',
expression: adjustExpressionRangeStartAndEnd(value)
}, getBaseProps(value))
}, getBaseProps(node));
}

function adjustRangeStartAndEndOfNode(node) {
var _ref = node.range || [node.start, node.end],
_ref2 = _slicedToArray(_ref, 2),
start = _ref2[0],
end = _ref2[1];

return _extends({}, node, {
end: end,
range: [start, end],
start: start
});
}

function adjustExpressionRangeStartAndEnd(_ref3) {
var expressions = _ref3.expressions,
quasis = _ref3.quasis,
expression = _objectWithoutProperties(_ref3, ['expressions', 'quasis']);

return _extends({}, adjustRangeStartAndEndOfNode(expression), expressions ? { expressions: expressions.map(adjustRangeStartAndEndOfNode) } : {}, quasis ? { quasis: quasis.map(adjustRangeStartAndEndOfNode) } : {});
}

function getBaseProps(_ref4) {
var loc = _ref4.loc,
node = _objectWithoutProperties(_ref4, ['loc']);

var _adjustRangeStartAndE = adjustRangeStartAndEndOfNode(node),
end = _adjustRangeStartAndE.end,
range = _adjustRangeStartAndE.range,
start = _adjustRangeStartAndE.start;

return {
end: end,
loc: getBaseLocation(loc),
range: range,
start: start
};
}

function getBaseLocation(_ref5) {
var start = _ref5.start,
end = _ref5.end,
source = _ref5.source,
filename = _ref5.filename;

return _extends({
start: start,
end: end
}, source !== undefined ? { source: source } : {}, filename !== undefined ? { filename: filename } : {});
}
57 changes: 57 additions & 0 deletions lib/getPropValue.js
@@ -0,0 +1,57 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = getPropValue;
exports.getLiteralPropValue = getLiteralPropValue;

var _values = require('./values');

var _values2 = _interopRequireDefault(_values);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var extractValue = function extractValue(attribute, extractor) {
if (attribute && attribute.type === 'JSXAttribute') {
if (attribute.value === null) {
// Null valued attributes imply truthiness.
// For example: <div aria-hidden />
// See: https://facebook.github.io/react/docs/jsx-in-depth.html#boolean-attributes
return true;
}

return extractor(attribute.value);
}

return undefined;
};

/**
* Returns the value of a given attribute.
* Different types of attributes have their associated
* values in different properties on the object.
*
* This function should return the most *closely* associated
* value with the intention of the JSX.
*
* @param attribute - The JSXAttribute collected by AST parser.
*/
function getPropValue(attribute) {
return extractValue(attribute, _values2.default);
}

/**
* Returns the value of a given attribute.
* Different types of attributes have their associated
* values in different properties on the object.
*
* This function should return a value only if we can extract
* a literal value from its attribute (i.e. values that have generic
* types in JavaScript - strings, numbers, booleans, etc.)
*
* @param attribute - The JSXAttribute collected by AST parser.
*/
function getLiteralPropValue(attribute) {
return extractValue(attribute, _values.getLiteralValue);
}
74 changes: 74 additions & 0 deletions lib/hasProp.js
@@ -0,0 +1,74 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = hasProp;
exports.hasAnyProp = hasAnyProp;
exports.hasEveryProp = hasEveryProp;

var _propName = require('./propName');

var _propName2 = _interopRequireDefault(_propName);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var DEFAULT_OPTIONS = {
spreadStrict: true,
ignoreCase: true
};

/**
* Returns boolean indicating whether an prop exists on the props
* property of a JSX element node.
*/
function hasProp() {
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var prop = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_OPTIONS;

var propToCheck = options.ignoreCase ? prop.toUpperCase() : prop;

return props.some(function (attribute) {
// If the props contain a spread prop, then refer to strict param.
if (attribute.type === 'JSXSpreadAttribute') {
return !options.spreadStrict;
}

var currentProp = options.ignoreCase ? (0, _propName2.default)(attribute).toUpperCase() : (0, _propName2.default)(attribute);

return propToCheck === currentProp;
});
}

/**
* Given the props on a node and a list of props to check, this returns a boolean
* indicating if any of them exist on the node.
*/
function hasAnyProp() {
var nodeProps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_OPTIONS;

var propsToCheck = typeof props === 'string' ? props.split(' ') : props;

return propsToCheck.some(function (prop) {
return hasProp(nodeProps, prop, options);
});
}

/**
* Given the props on a node and a list of props to check, this returns a boolean
* indicating if all of them exist on the node
*/
function hasEveryProp() {
var nodeProps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_OPTIONS;

var propsToCheck = typeof props === 'string' ? props.split(' ') : props;

return propsToCheck.every(function (prop) {
return hasProp(nodeProps, prop, options);
});
}
40 changes: 40 additions & 0 deletions lib/index.js
@@ -0,0 +1,40 @@
'use strict';

var _hasProp = require('./hasProp');

var _hasProp2 = _interopRequireDefault(_hasProp);

var _elementType = require('./elementType');

var _elementType2 = _interopRequireDefault(_elementType);

var _eventHandlers = require('./eventHandlers');

var _eventHandlers2 = _interopRequireDefault(_eventHandlers);

var _getProp = require('./getProp');

var _getProp2 = _interopRequireDefault(_getProp);

var _getPropValue = require('./getPropValue');

var _getPropValue2 = _interopRequireDefault(_getPropValue);

var _propName = require('./propName');

var _propName2 = _interopRequireDefault(_propName);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

module.exports = {
hasProp: _hasProp2.default,
hasAnyProp: _hasProp.hasAnyProp,
hasEveryProp: _hasProp.hasEveryProp,
elementType: _elementType2.default,
eventHandlers: _eventHandlers2.default,
eventHandlersByType: _eventHandlers.eventHandlersByType,
getProp: _getProp2.default,
getPropValue: _getPropValue2.default,
getLiteralPropValue: _getPropValue.getLiteralPropValue,
propName: _propName2.default
};

0 comments on commit 3e10a90

Please sign in to comment.