Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

babel-plugin-transform-react-pug

Package Overview
Dependencies
Maintainers
2
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

babel-plugin-transform-react-pug - npm Package Compare versions

Comparing version 3.1.8 to 3.2.0

lib/__tests__/interpolation.test.js

35

lib/context.js

@@ -38,3 +38,3 @@ 'use strict';

var Context = function () {
function Context(definesScope, key, parent, file, path) {
function Context(definesScope, key, parent, file, path, interpolations) {
(0, _classCallCheck3.default)(this, Context);

@@ -52,2 +52,3 @@ this._variables = new _map2.default();

this.path = path;
this._interpolations = interpolations;
}

@@ -98,8 +99,11 @@

var variable = this._variables.get(name);
if (variable) {
return variable;
}
if (this._parent) {
return this._parent.getVariable(name);
}
// TODO: maybe actually verify existance/non-const in parent scope?

@@ -114,3 +118,5 @@ return null;

}
var oldVariable = this._variables.get(name);
if (oldVariable) {

@@ -123,2 +129,3 @@ if (oldVariable.kind !== 'var' || kind !== 'var') {

}
var variable = {

@@ -128,2 +135,3 @@ kind: kind,

};
this.variablesToDeclare.push(variable.id);

@@ -143,6 +151,27 @@ this._variables.set(name, variable);

}
/**
* Check whether interpolations exist for the context, if not,
* recursively check the parent context for the interpolation.
* @param { String } reference - The interpolation reference
* @returns { ?Expression } The interpolation or nothing.
*/
}, {
key: 'getInterpolationByRef',
value: function getInterpolationByRef(reference) {
var interpolation = null;
if (this._interpolations && (interpolation = this._interpolations.get(reference))) {
return interpolation;
} else if (this._parent) {
return this._parent.getInterpolationByRef(reference);
}
return this.getInterpolationByRef(reference);
}
}], [{
key: 'create',
value: function create(file, path) {
return new Context(true, new _blockKey.BaseKey(), null, file, path);
value: function create(file, path, interpolations) {
return new Context(true, new _blockKey.BaseKey(), null, file, path, interpolations);
}

@@ -149,0 +178,0 @@ }]);

@@ -10,3 +10,5 @@ 'use strict';

