From 44a69b10a6bd1e3c52bdb86e844babe2d8adec59 Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Mon, 5 Mar 2018 21:30:18 +0300 Subject: [PATCH 01/15] Updates after pulling --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0d8c462..3420731 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "babel-plugin-transform-react-pug", - "version": "4.0.0", + "version": "4.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f4d65d0..66d4d82 100644 --- a/package.json +++ b/package.json @@ -66,4 +66,4 @@ "type": "git", "url": "https://github.com/pugjs/babel-plugin-transform-react-pug.git" } -} \ No newline at end of file +} From 71b2f72323537065c2124d843f75ef2f7a779ceb Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Mon, 5 Mar 2018 22:09:57 +0300 Subject: [PATCH 02/15] Add tests for handling unescaped attributes --- src/__tests__/attributes-unescaped.test.js | 56 ++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/__tests__/attributes-unescaped.test.js diff --git a/src/__tests__/attributes-unescaped.test.js b/src/__tests__/attributes-unescaped.test.js new file mode 100644 index 0000000..d238fd8 --- /dev/null +++ b/src/__tests__/attributes-unescaped.test.js @@ -0,0 +1,56 @@ +import React from 'react'; +import {transform} from 'babel-core'; +import renderer from 'react-test-renderer'; +import transformReactPug from '../'; + +const transformationOptions = { + babelrc: false, + plugins: [transformReactPug], +}; + +const transformer = code => { + return transform(`pug\`${code}\``, transformationOptions).code; +}; + +const ExpectedError = /Unescaped attributes/; + +test('throws error when pass string', () => { + const wrapped = () => + transformer(` + div(name!="hello") + `); + + expect(wrapped).toThrowError(ExpectedError); +}); + +test('throws error when pass variable', () => { + const wrapped = () => + transformer(` + - const variable = 'value' + div(name!=variable.toString()) + `); + + expect(wrapped).toThrowError(ExpectedError); +}); + +test('does not throw error when pass variable or just string', () => { + const wrapped = () => + transformer(` + - const variable = 'value' + div#id.class( + data-string="hello" data-variable=variable + ) + div(class=['one', 'two']) + `); + + expect(wrapped).not.toThrowError(ExpectedError); +}); + +test('does not throw error when pass boolean variables', () => { + const wrapped = () => + transformer(` + div(data-first data-second data-third) + `); + + expect(wrapped).not.toThrowError(ExpectedError); +}); From 1daa3485ef2bffc96da760acff261a29e324e43e Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Mon, 5 Mar 2018 22:10:17 +0300 Subject: [PATCH 03/15] Add tests for attributes shorthands --- .../attributes-shorthand.test.js.snap | 25 +++++++++++++++++++ src/__tests__/attributes-shorthand.input.js | 13 ++++++++++ src/__tests__/attributes-shorthand.test.js | 3 +++ 3 files changed, 41 insertions(+) create mode 100644 src/__tests__/__snapshots__/attributes-shorthand.test.js.snap create mode 100644 src/__tests__/attributes-shorthand.input.js create mode 100644 src/__tests__/attributes-shorthand.test.js diff --git a/src/__tests__/__snapshots__/attributes-shorthand.test.js.snap b/src/__tests__/__snapshots__/attributes-shorthand.test.js.snap new file mode 100644 index 0000000..557f0dd --- /dev/null +++ b/src/__tests__/__snapshots__/attributes-shorthand.test.js.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`JavaScript output: transformed source code 1`] = ` +"// To prevent warnings in console from react +const test = 10; + +module.exports =
;" +`; + +exports[`html output: generated html 1`] = ` +
+
+
+`; + +exports[`static html output: static html 1`] = `"
"`; diff --git a/src/__tests__/attributes-shorthand.input.js b/src/__tests__/attributes-shorthand.input.js new file mode 100644 index 0000000..41583a9 --- /dev/null +++ b/src/__tests__/attributes-shorthand.input.js @@ -0,0 +1,13 @@ +// To prevent warnings in console from react +const test = 10; + +module.exports = pug` + div( + data-first + data-second + data-positive=true + data-negative=false + data-check + ) + div(data-one data-two) +`; diff --git a/src/__tests__/attributes-shorthand.test.js b/src/__tests__/attributes-shorthand.test.js new file mode 100644 index 0000000..e7b91de --- /dev/null +++ b/src/__tests__/attributes-shorthand.test.js @@ -0,0 +1,3 @@ +import testHelper from './test-helper'; + +testHelper(__dirname + '/attributes-shorthand.input.js'); From 4d82ce9c67e39237f5ed0c5a6fff20cd342bfc67 Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Mon, 5 Mar 2018 22:10:50 +0300 Subject: [PATCH 04/15] Add the possibility to handle attributes correctly --- src/visitors/Tag.js | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/visitors/Tag.js b/src/visitors/Tag.js index 633ce85..703fcc4 100644 --- a/src/visitors/Tag.js +++ b/src/visitors/Tag.js @@ -54,8 +54,16 @@ function getAttributes( const expr = parseExpression(val === true ? 'true' : val, context); - if (!mustEscape && (!t.isStringLiteral(expr) || /(\<\>\&)/.test(val))) { - throw new Error('Unescaped attributes are not supported in react-pug'); + if (!mustEscape) { + const isStringViaAliases = + t.isStringLiteral(expr) && !['className', 'id'].includes(name); + const isNotString = !t.isStringLiteral(expr); + + if (isStringViaAliases || isNotString) { + throw new Error( + 'Unescaped attributes are not supported in react-pug', + ); + } } if (expr == null) { @@ -83,14 +91,14 @@ function getAttributes( const value = classes.every(cls => t.isStringLiteral(cls)) ? t.stringLiteral(classes.map(cls => (cls: any).value).join(' ')) : t.jSXExpressionContainer( - t.callExpression( - t.memberExpression( - t.arrayExpression(classes), - t.identifier('join'), + t.callExpression( + t.memberExpression( + t.arrayExpression(classes), + t.identifier('join'), + ), + [t.stringLiteral(' ')], ), - [t.stringLiteral(' ')], - ), - ); + ); attrs.push(t.jSXAttribute(t.jSXIdentifier('className'), value)); } return attrs; From b7f9ac33737d377e4bf02e0ef32b9f1d101b573a Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Mon, 5 Mar 2018 22:29:41 +0300 Subject: [PATCH 05/15] Expect mustEscape set to `false` for boolean attributes --- src/visitors/Tag.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/visitors/Tag.js b/src/visitors/Tag.js index 703fcc4..31edbc7 100644 --- a/src/visitors/Tag.js +++ b/src/visitors/Tag.js @@ -57,9 +57,11 @@ function getAttributes( if (!mustEscape) { const isStringViaAliases = t.isStringLiteral(expr) && !['className', 'id'].includes(name); - const isNotString = !t.isStringLiteral(expr); - if (isStringViaAliases || isNotString) { + const isNotStringOrBoolean = + !t.isStringLiteral(expr) && !t.isBooleanLiteral(expr); + + if (isStringViaAliases || isNotStringOrBoolean) { throw new Error( 'Unescaped attributes are not supported in react-pug', ); From b2cf339c2925ca2f4ef8c6b2d464036547308e31 Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Mon, 5 Mar 2018 22:38:07 +0300 Subject: [PATCH 06/15] Consider that boolean attributes does not nead to be escaped --- src/visitors/Tag.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/visitors/Tag.js b/src/visitors/Tag.js index 31edbc7..21a5ab6 100644 --- a/src/visitors/Tag.js +++ b/src/visitors/Tag.js @@ -35,6 +35,16 @@ function getAttributes( ): Array { const classes = []; const attrs = node.attrs + .map(node => { + if (node.val === true) { + return { + ...node, + mustEscape: false, + }; + } + + return node; + }) .map(({name, val, mustEscape}) => { if (/\.\.\./.test(name) && val === true) { return t.jSXSpreadAttribute(parseExpression(name.substr(3), context)); From 6e910f5b5bdf64b9e62a3e43c798890678ed9fb9 Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Mon, 5 Mar 2018 23:06:17 +0300 Subject: [PATCH 07/15] Allow throwing context-related errors for inline code --- src/context.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/context.js b/src/context.js index be3db6d..3e6d23a 100644 --- a/src/context.js +++ b/src/context.js @@ -1,6 +1,6 @@ // @flow -import {readFileSync} from 'fs'; +import {readFileSync, existsSync} from 'fs'; import error from 'pug-error'; import type {Key} from './block-key'; import {getCurrentLocation} from './babel-types'; @@ -42,12 +42,17 @@ class Context { } error(code: string, message: string): Error { - const src = readFileSync(this.file.opts.filename, 'utf8'); - return error(code, message, { + const options: Object = { filename: this.file.opts.filename, line: getCurrentLocation().start.line - 1, - src, - }); + src: null, + }; + + if (existsSync(options.filename)) { + options.src = readFileSync(this.file.opts.filename, 'utf8'); + } + + return error(code, message, options); } noKey(fn: (context: Context) => T): T { From 0eaaaf8fe58b85b06338bb9cbc577579e0f39c46 Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Tue, 6 Mar 2018 00:31:48 +0300 Subject: [PATCH 08/15] Upgrade flow-bin --- .flowconfig | 6 ++++-- package-lock.json | 6 +++--- package.json | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.flowconfig b/.flowconfig index ceea7c1..c44edac 100644 --- a/.flowconfig +++ b/.flowconfig @@ -4,8 +4,10 @@ [include] [libs] - - ./scripts/babel-nodes.js +[lints] + [options] + +[strict] diff --git a/package-lock.json b/package-lock.json index 3420731..72445f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2119,9 +2119,9 @@ } }, "flow-bin": { - "version": "0.65.0", - "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.65.0.tgz", - "integrity": "sha512-/Ny7pElDdmwgxq8ALf87/MylzXWAh2Kny1kxGUOG1TxwGEQMctgENtLpuwx8fwvlIUebgJWF8ylhWOcmiNKDpA==", + "version": "0.66.0", + "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.66.0.tgz", + "integrity": "sha1-qW3ecBXcM0P9VSp7SWPAK+cFyiY=", "dev": true }, "for-in": { diff --git a/package.json b/package.json index 66d4d82..5dd8675 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "babel-plugin-transform-flow-strip-types": "^6.22.0", "babel-preset-forbeslindesay": "^2.1.0", "babel-types": "^6.24.1", - "flow-bin": "^0.65.0", + "flow-bin": "^0.66.0", "husky": "^0.14.3", "jest": "^22.1.4", "lint-staged": "^7.0.0", From dfd931533c13168be8d1913438a312df5429d2f3 Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Tue, 6 Mar 2018 00:35:32 +0300 Subject: [PATCH 09/15] Show errors with referencing to context --- src/visitors/Tag.js | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/visitors/Tag.js b/src/visitors/Tag.js index 21a5ab6..3cedcc9 100644 --- a/src/visitors/Tag.js +++ b/src/visitors/Tag.js @@ -6,6 +6,14 @@ import t from '../babel-types'; import {visitJsx, visitJsxExpressions} from '../visitors'; import {getInterpolationRefs} from '../utils/interpolation'; +type PugAttribute = { + name: string, + val: string, + mustEscape: boolean, +}; + +type Attribute = JSXAttribute | JSXSpreadAttribute; + /** * Get children nodes from the node, passing the node's * context to the children and generating JSX values. @@ -27,15 +35,12 @@ function getChildren(node: Object, context: Context): Array { * them into JSX attributes. * @param {Object} node - The node * @param {Context} context - The context - * @returns {Array} + * @returns {Array} */ -function getAttributes( - node: Object, - context: Context, -): Array { - const classes = []; - const attrs = node.attrs - .map(node => { +function getAttributes(node: Object, context: Context): Array { + const classes: Array = []; + const attrs: Array = node.attrs + .map((node: PugAttribute): PugAttribute => { if (node.val === true) { return { ...node, @@ -45,7 +50,7 @@ function getAttributes( return node; }) - .map(({name, val, mustEscape}) => { + .map(({name, val, mustEscape}: PugAttribute): Attribute | null => { if (/\.\.\./.test(name) && val === true) { return t.jSXSpreadAttribute(parseExpression(name.substr(3), context)); } @@ -65,14 +70,15 @@ function getAttributes( const expr = parseExpression(val === true ? 'true' : val, context); if (!mustEscape) { - const isStringViaAliases = + const isStringViaAliases: boolean = t.isStringLiteral(expr) && !['className', 'id'].includes(name); - const isNotStringOrBoolean = + const isNotStringOrBoolean: boolean = !t.isStringLiteral(expr) && !t.isBooleanLiteral(expr); if (isStringViaAliases || isNotStringOrBoolean) { - throw new Error( + throw context.error( + 'INVALID_EXPRESSION', 'Unescaped attributes are not supported in react-pug', ); } @@ -99,6 +105,7 @@ function getAttributes( return t.jSXAttribute(t.jSXIdentifier(name), jsxValue); }) .filter(Boolean); + if (classes.length) { const value = classes.every(cls => t.isStringLiteral(cls)) ? t.stringLiteral(classes.map(cls => (cls: any).value).join(' ')) @@ -113,6 +120,7 @@ function getAttributes( ); attrs.push(t.jSXAttribute(t.jSXIdentifier('className'), value)); } + return attrs; } From bb616d93fcffb78e1034b8d65efb111e4d6fe9bb Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Tue, 6 Mar 2018 18:20:56 +0300 Subject: [PATCH 10/15] Get rid of extra types --- src/visitors/Tag.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/visitors/Tag.js b/src/visitors/Tag.js index 3cedcc9..5839198 100644 --- a/src/visitors/Tag.js +++ b/src/visitors/Tag.js @@ -70,10 +70,10 @@ function getAttributes(node: Object, context: Context): Array { const expr = parseExpression(val === true ? 'true' : val, context); if (!mustEscape) { - const isStringViaAliases: boolean = + const isStringViaAliases = t.isStringLiteral(expr) && !['className', 'id'].includes(name); - const isNotStringOrBoolean: boolean = + const isNotStringOrBoolean = !t.isStringLiteral(expr) && !t.isBooleanLiteral(expr); if (isStringViaAliases || isNotStringOrBoolean) { From efb0089c71fe19a45c13dd0597f285d6d25d9861 Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Tue, 6 Mar 2018 18:23:37 +0300 Subject: [PATCH 11/15] Make code more clear: Get rid of .includes method for array of 2 items --- src/visitors/Tag.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/visitors/Tag.js b/src/visitors/Tag.js index 5839198..fbc940c 100644 --- a/src/visitors/Tag.js +++ b/src/visitors/Tag.js @@ -71,7 +71,7 @@ function getAttributes(node: Object, context: Context): Array { if (!mustEscape) { const isStringViaAliases = - t.isStringLiteral(expr) && !['className', 'id'].includes(name); + t.isStringLiteral(expr) && name !== 'className' && name !== 'id'; const isNotStringOrBoolean = !t.isStringLiteral(expr) && !t.isBooleanLiteral(expr); From 5f9c7610f8a9d74c432efcb9853ff06cbe341b96 Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Tue, 6 Mar 2018 18:45:06 +0300 Subject: [PATCH 12/15] Update react dependencies and remove temporary workaround --- package-lock.json | 144 +++++++++++++++++++++++++------------------- package.json | 8 +-- src/visitors/Tag.js | 10 --- 3 files changed, 87 insertions(+), 75 deletions(-) diff --git a/package-lock.json b/package-lock.json index 72445f1..017191c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,6 +61,19 @@ } } }, + "@types/babel-types": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.1.tgz", + "integrity": "sha512-EkcOk09rjhivbovP8WreGRbXW20YRfe/qdgXOGq3it3u3aAOWDRNsQhL/XPAWFF7zhZZ+uR+nT+3b+TCkIap1w==" + }, + "@types/babylon": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.2.tgz", + "integrity": "sha512-+Jty46mPaWe1VAyZbfvgJM4BAdklLWxrT5tc/RjvCgLrtk6gzRY6AOnoWFv4p6hVxhJshDdr2hGVn56alBp97Q==", + "requires": { + "@types/babel-types": "7.0.1" + } + }, "abab": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", @@ -68,9 +81,9 @@ "dev": true }, "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" }, "acorn-globals": { "version": "4.1.0", @@ -1332,9 +1345,9 @@ } }, "clean-css": { - "version": "3.4.26", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.26.tgz", - "integrity": "sha1-VTI7NE/zvO5oSi6sgck9+Ppz3us=", + "version": "3.4.28", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", + "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=", "requires": { "commander": "2.8.1", "source-map": "0.4.4" @@ -1447,12 +1460,41 @@ "dev": true }, "constantinople": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.0.tgz", - "integrity": "sha1-dWnKqKo/jVk11i4fqW+fcCzYHHk=", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz", + "integrity": "sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw==", "requires": { - "acorn": "3.3.0", - "is-expression": "2.1.0" + "@types/babel-types": "7.0.1", + "@types/babylon": "6.16.2", + "babel-types": "6.26.0", + "babylon": "6.18.0" + }, + "dependencies": { + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "2.4.1", + "regenerator-runtime": "0.11.1" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "1.0.3" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } } }, "content-type-parser": { @@ -1476,8 +1518,7 @@ "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", - "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=", - "dev": true + "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=" }, "core-util-is": { "version": "1.0.2", @@ -1806,8 +1847,7 @@ "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, "exec-sh": { "version": "0.2.0", @@ -3623,11 +3663,11 @@ } }, "is-expression": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-2.1.0.tgz", - "integrity": "sha1-kb6dR968/vB3l36XIr5tz7RGXvA=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-3.0.0.tgz", + "integrity": "sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8=", "requires": { - "acorn": "3.3.0", + "acorn": "4.0.13", "object-assign": "4.1.1" } }, @@ -7006,8 +7046,7 @@ "lodash": { "version": "4.17.4", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", - "dev": true + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" }, "lodash.sortby": { "version": "4.7.0", @@ -7823,66 +7862,50 @@ "integrity": "sha1-U659nSm7A89WRJOgJhCfVMR/XyY=" }, "pug-filters": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-2.1.2.tgz", - "integrity": "sha1-NZC0Gts0dJ9x0/HxqfdFAREZEXs=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-3.0.0.tgz", + "integrity": "sha1-SSTwIDwd6iDH4UiuwgGJiGa3ydI=", "requires": { - "clean-css": "3.4.26", - "constantinople": "3.1.0", + "clean-css": "3.4.28", + "constantinople": "3.1.2", "jstransformer": "1.0.0", "pug-error": "1.3.2", - "pug-walk": "1.1.2", - "resolve": "1.3.3", + "pug-walk": "1.1.6", + "resolve": "1.5.0", "uglify-js": "2.8.27" } }, "pug-lexer": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-3.1.0.tgz", - "integrity": "sha1-/QhzdtSmdbT1n4/vQiiDQ06VgaI=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-4.0.0.tgz", + "integrity": "sha1-IQwYRX7y4XYCQnQMXmR715TOwng=", "requires": { "character-parser": "2.2.0", "is-expression": "3.0.0", "pug-error": "1.3.2" - }, - "dependencies": { - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" - }, - "is-expression": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-3.0.0.tgz", - "integrity": "sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8=", - "requires": { - "acorn": "4.0.13", - "object-assign": "4.1.1" - } - } } }, "pug-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-4.0.0.tgz", - "integrity": "sha512-ocEUFPdLG9awwFj0sqi1uiZLNvfoodCMULZzkRqILryIWc/UUlDlxqrKhKjAIIGPX/1SNsvxy63+ayEGocGhQg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-4.0.1.tgz", + "integrity": "sha1-vSq99clYcet5En5GWWlduncPW4c=", "requires": { "pug-error": "1.3.2", "token-stream": "0.0.1" } }, "pug-strip-comments": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-1.0.2.tgz", - "integrity": "sha1-0xOvoBvMN0mA4TmeI+vy65vchRM=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-1.0.3.tgz", + "integrity": "sha1-8VWVkiBu3G+FMQ2s9K+0igJa9Z8=", "requires": { "pug-error": "1.3.2" } }, "pug-walk": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.2.tgz", - "integrity": "sha1-3rskwHCpXV/Crr81iSYYM9IzLjs=" + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.6.tgz", + "integrity": "sha1-fKvNc3zb+uz7DzKvcSfrrPQjlHo=" }, "punycode": { "version": "1.4.1", @@ -8245,9 +8268,9 @@ "dev": true }, "resolve": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", - "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", "requires": { "path-parse": "1.0.5" } @@ -8898,8 +8921,7 @@ "to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" }, "to-object-path": { "version": "0.3.0", diff --git a/package.json b/package.json index 5dd8675..fd23ee9 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,10 @@ "babylon": "6.18.0", "common-prefix": "^1.1.0", "pug-error": "^1.3.2", - "pug-filters": "^2.1.2", - "pug-lexer": "^3.1.0", - "pug-parser": "^4.0.0", - "pug-strip-comments": "1.0.2" + "pug-filters": "^3.0.0", + "pug-lexer": "^4.0.0", + "pug-parser": "^4.0.1", + "pug-strip-comments": "^1.0.3" }, "devDependencies": { "babel-cli": "^6.24.1", diff --git a/src/visitors/Tag.js b/src/visitors/Tag.js index fbc940c..4534ae2 100644 --- a/src/visitors/Tag.js +++ b/src/visitors/Tag.js @@ -40,16 +40,6 @@ function getChildren(node: Object, context: Context): Array { function getAttributes(node: Object, context: Context): Array { const classes: Array = []; const attrs: Array = node.attrs - .map((node: PugAttribute): PugAttribute => { - if (node.val === true) { - return { - ...node, - mustEscape: false, - }; - } - - return node; - }) .map(({name, val, mustEscape}: PugAttribute): Attribute | null => { if (/\.\.\./.test(name) && val === true) { return t.jSXSpreadAttribute(parseExpression(name.substr(3), context)); From 59f3f7f449aa2843b19a791c12a595086acce1e7 Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Tue, 20 Mar 2018 12:25:30 +0300 Subject: [PATCH 13/15] Add tests for numbers as a value of attribute --- src/__tests__/attributes-unescaped.test.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/__tests__/attributes-unescaped.test.js b/src/__tests__/attributes-unescaped.test.js index d238fd8..b5d901b 100644 --- a/src/__tests__/attributes-unescaped.test.js +++ b/src/__tests__/attributes-unescaped.test.js @@ -23,6 +23,15 @@ test('throws error when pass string', () => { expect(wrapped).toThrowError(ExpectedError); }); +test('throws error when pass number', () => { + const wrapped = () => + transformer(` + div(name!=42) + `); + + expect(wrapped).toThrowError(ExpectedError); +}); + test('throws error when pass variable', () => { const wrapped = () => transformer(` @@ -38,7 +47,9 @@ test('does not throw error when pass variable or just string', () => { transformer(` - const variable = 'value' div#id.class( - data-string="hello" data-variable=variable + data-string="hello" + data-variable=variable + data-number=42 ) div(class=['one', 'two']) `); From ecc69e909fdd9a0cb22cf82667ac0dce293de6bf Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Tue, 20 Mar 2018 12:31:50 +0300 Subject: [PATCH 14/15] Small refactoring: rename variables and simplify the logic --- src/visitors/Tag.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/visitors/Tag.js b/src/visitors/Tag.js index 4534ae2..353fdcb 100644 --- a/src/visitors/Tag.js +++ b/src/visitors/Tag.js @@ -60,13 +60,10 @@ function getAttributes(node: Object, context: Context): Array { const expr = parseExpression(val === true ? 'true' : val, context); if (!mustEscape) { - const isStringViaAliases = - t.isStringLiteral(expr) && name !== 'className' && name !== 'id'; + const canSkipEscaping = + (name === 'className' || name === 'id') && t.isStringLiteral(expr); - const isNotStringOrBoolean = - !t.isStringLiteral(expr) && !t.isBooleanLiteral(expr); - - if (isStringViaAliases || isNotStringOrBoolean) { + if (!canSkipEscaping) { throw context.error( 'INVALID_EXPRESSION', 'Unescaped attributes are not supported in react-pug', From 32e4f297de78ce5e533c46e61c22b41c64f74390 Mon Sep 17 00:00:00 2001 From: Eugene Zhlobo Date: Tue, 20 Mar 2018 12:52:43 +0300 Subject: [PATCH 15/15] Update dependencies to get new API of pug-parser --- package-lock.json | 20 ++++++++++---------- package.json | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 017191c..eda9d94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7862,15 +7862,15 @@ "integrity": "sha1-U659nSm7A89WRJOgJhCfVMR/XyY=" }, "pug-filters": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-3.0.0.tgz", - "integrity": "sha1-SSTwIDwd6iDH4UiuwgGJiGa3ydI=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-3.0.1.tgz", + "integrity": "sha1-Fj73O/ux8VRNAysrQPRRMOtS3Ms=", "requires": { "clean-css": "3.4.28", "constantinople": "3.1.2", "jstransformer": "1.0.0", "pug-error": "1.3.2", - "pug-walk": "1.1.6", + "pug-walk": "1.1.7", "resolve": "1.5.0", "uglify-js": "2.8.27" } @@ -7886,9 +7886,9 @@ } }, "pug-parser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-4.0.1.tgz", - "integrity": "sha1-vSq99clYcet5En5GWWlduncPW4c=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-5.0.0.tgz", + "integrity": "sha1-45Stmz/KkxI5QK/4hcBuRKt+aOQ=", "requires": { "pug-error": "1.3.2", "token-stream": "0.0.1" @@ -7903,9 +7903,9 @@ } }, "pug-walk": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.6.tgz", - "integrity": "sha1-fKvNc3zb+uz7DzKvcSfrrPQjlHo=" + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.7.tgz", + "integrity": "sha1-wA1cUSi6xYBr7BXSt+fNq+QlMfM=" }, "punycode": { "version": "1.4.1", diff --git a/package.json b/package.json index fd23ee9..f675404 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,9 @@ "babylon": "6.18.0", "common-prefix": "^1.1.0", "pug-error": "^1.3.2", - "pug-filters": "^3.0.0", + "pug-filters": "^3.0.1", "pug-lexer": "^4.0.0", - "pug-parser": "^4.0.1", + "pug-parser": "^5.0.0", "pug-strip-comments": "^1.0.3" }, "devDependencies": {