diff --git a/src/extract/transpile/meta.js b/src/extract/transpile/meta.js index d9ac8de4c..a4fc88d0d 100644 --- a/src/extract/transpile/meta.js +++ b/src/extract/transpile/meta.js @@ -7,8 +7,17 @@ const coffeeWrap = require("./coffeeWrap")(); const litCoffeeWrap = require("./coffeeWrap")(true); const supportedTranspilers = require("../../../package.json").supportedTranspilers; +/* + jsx - acorn_loose will handle this correctly when imports + etc are on top, which is the most likely use case. + Alternatives (making a jsxWrap with babel-core & a bunch + of plugins or using acorn-jsx) might be more correct in + edge cases but are either much harder to implement or + likely to fail in basic use cases. + */ const extension2wrapper = { ".js" : javaScriptWrap, + ".jsx" : javaScriptWrap, ".ts" : typeScriptWrap, ".tsx" : typeScriptWrap, ".d.ts" : typeScriptWrap, diff --git a/test/extract/transpile/fixtures/jsx.js b/test/extract/transpile/fixtures/jsx.js new file mode 100644 index 000000000..1acae7fb3 --- /dev/null +++ b/test/extract/transpile/fixtures/jsx.js @@ -0,0 +1,63 @@ +// 1:1 copied from https://github.com/mozilla/payments-ui +import React, { Component, PropTypes } from 'react'; + +import PayMethodChoice from 'components/pay-method-choice'; +import ProductDetail from 'components/product-detail'; + +import * as products from 'products'; +import { gettext } from 'utils'; +import tracking from 'tracking'; + + +export default class ProductPayChooser extends Component { + + static propTypes = { + payMethods: PropTypes.array.isRequired, + payWithNewCard: PropTypes.func.isRequired, + processPayment: PropTypes.func.isRequired, + productId: PropTypes.string.isRequired, + userDefinedAmount: PropTypes.string, + } + + componentDidMount() { + tracking.setPage('/product-pay-chooser'); + } + + handleSubmit = (payMethodUri, processingId) => { + this.props.processPayment({productId: this.props.productId, + userDefinedAmount: this.props.userDefinedAmount, + payMethodUri: payMethodUri, + processingId: processingId}); + } + + render() { + var product = products.get(this.props.productId); + var submitPrompt; + if (product.seller.kind === 'donations') { + submitPrompt = gettext('Donate now'); + } else { + // TODO: also handle non-recurring, non-donations here. + submitPrompt = gettext('Subscribe'); + } + + return ( +
+ ); + } +} diff --git a/test/extract/transpile/fixtures/jsx.jsx b/test/extract/transpile/fixtures/jsx.jsx new file mode 100644 index 000000000..1acae7fb3 --- /dev/null +++ b/test/extract/transpile/fixtures/jsx.jsx @@ -0,0 +1,63 @@ +// 1:1 copied from https://github.com/mozilla/payments-ui +import React, { Component, PropTypes } from 'react'; + +import PayMethodChoice from 'components/pay-method-choice'; +import ProductDetail from 'components/product-detail'; + +import * as products from 'products'; +import { gettext } from 'utils'; +import tracking from 'tracking'; + + +export default class ProductPayChooser extends Component { + + static propTypes = { + payMethods: PropTypes.array.isRequired, + payWithNewCard: PropTypes.func.isRequired, + processPayment: PropTypes.func.isRequired, + productId: PropTypes.string.isRequired, + userDefinedAmount: PropTypes.string, + } + + componentDidMount() { + tracking.setPage('/product-pay-chooser'); + } + + handleSubmit = (payMethodUri, processingId) => { + this.props.processPayment({productId: this.props.productId, + userDefinedAmount: this.props.userDefinedAmount, + payMethodUri: payMethodUri, + processingId: processingId}); + } + + render() { + var product = products.get(this.props.productId); + var submitPrompt; + if (product.seller.kind === 'donations') { + submitPrompt = gettext('Donate now'); + } else { + // TODO: also handle non-recurring, non-donations here. + submitPrompt = gettext('Subscribe'); + } + + return ( + + ); + } +} diff --git a/test/extract/transpile/jsxWrap.spec.js b/test/extract/transpile/jsxWrap.spec.js new file mode 100644 index 000000000..b5aa1431a --- /dev/null +++ b/test/extract/transpile/jsxWrap.spec.js @@ -0,0 +1,23 @@ +"use strict"; + +const expect = require("chai").expect; +const fs = require('fs'); +const wrap = require("../../../src/extract/transpile/javaScriptWrap"); + +describe("jsx transpiler (the plain old javascript one)", () => { + it("tells the jsx transpiler is available", () => { + expect( + wrap.isAvailable() + ).to.equal(true); + }); + + it("transpiles jsx", () => { + expect( + wrap.transpile( + fs.readFileSync("./test/extract/transpile/fixtures/jsx.jsx", 'utf8') + ) + ).to.equal( + fs.readFileSync("./test/extract/transpile/fixtures/jsx.js", 'utf8') + ); + }); +}); diff --git a/test/extract/transpile/meta.spec.js b/test/extract/transpile/meta.spec.js index 5071aa112..1c726f16f 100644 --- a/test/extract/transpile/meta.spec.js +++ b/test/extract/transpile/meta.spec.js @@ -9,7 +9,7 @@ describe("transpiler meta", () => { it("tells which extensions can be scanned", () => { expect( meta.scannableExtensions - ).to.deep.equal([".js", ".ts", ".tsx", ".d.ts", ".coffee", ".litcoffee", ".coffee.md"]); + ).to.deep.equal([".js", ".jsx", ".ts", ".tsx", ".d.ts", ".coffee", ".litcoffee", ".coffee.md"]); }); it("returns the 'js' wrapper for unknown extensions", () => { diff --git a/test/main/fixtures/jsx.json b/test/main/fixtures/jsx.json new file mode 100644 index 000000000..dc7c59e77 --- /dev/null +++ b/test/main/fixtures/jsx.json @@ -0,0 +1,166 @@ +{ + "dependencies": [ + { + "source": "test/main/fixtures/jsx/index.js", + "dependencies": [ + { + "resolved": "test/main/fixtures/jsx/jsx.jsx", + "coreModule": false, + "followable": true, + "couldNotResolve": false, + "dependencyTypes": [ + "local" + ], + "module": "./jsx", + "moduleSystem": "cjs", + "valid": true + } + ] + }, + { + "source": "test/main/fixtures/jsx/jsx.jsx", + "dependencies": [ + { + "resolved": "components/pay-method-choice", + "coreModule": false, + "followable": false, + "couldNotResolve": true, + "dependencyTypes": [ + "unknown" + ], + "module": "components/pay-method-choice", + "moduleSystem": "es6", + "valid": true + }, + { + "resolved": "components/product-detail", + "coreModule": false, + "followable": false, + "couldNotResolve": true, + "dependencyTypes": [ + "unknown" + ], + "module": "components/product-detail", + "moduleSystem": "es6", + "valid": true + }, + { + "resolved": "products", + "coreModule": false, + "followable": false, + "couldNotResolve": true, + "dependencyTypes": [ + "unknown" + ], + "module": "products", + "moduleSystem": "es6", + "valid": true + }, + { + "resolved": "react", + "coreModule": false, + "followable": false, + "couldNotResolve": true, + "dependencyTypes": [ + "unknown" + ], + "module": "react", + "moduleSystem": "es6", + "valid": true + }, + { + "resolved": "tracking", + "coreModule": false, + "followable": false, + "couldNotResolve": true, + "dependencyTypes": [ + "unknown" + ], + "module": "tracking", + "moduleSystem": "es6", + "valid": true + }, + { + "resolved": "utils", + "coreModule": false, + "followable": false, + "couldNotResolve": true, + "dependencyTypes": [ + "unknown" + ], + "module": "utils", + "moduleSystem": "es6", + "valid": true + } + ] + }, + { + "source": "components/pay-method-choice", + "followable": false, + "coreModule": false, + "couldNotResolve": true, + "dependencyTypes": [ + "unknown" + ], + "dependencies": [] + }, + { + "source": "components/product-detail", + "followable": false, + "coreModule": false, + "couldNotResolve": true, + "dependencyTypes": [ + "unknown" + ], + "dependencies": [] + }, + { + "source": "products", + "followable": false, + "coreModule": false, + "couldNotResolve": true, + "dependencyTypes": [ + "unknown" + ], + "dependencies": [] + }, + { + "source": "react", + "followable": false, + "coreModule": false, + "couldNotResolve": true, + "dependencyTypes": [ + "unknown" + ], + "dependencies": [] + }, + { + "source": "tracking", + "followable": false, + "coreModule": false, + "couldNotResolve": true, + "dependencyTypes": [ + "unknown" + ], + "dependencies": [] + }, + { + "source": "utils", + "followable": false, + "coreModule": false, + "couldNotResolve": true, + "dependencyTypes": [ + "unknown" + ], + "dependencies": [] + } + ], + "summary": { + "violations": [], + "error": 0, + "warn": 0, + "info": 0, + "totalCruised": 8, + "optionsUsed": {} + } +} diff --git a/test/main/fixtures/jsx/index.js b/test/main/fixtures/jsx/index.js new file mode 100644 index 000000000..4b5bcd84d --- /dev/null +++ b/test/main/fixtures/jsx/index.js @@ -0,0 +1,3 @@ +const jsx = require('./jsx'); + +console.log(jsx); diff --git a/test/main/fixtures/jsx/jsx.jsx b/test/main/fixtures/jsx/jsx.jsx new file mode 100644 index 000000000..1acae7fb3 --- /dev/null +++ b/test/main/fixtures/jsx/jsx.jsx @@ -0,0 +1,63 @@ +// 1:1 copied from https://github.com/mozilla/payments-ui +import React, { Component, PropTypes } from 'react'; + +import PayMethodChoice from 'components/pay-method-choice'; +import ProductDetail from 'components/product-detail'; + +import * as products from 'products'; +import { gettext } from 'utils'; +import tracking from 'tracking'; + + +export default class ProductPayChooser extends Component { + + static propTypes = { + payMethods: PropTypes.array.isRequired, + payWithNewCard: PropTypes.func.isRequired, + processPayment: PropTypes.func.isRequired, + productId: PropTypes.string.isRequired, + userDefinedAmount: PropTypes.string, + } + + componentDidMount() { + tracking.setPage('/product-pay-chooser'); + } + + handleSubmit = (payMethodUri, processingId) => { + this.props.processPayment({productId: this.props.productId, + userDefinedAmount: this.props.userDefinedAmount, + payMethodUri: payMethodUri, + processingId: processingId}); + } + + render() { + var product = products.get(this.props.productId); + var submitPrompt; + if (product.seller.kind === 'donations') { + submitPrompt = gettext('Donate now'); + } else { + // TODO: also handle non-recurring, non-donations here. + submitPrompt = gettext('Subscribe'); + } + + return ( + + ); + } +} diff --git a/test/main/main.spec.js b/test/main/main.spec.js index f354ade9f..5b4f53b20 100644 --- a/test/main/main.spec.js +++ b/test/main/main.spec.js @@ -4,6 +4,7 @@ const expect = chai.expect; const main = require("../../src/main"); const tsFixture = require('./fixtures/ts.json'); const tsxFixture = require('./fixtures/tsx.json'); +const jsxFixture = require('./fixtures/jsx.json'); const depSchema = require('../../src/extract/jsonschema.json'); chai.use(require('chai-json-schema')); @@ -21,4 +22,10 @@ describe("main", () => { expect(lResult).to.deep.equal(tsxFixture); expect(lResult).to.be.jsonSchema(depSchema); }); + it("And jsx", () => { + const lResult = main.cruise(["test/main/fixtures/jsx"]); + + expect(lResult).to.deep.equal(jsxFixture); + expect(lResult).to.be.jsonSchema(depSchema); + }); });