(0, _babelTypes.setBabelTypes)(t);
function isReactPugReference(node) {

@@ -16,16 +18,37 @@ // TODO: do this better

}
return {
visitor: {
TaggedTemplateExpression: function TaggedTemplateExpression(path) {
if (isReactPugReference(path.node.tag) && path.node.quasi.expressions.length === 0 && path.node.quasi.quasis.length === 1) {
var src = path.node.quasi.quasis[0].value.raw;
var minIndent = src.split('\n').reduce(function (minIndent, line) {
var node = path.node;
var _node$quasi = node.quasi,
quasis = _node$quasi.quasis,
expressions = _node$quasi.expressions;
if (isReactPugReference(node.tag) && quasis.length >= 1) {
var template = void 0,
interpolationRef = void 0;
if (expressions.length) {
var interpolatedTpl = (0, _interpolation.getInterpolatedTemplate)(quasis, expressions);
template = interpolatedTpl.template;
interpolationRef = interpolatedTpl.interpolationRef;
} else {
template = quasis[0].value.raw;
}
var src = template.split('\n');
var minIndent = src.reduce(function (minIndent, line) {
return line.trim().length ? Math.min(/^ */.exec(line)[0].length, minIndent) : minIndent;
}, Infinity);
src = src.split('\n').map(function (line) {
src = src.map(function (line) {
return line.substr(minIndent);
}).join('\n');
var ast = (0, _parsePug2.default)(src);
var context = _context2.default.create(this.file, path);
var context = _context2.default.create(this.file, path, interpolationRef);
var transformed = ast.nodes.map(function (node) {

@@ -35,6 +58,7 @@ return (0, _visitors.visitExpression)(node, context);

var expression = transformed.length === 1 ? transformed[0] : t.arrayExpression(transformed);
if (context.variablesToDeclare.length) {}
context.variablesToDeclare.forEach(function (id) {
path.scope.push({ kind: 'let', id: id });
});
path.replaceWith(expression);

@@ -59,4 +83,6 @@ }

var _interpolation = require('./utils/interpolation');
var _babelTypes = require('./babel-types');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -20,18 +20,45 @@ 'use strict';

var _interpolation = require('./interpolation');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function parseExpression(src, context) {
if ((0, _interpolation.getInterpolationRefs)(src)) {
var matched = src.split(_interpolation.INTERPOLATION_REFERENCE_REGEX);
var isInterpolation = matched.every(function (text) {
return text === '';
});
if (!isInterpolation) {
var errMsg = matched.length === 1 ? 'Interpolation does not exist' : 'Only an interpolation can be specified. You may want to remove ' + matched.join(' ') + '.';
throw context.error('INVALID_EXPRESSION', errMsg);
}
var interpolation = context.getInterpolationByRef(src);
if (interpolation == null) {
throw context.error('INVALID_EXPRESSION', 'Interpolation does not exist for ' + src);
}
return interpolation;
}
var val = (0, _parse2.default)('x = (' + src + ');', context);
if (val.length !== 1) {
var err = context.error('INVALID_EXPRESSION', 'There was an error parsing the expression "' + src + '".');
var err = context.error('INVALID_EXPRESSION', 'There was an error parsing the expression ' + src + '.');
throw err;
}
var expressionStatement = _babelTypes2.default.asExpressionStatement(val[0]);
var assignmentExpression = expressionStatement && _babelTypes2.default.asAssignmentExpression(expressionStatement.expression);
if (!assignmentExpression) {
var _err = context.error('INVALID_EXPRESSION', 'There was an error parsing the expression "' + src + '".');
var _err = context.error('INVALID_EXPRESSION', 'There was an error parsing the expression ' + src + '.');
throw _err;
}
(0, _addLocToAst2.default)(assignmentExpression);
return assignmentExpression.right;
}

@@ -17,4 +17,14 @@ 'use strict';

var _interpolation = require('../utils/interpolation');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Get children nodes from the node, passing the node's
* context to the children and generating JSX values.
* @param {Object} node - The node
* @param {Context} context - The context to apply to the children
* nodes
* @returns {Array<JSXValue>}
*/
function getChildren(node, context) {

@@ -28,2 +38,11 @@ return context.noKey(function (childContext) {

/**
* Iterate through the node's attributes and convert
* them into JSX attributes.
* @param {Object} node - The node
* @param {Context} context - The context
* @returns {Array<JSXAttribute|JSXSpreadAttribute>}
*/
function getAttributes(node, context) {

@@ -36,5 +55,7 @@ var classes = [];

if (/\.\.\./.test(name) && val === true) {
return _babelTypes2.default.jSXSpreadAttribute((0, _parseExpression2.default)(name.substr(3), context));
}
switch (name) {

@@ -51,6 +72,13 @@ case 'for':

}
var expr = (0, _parseExpression2.default)(val === true ? 'true' : val, context);
if (!mustEscape && (!_babelTypes2.default.isStringLiteral(expr) || /(\<\>\&)/.test(val))) {
throw new Error('Unescaped attributes are not supported in react-pug');
}
if (expr == null) {
return null;
}
if (name === 'className') {

@@ -60,6 +88,9 @@ classes.push(expr);

}
var jsxValue = _babelTypes2.default.asStringLiteral(expr) || _babelTypes2.default.asJSXElement(expr) || _babelTypes2.default.jSXExpressionContainer(expr);
if (/\.\.\./.test(name)) {
throw new Error('spread attributes must not have a value');
}
return _babelTypes2.default.jSXAttribute(_babelTypes2.default.jSXIdentifier(name), jsxValue);

@@ -78,25 +109,100 @@ }).filter(Boolean);

function build(node, context) {
var name = _babelTypes2.default.jSXIdentifier(node.name);
/**
* Retrieve attributes and children of the passed node.
* @param {Object} node - The node
* @param {Context} context - The context
* @returns {Object} Contains the attributes and children
* of the node.
*/
function getAttributesAndChildren(node, context) {
var children = getChildren(node, context);
if (node.attributeBlocks.length) {
throw new Error('Attribute blocks are not yet supported in react-pug');
}
var attrs = getAttributes(node, context);
context.key.handleAttributes(attrs);
var open = _babelTypes2.default.jSXOpeningElement(name, attrs, // Array<JSXAttribute | JSXSpreadAttribute>
children.length === 0);
return { attrs: attrs, children: children };
}
var close = children.length === 0 ? null : _babelTypes2.default.jSXClosingElement(name);
/**
* Generate a JSX element.
* @param { string } name - The name of the JSX element
* @param { Array<JSXAttribute|JSXSpreadAttribute> } attrs -
* The attributes for the JSX element
* @param { Array<JSXValue> } children - The children for
* the JSX element
* @returns { JSXElement } The JSX element.
*/
function buildJSXElement(name, attrs, children) {
var tagName = _babelTypes2.default.jSXIdentifier(name);
var noChildren = children.length === 0;
return _babelTypes2.default.jSXElement(open, close, children, children.length === 0);
var open = _babelTypes2.default.jSXOpeningElement(tagName, attrs, // Array<JSXAttribute | JSXSpreadAttribute>
noChildren);
var close = noChildren ? null : _babelTypes2.default.jSXClosingElement(tagName);
return _babelTypes2.default.jSXElement(open, close, children, noChildren);
}
/**
* Check whether an interpolation exists, if so, check whether
* the interpolation is a react component and return either
* the component as a JSX element or the interpolation.
* @param {string} name - The interpolation reference
* @param {Context} context - The current context to retrieve
* the interpolation from
* @param {Array<JSXValue>} children - Whether the element has
* attributes or children
* @returns {?Object} The context's interpolation or a JSX element.
*/
function getInterpolationByContext(name, context, attrs, children) {
if (!(0, _interpolation.getInterpolationRefs)(name)) {
return null;
}
var interpolation = context.getInterpolationByRef(name);
var isReactComponent = _babelTypes2.default.isIdentifier(interpolation) && interpolation.name.charAt(0) === interpolation.name.charAt(0).toUpperCase();
if (attrs.length || children.length) {
if (isReactComponent) {
return buildJSXElement(interpolation.name, attrs, children);
} else {
throw context.error('INVALID_EXPRESSION', 'Only components can have children and attributes');
}
}
return interpolation;
}
var TagVisitor = {
jsx: function jsx(node, context) {
return build(node, context);
var _getAttributesAndChil = getAttributesAndChildren(node, context),
attrs = _getAttributesAndChil.attrs,
children = _getAttributesAndChil.children;
var interpolation = getInterpolationByContext(node.name, context, attrs, children);
if (interpolation != null) {
return _babelTypes2.default.asJSXElement(interpolation) || _babelTypes2.default.jSXExpressionContainer(interpolation);
}
return buildJSXElement(node.name, attrs, children);
},
expression: function expression(node, context) {
return build(node, context);
var _getAttributesAndChil2 = getAttributesAndChildren(node, context),
attrs = _getAttributesAndChil2.attrs,
children = _getAttributesAndChil2.children;
var interpolation = getInterpolationByContext(node.name, context, attrs, children);
if (interpolation != null) {
return interpolation;
}
return buildJSXElement(node.name, attrs, children);
}

@@ -103,0 +209,0 @@ };

@@ -11,10 +11,66 @@ 'use strict';

var _interpolation = require('../utils/interpolation');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Find interpolation references in the text
* and interweave the text with interpolations.
* @param {string} value - The value to interpolate
* @param {Array<string>} refs - The array of references
* @param {Context} context - The context of the expression.
* @returns {Expression} The interpolation or an array containing
* text and interpolations.
*/
function buildInterpolation(value, refs, context) {
var splitText = value.split(_interpolation.INTERPOLATION_REFERENCE_REGEX);
if (refs.length === 1 && splitText.every(function (text) {
return text === '';
})) {
var ref = context.getInterpolationByRef(refs[0]);
return ref || _babelTypes2.default.nullLiteral();
}
var textArr = splitText.reduce(function (arr, value, index) {
var valueArr = value ? [_babelTypes2.default.stringLiteral(value)] : [];
var interpolation = refs[index] ? context.getInterpolationByRef(refs[index]) : null;
if (interpolation) {
valueArr.push(interpolation);
}
return arr.concat(valueArr);
}, []);
return _babelTypes2.default.callExpression(_babelTypes2.default.memberExpression(_babelTypes2.default.arrayExpression(textArr), _babelTypes2.default.identifier('join')), [_babelTypes2.default.stringLiteral('')]);
}
var TextVisitor = {
jsx: function jsx(node, context) {
return _babelTypes2.default.jSXText(node.val);
jsx: function jsx(_ref, context) {
var val = _ref.val;
var refs = (0, _interpolation.getInterpolationRefs)(val);
if (refs) {
var expr = buildInterpolation(val, refs, context);
return _babelTypes2.default.jSXExpressionContainer(expr);
}
return _babelTypes2.default.jSXText(val);
},
expression: function expression(node, context) {
return _babelTypes2.default.stringLiteral(node.val);
expression: function expression(_ref2, context) {
var val = _ref2.val;
var refs = (0, _interpolation.getInterpolationRefs)(val);
if (refs) {
return buildInterpolation(val, refs, context);
}
return _babelTypes2.default.stringLiteral(val);
}

@@ -21,0 +77,0 @@ };

{
"name": "babel-plugin-transform-react-pug",
"version": "3.1.8",
"version": "3.2.0",
"description": "A plugin for transpiling pug templates to jsx",

@@ -39,5 +39,17 @@ "main": "lib/index.js",

"lint": "eslint src",
"test": "jest ./src/**/*.test.js --coverage",
"watch": "jest ./src/**/*.test.js --coverage --watch"
"test": "jest --coverage",
"watch": "jest --coverage --watch"
},
"jest": {
"testEnvironment": "node",
"testRegex": "src/__tests__/.*(\\.test.js)$",
"collectCoverageFrom": [
"src/**/*.js",
"!src/__tests__/*.js",
"!src/babel-types.js"
],
"snapshotSerializers": [
"./scripts/filename-serializer.js"
]
},
"repository": {

@@ -44,0 +56,0 @@ "type": "git",

@@ -109,1 +109,19 @@ # babel-plugin-transform-react-pug

```
### Example 4 - Using interpolation in your Pug Component
If you'd prefer to use interpolation, you can! This is possible by using `${ }` within your template.
This lets you benefit from syntax highlighting and linting!
```js
import React from 'react';
const List = (props) => {
return pug`
ul.list(className=${ props.modifier })
${ props.items.map((item, index) => pug`li.list__item(key=${ index }) ${ item }` ) }
`
}
```
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc