├── .eslintignore ├── .npmignore ├── jsconfig.json ├── test ├── __snapshots__ │ ├── issues-6.test.js.snap │ ├── svg.test.js.snap │ ├── children-json.test.js.snap │ ├── sourcemaps.test.js.snap │ ├── issues-35.test.js.snap │ ├── children-string-prototype.test.js.snap │ ├── attributes-key.test.js.snap │ ├── children-mixed.test.js.snap │ ├── children-ternary.test.js.snap │ ├── children-expressions.test.js.snap │ ├── selectors-literal.test.js.snap │ ├── children-literal.test.js.snap │ ├── children-m.test.js.snap │ ├── children-m.trust.test.js.snap │ ├── children-array.test.js.snap │ └── attributes-class-classname.test.js.snap ├── sourcemaps.test.js ├── issues-6.test.js ├── svg.test.js ├── lib │ └── code.js ├── children-mixed.test.js ├── issues-35.test.js ├── children-json.test.js ├── children-string-prototype.test.js ├── attributes-key.test.js ├── children-ternary.test.js ├── children-expressions.test.js ├── selectors-literal.test.js ├── children-literal.test.js ├── children-m.test.js ├── children-m.trust.test.js ├── attributes-class-classname.test.js └── children-array.test.js ├── .publishrc ├── .gitattributes ├── src ├── match.js ├── index.js ├── parse.js ├── create.js └── valid.js ├── .travis.yml ├── LICENSE ├── CHANGES.md ├── .gitignore ├── package.json └── readme.md /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | test/specimens 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | coverage 3 | test 4 | .eslintignore 5 | .travis.yml 6 | .gitattributes 7 | .gitignore 8 | .publishrc 9 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES5" 5 | }, 6 | "exclude": [ 7 | "node_modules", 8 | "coverage" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /test/__snapshots__/issues-6.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Issues #6 quoted properties should be supported 1`] = `"m.vnode(\\"div\\",undefined,{\\"fooga\\":0},[],undefined,undefined);"`; 4 | -------------------------------------------------------------------------------- /.publishrc: -------------------------------------------------------------------------------- 1 | { 2 | "validations": { 3 | "vulnerableDependencies": true, 4 | "uncommittedChanges": true, 5 | "untrackedFiles": true, 6 | "sensitiveData": true, 7 | "branch": "rewrite", 8 | "gitTag": true 9 | }, 10 | "confirm": true, 11 | "prePublishScript": "npm test" 12 | } 13 | -------------------------------------------------------------------------------- /test/sourcemaps.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Source Maps", () => { 6 | it("should output an accurate source map", () => { 7 | expect( 8 | code(`m(".fooga")`, { sourceMaps : "inline" }) 9 | ) 10 | .toMatchSnapshot(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /test/issues-6.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Issues", () => { 6 | describe("#6 quoted properties", () => { 7 | it("should be supported", () => 8 | expect( 9 | code(`m("div", { "fooga" : 0 })`) 10 | ) 11 | .toMatchSnapshot() 12 | ); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/__snapshots__/svg.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`SVG should support nested svg selectors 1`] = `"m.vnode(\\"svg\\",undefined,undefined,[m.vnode(\\"g\\",undefined,undefined,[],undefined,undefined)],undefined,undefined);"`; 4 | 5 | exports[`SVG should support svg selectors 1`] = `"m.vnode(\\"svg\\",undefined,undefined,[],undefined,undefined);"`; 6 | -------------------------------------------------------------------------------- /test/__snapshots__/children-json.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Children JSON.prototype children should know that JSON.stringify is safe 1`] = `"m.vnode(\\"div\\",undefined,undefined,undefined,JSON.stringify({}),undefined);"`; 4 | 5 | exports[`Children JSON.prototype children shouldn't transform JSON.parse since it may not be safe 1`] = `"m(\\"div\\",JSON.parse({}));"`; 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /test/svg.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("SVG", () => { 6 | it("should support svg selectors", () => 7 | expect( 8 | code(`m("svg")`) 9 | ) 10 | .toMatchSnapshot() 11 | ); 12 | 13 | it("should support nested svg selectors", () => 14 | expect( 15 | code(`m("svg", m("g"))`) 16 | ) 17 | .toMatchSnapshot() 18 | ); 19 | }); 20 | -------------------------------------------------------------------------------- /test/__snapshots__/sourcemaps.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Source Maps should output an accurate source map 1`] = ` 4 | "m.vnode(\\"div\\",undefined,{className:\\"fooga\\"},[],undefined,undefined); 5 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInVua25vd24iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEiLCJmaWxlIjoidW5rbm93biIsInNvdXJjZXNDb250ZW50IjpbIm0oXCIuZm9vZ2FcIikiXX0=" 6 | `; 7 | -------------------------------------------------------------------------------- /test/__snapshots__/issues-35.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Issues #35 hyphenated attributes should be supported as an attribute 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"fooga\\",\\"wooga-booga\\":1},[],undefined,undefined);"`; 4 | 5 | exports[`Issues #35 hyphenated attributes should be supported in the selector 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"fooga\\",\\"wooga-booga\\":\\"1\\"},[],undefined,undefined);"`; 6 | -------------------------------------------------------------------------------- /test/lib/code.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var babel = require("babel-core"), 4 | 5 | plugin = require("../../"); 6 | 7 | module.exports = function(source, options) { 8 | var result = babel.transform(source, Object.assign({ 9 | compact : true, 10 | plugins : [ 11 | plugin 12 | ], 13 | generatorOpts : { 14 | quotes : "double" 15 | } 16 | }, options || {})); 17 | 18 | return result.code; 19 | }; 20 | -------------------------------------------------------------------------------- /test/__snapshots__/children-string-prototype.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Children String.prototype method children should support String.prototype methods using array notation 1`] = `"m.vnode(\\"div\\",undefined,undefined,undefined,\\"fooga\\"[\\"replace\\"](\\"f\\",\\"g\\"),undefined);"`; 4 | 5 | exports[`Children String.prototype method children should support String.prototype methods using dot notation 1`] = `"m.vnode(\\"div\\",undefined,undefined,undefined,\\"fooga\\".replace(\\"f\\",\\"g\\"),undefined);"`; 6 | -------------------------------------------------------------------------------- /src/match.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var match = require("lodash.ismatchwith"); 4 | 5 | // Small wrapper around lodash to support function/regexp testing 6 | module.exports = (target, filter) => 7 | match(target, filter, (val, test) => { 8 | // Support function comparisons 9 | if(typeof test === "function") { 10 | return test(val); 11 | } 12 | 13 | // Support RegExp comparisons 14 | if(test instanceof RegExp) { 15 | return test.test(val); 16 | } 17 | 18 | // Use default comparison 19 | return undefined; 20 | }); 21 | -------------------------------------------------------------------------------- /test/children-mixed.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Children", () => { 6 | describe("Mixed Children", () => { 7 | it("should support mixed array and literal children", () => 8 | expect( 9 | code(`m("0", [ 1 ], 2)`) 10 | ) 11 | .toMatchSnapshot() 12 | ); 13 | 14 | it("should support multiple arrays of children", () => 15 | expect( 16 | code(`m("0", [ 1 ], [ 2 ], [ 3 ])`) 17 | ) 18 | .toMatchSnapshot() 19 | ); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/issues-35.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Issues", () => { 6 | describe("#35 hyphenated attributes", () => { 7 | it("should be supported in the selector", () => 8 | expect( 9 | code(`m(".fooga[wooga-booga=1]")`) 10 | ) 11 | .toMatchSnapshot() 12 | ); 13 | 14 | it("should be supported as an attribute", () => 15 | expect( 16 | code(`m(".fooga", { "wooga-booga" : 1 })`) 17 | ) 18 | .toMatchSnapshot() 19 | ); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/children-json.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Children", () => { 6 | describe("JSON.prototype children", () => { 7 | it("should know that JSON.stringify is safe", () => 8 | expect( 9 | code(`m("div", JSON.stringify({}))`) 10 | ) 11 | .toMatchSnapshot() 12 | ); 13 | 14 | it("shouldn't transform JSON.parse since it may not be safe", () => 15 | expect( 16 | code(`m("div", JSON.parse({}))`) 17 | ) 18 | .toMatchSnapshot() 19 | ); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/__snapshots__/attributes-key.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Attributes key should extract the key attribute (boolean) 1`] = `"m.vnode(\\"div\\",true,undefined,[],undefined,undefined);"`; 4 | 5 | exports[`Attributes key should extract the key attribute (identifier) 1`] = `"m.vnode(\\"div\\",fooga,undefined,[],undefined,undefined);"`; 6 | 7 | exports[`Attributes key should extract the key attribute (number) 1`] = `"m.vnode(\\"div\\",1,undefined,[],undefined,undefined);"`; 8 | 9 | exports[`Attributes key should extract the key attribute (string) 1`] = `"m.vnode(\\"div\\",\\"1\\",undefined,[],undefined,undefined);"`; 10 | -------------------------------------------------------------------------------- /test/children-string-prototype.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Children", () => { 6 | describe("String.prototype method children", () => { 7 | it("should support String.prototype methods using dot notation", () => 8 | expect( 9 | code(`m("div", "fooga".replace("f", "g"))`) 10 | ) 11 | .toMatchSnapshot() 12 | ); 13 | 14 | it("should support String.prototype methods using array notation", () => 15 | expect( 16 | code(`m("div", "fooga"["replace"]("f", "g"))`) 17 | ) 18 | .toMatchSnapshot() 19 | ); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/__snapshots__/children-mixed.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Children Mixed Children should support mixed array and literal children 1`] = `"m.vnode(\\"0\\",undefined,undefined,[m.vnode(\\"[\\",undefined,undefined,[m.vnode(\\"#\\",undefined,undefined,1,undefined,undefined)],undefined,undefined),m.vnode(\\"#\\",undefined,undefined,2,undefined,undefined)],undefined,undefined);"`; 4 | 5 | exports[`Children Mixed Children should support multiple arrays of children 1`] = `"m.vnode(\\"0\\",undefined,undefined,[m.vnode(\\"[\\",undefined,undefined,[m.vnode(\\"#\\",undefined,undefined,1,undefined,undefined)],undefined,undefined),m.vnode(\\"[\\",undefined,undefined,[m.vnode(\\"#\\",undefined,undefined,2,undefined,undefined)],undefined,undefined),m.vnode(\\"[\\",undefined,undefined,[m.vnode(\\"#\\",undefined,undefined,3,undefined,undefined)],undefined,undefined)],undefined,undefined);"`; 6 | -------------------------------------------------------------------------------- /test/__snapshots__/children-ternary.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Children Ternary expressions should convert nested ternaries when all entries are literals (strings) 1`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,foo?\\"1\\":bar?\\"2\\":\\"3\\",undefined);"`; 4 | 5 | exports[`Children Ternary expressions should convert when all entries are literals (string : number) 1`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,foo?\\"1\\":2,undefined);"`; 6 | 7 | exports[`Children Ternary expressions should convert when all entries are literals (strings) 1`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,foo?\\"1\\":\\"2\\",undefined);"`; 8 | 9 | exports[`Children Ternary expressions should not convert when entries are not literals 1`] = `"m(\\"0\\",foo?bar:\\"baz\\");"`; 10 | 11 | exports[`Children Ternary expressions should not convert when entries are not literals 2`] = `"m(\\"0\\",foo?{class:options.class}:null);"`; 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | 4 | node_js: 5 | - node 6 | - '6' 7 | - '4' 8 | 9 | cache: 10 | directories: 11 | - node_modules 12 | 13 | deploy: 14 | provider: npm 15 | email: npm@patcavit.com 16 | api_key: 17 | secure: XW08FMLCBaNHMcTVs9khQbibyWs+XNUOXvk59MHoByxYEd4gqbTX21pODN33kgaPom0oNFNmCz5vppxOZfLTL9h74Z1LpQzHni8zwhuOOhbvSzZ4UJdIZFOw4qIqE0/WWbNQvK1wFI7gLtajiHZH8Ey1vfHLj8DHu4ZAGb+P0VPOqFWYvdMeKXShCXyH4GAjkC3fy9comqfcoRhCrRWtrivEaAkVrWqRmMWQwbr98uanrJ4n/HYy5gSUUEyEr8Qc2xYjsCgm2g7FWvCgybwoL1fEciKL2DAs8Fp9+ui/aDaT6E0i981W1OtRGpmgaKDE4Hw92YaMnIZOIOHsV/91gxJZ57YLOlGTt7wJfh+0TfoSfgxokXSSB2bSAISWHW//DsdI379tDK1ngwvsa72wGtbqXTtOr7+UaxqLu+B1c4ijniDtb8BsySW5tMojzBvU/9H03na3g4x99cjmO5xCE+Cr1GhFw/ZVET/phCGMTYHcVZGZvd96WFhsf+OgLtwplDDQEkI6mUDT1EJJYawTxSu4emhh+ddd8hK+Izj6Zb/wyk3EHEFisoNqqV2sezHuW9zJTtwaDbXrOOiG8/Uq8heUzh4O4BGWDP7udSDT/TugGXRt56QPVRMK85jJZ6KzO3+Q2Km3Q9JHBgggpW6VFU9dI7eyCQcplhouDMI+S+Y= 18 | on: 19 | tags: true 20 | repo: MithrilJS/mopt 21 | branch: master 22 | node: 'node' 23 | -------------------------------------------------------------------------------- /test/attributes-key.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Attributes", () => { 6 | describe("key", () => { 7 | it("should extract the key attribute (number)", () => 8 | expect( 9 | code(`m("div", { key : 1 })`) 10 | ) 11 | .toMatchSnapshot() 12 | ); 13 | 14 | it("should extract the key attribute (string)", () => 15 | expect( 16 | code(`m("div", { key : "1" })`) 17 | ) 18 | .toMatchSnapshot() 19 | ); 20 | 21 | it("should extract the key attribute (boolean)", () => 22 | expect( 23 | code(`m("div", { key : true })`) 24 | ) 25 | .toMatchSnapshot() 26 | ); 27 | 28 | it("should extract the key attribute (identifier)", () => 29 | expect( 30 | code(`m("div", { key : fooga })`) 31 | ) 32 | .toMatchSnapshot() 33 | ); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/__snapshots__/children-expressions.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Children Expression children should convert expressions containing more than 2 values 1`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,\\"1\\"+\\"2\\"+\\"3\\",undefined);"`; 4 | 5 | exports[`Children Expression children should convert expressions with operators other than + 1`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,1-2,undefined);"`; 6 | 7 | exports[`Children Expression children should not convert non-literal values 1`] = `"m(\\"0\\",a+b);"`; 8 | 9 | exports[`Children Expression children should support expressions with literal values (numbers) 1`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,1+2,undefined);"`; 10 | 11 | exports[`Children Expression children should support expressions with literal values (strings + numbers) 1`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,1+\\"2\\",undefined);"`; 12 | 13 | exports[`Children Expression children should support expressions with literal values (strings) 1`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,\\"1\\"+\\"2\\",undefined);"`; 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Pat Cavit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/children-ternary.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Children", () => { 6 | describe("Ternary expressions", () => { 7 | it("should convert when all entries are literals (strings)", () => 8 | expect( 9 | code(`m("0", foo ? "1" : "2")`) 10 | ) 11 | .toMatchSnapshot() 12 | ); 13 | 14 | it("should convert when all entries are literals (string : number)", () => 15 | expect( 16 | code(`m("0", foo ? "1" : 2)`) 17 | ) 18 | .toMatchSnapshot() 19 | ); 20 | 21 | it("should convert nested ternaries when all entries are literals (strings)", () => 22 | expect( 23 | code(`m("0", foo ? "1" : bar ? "2" : "3")`) 24 | ) 25 | .toMatchSnapshot() 26 | ); 27 | 28 | it("should not convert when entries are not literals", () => { 29 | // Can't convert this, dunno what `bar` is 30 | expect( 31 | code(`m("0", foo ? bar : "baz")`) 32 | ) 33 | .toMatchSnapshot(); 34 | 35 | // Not a text child, so can't safely optimize 36 | expect( 37 | code(`m("0", foo ? { class : options.class } : null)`) 38 | ) 39 | .toMatchSnapshot(); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /test/__snapshots__/selectors-literal.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Selectors Literal selectors should ignore non-string selectors 1`] = `"m(fooga);"`; 4 | 5 | exports[`Selectors Literal selectors should support attribute selectors 1`] = `"m.vnode(\\"div\\",undefined,{title:\\"bar\\"},[],undefined,undefined);"`; 6 | 7 | exports[`Selectors Literal selectors should support class selectors 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"foo\\"},[],undefined,undefined);"`; 8 | 9 | exports[`Selectors Literal selectors should support double-quoted attribute selectors 1`] = `"m.vnode(\\"div\\",undefined,{title:\\"bar\\"},[],undefined,undefined);"`; 10 | 11 | exports[`Selectors Literal selectors should support empty attribute selectors 1`] = `"m.vnode(\\"div\\",undefined,{fooga:true},[],undefined,undefined);"`; 12 | 13 | exports[`Selectors Literal selectors should support id selectors 1`] = `"m.vnode(\\"div\\",undefined,{id:\\"foo\\"},[],undefined,undefined);"`; 14 | 15 | exports[`Selectors Literal selectors should support single-quoted attribute selectors 1`] = `"m.vnode(\\"div\\",undefined,{title:\\"bar\\"},[],undefined,undefined);"`; 16 | 17 | exports[`Selectors Literal selectors should support tag selectors 1`] = `"m.vnode(\\"div\\",undefined,undefined,[],undefined,undefined);"`; 18 | 19 | exports[`Selectors Literal selectors should support the empty selector 1`] = `"m.vnode(\\"div\\",undefined,undefined,[],undefined,undefined);"`; 20 | -------------------------------------------------------------------------------- /test/children-expressions.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Children", () => { 6 | describe("Expression children", () => { 7 | it("should support expressions with literal values (strings)", () => 8 | expect( 9 | code(`m("0", "1" + "2")`) 10 | ) 11 | .toMatchSnapshot() 12 | ); 13 | 14 | it("should support expressions with literal values (numbers)", () => 15 | expect( 16 | code(`m("0", 1 + 2)`) 17 | ) 18 | .toMatchSnapshot() 19 | ); 20 | 21 | it("should support expressions with literal values (strings + numbers)", () => 22 | expect( 23 | code(`m("0", 1 + "2")`) 24 | ) 25 | .toMatchSnapshot() 26 | ); 27 | 28 | it("should convert expressions containing more than 2 values", () => 29 | expect( 30 | code(`m("0", "1" + "2" + "3")`) 31 | ) 32 | .toMatchSnapshot() 33 | ); 34 | 35 | it("should convert expressions with operators other than +", () => 36 | expect( 37 | code(`m("0", 1 - 2)`) 38 | ) 39 | .toMatchSnapshot() 40 | ); 41 | 42 | it("should not convert non-literal values", () => 43 | expect( 44 | code(`m("0", a + b)`) 45 | ) 46 | .toMatchSnapshot() 47 | ); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # Changes 2 | 3 | ## 5.1.1 4 | 5 | - chore: fix deployment process 6 | 7 | ## 5.1.0 8 | 9 | - refactor: template literal support cleaned up 10 | 11 | ## 5.0.2 12 | 13 | - fix: non-string class/className attributes (#58) 14 | 15 | ## 5.0.1 16 | 17 | - docs: readme formatting and some badge fixups 18 | 19 | ## 5.0.0 20 | 21 | - build: new repo location! 22 | - docs: clean up version confusion 23 | 24 | ## 4.3.1 25 | 26 | - Working through some release weirdness, AGAIN. Still sorry about the noise. 27 | 28 | ## 4.3.0 29 | 30 | - feat: improve source map accuracy 31 | - fix: Properly transform array children 32 | - feat: Support binary expression children 33 | - feat: optimize template literals 34 | - feat: Optimize simple ternaries 35 | - feat: optimize JSON.stringify 36 | - feat: optimize some String.prototype methods 37 | 38 | ## 4.2.0 39 | 40 | - Generate correct fragment nodes and optimize `m.trust()` into it's low-level `m.vnode()` representation 41 | 42 | ## 4.1.4 43 | 44 | - Fix up some bad handling of array children 45 | 46 | ## 4.1.3 47 | 48 | - Working through some release weirdness, sorry for the noise. 49 | 50 | ## 4.1.2 51 | 52 | - Clean up CHANGES.md 53 | 54 | ## 4.1.1 55 | 56 | - Testing release process 57 | 58 | ## 4.1.0 59 | 60 | - Handle key attributes 61 | 62 | ## 4.0.7 63 | 64 | - More accurate examples in the readme 65 | 66 | ## 4.0.6 67 | 68 | - Fix bad release config 69 | 70 | ## 4.0.5 71 | 72 | - Starting over, this is a test release :construction: :warning: :zap: :skull: 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # VScode 2 | .vscode 3 | 4 | # Logs 5 | logs 6 | *.log 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # Commenting this out is preferred by some people, see 27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 28 | node_modules 29 | 30 | # Users Environment Variables 31 | .lock-wscript 32 | 33 | # ========================= 34 | # Operating System Files 35 | # ========================= 36 | 37 | # OSX 38 | # ========================= 39 | 40 | .DS_Store 41 | .AppleDouble 42 | .LSOverride 43 | 44 | # Thumbnails 45 | ._* 46 | 47 | # Files that might appear on external disk 48 | .Spotlight-V100 49 | .Trashes 50 | 51 | # Directories potentially created on remote AFP share 52 | .AppleDB 53 | .AppleDesktop 54 | Network Trash Folder 55 | Temporary Items 56 | .apdisk 57 | 58 | # Windows 59 | # ========================= 60 | 61 | # Windows image file caches 62 | Thumbs.db 63 | ehthumbs.db 64 | 65 | # Folder config file 66 | Desktop.ini 67 | 68 | # Recycle Bin used on file shares 69 | $RECYCLE.BIN/ 70 | 71 | # Windows Installer files 72 | *.cab 73 | *.msi 74 | *.msm 75 | *.msp 76 | 77 | # Windows shortcuts 78 | *.lnk 79 | -------------------------------------------------------------------------------- /test/__snapshots__/children-literal.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Children literal children should not transform invocations containing identifiers 1`] = `"m(\\".fooga\\",identifier);"`; 4 | 5 | exports[`Children literal children should support attrs + multiple children 1`] = `"m.vnode(\\"1\\",undefined,{title:\\"bar\\"},[m.vnode(\\"#\\",undefined,undefined,\\"2\\",undefined,undefined),m.vnode(\\"#\\",undefined,undefined,\\"3\\",undefined,undefined)],undefined,undefined);"`; 6 | 7 | exports[`Children literal children should support attrs + single literal children children 1`] = `"m.vnode(\\"1\\",undefined,{title:\\"bar\\"},undefined,\\"2\\",undefined);"`; 8 | 9 | exports[`Children literal children should support multiple literal children 1`] = `"m.vnode(\\"1\\",undefined,undefined,[m.vnode(\\"#\\",undefined,undefined,\\"2\\",undefined,undefined),m.vnode(\\"#\\",undefined,undefined,\\"3\\",undefined,undefined)],undefined,undefined);"`; 10 | 11 | exports[`Children literal children should support single literal children (boolean) 1`] = `"m.vnode(\\"1\\",undefined,undefined,undefined,true,undefined);"`; 12 | 13 | exports[`Children literal children should support single literal children (number) 1`] = `"m.vnode(\\"1\\",undefined,undefined,undefined,2,undefined);"`; 14 | 15 | exports[`Children literal children should support single literal children (string) 1`] = `"m.vnode(\\"1\\",undefined,undefined,undefined,\\"2\\",undefined);"`; 16 | 17 | exports[`Children literal children should support single literal children (template) 1`] = `"m.vnode(\\"1\\",undefined,undefined,undefined,\`2\`,undefined);"`; 18 | -------------------------------------------------------------------------------- /test/selectors-literal.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Selectors", () => { 6 | describe("Literal selectors", () => { 7 | it("should support the empty selector", () => 8 | expect( 9 | code(`m("")`) 10 | ) 11 | .toMatchSnapshot() 12 | ); 13 | 14 | it("should support tag selectors", () => 15 | expect( 16 | code(`m("div")`) 17 | ) 18 | .toMatchSnapshot() 19 | ); 20 | 21 | it("should support class selectors", () => 22 | expect( 23 | code(`m(".foo")`) 24 | ) 25 | .toMatchSnapshot() 26 | ); 27 | 28 | it("should support id selectors", () => 29 | expect( 30 | code(`m("#foo")`) 31 | ) 32 | .toMatchSnapshot() 33 | ); 34 | 35 | it("should support empty attribute selectors", () => 36 | expect( 37 | code(`m("div[fooga]")`) 38 | ) 39 | .toMatchSnapshot() 40 | ); 41 | 42 | it("should support attribute selectors", () => 43 | expect( 44 | code(`m("[title=bar]")`) 45 | ) 46 | .toMatchSnapshot() 47 | ); 48 | 49 | it("should support single-quoted attribute selectors", () => 50 | expect( 51 | code(`m("[title='bar']")`) 52 | ) 53 | .toMatchSnapshot() 54 | ); 55 | 56 | it("should support double-quoted attribute selectors", () => 57 | expect( 58 | code(`m('[title="bar"]')`) 59 | ) 60 | .toMatchSnapshot() 61 | ); 62 | 63 | it("should ignore non-string selectors", () => 64 | expect( 65 | code(`m(fooga)`) 66 | ) 67 | .toMatchSnapshot() 68 | ); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /test/children-literal.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Children", () => { 6 | describe("literal children", () => { 7 | it("should support single literal children (string)", () => 8 | expect( 9 | code(`m("1", "2")`) 10 | ) 11 | .toMatchSnapshot() 12 | ); 13 | 14 | it("should support single literal children (number)", () => 15 | expect( 16 | code(`m("1", 2)`) 17 | ) 18 | .toMatchSnapshot() 19 | ); 20 | 21 | it("should support single literal children (boolean)", () => 22 | expect( 23 | code(`m("1", true)`) 24 | ) 25 | .toMatchSnapshot() 26 | ); 27 | 28 | it("should support single literal children (template)", () => 29 | expect( 30 | code(`m("1", \`2\`)`) 31 | ) 32 | .toMatchSnapshot() 33 | ); 34 | 35 | it("should support attrs + single literal children children", () => 36 | expect( 37 | code(`m("1", { title : "bar" }, "2")`) 38 | ) 39 | .toMatchSnapshot() 40 | ); 41 | 42 | it("should support multiple literal children", () => 43 | expect( 44 | code(`m("1", "2", "3")`) 45 | ) 46 | .toMatchSnapshot() 47 | ); 48 | 49 | it("should support attrs + multiple children", () => 50 | expect( 51 | code(`m("1", { title : "bar" }, "2", "3")`) 52 | ) 53 | .toMatchSnapshot() 54 | ); 55 | 56 | it("should not transform invocations containing identifiers", () => 57 | // Identifiers can't be resolved at compile time, so ignore 58 | expect( 59 | code(`m(".fooga", identifier)`) 60 | ) 61 | .toMatchSnapshot() 62 | ); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mopt", 3 | "version": "5.1.1", 4 | "description": "Babel plugin to statically optimize Mithril m() calls", 5 | "main": "./src/index.js", 6 | "author": "Pat Cavit ", 7 | "repository": "mithriljs/mopt", 8 | "license": "MIT", 9 | "keywords": [ 10 | "mithril", 11 | "optimization", 12 | "ast", 13 | "babel-plugin" 14 | ], 15 | "dependencies": { 16 | "lodash.ismatchwith": "^4.4.0", 17 | "lodash.partition": "^4.6.0" 18 | }, 19 | "devDependencies": { 20 | "@studio/changes": "^1.0.4", 21 | "babel-core": "^6.21.0", 22 | "eslint": "^3.12.2", 23 | "eslint-config-arenanet": "^3.1.0", 24 | "husky": "^0.13.2", 25 | "jest": "^20.0.4", 26 | "lint-staged": "^3.6.0", 27 | "mithril": "^1.1.1", 28 | "validate-commit-msg": "^2.8.2" 29 | }, 30 | "scripts": { 31 | "cover": "jest --coverage", 32 | "commitmsg": "validate-commit-msg", 33 | "lint": "eslint .", 34 | "release": "npm version -m \"v%s\"", 35 | "prepush": "npm test", 36 | "test": "jest", 37 | "posttest": "npm run lint", 38 | "preversion": "npm test", 39 | "version": "changes", 40 | "postversion": "git push --follow-tags" 41 | }, 42 | "config": { 43 | "validate-commit-msg": { 44 | "helpMessage": "\n-----------\n\nThere was a small validation problem with your commit message:\n\n> %s\nAn example valid commit message could be:\n\n> feat: Added a new feature\n> chore: Updated packge\n\nIf you really need to, you can skip the validation using\n\n> git commit --no-verify" 45 | } 46 | }, 47 | "eslintConfig": { 48 | "extends": "arenanet", 49 | "env": { 50 | "node": true, 51 | "jest": true 52 | }, 53 | "rules": { 54 | "indent": "off" 55 | } 56 | }, 57 | "jest": { 58 | "coveragePathIgnorePatterns": [ 59 | "node_modules", 60 | "test/lib" 61 | ] 62 | }, 63 | "lint-staged": { 64 | "*.js": [ 65 | "eslint --fix", 66 | "git add" 67 | ] 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /test/children-m.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Children", () => { 6 | describe("Nested m()", () => { 7 | it("should support nested m() invocations", () => 8 | expect( 9 | code(`m("0", m("1"))`) 10 | ) 11 | .toMatchSnapshot() 12 | ); 13 | 14 | it("should support an array with an m() invocation", () => 15 | expect( 16 | code(`m("0", [ m("1") ])`) 17 | ) 18 | .toMatchSnapshot() 19 | ); 20 | 21 | it("should support an array with m() invocations", () => 22 | expect( 23 | code(`m("0", [ m("1"), m("2") ])`) 24 | ) 25 | .toMatchSnapshot() 26 | ); 27 | 28 | it("should support arrays of nested m() invocations & plain nodes", () => 29 | expect( 30 | code(`m("one", [ m("two"), "three" ])`) 31 | ) 32 | .toMatchSnapshot() 33 | ); 34 | 35 | it("should support multiple nested m() invocations", () => 36 | expect( 37 | code(`m("0", m("1"), m("2"), m("3"))`) 38 | ) 39 | .toMatchSnapshot() 40 | ); 41 | 42 | it("should support attrs + nested m() invocations", () => 43 | expect( 44 | code(`m("0", { title : "bar" }, m("1"))`) 45 | ) 46 | .toMatchSnapshot() 47 | ); 48 | 49 | it("should supported attrs + arrays of nested m() invocations", () => 50 | expect( 51 | code(`m("0", { title : "bar" }, [ m("1") ])`) 52 | ) 53 | .toMatchSnapshot() 54 | ); 55 | 56 | it("should support attrs + multiple nested m() invocations", () => 57 | expect( 58 | code(`m("0", { title : "bar" }, m("1"), m("2"), m("3"))`) 59 | ) 60 | .toMatchSnapshot() 61 | ); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/__snapshots__/children-m.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Children Nested m() should support an array with an m() invocation 1`] = `"m.vnode(\\"0\\",undefined,undefined,[m.vnode(\\"1\\",undefined,undefined,[],undefined,undefined)],undefined,undefined);"`; 4 | 5 | exports[`Children Nested m() should support an array with m() invocations 1`] = `"m.vnode(\\"0\\",undefined,undefined,[m.vnode(\\"1\\",undefined,undefined,[],undefined,undefined),m.vnode(\\"2\\",undefined,undefined,[],undefined,undefined)],undefined,undefined);"`; 6 | 7 | exports[`Children Nested m() should support arrays of nested m() invocations & plain nodes 1`] = `"m.vnode(\\"one\\",undefined,undefined,[m.vnode(\\"two\\",undefined,undefined,[],undefined,undefined),m.vnode(\\"#\\",undefined,undefined,\\"three\\",undefined,undefined)],undefined,undefined);"`; 8 | 9 | exports[`Children Nested m() should support attrs + multiple nested m() invocations 1`] = `"m.vnode(\\"0\\",undefined,{title:\\"bar\\"},[m.vnode(\\"1\\",undefined,undefined,[],undefined,undefined),m.vnode(\\"2\\",undefined,undefined,[],undefined,undefined),m.vnode(\\"3\\",undefined,undefined,[],undefined,undefined)],undefined,undefined);"`; 10 | 11 | exports[`Children Nested m() should support attrs + nested m() invocations 1`] = `"m.vnode(\\"0\\",undefined,{title:\\"bar\\"},[m.vnode(\\"1\\",undefined,undefined,[],undefined,undefined)],undefined,undefined);"`; 12 | 13 | exports[`Children Nested m() should support multiple nested m() invocations 1`] = `"m.vnode(\\"0\\",undefined,undefined,[m.vnode(\\"1\\",undefined,undefined,[],undefined,undefined),m.vnode(\\"2\\",undefined,undefined,[],undefined,undefined),m.vnode(\\"3\\",undefined,undefined,[],undefined,undefined)],undefined,undefined);"`; 14 | 15 | exports[`Children Nested m() should support nested m() invocations 1`] = `"m.vnode(\\"0\\",undefined,undefined,[m.vnode(\\"1\\",undefined,undefined,[],undefined,undefined)],undefined,undefined);"`; 16 | 17 | exports[`Children Nested m() should supported attrs + arrays of nested m() invocations 1`] = `"m.vnode(\\"0\\",undefined,{title:\\"bar\\"},[m.vnode(\\"1\\",undefined,undefined,[],undefined,undefined)],undefined,undefined);"`; 18 | -------------------------------------------------------------------------------- /test/children-m.trust.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Children", () => { 6 | describe("Nested m.trust()", () => { 7 | it("should support nested m.trust() invocations", () => 8 | expect( 9 | code(`m("1", m.trust("1"))`) 10 | ) 11 | .toMatchSnapshot() 12 | ); 13 | 14 | it("should support a single-item array of nested m.trust() invocations", () => 15 | expect( 16 | code(`m("1", [ m.trust("2") ])`) 17 | ) 18 | .toMatchSnapshot() 19 | ); 20 | 21 | it("should support a multi-item array of nested m.trust() invocations", () => 22 | expect( 23 | code(`m("1", [ m.trust("2"), m.trust("3") ])`) 24 | ) 25 | .toMatchSnapshot() 26 | ); 27 | 28 | it("should support arrays of nested m.trust() invocations & plain nodes", () => 29 | expect( 30 | code(`m("1", [ m("2"), "3" ])`) 31 | ) 32 | .toMatchSnapshot() 33 | ); 34 | 35 | it("should support multiple nested m.trust() invocations", () => 36 | expect( 37 | code(`m("1", m.trust("2"), m.trust("3"), m.trust("4"))`) 38 | ) 39 | .toMatchSnapshot() 40 | ); 41 | 42 | it("should support attrs + nested m.trust() invocations", () => 43 | expect( 44 | code(`m("1", { title : "bar" }, m.trust("2"))`) 45 | ) 46 | .toMatchSnapshot() 47 | ); 48 | 49 | it("should supported attrs + arrays of nested m.trust() invocations", () => 50 | expect( 51 | code(`m("1", { title : "bar" }, [ m.trust("2") ])`) 52 | ) 53 | .toMatchSnapshot() 54 | ); 55 | 56 | it("should support attrs + multiple nested m.trust() invocations", () => 57 | expect( 58 | code(`m("1", { title : "bar" }, m.trust("2"), m.trust("3"), m.trust("4"))`) 59 | ) 60 | .toMatchSnapshot() 61 | ); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | mopt [![NPM Version](https://img.shields.io/npm/v/mopt.svg)](https://www.npmjs.com/package/mopt) [![NPM License](https://img.shields.io/npm/l/mopt.svg)](https://www.npmjs.com/package/mopt) 2 | ================= 3 | 4 |

5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |

18 | 19 | A [babel](babeljs.io) plugin to statically optimize [mithril](http://mithril.js.org) hyperscript function invocations. 20 | 21 | ```js 22 | // This hyperscript function invocation 23 | m(".fooga"); 24 | 25 | // Gets optimized into 26 | m.vnode("div",undefined,{className:"fooga"},undefined,undefined,undefined); 27 | ``` 28 | Please file an issue if you come across any cases that this doesn't handle, I'd love to improve the number of structures I can rewrite! 29 | 30 | ## Mithril Version Warning 31 | 32 | `mopt` **only** works with `mithril@1.x`. 33 | 34 | For optimizing `mithril@0.2.x` see [mithril-objectify](https://npmjs.com/mithril-objectify). 35 | 36 | ## Installation 37 | 38 | Install with npm 39 | 40 | `npm i mopt` 41 | 42 | ## Usage with Babel 43 | 44 | ### `.babelrc` 45 | 46 | ```js 47 | // .babelrc 48 | { 49 | "plugins": [ "mopt" ] 50 | } 51 | ``` 52 | 53 | ### CLI 54 | 55 | `$ babel --plugins mopt script.js` 56 | 57 | ### API 58 | 59 | ```js 60 | require("babel-core").transform("", { 61 | plugins: [ "mopt" ] 62 | }); 63 | ``` 64 | 65 | ## Usage with a bundler 66 | ### Rollup - [`rollup-plugin-babel`](https://www.npmjs.com/package/rollup-plugin-babel) 67 | ### Browserify - [`babelify`](https://www.npmjs.com/package/babelify) 68 | ### WebPack - [`babel-loader`](https://www.npmjs.com/package/babel-loader) 69 | -------------------------------------------------------------------------------- /test/__snapshots__/children-m.trust.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Children Nested m.trust() should support a multi-item array of nested m.trust() invocations 1`] = `"m.vnode(\\"1\\",undefined,undefined,[m.vnode(\\"<\\",undefined,undefined,\\"2\\",undefined,undefined),m.vnode(\\"<\\",undefined,undefined,\\"3\\",undefined,undefined)],undefined,undefined);"`; 4 | 5 | exports[`Children Nested m.trust() should support a single-item array of nested m.trust() invocations 1`] = `"m.vnode(\\"1\\",undefined,undefined,[m.vnode(\\"<\\",undefined,undefined,\\"2\\",undefined,undefined)],undefined,undefined);"`; 6 | 7 | exports[`Children Nested m.trust() should support arrays of nested m.trust() invocations & plain nodes 1`] = `"m.vnode(\\"1\\",undefined,undefined,[m.vnode(\\"2\\",undefined,undefined,[],undefined,undefined),m.vnode(\\"#\\",undefined,undefined,\\"3\\",undefined,undefined)],undefined,undefined);"`; 8 | 9 | exports[`Children Nested m.trust() should support attrs + multiple nested m.trust() invocations 1`] = `"m.vnode(\\"1\\",undefined,{title:\\"bar\\"},[m.vnode(\\"<\\",undefined,undefined,\\"2\\",undefined,undefined),m.vnode(\\"<\\",undefined,undefined,\\"3\\",undefined,undefined),m.vnode(\\"<\\",undefined,undefined,\\"4\\",undefined,undefined)],undefined,undefined);"`; 10 | 11 | exports[`Children Nested m.trust() should support attrs + nested m.trust() invocations 1`] = `"m.vnode(\\"1\\",undefined,{title:\\"bar\\"},[m.vnode(\\"<\\",undefined,undefined,\\"2\\",undefined,undefined)],undefined,undefined);"`; 12 | 13 | exports[`Children Nested m.trust() should support multiple nested m.trust() invocations 1`] = `"m.vnode(\\"1\\",undefined,undefined,[m.vnode(\\"<\\",undefined,undefined,\\"2\\",undefined,undefined),m.vnode(\\"<\\",undefined,undefined,\\"3\\",undefined,undefined),m.vnode(\\"<\\",undefined,undefined,\\"4\\",undefined,undefined)],undefined,undefined);"`; 14 | 15 | exports[`Children Nested m.trust() should support nested m.trust() invocations 1`] = `"m.vnode(\\"1\\",undefined,undefined,[m.vnode(\\"<\\",undefined,undefined,\\"1\\",undefined,undefined)],undefined,undefined);"`; 16 | 17 | exports[`Children Nested m.trust() should supported attrs + arrays of nested m.trust() invocations 1`] = `"m.vnode(\\"1\\",undefined,{title:\\"bar\\"},[m.vnode(\\"<\\",undefined,undefined,\\"2\\",undefined,undefined)],undefined,undefined);"`; 18 | -------------------------------------------------------------------------------- /test/attributes-class-classname.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"), 4 | 5 | selectors = { 6 | tag : `"selector"`, 7 | class : `".selector"`, 8 | tmpl : `\`template\``, 9 | 10 | "class + attr" : `".selector[attr]"` 11 | }, 12 | 13 | classes = { 14 | missing : false, 15 | empty : `""`, 16 | value : `"class"`, 17 | tmpl : `\`class\`` 18 | }, 19 | 20 | classnames = { 21 | missing : false, 22 | empty : `""`, 23 | value : `"className"`, 24 | tmpl : `\`className\`` 25 | }, 26 | 27 | strings = { 28 | missing : false, 29 | value : `"inner"` 30 | }; 31 | 32 | describe("Attributes", () => { 33 | describe("class vs className", () => { 34 | var combinations = []; 35 | 36 | Object.keys(selectors).forEach((selectorval) => 37 | Object.keys(classes).forEach((classval) => 38 | Object.keys(classnames).forEach((classnameval) => 39 | Object.keys(strings).forEach((stringval) => { 40 | combinations.push({ 41 | name : `selector ${selectorval}, class ${classval}, className ${classnameval}, string ${stringval}`, 42 | selector : selectors[selectorval], 43 | class : classes[classval], 44 | classname : classnames[classnameval], 45 | string : strings[stringval] 46 | }); 47 | }) 48 | ) 49 | ) 50 | ); 51 | 52 | combinations.forEach((test) => { 53 | it(test.name, () => { 54 | var str = "", 55 | 56 | hasClass = typeof test.class === "string", 57 | hasClassName = typeof test.classname === "string", 58 | hasString = typeof test.string === "string"; 59 | 60 | str += `m(${test.selector}`; 61 | 62 | if(hasClass || hasClassName) { 63 | str += `, {`; 64 | 65 | if(hasClass) { 66 | str += `class: ${test.class}`; 67 | } 68 | 69 | if(hasClassName) { 70 | if(hasClass) { 71 | str += `, `; 72 | } 73 | 74 | str += `className: ${test.classname}`; 75 | } 76 | 77 | str += `}`; 78 | } 79 | 80 | if(hasString) { 81 | str += `, ${test.string}`; 82 | } 83 | 84 | str += `);`; 85 | 86 | expect(code(str)).toMatchSnapshot(); 87 | }); 88 | }); 89 | }); 90 | }); 91 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var partition = require("lodash.partition"), 4 | 5 | valid = require("./valid.js"), 6 | parse = require("./parse.js"), 7 | match = require("./match.js"), 8 | create = require("./create.js"); 9 | 10 | // Combine any selector class/classNames with anything defined in code 11 | function processAttrs(types, attrs, loc) { 12 | var props = partition(attrs, (prop) => 13 | match(prop, { 14 | key : { name : /^class$|^className$/ } 15 | }) 16 | ), 17 | 18 | strings = props[0].filter((prop) => 19 | valid.isStringish(prop.value) 20 | ); 21 | 22 | // All class/className props were strings, if they're all empty we can early-out 23 | if( 24 | strings.length && 25 | strings.length === props[0].length && 26 | strings.every((node) => valid.isString(node.value) && !node.value.value.length) 27 | ) { 28 | return props[1]; 29 | } 30 | 31 | // Some class/className props were strings 32 | if(strings.length) { 33 | props[1].unshift( 34 | create.prop( 35 | types, 36 | "className", 37 | create.stringify(types, props[0].map((prop) => prop.value), loc), 38 | loc 39 | ) 40 | ); 41 | 42 | return props[1]; 43 | } 44 | 45 | // Combine everything 46 | return attrs; 47 | } 48 | 49 | module.exports = function(babel) { 50 | var t = babel.types, 51 | undef = t.identifier("undefined"); 52 | 53 | return { 54 | visitor : { 55 | CallExpression(path) { 56 | var selector, args, parts, attrs; 57 | 58 | if(!valid.isMithril(path.node)) { 59 | return; 60 | } 61 | 62 | selector = parse.selector(t, path.node); 63 | args = parse.args(t, path.node); 64 | 65 | attrs = processAttrs(t, selector.attrs.concat(args.attrs), path.node.loc); 66 | 67 | // Find any `key` properties and extract them 68 | parts = partition(attrs, (attr) => match(attr, { 69 | key : { name : "key" } 70 | })); 71 | 72 | // Vnode(tag, key, attrs, children, text, dom) 73 | path.replaceWith( 74 | create.vnode( 75 | t, 76 | selector.tag, 77 | 78 | // Use the last key attribute found 79 | parts[0].length ? parts[0].pop().value : undef, 80 | 81 | // Create attributes object 82 | parts[1].length ? t.objectExpression(parts[1]) : undef, 83 | args.children || undef, 84 | args.text || undef, 85 | undef, 86 | path.node.loc 87 | ) 88 | ); 89 | } 90 | } 91 | }; 92 | }; 93 | -------------------------------------------------------------------------------- /test/__snapshots__/children-array.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Children Array Children should handle Array.prototype methods that return a string 1`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,[1,2].join(\\"\\"),undefined);"`; 4 | 5 | exports[`Children Array Children should handle Array.prototype methods that return a string 2`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,[1,2][\\"join\\"](\\"\\"),undefined);"`; 6 | 7 | exports[`Children Array Children should normalize non-text array children 1`] = `"m.vnode(\\"0\\",undefined,undefined,[m.vnode(\\"#\\",undefined,undefined,1,undefined,undefined),m.vnode.normalize(bar)],undefined,undefined);"`; 8 | 9 | exports[`Children Array Children should support array children w/ > 1 entry 1`] = `"m.vnode(\\"0\\",undefined,undefined,[m.vnode(\\"#\\",undefined,undefined,1,undefined,undefined),m.vnode(\\"#\\",undefined,undefined,2,undefined,undefined)],undefined,undefined);"`; 10 | 11 | exports[`Children Array Children should support array children w/ 1 entry 1`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,1,undefined);"`; 12 | 13 | exports[`Children Array Children should support array children w/ 1 entry 2`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,\\"1\\",undefined);"`; 14 | 15 | exports[`Children Array Children should support array children w/ 1 entry 3`] = `"m.vnode(\\"0\\",undefined,undefined,undefined,\`1\`,undefined);"`; 16 | 17 | exports[`Children Array Children should support attrs + array children w/ > 1 entry 1`] = `"m.vnode(\\"0\\",undefined,{title:\\"bar\\"},[m.vnode(\\"#\\",undefined,undefined,1,undefined,undefined),m.vnode(\\"#\\",undefined,undefined,2,undefined,undefined),m.vnode(\\"#\\",undefined,undefined,3,undefined,undefined)],undefined,undefined);"`; 18 | 19 | exports[`Children Array Children should support attrs + array children w/ 1 entry 1`] = `"m.vnode(\\"0\\",undefined,{title:\\"bar\\"},undefined,1,undefined);"`; 20 | 21 | exports[`Children Array Children should support wrapping Array.prototype children when there are multiple children 1`] = `"m.vnode(\\"0\\",undefined,undefined,[m.vnode(\\"[\\",undefined,undefined,[m.vnode(\\"#\\",undefined,undefined,1,undefined,undefined)],undefined,undefined),m.vnode.normalize([2].map(function(val){return val;}))],undefined,undefined);"`; 22 | 23 | exports[`Children Array Children should wrap Array.prototype children that return an array in m.vnode.normalizeChildren 1`] = `"m.vnode(\\"0\\",undefined,undefined,m.vnode.normalizeChildren([1,2].map(function(val){return val;})),undefined,undefined);"`; 24 | 25 | exports[`Children Array Children should wrap Array.prototype children that return an array in m.vnode.normalizeChildren 2`] = `"m.vnode(\\"0\\",undefined,undefined,m.vnode.normalizeChildren([1,2].filter(function(val){return val===1;})),undefined,undefined);"`; 26 | 27 | exports[`Children Array Children shouldn't convert when there are Array.prototype children that do not return an array 1`] = `"m(\\"0\\",[1,2].forEach(function(val){return val===1;}));"`; 28 | 29 | exports[`Children Array Children shouldn't convert when there are Array.prototype children that do not return an array 2`] = `"m(\\"0\\",[1,2].some(function(val){return val===1;}));"`; 30 | 31 | exports[`Children Array Children shouldn't convert when there are Array.prototype children with a non-array object 1`] = `"m(\\"0\\",a.map(function(val){return val;}));"`; 32 | -------------------------------------------------------------------------------- /test/children-array.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var code = require("./lib/code"); 4 | 5 | describe("Children", () => { 6 | describe("Array Children", () => { 7 | it("should support array children w/ 1 entry", () => { 8 | expect( 9 | code(`m("0", [ 1 ])`) 10 | ) 11 | .toMatchSnapshot(); 12 | 13 | expect( 14 | code(`m("0", [ "1" ])`) 15 | ) 16 | .toMatchSnapshot(); 17 | 18 | expect( 19 | code(`m("0", [ \`1\` ])`) 20 | ) 21 | .toMatchSnapshot(); 22 | }); 23 | 24 | it("should support attrs + array children w/ 1 entry", () => 25 | expect( 26 | code(`m("0", { title : "bar" }, [ 1 ])`) 27 | ) 28 | .toMatchSnapshot() 29 | ); 30 | 31 | it("should support array children w/ > 1 entry", () => 32 | expect( 33 | code(`m("0", [ 1, 2 ])`) 34 | ) 35 | .toMatchSnapshot() 36 | ); 37 | 38 | it("should support attrs + array children w/ > 1 entry", () => 39 | expect( 40 | code(`m("0", { title : "bar" }, [ 1, 2, 3 ])`) 41 | ) 42 | .toMatchSnapshot() 43 | ); 44 | 45 | it("should normalize non-text array children", () => 46 | expect( 47 | code(`m("0", [ 1, bar ])`) 48 | ) 49 | .toMatchSnapshot() 50 | ); 51 | 52 | it("should wrap Array.prototype children that return an array in m.vnode.normalizeChildren", () => { 53 | expect( 54 | code(`m("0", [ 1, 2 ].map(function(val) { return val; }))`) 55 | ) 56 | .toMatchSnapshot(); 57 | 58 | expect( 59 | code(`m("0", [ 1, 2 ].filter(function(val) { return val === 1; }))`) 60 | ) 61 | .toMatchSnapshot(); 62 | }); 63 | 64 | it("shouldn't convert when there are Array.prototype children that do not return an array", () => { 65 | expect( 66 | code(`m("0", [ 1, 2 ].forEach(function(val) { return val === 1 }))`) 67 | ) 68 | .toMatchSnapshot(); 69 | 70 | expect( 71 | code(`m("0", [ 1, 2 ].some(function(val) { return val === 1 }))`) 72 | ) 73 | .toMatchSnapshot(); 74 | }); 75 | 76 | it("shouldn't convert when there are Array.prototype children with a non-array object", () => 77 | expect( 78 | code(`m("0", a.map(function(val) { return val; }))`) 79 | ) 80 | .toMatchSnapshot() 81 | ); 82 | 83 | it("should support wrapping Array.prototype children when there are multiple children", () => 84 | expect( 85 | code(`m("0", [ 1 ], [ 2 ].map(function(val) { return val; }))`) 86 | ) 87 | .toMatchSnapshot() 88 | ); 89 | 90 | it("should handle Array.prototype methods that return a string", () => { 91 | expect( 92 | code(`m("0", [ 1, 2 ].join(""))`) 93 | ) 94 | .toMatchSnapshot(); 95 | 96 | // Yes this looks insane, but it's still valid 97 | expect( 98 | code(`m("0", [ 1, 2 ]["join"](""))`) 99 | ) 100 | .toMatchSnapshot(); 101 | }); 102 | }); 103 | }); 104 | -------------------------------------------------------------------------------- /src/parse.js: -------------------------------------------------------------------------------- 1 | var valid = require("./valid.js"), 2 | create = require("./create.js"), 3 | 4 | selectorRegex = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, 5 | attrRegex = /\[(.+?)(?:=("|'|)(.*?)\2)?\]/; 6 | 7 | exports.selector = (types, node) => { 8 | var src = node.arguments[0].value, 9 | css = [], 10 | out = { 11 | src, 12 | attrs : [], 13 | tag : "div" 14 | }; 15 | 16 | if(!src) { 17 | return out; 18 | } 19 | 20 | src.match(selectorRegex).forEach(function(part) { 21 | var lead = part.charAt(0), 22 | parts; 23 | 24 | if(lead === "#") { 25 | out.attrs.push( 26 | create.prop(types, "id", part.slice(1), node.arguments[0].loc) 27 | ); 28 | 29 | return; 30 | } 31 | 32 | if(lead === ".") { 33 | css.push(part.slice(1)); 34 | 35 | return; 36 | } 37 | 38 | if(lead === "[") { 39 | parts = part.match(attrRegex); 40 | 41 | out.attrs.push( 42 | create.prop(types, parts[1], parts[3] ? parts[3] : true, node.arguments[0].loc) 43 | ); 44 | 45 | return; 46 | } 47 | 48 | out.tag = part; 49 | }); 50 | 51 | if(css.length > 0) { 52 | out.attrs.push( 53 | create.prop(types, "className", css.join(" "), node.arguments[0].loc) 54 | ); 55 | } 56 | 57 | return out; 58 | }; 59 | 60 | function parseChildren(types, nodes) { 61 | return nodes.map((node) => { 62 | // optimize simple text nodes 63 | if(valid.isText(node)) { 64 | return create.textVnode(types, node, node.loc); 65 | } 66 | 67 | // optimize m.trust 68 | if(valid.isMTrust(node)) { 69 | return create.trustVnode(types, node, node.loc); 70 | } 71 | 72 | // Will be transformed later 73 | if(valid.isM(node)) { 74 | return node; 75 | } 76 | 77 | // Turn arrays into fragments 78 | if(types.isArrayExpression(node)) { 79 | return create.fragmentVnode( 80 | types, 81 | types.arrayExpression(parseChildren(types, node.elements)), 82 | node.loc 83 | ); 84 | } 85 | 86 | // Can't optimize, normalize at run time :( 87 | return create.normalize(types, node, node.loc); 88 | }); 89 | } 90 | 91 | // m("...", "...") 92 | // m("...", "...", "...") 93 | // m("...", {...}) 94 | // m("...", {...}, "...") 95 | // m("...", {...}, "...", ...) 96 | // m("...", [...]) 97 | // m("...", {...}, [...]) 98 | exports.args = (types, node) => { 99 | /* eslint max-statements:off */ 100 | var out = { 101 | attrs : [], 102 | text : null, 103 | children : null 104 | }, 105 | start = 1, 106 | children; 107 | 108 | if(valid.isAttributes(node.arguments[1])) { 109 | out.attrs = out.attrs.concat(node.arguments[1].properties); 110 | 111 | start = 2; 112 | } 113 | 114 | children = node.arguments.slice(start); 115 | 116 | // Special-cased for a single text node or an array with a single text node 117 | // m("...", 1) 118 | // m("...", "one") 119 | // m("...", true) 120 | // m("...", [ 1 ]) 121 | if(children.length === 1) { 122 | // m("...", "one") 123 | if(valid.isText(children[0])) { 124 | out.text = children[0]; 125 | 126 | return out; 127 | } 128 | 129 | // m("...", [ "one" ]) 130 | if(valid.isTextArray(children[0])) { 131 | out.text = children[0].elements[0]; 132 | 133 | return out; 134 | } 135 | 136 | // m("...", [ 1, m("..."), m.trust("...") ]) 137 | if(types.isArrayExpression(children[0])) { 138 | out.children = types.arrayExpression( 139 | parseChildren(types, children[0].elements) 140 | ); 141 | 142 | return out; 143 | } 144 | 145 | // TODO: needs to wrap array in m.vnode.normalizeChildren 146 | // m("...", [...].map(...)) 147 | // m("...", [...].filter(...)) 148 | if(valid.isArray(children[0])) { 149 | out.children = create.normalizeChildren(types, children[0], children[0].loc); 150 | 151 | return out; 152 | } 153 | } 154 | 155 | // m("...", ... ) 156 | out.children = types.arrayExpression( 157 | parseChildren(types, children) 158 | ); 159 | 160 | return out; 161 | }; 162 | -------------------------------------------------------------------------------- /src/create.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var valid = require("./valid.js"); 4 | 5 | function valnode(types, value) { 6 | return types.isNode(value) ? 7 | value : 8 | types.valueToNode(value); 9 | } 10 | 11 | function location(node, loc) { 12 | node.loc = loc; 13 | 14 | return node; 15 | } 16 | 17 | // Takes an array of nodes and returns string + nested binary expressions as needed 18 | exports.stringify = (types, nodes, loc) => 19 | nodes.reduce((prev, curr) => { 20 | // If prev is empty string it's ignored 21 | if(valid.isString(prev) && !prev.value.length) { 22 | return curr; 23 | } 24 | 25 | if(valid.isString(curr)) { 26 | // filter out empty strings 27 | if(!curr.value.length) { 28 | return prev; 29 | } 30 | 31 | // multiple strings can be simply concatted 32 | if(valid.isString(prev)) { 33 | prev.value += ` ${curr.value}`; 34 | 35 | return prev; 36 | } 37 | 38 | // appending to something, need to add space seperator 39 | curr.value = ` ${curr.value}`; 40 | 41 | return location( 42 | types.binaryExpression( 43 | "+", 44 | prev, 45 | curr 46 | ), 47 | loc 48 | ); 49 | } 50 | 51 | // If previous value is a string statically inject the necessary space 52 | if(valid.isString(prev)) { 53 | prev.value += " "; 54 | 55 | return location( 56 | types.binaryExpression( 57 | "+", 58 | prev, 59 | curr 60 | ), 61 | loc 62 | ); 63 | } 64 | 65 | // Non-string previous values need to explicitly add the space via concatenation 66 | // (assuming the current value isn't a string) 67 | return location( 68 | types.binaryExpression( 69 | "+", 70 | prev, 71 | types.binaryExpression( 72 | "+", 73 | types.stringLiteral(" "), 74 | curr 75 | ) 76 | ), 77 | loc 78 | ); 79 | }); 80 | 81 | exports.vnode = (types, tag, key, attrs, children, text, dom, loc) => 82 | /* eslint max-params: off */ 83 | location( 84 | types.callExpression( 85 | types.memberExpression( 86 | types.identifier("m"), 87 | types.identifier("vnode") 88 | ), 89 | [ 90 | // tag, key, attrs, children, text, dom 91 | types.stringLiteral(tag), 92 | key || types.identifier("undefined"), 93 | attrs || types.identifier("undefined"), 94 | children ? valnode(types, children) : types.identifier("undefined"), 95 | text || types.identifier("undefined"), 96 | dom || types.identifier("undefined") 97 | ] 98 | ), 99 | loc 100 | ); 101 | 102 | exports.prop = (types, key, value, loc) => 103 | location( 104 | types.objectProperty( 105 | types.isValidIdentifier(key) ? 106 | types.identifier(key) : 107 | types.stringLiteral(key), 108 | valnode(types, value) 109 | ), 110 | loc 111 | ); 112 | 113 | exports.normalize = (types, node, loc) => 114 | location( 115 | types.callExpression( 116 | types.memberExpression( 117 | types.memberExpression( 118 | types.identifier("m"), 119 | types.identifier("vnode") 120 | ), 121 | types.identifier("normalize") 122 | ), 123 | [ node ] 124 | ), 125 | loc 126 | ); 127 | 128 | exports.normalizeChildren = (types, node, loc) => 129 | location( 130 | types.callExpression( 131 | types.memberExpression( 132 | types.memberExpression( 133 | types.identifier("m"), 134 | types.identifier("vnode") 135 | ), 136 | types.identifier("normalizeChildren") 137 | ), 138 | [ node ] 139 | ), 140 | loc 141 | ); 142 | 143 | exports.textVnode = (types, value, loc) => 144 | exports.vnode(types, "#", null, null, value, null, null, loc); 145 | 146 | exports.trustVnode = (types, value, loc) => 147 | exports.vnode(types, "<", null, null, value.arguments[0], null, null, loc); 148 | 149 | exports.fragmentVnode = (types, value, loc) => 150 | exports.vnode(types, "[", null, null, value, null, null, loc); 151 | -------------------------------------------------------------------------------- /src/valid.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var match = require("./match.js"), 4 | 5 | stringToStringRegex = /charAt|charCodeAt|codePointAt|concat|fromCharCode|fromCodePoint|normalize|repeat|replace|slice|substr|substring|toLocaleLowerCase|toLocaleUpperCase|toLowerCase|toString|toUpperCase|trim|trimLeft|trimRight|valueOf/, 6 | arrayToArrayRegex = /concat|copyWithin|filter|map|reverse|slice|sort|splice/, 7 | arrayToStringRegex = /join/; 8 | 9 | exports.isString = (node) => 10 | // Simple string or template literal 11 | match(node, { 12 | type : "StringLiteral" 13 | }); 14 | 15 | exports.isStringish = (node) => 16 | // Simple string 17 | exports.isString( 18 | node 19 | ) || 20 | // template literal 21 | match(node, { 22 | type : "TemplateLiteral" 23 | }) || 24 | // String.prototype methods that return a string 25 | match(node, { 26 | type : "CallExpression", 27 | callee : { 28 | type : "MemberExpression", 29 | object : exports.isStringish, 30 | property : (prop) => stringToStringRegex.test(prop.name) || stringToStringRegex.test(prop.value) 31 | } 32 | }) || 33 | // JSON.stringify returns a string 34 | match(node, { 35 | type : "CallExpression", 36 | callee : { 37 | type : "MemberExpression", 38 | object : { name : "JSON" }, 39 | property : { name : "stringify" } 40 | } 41 | }) || 42 | // Array.prototype methods that return a string 43 | match(node, { 44 | type : "CallExpression", 45 | callee : { 46 | type : "MemberExpression", 47 | object : exports.isArray, 48 | property : (prop) => arrayToStringRegex.test(prop.name) || arrayToStringRegex.test(prop.value) 49 | } 50 | }) || 51 | // Conditionals via ternary logic 52 | match(node, { 53 | type : "ConditionalExpression", 54 | consequent : exports.isText, 55 | alternate : exports.isText 56 | }) || 57 | // String concatenation via plus signs 58 | match(node, { 59 | type : "BinaryExpression", 60 | left : exports.isText, 61 | right : exports.isText 62 | }); 63 | 64 | exports.isText = (node) => 65 | match(node, { 66 | type : /NumericLiteral|BooleanLiteral/ 67 | }) || 68 | exports.isStringish(node); 69 | 70 | exports.isTextArray = (node) => 71 | match(node, { 72 | type : "ArrayExpression", 73 | elements : (elements) => elements.length === 1 && exports.isText(elements[0]) 74 | }); 75 | 76 | // m(...) 77 | exports.isM = (node) => 78 | match(node, { 79 | type : "CallExpression", 80 | callee : { name : "m" } 81 | }); 82 | 83 | exports.isMVnode = (node) => 84 | match(node, { 85 | type : "CallExpression", 86 | callee : { 87 | type : "MemberExpression", 88 | object : { name : "m" }, 89 | property : { name : "vnode" } 90 | } 91 | }); 92 | 93 | exports.isMTrust = (node) => 94 | match(node, { 95 | type : "CallExpression", 96 | callee : { 97 | type : "MemberExpression", 98 | object : { name : "m" }, 99 | property : { name : "trust" } 100 | } 101 | }); 102 | 103 | exports.isArray = (node) => 104 | match(node, { type : "ArrayExpression" }) || 105 | match(node, { 106 | type : "CallExpression", 107 | callee : { 108 | type : "MemberExpression", 109 | object : exports.isArray, 110 | property : (prop) => arrayToArrayRegex.test(prop.name) || arrayToArrayRegex.test(prop.value) 111 | } 112 | }); 113 | 114 | // Is this a valid child node that we understand? 115 | exports.isChild = (node) => 116 | exports.isText(node) || 117 | exports.isTextArray(node) || 118 | exports.isM(node) || 119 | exports.isMVnode(node) || 120 | exports.isMTrust(node) || 121 | exports.isArray(node); 122 | 123 | // Are these valid children nodes that we understand? 124 | exports.isChildren = (nodes) => 125 | nodes.every(exports.isChild); 126 | 127 | // Is this node an attributes object? 128 | exports.isAttributes = (node) => 129 | match(node, { 130 | type : "ObjectExpression" 131 | }); 132 | 133 | // Is this node a mithril invocation? 134 | exports.isMithril = (node) => { 135 | var start = 1; 136 | 137 | // m(...) 138 | if(!exports.isM(node)) { 139 | return false; 140 | } 141 | 142 | // m("...") 143 | // Can't do anything more exciting here because it isn't parsable :( 144 | if(!match(node.arguments[0], { type : "StringLiteral" })) { 145 | return false; 146 | } 147 | 148 | // m("...") 149 | if(node.arguments.length === 1) { 150 | return true; 151 | } 152 | 153 | // m("...", {...} ) 154 | if(exports.isAttributes(node.arguments[1])) { 155 | start = 2; 156 | } 157 | 158 | // m("...", "...") 159 | // m("...", [...]) 160 | // m("...", {...}, "...") 161 | // m("...", {...}, [...]) 162 | // m("...", {...}, "...", ...) 163 | return exports.isChildren(node.arguments.slice(start)); 164 | }; 165 | -------------------------------------------------------------------------------- /test/__snapshots__/attributes-class-classname.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Attributes class vs className selector class + attr, class empty, className empty, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\",attr:true},[],undefined,undefined);"`; 4 | 5 | exports[`Attributes class vs className selector class + attr, class empty, className empty, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\",attr:true},undefined,\\"inner\\",undefined);"`; 6 | 7 | exports[`Attributes class vs className selector class + attr, class empty, className missing, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\",attr:true},[],undefined,undefined);"`; 8 | 9 | exports[`Attributes class vs className selector class + attr, class empty, className missing, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\",attr:true},undefined,\\"inner\\",undefined);"`; 10 | 11 | exports[`Attributes class vs className selector class + attr, class empty, className tmpl, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`className\`,attr:true},[],undefined,undefined);"`; 12 | 13 | exports[`Attributes class vs className selector class + attr, class empty, className tmpl, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`className\`,attr:true},undefined,\\"inner\\",undefined);"`; 14 | 15 | exports[`Attributes class vs className selector class + attr, class empty, className value, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector className\\",attr:true},[],undefined,undefined);"`; 16 | 17 | exports[`Attributes class vs className selector class + attr, class empty, className value, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector className\\",attr:true},undefined,\\"inner\\",undefined);"`; 18 | 19 | exports[`Attributes class vs className selector class + attr, class missing, className empty, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\",attr:true},[],undefined,undefined);"`; 20 | 21 | exports[`Attributes class vs className selector class + attr, class missing, className empty, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\",attr:true},undefined,\\"inner\\",undefined);"`; 22 | 23 | exports[`Attributes class vs className selector class + attr, class missing, className missing, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\",attr:true},[],undefined,undefined);"`; 24 | 25 | exports[`Attributes class vs className selector class + attr, class missing, className missing, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\",attr:true},undefined,\\"inner\\",undefined);"`; 26 | 27 | exports[`Attributes class vs className selector class + attr, class missing, className tmpl, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`className\`,attr:true},[],undefined,undefined);"`; 28 | 29 | exports[`Attributes class vs className selector class + attr, class missing, className tmpl, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`className\`,attr:true},undefined,\\"inner\\",undefined);"`; 30 | 31 | exports[`Attributes class vs className selector class + attr, class missing, className value, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector className\\",attr:true},[],undefined,undefined);"`; 32 | 33 | exports[`Attributes class vs className selector class + attr, class missing, className value, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector className\\",attr:true},undefined,\\"inner\\",undefined);"`; 34 | 35 | exports[`Attributes class vs className selector class + attr, class tmpl, className empty, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`,attr:true},[],undefined,undefined);"`; 36 | 37 | exports[`Attributes class vs className selector class + attr, class tmpl, className empty, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`,attr:true},undefined,\\"inner\\",undefined);"`; 38 | 39 | exports[`Attributes class vs className selector class + attr, class tmpl, className missing, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`,attr:true},[],undefined,undefined);"`; 40 | 41 | exports[`Attributes class vs className selector class + attr, class tmpl, className missing, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`,attr:true},undefined,\\"inner\\",undefined);"`; 42 | 43 | exports[`Attributes class vs className selector class + attr, class tmpl, className tmpl, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`+(\\" \\"+\`className\`),attr:true},[],undefined,undefined);"`; 44 | 45 | exports[`Attributes class vs className selector class + attr, class tmpl, className tmpl, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`+(\\" \\"+\`className\`),attr:true},undefined,\\"inner\\",undefined);"`; 46 | 47 | exports[`Attributes class vs className selector class + attr, class tmpl, className value, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`+\\" className\\",attr:true},[],undefined,undefined);"`; 48 | 49 | exports[`Attributes class vs className selector class + attr, class tmpl, className value, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`+\\" className\\",attr:true},undefined,\\"inner\\",undefined);"`; 50 | 51 | exports[`Attributes class vs className selector class + attr, class value, className empty, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class\\",attr:true},[],undefined,undefined);"`; 52 | 53 | exports[`Attributes class vs className selector class + attr, class value, className empty, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class\\",attr:true},undefined,\\"inner\\",undefined);"`; 54 | 55 | exports[`Attributes class vs className selector class + attr, class value, className missing, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class\\",attr:true},[],undefined,undefined);"`; 56 | 57 | exports[`Attributes class vs className selector class + attr, class value, className missing, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class\\",attr:true},undefined,\\"inner\\",undefined);"`; 58 | 59 | exports[`Attributes class vs className selector class + attr, class value, className tmpl, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class \\"+\`className\`,attr:true},[],undefined,undefined);"`; 60 | 61 | exports[`Attributes class vs className selector class + attr, class value, className tmpl, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class \\"+\`className\`,attr:true},undefined,\\"inner\\",undefined);"`; 62 | 63 | exports[`Attributes class vs className selector class + attr, class value, className value, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class className\\",attr:true},[],undefined,undefined);"`; 64 | 65 | exports[`Attributes class vs className selector class + attr, class value, className value, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class className\\",attr:true},undefined,\\"inner\\",undefined);"`; 66 | 67 | exports[`Attributes class vs className selector class, class empty, className empty, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\"},[],undefined,undefined);"`; 68 | 69 | exports[`Attributes class vs className selector class, class empty, className empty, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\"},undefined,\\"inner\\",undefined);"`; 70 | 71 | exports[`Attributes class vs className selector class, class empty, className missing, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\"},[],undefined,undefined);"`; 72 | 73 | exports[`Attributes class vs className selector class, class empty, className missing, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\"},undefined,\\"inner\\",undefined);"`; 74 | 75 | exports[`Attributes class vs className selector class, class empty, className tmpl, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`className\`},[],undefined,undefined);"`; 76 | 77 | exports[`Attributes class vs className selector class, class empty, className tmpl, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`className\`},undefined,\\"inner\\",undefined);"`; 78 | 79 | exports[`Attributes class vs className selector class, class empty, className value, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector className\\"},[],undefined,undefined);"`; 80 | 81 | exports[`Attributes class vs className selector class, class empty, className value, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector className\\"},undefined,\\"inner\\",undefined);"`; 82 | 83 | exports[`Attributes class vs className selector class, class missing, className empty, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\"},[],undefined,undefined);"`; 84 | 85 | exports[`Attributes class vs className selector class, class missing, className empty, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\"},undefined,\\"inner\\",undefined);"`; 86 | 87 | exports[`Attributes class vs className selector class, class missing, className missing, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\"},[],undefined,undefined);"`; 88 | 89 | exports[`Attributes class vs className selector class, class missing, className missing, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector\\"},undefined,\\"inner\\",undefined);"`; 90 | 91 | exports[`Attributes class vs className selector class, class missing, className tmpl, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`className\`},[],undefined,undefined);"`; 92 | 93 | exports[`Attributes class vs className selector class, class missing, className tmpl, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`className\`},undefined,\\"inner\\",undefined);"`; 94 | 95 | exports[`Attributes class vs className selector class, class missing, className value, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector className\\"},[],undefined,undefined);"`; 96 | 97 | exports[`Attributes class vs className selector class, class missing, className value, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector className\\"},undefined,\\"inner\\",undefined);"`; 98 | 99 | exports[`Attributes class vs className selector class, class tmpl, className empty, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`},[],undefined,undefined);"`; 100 | 101 | exports[`Attributes class vs className selector class, class tmpl, className empty, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`},undefined,\\"inner\\",undefined);"`; 102 | 103 | exports[`Attributes class vs className selector class, class tmpl, className missing, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`},[],undefined,undefined);"`; 104 | 105 | exports[`Attributes class vs className selector class, class tmpl, className missing, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`},undefined,\\"inner\\",undefined);"`; 106 | 107 | exports[`Attributes class vs className selector class, class tmpl, className tmpl, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`+(\\" \\"+\`className\`)},[],undefined,undefined);"`; 108 | 109 | exports[`Attributes class vs className selector class, class tmpl, className tmpl, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`+(\\" \\"+\`className\`)},undefined,\\"inner\\",undefined);"`; 110 | 111 | exports[`Attributes class vs className selector class, class tmpl, className value, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`+\\" className\\"},[],undefined,undefined);"`; 112 | 113 | exports[`Attributes class vs className selector class, class tmpl, className value, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector \\"+\`class\`+\\" className\\"},undefined,\\"inner\\",undefined);"`; 114 | 115 | exports[`Attributes class vs className selector class, class value, className empty, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class\\"},[],undefined,undefined);"`; 116 | 117 | exports[`Attributes class vs className selector class, class value, className empty, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class\\"},undefined,\\"inner\\",undefined);"`; 118 | 119 | exports[`Attributes class vs className selector class, class value, className missing, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class\\"},[],undefined,undefined);"`; 120 | 121 | exports[`Attributes class vs className selector class, class value, className missing, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class\\"},undefined,\\"inner\\",undefined);"`; 122 | 123 | exports[`Attributes class vs className selector class, class value, className tmpl, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class \\"+\`className\`},[],undefined,undefined);"`; 124 | 125 | exports[`Attributes class vs className selector class, class value, className tmpl, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class \\"+\`className\`},undefined,\\"inner\\",undefined);"`; 126 | 127 | exports[`Attributes class vs className selector class, class value, className value, string missing 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class className\\"},[],undefined,undefined);"`; 128 | 129 | exports[`Attributes class vs className selector class, class value, className value, string value 1`] = `"m.vnode(\\"div\\",undefined,{className:\\"selector class className\\"},undefined,\\"inner\\",undefined);"`; 130 | 131 | exports[`Attributes class vs className selector tag, class empty, className empty, string missing 1`] = `"m.vnode(\\"selector\\",undefined,undefined,[],undefined,undefined);"`; 132 | 133 | exports[`Attributes class vs className selector tag, class empty, className empty, string value 1`] = `"m.vnode(\\"selector\\",undefined,undefined,undefined,\\"inner\\",undefined);"`; 134 | 135 | exports[`Attributes class vs className selector tag, class empty, className missing, string missing 1`] = `"m.vnode(\\"selector\\",undefined,undefined,[],undefined,undefined);"`; 136 | 137 | exports[`Attributes class vs className selector tag, class empty, className missing, string value 1`] = `"m.vnode(\\"selector\\",undefined,undefined,undefined,\\"inner\\",undefined);"`; 138 | 139 | exports[`Attributes class vs className selector tag, class empty, className tmpl, string missing 1`] = `"m.vnode(\\"selector\\",undefined,{className:\`className\`},[],undefined,undefined);"`; 140 | 141 | exports[`Attributes class vs className selector tag, class empty, className tmpl, string value 1`] = `"m.vnode(\\"selector\\",undefined,{className:\`className\`},undefined,\\"inner\\",undefined);"`; 142 | 143 | exports[`Attributes class vs className selector tag, class empty, className value, string missing 1`] = `"m.vnode(\\"selector\\",undefined,{className:\\"className\\"},[],undefined,undefined);"`; 144 | 145 | exports[`Attributes class vs className selector tag, class empty, className value, string value 1`] = `"m.vnode(\\"selector\\",undefined,{className:\\"className\\"},undefined,\\"inner\\",undefined);"`; 146 | 147 | exports[`Attributes class vs className selector tag, class missing, className empty, string missing 1`] = `"m.vnode(\\"selector\\",undefined,undefined,[],undefined,undefined);"`; 148 | 149 | exports[`Attributes class vs className selector tag, class missing, className empty, string value 1`] = `"m.vnode(\\"selector\\",undefined,undefined,undefined,\\"inner\\",undefined);"`; 150 | 151 | exports[`Attributes class vs className selector tag, class missing, className missing, string missing 1`] = `"m.vnode(\\"selector\\",undefined,undefined,[],undefined,undefined);"`; 152 | 153 | exports[`Attributes class vs className selector tag, class missing, className missing, string value 1`] = `"m.vnode(\\"selector\\",undefined,undefined,undefined,\\"inner\\",undefined);"`; 154 | 155 | exports[`Attributes class vs className selector tag, class missing, className tmpl, string missing 1`] = `"m.vnode(\\"selector\\",undefined,{className:\`className\`},[],undefined,undefined);"`; 156 | 157 | exports[`Attributes class vs className selector tag, class missing, className tmpl, string value 1`] = `"m.vnode(\\"selector\\",undefined,{className:\`className\`},undefined,\\"inner\\",undefined);"`; 158 | 159 | exports[`Attributes class vs className selector tag, class missing, className value, string missing 1`] = `"m.vnode(\\"selector\\",undefined,{className:\\"className\\"},[],undefined,undefined);"`; 160 | 161 | exports[`Attributes class vs className selector tag, class missing, className value, string value 1`] = `"m.vnode(\\"selector\\",undefined,{className:\\"className\\"},undefined,\\"inner\\",undefined);"`; 162 | 163 | exports[`Attributes class vs className selector tag, class tmpl, className empty, string missing 1`] = `"m.vnode(\\"selector\\",undefined,{className:\`class\`},[],undefined,undefined);"`; 164 | 165 | exports[`Attributes class vs className selector tag, class tmpl, className empty, string value 1`] = `"m.vnode(\\"selector\\",undefined,{className:\`class\`},undefined,\\"inner\\",undefined);"`; 166 | 167 | exports[`Attributes class vs className selector tag, class tmpl, className missing, string missing 1`] = `"m.vnode(\\"selector\\",undefined,{className:\`class\`},[],undefined,undefined);"`; 168 | 169 | exports[`Attributes class vs className selector tag, class tmpl, className missing, string value 1`] = `"m.vnode(\\"selector\\",undefined,{className:\`class\`},undefined,\\"inner\\",undefined);"`; 170 | 171 | exports[`Attributes class vs className selector tag, class tmpl, className tmpl, string missing 1`] = `"m.vnode(\\"selector\\",undefined,{className:\`class\`+(\\" \\"+\`className\`)},[],undefined,undefined);"`; 172 | 173 | exports[`Attributes class vs className selector tag, class tmpl, className tmpl, string value 1`] = `"m.vnode(\\"selector\\",undefined,{className:\`class\`+(\\" \\"+\`className\`)},undefined,\\"inner\\",undefined);"`; 174 | 175 | exports[`Attributes class vs className selector tag, class tmpl, className value, string missing 1`] = `"m.vnode(\\"selector\\",undefined,{className:\`class\`+\\" className\\"},[],undefined,undefined);"`; 176 | 177 | exports[`Attributes class vs className selector tag, class tmpl, className value, string value 1`] = `"m.vnode(\\"selector\\",undefined,{className:\`class\`+\\" className\\"},undefined,\\"inner\\",undefined);"`; 178 | 179 | exports[`Attributes class vs className selector tag, class value, className empty, string missing 1`] = `"m.vnode(\\"selector\\",undefined,{className:\\"class\\"},[],undefined,undefined);"`; 180 | 181 | exports[`Attributes class vs className selector tag, class value, className empty, string value 1`] = `"m.vnode(\\"selector\\",undefined,{className:\\"class\\"},undefined,\\"inner\\",undefined);"`; 182 | 183 | exports[`Attributes class vs className selector tag, class value, className missing, string missing 1`] = `"m.vnode(\\"selector\\",undefined,{className:\\"class\\"},[],undefined,undefined);"`; 184 | 185 | exports[`Attributes class vs className selector tag, class value, className missing, string value 1`] = `"m.vnode(\\"selector\\",undefined,{className:\\"class\\"},undefined,\\"inner\\",undefined);"`; 186 | 187 | exports[`Attributes class vs className selector tag, class value, className tmpl, string missing 1`] = `"m.vnode(\\"selector\\",undefined,{className:\\"class \\"+\`className\`},[],undefined,undefined);"`; 188 | 189 | exports[`Attributes class vs className selector tag, class value, className tmpl, string value 1`] = `"m.vnode(\\"selector\\",undefined,{className:\\"class \\"+\`className\`},undefined,\\"inner\\",undefined);"`; 190 | 191 | exports[`Attributes class vs className selector tag, class value, className value, string missing 1`] = `"m.vnode(\\"selector\\",undefined,{className:\\"class className\\"},[],undefined,undefined);"`; 192 | 193 | exports[`Attributes class vs className selector tag, class value, className value, string value 1`] = `"m.vnode(\\"selector\\",undefined,{className:\\"class className\\"},undefined,\\"inner\\",undefined);"`; 194 | 195 | exports[`Attributes class vs className selector tmpl, class empty, className empty, string missing 1`] = `"m(\`template\`,{class:\\"\\",className:\\"\\"});"`; 196 | 197 | exports[`Attributes class vs className selector tmpl, class empty, className empty, string value 1`] = `"m(\`template\`,{class:\\"\\",className:\\"\\"},\\"inner\\");"`; 198 | 199 | exports[`Attributes class vs className selector tmpl, class empty, className missing, string missing 1`] = `"m(\`template\`,{class:\\"\\"});"`; 200 | 201 | exports[`Attributes class vs className selector tmpl, class empty, className missing, string value 1`] = `"m(\`template\`,{class:\\"\\"},\\"inner\\");"`; 202 | 203 | exports[`Attributes class vs className selector tmpl, class empty, className tmpl, string missing 1`] = `"m(\`template\`,{class:\\"\\",className:\`className\`});"`; 204 | 205 | exports[`Attributes class vs className selector tmpl, class empty, className tmpl, string value 1`] = `"m(\`template\`,{class:\\"\\",className:\`className\`},\\"inner\\");"`; 206 | 207 | exports[`Attributes class vs className selector tmpl, class empty, className value, string missing 1`] = `"m(\`template\`,{class:\\"\\",className:\\"className\\"});"`; 208 | 209 | exports[`Attributes class vs className selector tmpl, class empty, className value, string value 1`] = `"m(\`template\`,{class:\\"\\",className:\\"className\\"},\\"inner\\");"`; 210 | 211 | exports[`Attributes class vs className selector tmpl, class missing, className empty, string missing 1`] = `"m(\`template\`,{className:\\"\\"});"`; 212 | 213 | exports[`Attributes class vs className selector tmpl, class missing, className empty, string value 1`] = `"m(\`template\`,{className:\\"\\"},\\"inner\\");"`; 214 | 215 | exports[`Attributes class vs className selector tmpl, class missing, className missing, string missing 1`] = `"m(\`template\`);"`; 216 | 217 | exports[`Attributes class vs className selector tmpl, class missing, className missing, string value 1`] = `"m(\`template\`,\\"inner\\");"`; 218 | 219 | exports[`Attributes class vs className selector tmpl, class missing, className tmpl, string missing 1`] = `"m(\`template\`,{className:\`className\`});"`; 220 | 221 | exports[`Attributes class vs className selector tmpl, class missing, className tmpl, string value 1`] = `"m(\`template\`,{className:\`className\`},\\"inner\\");"`; 222 | 223 | exports[`Attributes class vs className selector tmpl, class missing, className value, string missing 1`] = `"m(\`template\`,{className:\\"className\\"});"`; 224 | 225 | exports[`Attributes class vs className selector tmpl, class missing, className value, string value 1`] = `"m(\`template\`,{className:\\"className\\"},\\"inner\\");"`; 226 | 227 | exports[`Attributes class vs className selector tmpl, class tmpl, className empty, string missing 1`] = `"m(\`template\`,{class:\`class\`,className:\\"\\"});"`; 228 | 229 | exports[`Attributes class vs className selector tmpl, class tmpl, className empty, string value 1`] = `"m(\`template\`,{class:\`class\`,className:\\"\\"},\\"inner\\");"`; 230 | 231 | exports[`Attributes class vs className selector tmpl, class tmpl, className missing, string missing 1`] = `"m(\`template\`,{class:\`class\`});"`; 232 | 233 | exports[`Attributes class vs className selector tmpl, class tmpl, className missing, string value 1`] = `"m(\`template\`,{class:\`class\`},\\"inner\\");"`; 234 | 235 | exports[`Attributes class vs className selector tmpl, class tmpl, className tmpl, string missing 1`] = `"m(\`template\`,{class:\`class\`,className:\`className\`});"`; 236 | 237 | exports[`Attributes class vs className selector tmpl, class tmpl, className tmpl, string value 1`] = `"m(\`template\`,{class:\`class\`,className:\`className\`},\\"inner\\");"`; 238 | 239 | exports[`Attributes class vs className selector tmpl, class tmpl, className value, string missing 1`] = `"m(\`template\`,{class:\`class\`,className:\\"className\\"});"`; 240 | 241 | exports[`Attributes class vs className selector tmpl, class tmpl, className value, string value 1`] = `"m(\`template\`,{class:\`class\`,className:\\"className\\"},\\"inner\\");"`; 242 | 243 | exports[`Attributes class vs className selector tmpl, class value, className empty, string missing 1`] = `"m(\`template\`,{class:\\"class\\",className:\\"\\"});"`; 244 | 245 | exports[`Attributes class vs className selector tmpl, class value, className empty, string value 1`] = `"m(\`template\`,{class:\\"class\\",className:\\"\\"},\\"inner\\");"`; 246 | 247 | exports[`Attributes class vs className selector tmpl, class value, className missing, string missing 1`] = `"m(\`template\`,{class:\\"class\\"});"`; 248 | 249 | exports[`Attributes class vs className selector tmpl, class value, className missing, string value 1`] = `"m(\`template\`,{class:\\"class\\"},\\"inner\\");"`; 250 | 251 | exports[`Attributes class vs className selector tmpl, class value, className tmpl, string missing 1`] = `"m(\`template\`,{class:\\"class\\",className:\`className\`});"`; 252 | 253 | exports[`Attributes class vs className selector tmpl, class value, className tmpl, string value 1`] = `"m(\`template\`,{class:\\"class\\",className:\`className\`},\\"inner\\");"`; 254 | 255 | exports[`Attributes class vs className selector tmpl, class value, className value, string missing 1`] = `"m(\`template\`,{class:\\"class\\",className:\\"className\\"});"`; 256 | 257 | exports[`Attributes class vs className selector tmpl, class value, className value, string value 1`] = `"m(\`template\`,{class:\\"class\\",className:\\"className\\"},\\"inner\\");"`; 258 | --------------------------------------------------------------------------------