From fbda2e0edc52da29a0e6d99967b2fdc76422e45a Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Thu, 9 May 2019 11:37:41 -0700 Subject: [PATCH 01/29] Initial spike of co-located templates RFC. Still quite WIP, but "basically works" when using ember-cli master which includes https://github.com/ember-cli/ember-cli/commit/84c449a0d7f5ed15dc8161346b544e50a68c7f49 Co-authored-by: Robert Jackson --- ember-addon-main.js | 100 ++++- package.json | 6 +- tests/dummy/app/components/bar.hbs | 1 + tests/dummy/app/components/bar.js | 3 + tests/dummy/app/components/foo.hbs | 1 + .../app/components/pods-comp/template.hbs | 0 yarn.lock | 386 +++++++++++++----- 7 files changed, 397 insertions(+), 100 deletions(-) create mode 100644 tests/dummy/app/components/bar.hbs create mode 100644 tests/dummy/app/components/bar.js create mode 100644 tests/dummy/app/components/foo.hbs create mode 100644 tests/dummy/app/components/pods-comp/template.hbs diff --git a/ember-addon-main.js b/ember-addon-main.js index 8e43dc62..ada086c3 100644 --- a/ember-addon-main.js +++ b/ember-addon-main.js @@ -1,9 +1,93 @@ 'use strict'; +const fs = require('fs'); const path = require('path'); const utils = require('./utils'); const addDependencyTracker = require("./addDependencyTracker"); const hashForDep = require('hash-for-dep'); +const walkSync = require('walk-sync'); +const Plugin = require('broccoli-plugin'); + +class ColocatedTemplateProcessor extends Plugin { + constructor(tree, options) { + super([tree], options); + + this.options = options; + } + + build() { + // TODO: do we need to pass through all files, or only template files? + let files = walkSync(this.inputPaths[0], { directories: false }); + + let filesToCopy = []; + files.forEach(filePath => { + let filePathParts = path.parse(filePath); + let inputPath = path.join(this.inputPaths[0], filePath); + let isInsideComponentsFolder = filePath.includes('/components/'); + + // copy forward non-hbs files + // TODO: don't copy .js files that will ultimately be overridden + if (!isInsideComponentsFolder || filePathParts.ext !== '.hbs') { + filesToCopy.push(filePath); + return; + } + + // TODO: deal with alternate extensions (e.g. ts) + let possibleJSPath = path.join(filePathParts.dir, filePathParts.name + '.js'); + let hasJSFile = fs.existsSync(path.join(this.inputPaths[0], possibleJSPath)); + + if (filePathParts.name === 'template') { + // TODO: maybe warn? + return; + } + + let templateContents = fs.readFileSync(inputPath, { encoding: 'utf8' }); + let jsContents = null; + + // TODO: deal with hygiene + if (hasJSFile) { + // add the template, call setComponentTemplate + + jsContents = fs.readFileSync(path.join(this.inputPaths[0], possibleJSPath), { encoding: 'utf8' }); + jsContents = `${jsContents.replace('export default', 'const CLASS =')}\n; +const setComponentTemplate = Ember._setComponentTemplate; +const TEMPLATE = ${this.options.precompile(templateContents)}; +export default setComponentTemplate(TEMPLATE, CLASS);`; + } else { + // create JS file, use null component pattern + jsContents = `import templateOnlyComponent from "@ember/component/template-only"; +const setComponentTemplate = Ember._setComponentTemplate; +const TEMPLATE = ${this.options.precompile(templateContents)}; +const CLASS = templateOnlyComponent(); +export default setComponentTemplate(TEMPLATE, CLASS);`; + } + + + let outputPath = path.join(this.outputPath, possibleJSPath); + + // TODO: check for compat with Node 8 (recursive may only be present in 10+) + // TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT) + fs.mkdirSync(path.dirname(outputPath), { recursive: true }); + + fs.writeFileSync(outputPath, jsContents, { encoding: 'utf8' }); + }); + + filesToCopy.forEach(filePath => { + let inputPath = path.join(this.inputPaths[0], filePath); + let outputPath = path.join(this.outputPath, filePath); + + // avoid copying file over top of a previously written one + if (fs.existsSync(outputPath)) { + return; + } + + // TODO: check for compat with Node 8 (recursive may only be present in 10+) + // TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT) + fs.mkdirSync(path.dirname(outputPath), { recursive: true }); + fs.copyFileSync(inputPath, outputPath); + }) + } +} module.exports = { name: require('./package').name, @@ -37,6 +121,12 @@ module.exports = { // ensure that broccoli-ember-hbs-template-compiler is not processing hbs files registry.remove('template', 'broccoli-ember-hbs-template-compiler'); + let precompile = string => { + let htmlbarsOptions = this.htmlbarsOptions(); + let templateCompiler = htmlbarsOptions.templateCompiler; + return utils.template(templateCompiler, string); + } + registry.add('template', { name: 'ember-cli-htmlbars', ext: 'hbs', @@ -44,14 +134,12 @@ module.exports = { toTree(tree) { let htmlbarsOptions = this._addon.htmlbarsOptions(); let TemplateCompiler = require('./index'); - return new TemplateCompiler(tree, htmlbarsOptions); + let unifiedColocatedTemplates = new ColocatedTemplateProcessor(tree, { precompile }); + + return new TemplateCompiler(unifiedColocatedTemplates, htmlbarsOptions); }, - precompile(string) { - let htmlbarsOptions = this._addon.htmlbarsOptions(); - let templateCompiler = htmlbarsOptions.templateCompiler; - return utils.template(templateCompiler, string); - } + precompile, }); if (type === 'parent') { diff --git a/package.json b/package.json index 25943775..bd159e1e 100644 --- a/package.json +++ b/package.json @@ -35,16 +35,18 @@ }, "dependencies": { "broccoli-persistent-filter": "^2.3.1", + "broccoli-plugin": "^2.0.0", "hash-for-dep": "^1.5.1", "json-stable-stringify": "^1.0.1", - "strip-bom": "^3.0.0" + "strip-bom": "^3.0.0", + "walk-sync": "^1.1.3" }, "devDependencies": { "@ember/optional-features": "^0.7.0", "broccoli-test-helper": "^2.0.0", "chai": "^4.2.0", "co": "^4.6.0", - "ember-cli": "~3.9.0", + "ember-cli": "github:ember-cli/ember-cli", "ember-cli-app-version": "^3.2.0", "ember-cli-babel": "^7.8.0", "ember-cli-dependency-checker": "^3.2.0", diff --git a/tests/dummy/app/components/bar.hbs b/tests/dummy/app/components/bar.hbs new file mode 100644 index 00000000..9490021b --- /dev/null +++ b/tests/dummy/app/components/bar.hbs @@ -0,0 +1 @@ +Hello from bar! diff --git a/tests/dummy/app/components/bar.js b/tests/dummy/app/components/bar.js new file mode 100644 index 00000000..be51304f --- /dev/null +++ b/tests/dummy/app/components/bar.js @@ -0,0 +1,3 @@ +export default Component.extend({ + attributeBindings: ['lolol'], +}); diff --git a/tests/dummy/app/components/foo.hbs b/tests/dummy/app/components/foo.hbs new file mode 100644 index 00000000..627079e6 --- /dev/null +++ b/tests/dummy/app/components/foo.hbs @@ -0,0 +1 @@ +Stuff!! diff --git a/tests/dummy/app/components/pods-comp/template.hbs b/tests/dummy/app/components/pods-comp/template.hbs new file mode 100644 index 00000000..e69de29b diff --git a/yarn.lock b/yarn.lock index 504c8b8c..190d98d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,6 +29,37 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/core@^7.4.3": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.4.tgz#84055750b05fcd50f9915a826b44fa347a825250" + integrity sha512-lQgGX3FPRgbz2SKmhMtYgJvVzGZrmjaF4apZ2bLwofAKiSjxU0drPh4S/VasyYXwaTs+A1gvQ45BN8SQJzHsQQ== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.4.4" + "@babel/helpers" "^7.4.4" + "@babel/parser" "^7.4.4" + "@babel/template" "^7.4.4" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" + convert-source-map "^1.1.0" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.11" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.1.5": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.1.5.tgz#615f064d13d95f8f9157c7261f68eddf32ec15b3" + integrity sha512-IO31r62xfMI+wBJVmgx0JR9ZOHty8HkoYpQAjRWUGG9vykBTlGHdArZ8zoFtpUu2gs17K7qTl/TtPpiSi6t+MA== + dependencies: + "@babel/types" "^7.1.5" + jsesc "^2.5.1" + lodash "^4.17.10" + source-map "^0.5.0" + trim-right "^1.0.1" + "@babel/generator@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.0.tgz#c230e79589ae7a729fd4631b9ded4dc220418196" @@ -40,6 +71,17 @@ source-map "^0.5.0" trim-right "^1.0.1" +"@babel/generator@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.4.tgz#174a215eb843fc392c7edcaabeaa873de6e8f041" + integrity sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ== + dependencies: + "@babel/types" "^7.4.4" + jsesc "^2.5.1" + lodash "^4.17.11" + source-map "^0.5.0" + trim-right "^1.0.1" + "@babel/helper-annotate-as-pure@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" @@ -197,6 +239,13 @@ dependencies: "@babel/types" "^7.4.0" +"@babel/helper-split-export-declaration@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" + integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== + dependencies: + "@babel/types" "^7.4.4" + "@babel/helper-wrap-function@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.1.0.tgz#8cf54e9190706067f016af8f75cb3df829cc8c66" @@ -216,6 +265,15 @@ "@babel/traverse" "^7.4.3" "@babel/types" "^7.4.0" +"@babel/helpers@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.4.4.tgz#868b0ef59c1dd4e78744562d5ce1b59c89f2f2a5" + integrity sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A== + dependencies: + "@babel/template" "^7.4.4" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" + "@babel/highlight@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" @@ -225,11 +283,21 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/parser@^7.1.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.5.tgz#02f077ac8817d3df4a832ef59de67565e71cca4b" + integrity sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g== + "@babel/parser@^7.4.0", "@babel/parser@^7.4.3": version "7.4.3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.3.tgz#eb3ac80f64aa101c907d4ce5406360fe75b7895b" integrity sha512-gxpEUhTS1sGA63EGQGuA+WESPR/6tz6ng7tSHFCmaTJK/cGK8y37cBTspX+U2xCAue2IQVvF6Z0oigmjwD8YGQ== +"@babel/parser@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.4.tgz#5977129431b8fe33471730d255ce8654ae1250b6" + integrity sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w== + "@babel/plugin-proposal-async-generator-functions@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.1.0.tgz#41c1a702e10081456e23a7b74d891922dd1bb6ce" @@ -620,7 +688,46 @@ "@babel/parser" "^7.4.0" "@babel/types" "^7.4.0" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.0", "@babel/traverse@^7.4.3": +"@babel/template@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" + integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" + +"@babel/traverse@^7.1.0": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.5.tgz#5aafca2039aa058c104cf2bfeb9fc4a857ccbca9" + integrity sha512-eU6XokWypl0MVJo+MTSPUtlfPePkrqsF26O+l1qFGlCKWwmiYAYy2Sy44Qw8m2u/LbPCsxYt90rghmqhYMGpPA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.1.5" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/parser" "^7.1.5" + "@babel/types" "^7.1.5" + debug "^3.1.0" + globals "^11.1.0" + lodash "^4.17.10" + +"@babel/traverse@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.0.tgz#14006967dd1d2b3494cdd650c686db9daf0ddada" + integrity sha512-/DtIHKfyg2bBKnIN+BItaIlEg5pjAnzHOIQe5w+rHAw/rg9g0V7T4rqPX8BJPfW11kt3koyjAnTNwCzb28Y1PA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.4.0" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.0" + "@babel/parser" "^7.4.0" + "@babel/types" "^7.4.0" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.11" + +"@babel/traverse@^7.4.3": version "7.4.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.3.tgz#1a01f078fc575d589ff30c0f71bf3c3d9ccbad84" integrity sha512-HmA01qrtaCwwJWpSKpA948cBvU5BrmviAief/b3AVw936DtcdsTexlbyzNuDnthwhOQ37xshn7hvQaEQk7ISYQ== @@ -635,7 +742,31 @@ globals "^11.1.0" lodash "^4.17.11" -"@babel/types@^7.0.0", "@babel/types@^7.4.0": +"@babel/traverse@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.4.tgz#0776f038f6d78361860b6823887d4f3937133fe8" + integrity sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.4.4" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.11" + +"@babel/types@^7.0.0", "@babel/types@^7.1.5": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.1.5.tgz#12fe64e91a431234b7017b4227a78cc0eec4e081" + integrity sha512-sJeqa/d9eM/bax8Ivg+fXF7FpN3E/ZmTrWbkk6r+g7biVYfALMnLin4dKijsaqEhpd2xvOGfQTkQkD31YCVV4A== + dependencies: + esutils "^2.0.2" + lodash "^4.17.10" + to-fast-properties "^2.0.0" + +"@babel/types@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.0.tgz#670724f77d24cce6cc7d8cf64599d511d164894c" integrity sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA== @@ -644,6 +775,15 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" +"@babel/types@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.4.tgz#8db9e9a629bb7c29370009b4b779ed93fe57d5f0" + integrity sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ== + dependencies: + esutils "^2.0.2" + lodash "^4.17.11" + to-fast-properties "^2.0.0" + "@cnakazawa/watch@^1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef" @@ -1913,7 +2053,7 @@ broccoli-funnel-reducer@^1.0.0: resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" integrity sha1-ETZbKnha7JsXlyo234fu8kxcwOo= -broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1: +broccoli-funnel@^1.0.1: version "1.2.0" resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" integrity sha1-zdw6/F/xaFqAI0iP/3TOb7WlEpY= @@ -2084,6 +2224,16 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli rimraf "^2.3.4" symlink-or-copy "^1.1.8" +broccoli-plugin@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-2.0.0.tgz#c248d0241ba14be42b3253f6707370ee9d71c88e" + integrity sha512-p/p6pqDI+FlXwPSnwlFhzUgHNn1yj/EKaBys4/gL094+cVRbdsojFStrIjDoOtL8j+7iU+DazPnH3+/rD9PuLA== + dependencies: + promise-map-series "^0.2.1" + quick-temp "^0.1.3" + rimraf "^2.3.4" + symlink-or-copy "^1.1.8" + broccoli-slow-trees@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" @@ -2096,7 +2246,7 @@ broccoli-source@^1.1.0: resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" integrity sha1-VPDoLItz9GWAy7xPV48LMvyo+Ak= -broccoli-stew@^2.0.1: +broccoli-stew@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-2.1.0.tgz#ba73add17fda3b9b01d8cfb343a8b613b7136a0a" integrity sha512-tgCkuTWYl4uf7k7ib2D79KFEj2hCgnTUNPMnrCoAha0/4bywcNccmaZVWtL9Ex37yX5h5eAbnM/ak2ULoMwSSw== @@ -2128,7 +2278,7 @@ broccoli-test-helper@^2.0.0: tmp "^0.0.33" walk-sync "^0.3.3" -broccoli@^2.0.0, broccoli@^2.0.1: +broccoli@^2.0.0, broccoli@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/broccoli/-/broccoli-2.3.0.tgz#b3f71b2c3d02fc042988e208827a09c75dd7b350" integrity sha512-TeYMYlCGFK8EGk4Wce1G1uU3i52+YxRqP3WPOVDojC1zUk+Gi40wHBzUT2fncQZDl26dmCQMNugtHKjvUpcGQg== @@ -2243,10 +2393,10 @@ cacheable-request@^2.1.1: normalize-url "2.0.1" responselike "1.0.2" -calculate-cache-key-for-tree@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" - integrity sha1-DD5CycE088neU1jA8WeTYn6pdtY= +calculate-cache-key-for-tree@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-2.0.0.tgz#7ac57f149a4188eacb0a45b210689215d3fef8d6" + integrity sha512-Quw8a6y8CPmRd6eU+mwypktYCwUcf8yVFIRbNZ6tPQEckX9yd+EBVEPC/GSZZrMWH9e7Vz4pT7XhpmyApRByLQ== dependencies: json-stable-stringify "^1.0.1" @@ -2417,10 +2567,10 @@ cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" -cli-spinners@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" - integrity sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg== +cli-spinners@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.1.0.tgz#22c34b4d51f573240885b201efda4e4ec9fff3c7" + integrity sha512-8B00fJOEh1HPrx4fo5eW16XmE1PcL1tGpGrxy63CXGP9nHdPBN63X75hA1zhvQuhVztJWLqV58Roj2qlNM7cAA== cli-table3@^0.5.1: version "0.5.1" @@ -2552,23 +2702,23 @@ component-inherit@0.0.3: resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= -compressible@~2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" - integrity sha1-MmxfUH+7BV9UEWeCuWmoG2einac= +compressible@~2.0.16: + version "2.0.17" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1" + integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw== dependencies: - mime-db ">= 1.34.0 < 2" + mime-db ">= 1.40.0 < 2" -compression@^1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" - integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg== +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== dependencies: accepts "~1.3.5" bytes "3.0.0" - compressible "~2.0.14" + compressible "~2.0.16" debug "2.6.9" - on-headers "~1.0.1" + on-headers "~1.0.2" safe-buffer "5.1.2" vary "~1.1.2" @@ -2604,16 +2754,16 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -console-ui@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-3.0.0.tgz#8abee8f701f4c3729953f74233624623f0f72100" - integrity sha512-uPlaGvTGLcu5i1EYuhr3b7yYDPkcrHEJYn25iXCtnFUwctjWNEkfAUvhXa4Rda9mv0reiucRrikfYd3EZjJiHw== +console-ui@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-3.0.4.tgz#1df0b003ea7b6adcda3d2f781f567b3b75ee7cbb" + integrity sha512-1obVCKinYE179hoPKnlHzJY5q1fQdiuiUXrYbTkZDTE+UXxGFMayxFzJjKN9GLfEkTo/rg6+Iqt+yGaOqc3GXQ== dependencies: chalk "^2.1.0" inquirer "^6" json-stable-stringify "^1.0.1" - ora "^3.0.0" - through "^2.3.8" + ora "^3.4.0" + through2 "^3.0.1" consolidate@^0.15.1: version "0.15.1" @@ -2711,7 +2861,7 @@ debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.3. dependencies: ms "2.0.0" -debug@3.2.6, debug@^3.1.0: +debug@3.2.6, debug@^3.0.1, debug@^3.1.0: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -3031,11 +3181,6 @@ ember-cli-is-package-missing@^1.0.0: resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" integrity sha1-bmGEyvuSY13ZPKbJRrEEKS1OM5A= -ember-cli-lodash-subset@^1.0.7: - version "1.0.12" - resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" - integrity sha1-ry5366XcsNd/MwjTpv19NFD25Tc= - ember-cli-lodash-subset@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" @@ -3053,18 +3198,15 @@ ember-cli-path-utils@^1.0.0: resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" integrity sha1-Tjmvi1UwHN3FAXc5t3qAT7ogce0= -ember-cli-preprocess-registry@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.2.tgz#083efb21fd922c021ceba9e08f4d9278249fc4db" - integrity sha512-YJfcDHMBEjtD505CIhM8dtu5FO2Ku+0OTs/0kdLlj9mhXlbzC+k0JAS5c/0AQ+Nh2f+qZZJ8G19ySdzWwTLSCQ== +ember-cli-preprocess-registry@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.3.0.tgz#685837a314fbe57224bd54b189f4b9c23907a2de" + integrity sha512-60GYpw7VPeB7TvzTLZTuLTlHdOXvayxjAQ+IxM2T04Xkfyu75O2ItbWlftQW7NZVGkaCsXSRAmn22PG03VpLMA== dependencies: broccoli-clean-css "^1.1.0" - broccoli-funnel "^1.0.0" - broccoli-merge-trees "^1.0.0" - debug "^2.2.0" - ember-cli-lodash-subset "^1.0.7" + broccoli-funnel "^2.0.1" + debug "^3.0.1" process-relative-require "^1.0.0" - silent-error "^1.0.0" ember-cli-string-utils@^1.1.0: version "1.1.0" @@ -3111,18 +3253,17 @@ ember-cli-version-checker@^3.0.0, ember-cli-version-checker@^3.0.1, ember-cli-ve resolve-package-path "^1.2.6" semver "^5.6.0" -ember-cli@~3.9.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-3.9.0.tgz#7ee8120c48514488c692265c4a429625e8f0187e" - integrity sha512-y5PAdj08BApNUXL4IL4rOo3+8M6BQKobCx2zvczCyu9jjPaxfZ+X/xEw6UHXe5F3i3tWm7IwX9kG6sz5pv7vuQ== +"ember-cli@github:ember-cli/ember-cli": + version "3.11.0-beta.1" + resolved "https://codeload.github.com/ember-cli/ember-cli/tar.gz/84c449a0d7f5ed15dc8161346b544e50a68c7f49" dependencies: - "@babel/core" "^7.0.0" + "@babel/core" "^7.4.3" "@babel/plugin-transform-modules-amd" "^7.2.0" amd-name-resolver "^1.3.1" babel-plugin-module-resolver "^3.2.0" bower-config "^1.4.1" bower-endpoint-parser "0.2.2" - broccoli "^2.0.1" + broccoli "^2.3.0" broccoli-amd-funnel "^2.0.1" broccoli-babel-transpiler "^7.2.0" broccoli-builder "^0.18.14" @@ -3137,15 +3278,15 @@ ember-cli@~3.9.0: broccoli-module-normalizer "^1.3.0" broccoli-module-unification-reexporter "^1.0.0" broccoli-source "^1.1.0" - broccoli-stew "^2.0.1" - calculate-cache-key-for-tree "^1.1.0" + broccoli-stew "^2.1.0" + calculate-cache-key-for-tree "^2.0.0" capture-exit "^2.0.0" chalk "^2.4.2" ci-info "^2.0.0" clean-base-url "^1.0.0" - compression "^1.7.3" + compression "^1.7.4" configstore "^4.0.0" - console-ui "^3.0.0" + console-ui "^3.0.2" core-object "^3.1.5" dag-map "^2.0.2" diff "^4.0.1" @@ -3153,7 +3294,7 @@ ember-cli@~3.9.0: ember-cli-is-package-missing "^1.0.0" ember-cli-lodash-subset "^2.0.1" ember-cli-normalize-entity-name "^1.0.0" - ember-cli-preprocess-registry "^3.1.2" + ember-cli-preprocess-registry "^3.3.0" ember-cli-string-utils "^1.1.0" ember-source-channel-url "^1.1.0" ensure-posix-path "^1.0.2" @@ -3164,10 +3305,10 @@ ember-cli@~3.9.0: find-up "^3.0.0" find-yarn-workspace-root "^1.2.1" fs-extra "^7.0.1" - fs-tree-diff "^1.0.2" - get-caller-file "^2.0.1" + fs-tree-diff "^2.0.1" + get-caller-file "^2.0.5" git-repo-info "^2.1.0" - glob "^7.1.3" + glob "^7.1.4" heimdalljs "^0.2.6" heimdalljs-fs-monitor "^0.2.2" heimdalljs-graph "^0.3.5" @@ -3176,7 +3317,7 @@ ember-cli@~3.9.0: inflection "^1.12.0" is-git-url "^1.0.0" isbinaryfile "^3.0.3" - js-yaml "^3.12.2" + js-yaml "^3.13.1" json-stable-stringify "^1.0.1" leek "0.0.24" lodash.template "^4.4.0" @@ -3186,22 +3327,23 @@ ember-cli@~3.9.0: morgan "^1.9.1" nopt "^3.0.6" npm-package-arg "^6.1.0" + p-defer "^2.1.0" portfinder "^1.0.20" promise-map-series "^0.2.3" quick-temp "^0.1.8" - resolve "^1.10.0" + resolve "^1.10.1" + resolve-package-path "^1.2.7" rsvp "^4.8.4" - sane "^4.0.2" - semver "^5.6.0" + sane "^4.1.0" + semver "^6.0.0" silent-error "^1.1.1" - sort-package-json "^1.19.0" + sort-package-json "^1.22.1" symlink-or-copy "^1.2.0" temp "0.9.0" testem "^2.14.0" tiny-lr "^1.1.1" tree-sync "^1.4.0" uuid "^3.3.2" - validate-npm-package-name "^3.0.0" walk-sync "^1.1.3" watch-detector "^0.1.0" yam "^1.0.0" @@ -4071,17 +4213,7 @@ fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5 path-posix "^1.0.0" symlink-or-copy "^1.1.8" -fs-tree-diff@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-1.0.2.tgz#0e2931733a85b55feb3472c0b89a20b0c03ac0de" - integrity sha512-Zro2ACaPVDgVOx9+s5s5AfPlAD0kMJdbwGvTGF6KC1SjxjiGWxJvV4mUTDkFVSy3OUw2C/f1qpdjF81hGqSBAw== - dependencies: - heimdalljs-logger "^0.1.7" - object-assign "^4.1.0" - path-posix "^1.0.0" - symlink-or-copy "^1.1.8" - -fs-tree-diff@^2.0.0: +fs-tree-diff@^2.0.0, fs-tree-diff@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-2.0.1.tgz#343e4745ab435ec39ebac5f9059ad919cd034afa" integrity sha512-x+CfAZ/lJHQqwlD64pYM5QxWjzWhSjroaVsr8PW831zOApL55qPibed0c+xebaLWVr2BnHFoHdrwOv8pzt8R5A== @@ -4137,7 +4269,7 @@ get-caller-file@^1.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== -get-caller-file@^2.0.1: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -4267,6 +4399,18 @@ glob@^5.0.10: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + global-modules@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" @@ -4619,7 +4763,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= @@ -5005,7 +5149,7 @@ js-tokens@^3.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= -js-yaml@3.13.1, js-yaml@^3.12.0, js-yaml@^3.12.2, js-yaml@^3.2.5, js-yaml@^3.2.7: +js-yaml@3.13.1, js-yaml@^3.12.0, js-yaml@^3.13.1, js-yaml@^3.2.5, js-yaml@^3.2.7: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -5758,7 +5902,12 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -"mime-db@>= 1.34.0 < 2", mime-db@~1.36.0: +"mime-db@>= 1.40.0 < 2": + version "1.40.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" + integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== + +mime-db@~1.36.0: version "1.36.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" integrity sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw== @@ -6102,6 +6251,11 @@ on-headers@~1.0.1: resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c= +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -6136,16 +6290,16 @@ optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" -ora@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-3.1.0.tgz#dbedd8c03b5d017fb67083e87ee52f5ec89823ed" - integrity sha512-vRBPaNCclUi8pUxRF/G8+5qEQkc6EgzKK1G2ZNJUIGu088Un5qIxFXeDgymvPRM9nmrcUOGzQgS1Vmtz+NtlMw== +ora@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318" + integrity sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg== dependencies: chalk "^2.4.2" cli-cursor "^2.1.0" - cli-spinners "^1.3.1" + cli-spinners "^2.0.0" log-symbols "^2.2.0" - strip-ansi "^5.0.0" + strip-ansi "^5.2.0" wcwidth "^1.0.1" os-homedir@^1.0.0: @@ -6185,6 +6339,11 @@ p-defer@^1.0.0: resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= +p-defer@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-2.1.0.tgz#d9c97b40f8fb5c256a70b4aabec3c1c8c42f1fae" + integrity sha512-xMwL9id1bHn/UfNGFEMFwlULOprQUEOg6vhqSfr6oKxPFB0oSh0zhGq/9/tPSE+cyij2+RW6H8+0Ke4xsPdZ7Q== + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -6560,6 +6719,15 @@ rc@^1.0.1, rc@^1.1.6: minimist "^1.2.0" strip-json-comments "~2.0.1" +"readable-stream@2 || 3": + version "3.3.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.3.0.tgz#cb8011aad002eb717bf040291feba8569c986fb9" + integrity sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readable-stream@^2.0.0, readable-stream@^2.0.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" @@ -6805,6 +6973,14 @@ resolve-package-path@^1.0.11, resolve-package-path@^1.2.6: path-root "^0.1.1" resolve "^1.10.0" +resolve-package-path@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-1.2.7.tgz#2a7bc37ad96865e239330e3102c31322847e652e" + integrity sha512-fVEKHGeK85bGbVFuwO9o1aU0n3vqQGrezPc51JGu9UTXpFQfWq5qCeKxyaRUSvephs+06c5j5rPq/dzHGEo8+Q== + dependencies: + path-root "^0.1.1" + resolve "^1.10.0" + resolve-path@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" @@ -6825,13 +7001,20 @@ resolve@1.9.0: dependencies: path-parse "^1.0.6" -resolve@^1.1.3, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.8.1: +resolve@^1.1.3, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.8.1: version "1.12.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== dependencies: path-parse "^1.0.6" +resolve@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.1.tgz#664842ac960795bbe758221cdccda61fb64b5f18" + integrity sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA== + dependencies: + path-parse "^1.0.6" + responselike@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" @@ -6927,7 +7110,7 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sane@^4.0.0, sane@^4.0.2: +sane@^4.0.0, sane@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== @@ -6947,6 +7130,11 @@ semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semve resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== +semver@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.0.0.tgz#05e359ee571e5ad7ed641a6eec1e547ba52dea65" + integrity sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ== + send@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" @@ -7152,7 +7340,7 @@ sort-object-keys@^1.1.2: resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" integrity sha1-06bEjcKsl+a8lDZ2luA/bQnTeVI= -sort-package-json@^1.19.0: +sort-package-json@^1.22.1: version "1.22.1" resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.22.1.tgz#384ce7a098cd13be4109800d5ce2f0cf7826052e" integrity sha512-uVINQraFQvnlzNHFnQOT4MYy0qonIEzKwhrI2yrTiQjNo5QF4h3ffrnCk7a95QAwoK/RdkO/w8W9tJIcaOWC7g== @@ -7308,6 +7496,13 @@ string_decoder@0.10, string_decoder@~0.10.x: resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= +string_decoder@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== + dependencies: + safe-buffer "~5.1.0" + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -7329,7 +7524,7 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.0.0, strip-ansi@^5.1.0: +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== @@ -7468,7 +7663,14 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.1.0.tgz#1be0dc2a0dc244d44be8a09af6a85afb93c4dbc3" integrity sha1-G+DcKg3CRNRL6KCa9qha+5PE28M= -through@^2.3.6, through@^2.3.8: +through2@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a" + integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww== + dependencies: + readable-stream "2 || 3" + +through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -7742,7 +7944,7 @@ username-sync@^1.0.2: resolved "https://registry.yarnpkg.com/username-sync/-/username-sync-1.0.2.tgz#0a3697909fb7b5768d29e2921f573acfdd427592" integrity sha512-ayNkOJdoNSGNDBE46Nkc+l6IXmeugbzahZLSMkwvgRWv5y5ZqNY2IrzcgmkR4z32sj1W3tM3TuTUMqkqBzO+RA== -util-deprecate@^1.0.2, util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= From 764615e0698396d200cf90fee71cfc0cd66b9daf Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Sat, 10 Aug 2019 16:41:21 -0700 Subject: [PATCH 02/29] Use globals for now (blocked by https://github.com/ember-cli/ember-rfc176-data/pull/164) --- ember-addon-main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ember-addon-main.js b/ember-addon-main.js index ada086c3..c81a4c89 100644 --- a/ember-addon-main.js +++ b/ember-addon-main.js @@ -55,7 +55,7 @@ const TEMPLATE = ${this.options.precompile(templateContents)}; export default setComponentTemplate(TEMPLATE, CLASS);`; } else { // create JS file, use null component pattern - jsContents = `import templateOnlyComponent from "@ember/component/template-only"; + jsContents = `const templateOnlyComponent = Ember._templateOnlyComponent; const setComponentTemplate = Ember._setComponentTemplate; const TEMPLATE = ${this.options.precompile(templateContents)}; const CLASS = templateOnlyComponent(); From a640658a151fe472fb4a3ecc65a8a11ebf2848f1 Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Mon, 12 Aug 2019 12:43:23 -0700 Subject: [PATCH 03/29] Fix addon compilation --- ember-addon-main.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ember-addon-main.js b/ember-addon-main.js index c81a4c89..b230d4cd 100644 --- a/ember-addon-main.js +++ b/ember-addon-main.js @@ -23,7 +23,16 @@ class ColocatedTemplateProcessor extends Plugin { files.forEach(filePath => { let filePathParts = path.parse(filePath); let inputPath = path.join(this.inputPaths[0], filePath); - let isInsideComponentsFolder = filePath.includes('/components/'); + + // TODO: why are these different? + // Apps: my-app/components/foo.hbs, my-app/templates/components/foo.hbs + // Addons: components/foo.js, templates/components/foo.hbs + + // TODO: make this more robust + let isInsideComponentsFolder = + (filePath.includes('/components/') || filePath.startsWith('components/')) && + !filePath.includes('/templates/components/') && + !filePath.startsWith('templates/components'); // copy forward non-hbs files // TODO: don't copy .js files that will ultimately be overridden From 4c6017b8c5bb39cdcde8013ccaf905baec29412d Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Tue, 13 Aug 2019 11:37:33 -0700 Subject: [PATCH 04/29] Better error for missing default export --- ember-addon-main.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ember-addon-main.js b/ember-addon-main.js index b230d4cd..b2cb937d 100644 --- a/ember-addon-main.js +++ b/ember-addon-main.js @@ -58,7 +58,15 @@ class ColocatedTemplateProcessor extends Plugin { // add the template, call setComponentTemplate jsContents = fs.readFileSync(path.join(this.inputPaths[0], possibleJSPath), { encoding: 'utf8' }); - jsContents = `${jsContents.replace('export default', 'const CLASS =')}\n; + + if (jsContents.includes('export default')) { + jsContents = jsContents.replace('export default', 'const CLASS ='); + } else { + let message = `${filePath}\` does not contain a \`default export\`. Did you forget to export the component class?`; + jsContents = `${jsContents}\nthrow new Error(${JSON.stringify(message)})`; + } + + jsContents = `${jsContents} const setComponentTemplate = Ember._setComponentTemplate; const TEMPLATE = ${this.options.precompile(templateContents)}; export default setComponentTemplate(TEMPLATE, CLASS);`; From 942c30129e45ec0e42256931fb2147e5e5658e93 Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Thu, 22 Aug 2019 13:51:57 -0700 Subject: [PATCH 05/29] v3.2.0-alpha.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bd159e1e..a0a212e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-cli-htmlbars", - "version": "3.1.0", + "version": "3.2.0-alpha.0", "description": "A library for adding htmlbars to ember CLI", "keywords": [ "ember-addon", From 66dff2f82c3c9b367d6c9e7c0dc1bda53e0ba5d8 Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Sat, 24 Aug 2019 00:39:16 -0700 Subject: [PATCH 06/29] Fix some Node 8 issues --- ember-addon-main.js | 11 +++++------ package.json | 2 ++ yarn.lock | 5 +++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ember-addon-main.js b/ember-addon-main.js index b2cb937d..df625a52 100644 --- a/ember-addon-main.js +++ b/ember-addon-main.js @@ -1,6 +1,8 @@ 'use strict'; const fs = require('fs'); +const mkdirp = require('mkdirp'); +const copyFileSync = require('fs-copy-file-sync'); const path = require('path'); const utils = require('./utils'); const addDependencyTracker = require("./addDependencyTracker"); @@ -82,10 +84,8 @@ export default setComponentTemplate(TEMPLATE, CLASS);`; let outputPath = path.join(this.outputPath, possibleJSPath); - // TODO: check for compat with Node 8 (recursive may only be present in 10+) // TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT) - fs.mkdirSync(path.dirname(outputPath), { recursive: true }); - + mkdirp.sync(path.dirname(outputPath)); fs.writeFileSync(outputPath, jsContents, { encoding: 'utf8' }); }); @@ -98,10 +98,9 @@ export default setComponentTemplate(TEMPLATE, CLASS);`; return; } - // TODO: check for compat with Node 8 (recursive may only be present in 10+) // TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT) - fs.mkdirSync(path.dirname(outputPath), { recursive: true }); - fs.copyFileSync(inputPath, outputPath); + mkdirp.sync(path.dirname(outputPath)); + copyFileSync(inputPath, outputPath); }) } } diff --git a/package.json b/package.json index a0a212e2..2573f6f6 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,10 @@ "dependencies": { "broccoli-persistent-filter": "^2.3.1", "broccoli-plugin": "^2.0.0", + "fs-copy-file-sync": "^1.1.1", "hash-for-dep": "^1.5.1", "json-stable-stringify": "^1.0.1", + "mkdirp": "^0.5.1", "strip-bom": "^3.0.0", "walk-sync": "^1.1.3" }, diff --git a/yarn.lock b/yarn.lock index 190d98d2..ab7514d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4146,6 +4146,11 @@ from2@^2.1.1: inherits "^2.0.1" readable-stream "^2.0.0" +fs-copy-file-sync@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fs-copy-file-sync/-/fs-copy-file-sync-1.1.1.tgz#11bf32c096c10d126e5f6b36d06eece776062918" + integrity sha512-2QY5eeqVv4m2PfyMiEuy9adxNP+ajf+8AR05cEi+OAzPcOj90hvFImeZhTmKLBgSd9EvG33jsD7ZRxsx9dThkQ== + fs-extra@^0.24.0: version "0.24.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" From b9295c5b39c3f89ca32c231c24dcd4811db71e5b Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Sat, 24 Aug 2019 01:47:36 -0700 Subject: [PATCH 07/29] Fix lint --- tests/dummy/app/components/bar.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/dummy/app/components/bar.js b/tests/dummy/app/components/bar.js index be51304f..006191ce 100644 --- a/tests/dummy/app/components/bar.js +++ b/tests/dummy/app/components/bar.js @@ -1,3 +1,5 @@ +import Component from '@ember/component'; + export default Component.extend({ attributeBindings: ['lolol'], }); From 6b5a4d6b4a4a8b92b7902133f5917678c8e7982c Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 5 Sep 2019 10:20:15 -0400 Subject: [PATCH 08/29] Extract ColocatedTemplateProcessor to dedicated file. --- .eslintrc.js | 1 + colocated-broccoli-plugin.js | 104 +++++++++++++++++++++++++++++++++++ ember-addon-main.js | 101 +--------------------------------- package.json | 3 +- 4 files changed, 108 insertions(+), 101 deletions(-) create mode 100644 colocated-broccoli-plugin.js diff --git a/.eslintrc.js b/.eslintrc.js index 7f98bd28..de152a45 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -22,6 +22,7 @@ module.exports = { { files: [ '.template-lintrc.js', + 'colocated-broccoli-plugin.js', 'ember-cli-build.js', 'ember-addon-main.js', 'index.js', diff --git a/colocated-broccoli-plugin.js b/colocated-broccoli-plugin.js new file mode 100644 index 00000000..221c9352 --- /dev/null +++ b/colocated-broccoli-plugin.js @@ -0,0 +1,104 @@ +'use strict'; + +const fs = require('fs'); +const mkdirp = require('mkdirp'); +const copyFileSync = require('fs-copy-file-sync'); +const path = require('path'); +const walkSync = require('walk-sync'); +const Plugin = require('broccoli-plugin'); + +module.exports = class ColocatedTemplateProcessor extends Plugin { + constructor(tree, options) { + super([tree], options); + + this.options = options; + } + + build() { + // TODO: do we need to pass through all files, or only template files? + let files = walkSync(this.inputPaths[0], { directories: false }); + + let filesToCopy = []; + files.forEach(filePath => { + let filePathParts = path.parse(filePath); + let inputPath = path.join(this.inputPaths[0], filePath); + + // TODO: why are these different? + // Apps: my-app/components/foo.hbs, my-app/templates/components/foo.hbs + // Addons: components/foo.js, templates/components/foo.hbs + + // TODO: make this more robust + let isInsideComponentsFolder = + (filePath.includes('/components/') || filePath.startsWith('components/')) && + !filePath.includes('/templates/components/') && + !filePath.startsWith('templates/components'); + + // copy forward non-hbs files + // TODO: don't copy .js files that will ultimately be overridden + if (!isInsideComponentsFolder || filePathParts.ext !== '.hbs') { + filesToCopy.push(filePath); + return; + } + + // TODO: deal with alternate extensions (e.g. ts) + let possibleJSPath = path.join(filePathParts.dir, filePathParts.name + '.js'); + let hasJSFile = fs.existsSync(path.join(this.inputPaths[0], possibleJSPath)); + + if (filePathParts.name === 'template') { + // TODO: maybe warn? + return; + } + + let templateContents = fs.readFileSync(inputPath, { encoding: 'utf8' }); + let jsContents = null; + + // TODO: deal with hygiene + if (hasJSFile) { + // add the template, call setComponentTemplate + + jsContents = fs.readFileSync(path.join(this.inputPaths[0], possibleJSPath), { encoding: 'utf8' }); + + if (jsContents.includes('export default')) { + jsContents = jsContents.replace('export default', 'const CLASS ='); + } else { + let message = `${filePath}\` does not contain a \`default export\`. Did you forget to export the component class?`; + jsContents = `${jsContents}\nthrow new Error(${JSON.stringify(message)})`; + } + + jsContents = `${jsContents} +const setComponentTemplate = Ember._setComponentTemplate; +const TEMPLATE = ${this.options.precompile(templateContents)}; +export default setComponentTemplate(TEMPLATE, CLASS);`; + } else { + // create JS file, use null component pattern + jsContents = `const templateOnlyComponent = Ember._templateOnlyComponent; +const setComponentTemplate = Ember._setComponentTemplate; +const TEMPLATE = ${this.options.precompile(templateContents)}; +const CLASS = templateOnlyComponent(); +export default setComponentTemplate(TEMPLATE, CLASS);`; + } + + + let outputPath = path.join(this.outputPath, possibleJSPath); + + // TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT) + mkdirp.sync(path.dirname(outputPath)); + fs.writeFileSync(outputPath, jsContents, { encoding: 'utf8' }); + }); + + filesToCopy.forEach(filePath => { + let inputPath = path.join(this.inputPaths[0], filePath); + let outputPath = path.join(this.outputPath, filePath); + + // avoid copying file over top of a previously written one + if (fs.existsSync(outputPath)) { + return; + } + + // TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT) + mkdirp.sync(path.dirname(outputPath)); + copyFileSync(inputPath, outputPath); + }) + } +} + diff --git a/ember-addon-main.js b/ember-addon-main.js index df625a52..4e1be6e4 100644 --- a/ember-addon-main.js +++ b/ember-addon-main.js @@ -1,109 +1,10 @@ 'use strict'; -const fs = require('fs'); -const mkdirp = require('mkdirp'); -const copyFileSync = require('fs-copy-file-sync'); const path = require('path'); const utils = require('./utils'); const addDependencyTracker = require("./addDependencyTracker"); const hashForDep = require('hash-for-dep'); -const walkSync = require('walk-sync'); -const Plugin = require('broccoli-plugin'); - -class ColocatedTemplateProcessor extends Plugin { - constructor(tree, options) { - super([tree], options); - - this.options = options; - } - - build() { - // TODO: do we need to pass through all files, or only template files? - let files = walkSync(this.inputPaths[0], { directories: false }); - - let filesToCopy = []; - files.forEach(filePath => { - let filePathParts = path.parse(filePath); - let inputPath = path.join(this.inputPaths[0], filePath); - - // TODO: why are these different? - // Apps: my-app/components/foo.hbs, my-app/templates/components/foo.hbs - // Addons: components/foo.js, templates/components/foo.hbs - - // TODO: make this more robust - let isInsideComponentsFolder = - (filePath.includes('/components/') || filePath.startsWith('components/')) && - !filePath.includes('/templates/components/') && - !filePath.startsWith('templates/components'); - - // copy forward non-hbs files - // TODO: don't copy .js files that will ultimately be overridden - if (!isInsideComponentsFolder || filePathParts.ext !== '.hbs') { - filesToCopy.push(filePath); - return; - } - - // TODO: deal with alternate extensions (e.g. ts) - let possibleJSPath = path.join(filePathParts.dir, filePathParts.name + '.js'); - let hasJSFile = fs.existsSync(path.join(this.inputPaths[0], possibleJSPath)); - - if (filePathParts.name === 'template') { - // TODO: maybe warn? - return; - } - - let templateContents = fs.readFileSync(inputPath, { encoding: 'utf8' }); - let jsContents = null; - - // TODO: deal with hygiene - if (hasJSFile) { - // add the template, call setComponentTemplate - - jsContents = fs.readFileSync(path.join(this.inputPaths[0], possibleJSPath), { encoding: 'utf8' }); - - if (jsContents.includes('export default')) { - jsContents = jsContents.replace('export default', 'const CLASS ='); - } else { - let message = `${filePath}\` does not contain a \`default export\`. Did you forget to export the component class?`; - jsContents = `${jsContents}\nthrow new Error(${JSON.stringify(message)})`; - } - - jsContents = `${jsContents} -const setComponentTemplate = Ember._setComponentTemplate; -const TEMPLATE = ${this.options.precompile(templateContents)}; -export default setComponentTemplate(TEMPLATE, CLASS);`; - } else { - // create JS file, use null component pattern - jsContents = `const templateOnlyComponent = Ember._templateOnlyComponent; -const setComponentTemplate = Ember._setComponentTemplate; -const TEMPLATE = ${this.options.precompile(templateContents)}; -const CLASS = templateOnlyComponent(); -export default setComponentTemplate(TEMPLATE, CLASS);`; - } - - - let outputPath = path.join(this.outputPath, possibleJSPath); - - // TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT) - mkdirp.sync(path.dirname(outputPath)); - fs.writeFileSync(outputPath, jsContents, { encoding: 'utf8' }); - }); - - filesToCopy.forEach(filePath => { - let inputPath = path.join(this.inputPaths[0], filePath); - let outputPath = path.join(this.outputPath, filePath); - - // avoid copying file over top of a previously written one - if (fs.existsSync(outputPath)) { - return; - } - - // TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT) - mkdirp.sync(path.dirname(outputPath)); - copyFileSync(inputPath, outputPath); - }) - } -} +const ColocatedTemplateProcessor = require('./colocated-broccoli-plugin'); module.exports = { name: require('./package').name, diff --git a/package.json b/package.json index 2573f6f6..aec077a5 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,10 @@ "license": "MIT", "author": "Jonathan Jackson & Chase McCarthy", "files": [ - "index.js", "addDependencyTracker.js", + "colocated-broccoli-plugin.js", "ember-addon-main.js", + "index.js", "utils.js" ], "main": "index.js", From 3aabb5047efe4e416d46f24334a8d3c59c2eb7f4 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 5 Sep 2019 10:55:54 -0400 Subject: [PATCH 09/29] Update linting config to allow async functions. We can now rely on Node 8+, so this is "safe". --- .eslintrc.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index de152a45..ac972687 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,7 @@ module.exports = { root: true, parserOptions: { - ecmaVersion: 2017, + ecmaVersion: 2018, sourceType: 'module' }, plugins: [ @@ -41,7 +41,7 @@ module.exports = { ], parserOptions: { sourceType: 'script', - ecmaVersion: 2015 + ecmaVersion: 2018 }, env: { browser: false, @@ -60,7 +60,7 @@ module.exports = { ], parserOptions: { sourceType: 'script', - ecmaVersion: 2015 + ecmaVersion: 2018 }, env: { browser: false, From d7a579b8a6075e9724bf2fab3ae45f5766b2ece2 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 5 Sep 2019 11:06:03 -0400 Subject: [PATCH 10/29] Add broccoli-debug logging. Running `BROCCOLI_DEBUG=ember-cli-htmlbars:* ember b` will now emit files into `DEBUG/ember-cli-htmlbars/` showing the various stages of compilation (input, after colocation processing, and final output). --- ember-addon-main.js | 21 ++++++++++++++++++--- package.json | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ember-addon-main.js b/ember-addon-main.js index 4e1be6e4..5b382977 100644 --- a/ember-addon-main.js +++ b/ember-addon-main.js @@ -11,6 +11,17 @@ module.exports = { parentRegistry: null, + _getDebugTree() { + if (!this._cachedDebugTree) { + // when this.parent === this.project, `this.parent.name` is a function 😭 + let parentName = typeof this.parent.name === 'function' ? this.parent.name() : this.parent.name; + + this._cachedDebugTree = require('broccoli-debug').buildDebugCallback(`ember-cli-htmlbars:${parentName}`); + } + + return this._cachedDebugTree; + }, + purgeModule(templateCompilerPath) { // ensure we get a fresh templateCompilerModuleInstance per ember-addon // instance NOTE: this is a quick hack, and will only work as long as @@ -44,16 +55,20 @@ module.exports = { return utils.template(templateCompiler, string); } + let debugTree = this._getDebugTree(); + registry.add('template', { name: 'ember-cli-htmlbars', ext: 'hbs', _addon: this, toTree(tree) { + let inputTree = debugTree(tree, '01-input'); + let htmlbarsOptions = this._addon.htmlbarsOptions(); - let TemplateCompiler = require('./index'); - let unifiedColocatedTemplates = new ColocatedTemplateProcessor(tree, { precompile }); + let unifiedColocatedTemplates = debugTree(new ColocatedTemplateProcessor(inputTree, { precompile }), '02-colocated-output'); - return new TemplateCompiler(unifiedColocatedTemplates, htmlbarsOptions); + let TemplateCompiler = require('./index'); + return debugTree(new TemplateCompiler(unifiedColocatedTemplates, htmlbarsOptions), '03-output'); }, precompile, diff --git a/package.json b/package.json index 1b7ca7b4..10e9d54e 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "test:node:debug": "mocha debug node-tests/*.js" }, "dependencies": { + "broccoli-debug": "^0.6.5", "broccoli-persistent-filter": "^2.3.1", "broccoli-plugin": "^2.0.0", "fs-copy-file-sync": "^1.1.1", From f7f3f47f539c1d41314906ebe44fed16d4cc20d0 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 5 Sep 2019 11:43:19 -0400 Subject: [PATCH 11/29] Start fleshing out basic testing infrastructure. --- node-tests/colocated-plugin-test.js | 139 ++++++++++++++++++++++++++++ package.json | 1 + yarn.lock | 2 +- 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 node-tests/colocated-plugin-test.js diff --git a/node-tests/colocated-plugin-test.js b/node-tests/colocated-plugin-test.js new file mode 100644 index 00000000..670a1c82 --- /dev/null +++ b/node-tests/colocated-plugin-test.js @@ -0,0 +1,139 @@ +'use strict'; + +const assert = require('assert'); +const ColocatedTemplateCompiler = require('../colocated-broccoli-plugin'); +const { createTempDir, createBuilder } = require('broccoli-test-helper'); +const { stripIndent } = require('common-tags'); + +describe('ColocatedTemplateCompiler', function() { + this.timeout(10000); + + let input, output; + + beforeEach(async function() { + input = await createTempDir(); + }); + + afterEach(async function() { + await input.dispose(); + + if (output) { + await output.dispose(); + } + }); + + it('works for template only component', async function() { + input.write({ + 'app-name-here': { + components: { + 'foo.hbs': `{{yield}}`, + }, + templates: { + 'application.hbs': `{{outlet}}`, + }, + }, + }); + + let tree = new ColocatedTemplateCompiler(input.path(), { + precompile(template) { + return JSON.stringify({ template }); + }, + }); + + output = createBuilder(tree); + await output.build(); + + assert.deepStrictEqual(output.read(), { + 'app-name-here': { + components: { + 'foo.js': stripIndent` + const templateOnlyComponent = Ember._templateOnlyComponent; + const setComponentTemplate = Ember._setComponentTemplate; + const TEMPLATE = {"template":"{{yield}}"}; + const CLASS = templateOnlyComponent(); + export default setComponentTemplate(TEMPLATE, CLASS); + `, + }, + templates: { + 'application.hbs': '{{outlet}}', + }, + }, + }); + }); + + it('works for component with template and class', async function() { + input.write({ + 'app-name-here': { + components: { + 'foo.hbs': `{{yield}}`, + 'foo.js': stripIndent` + import Component from '@glimmer/component'; + + export default class FooComponent extends Component {} + `, + }, + templates: { + 'application.hbs': `{{outlet}}`, + }, + }, + }); + + let tree = new ColocatedTemplateCompiler(input.path(), { + precompile(template) { + return JSON.stringify({ template }); + }, + }); + + output = createBuilder(tree); + await output.build(); + + assert.deepStrictEqual(output.read(), { + 'app-name-here': { + components: { + 'foo.js': stripIndent` + import Component from '@glimmer/component'; + + const CLASS = class FooComponent extends Component {} + const setComponentTemplate = Ember._setComponentTemplate; + const TEMPLATE = {"template":"{{yield}}"}; + export default setComponentTemplate(TEMPLATE, CLASS); + `, + }, + templates: { + 'application.hbs': '{{outlet}}', + }, + }, + }); + }); + + it('does nothing for "classic" location components', async function() { + input.write({ + 'app-name-here': { + components: { + 'foo.js': stripIndent` + import Component from '@glimmer/component'; + + export default class FooComponent extends Component {} + `, + }, + templates: { + 'application.hbs': `{{outlet}}`, + components: { + 'foo.hbs': `{{yield}}`, + } + }, + }, + }); + + let tree = new ColocatedTemplateCompiler(input.path(), { + precompile(template) { + return JSON.stringify({ template }); + }, + }); + + output = createBuilder(tree); + await output.build(); + + assert.deepStrictEqual(output.read(), input.read()); + }); +}); diff --git a/package.json b/package.json index 10e9d54e..4d680d90 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "broccoli-test-helper": "^2.0.0", "chai": "^4.2.0", "co": "^4.6.0", + "common-tags": "^1.8.0", "ember-cli": "github:ember-cli/ember-cli", "ember-cli-app-version": "^3.2.0", "ember-cli-babel": "^7.11.0", diff --git a/yarn.lock b/yarn.lock index 43d4e213..ab72fe51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2766,7 +2766,7 @@ commander@~2.17.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== -common-tags@^1.4.0: +common-tags@^1.4.0, common-tags@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== From 24e8ad6fda2512c87d3fac9dfdc813059a27e7ce Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 8 Sep 2019 21:45:14 -0400 Subject: [PATCH 12/29] yarn lint:js --fix Mostly fixes prettier --- .eslintrc.js | 6 +++--- lib/colocated-broccoli-plugin.js | 10 +++++----- lib/ember-addon-main.js | 19 ++++++++++++++----- node-tests/colocated-plugin-test.js | 4 ++-- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 29ef40c0..22749063 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,7 +2,7 @@ module.exports = { root: true, parserOptions: { ecmaVersion: 2018, - sourceType: 'module' + sourceType: 'module', }, plugins: ['ember', 'prettier'], extends: ['eslint:recommended', 'plugin:ember/recommended', 'plugin:prettier/recommended'], @@ -28,7 +28,7 @@ module.exports = { excludedFiles: ['addon/**', 'addon-test-support/**', 'app/**', 'tests/dummy/app/**'], parserOptions: { sourceType: 'script', - ecmaVersion: 2018 + ecmaVersion: 2018, }, env: { browser: false, @@ -45,7 +45,7 @@ module.exports = { files: ['node-tests/**/*.js'], parserOptions: { sourceType: 'script', - ecmaVersion: 2018 + ecmaVersion: 2018, }, env: { browser: false, diff --git a/lib/colocated-broccoli-plugin.js b/lib/colocated-broccoli-plugin.js index 221c9352..8f154224 100644 --- a/lib/colocated-broccoli-plugin.js +++ b/lib/colocated-broccoli-plugin.js @@ -56,7 +56,9 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { if (hasJSFile) { // add the template, call setComponentTemplate - jsContents = fs.readFileSync(path.join(this.inputPaths[0], possibleJSPath), { encoding: 'utf8' }); + jsContents = fs.readFileSync(path.join(this.inputPaths[0], possibleJSPath), { + encoding: 'utf8', + }); if (jsContents.includes('export default')) { jsContents = jsContents.replace('export default', 'const CLASS ='); @@ -78,7 +80,6 @@ const CLASS = templateOnlyComponent(); export default setComponentTemplate(TEMPLATE, CLASS);`; } - let outputPath = path.join(this.outputPath, possibleJSPath); // TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT) @@ -98,7 +99,6 @@ export default setComponentTemplate(TEMPLATE, CLASS);`; // TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT) mkdirp.sync(path.dirname(outputPath)); copyFileSync(inputPath, outputPath); - }) + }); } -} - +}; diff --git a/lib/ember-addon-main.js b/lib/ember-addon-main.js index 0b345dcd..16bccaa6 100644 --- a/lib/ember-addon-main.js +++ b/lib/ember-addon-main.js @@ -14,9 +14,12 @@ module.exports = { _getDebugTree() { if (!this._cachedDebugTree) { // when this.parent === this.project, `this.parent.name` is a function 😭 - let parentName = typeof this.parent.name === 'function' ? this.parent.name() : this.parent.name; + let parentName = + typeof this.parent.name === 'function' ? this.parent.name() : this.parent.name; - this._cachedDebugTree = require('broccoli-debug').buildDebugCallback(`ember-cli-htmlbars:${parentName}`); + this._cachedDebugTree = require('broccoli-debug').buildDebugCallback( + `ember-cli-htmlbars:${parentName}` + ); } return this._cachedDebugTree; @@ -30,7 +33,7 @@ module.exports = { let htmlbarsOptions = this.htmlbarsOptions(); let templateCompiler = htmlbarsOptions.templateCompiler; return utils.template(templateCompiler, string); - } + }; let debugTree = this._getDebugTree(); @@ -42,10 +45,16 @@ module.exports = { let inputTree = debugTree(tree, '01-input'); let htmlbarsOptions = this._addon.htmlbarsOptions(); - let unifiedColocatedTemplates = debugTree(new ColocatedTemplateProcessor(inputTree, { precompile }), '02-colocated-output'); + let unifiedColocatedTemplates = debugTree( + new ColocatedTemplateProcessor(inputTree, { precompile }), + '02-colocated-output' + ); let TemplateCompiler = require('./template-compiler-plugin'); - return debugTree(new TemplateCompiler(unifiedColocatedTemplates, htmlbarsOptions), '03-output'); + return debugTree( + new TemplateCompiler(unifiedColocatedTemplates, htmlbarsOptions), + '03-output' + ); }, precompile, diff --git a/node-tests/colocated-plugin-test.js b/node-tests/colocated-plugin-test.js index 670a1c82..16476e9e 100644 --- a/node-tests/colocated-plugin-test.js +++ b/node-tests/colocated-plugin-test.js @@ -1,7 +1,7 @@ 'use strict'; const assert = require('assert'); -const ColocatedTemplateCompiler = require('../colocated-broccoli-plugin'); +const ColocatedTemplateCompiler = require('../lib/colocated-broccoli-plugin'); const { createTempDir, createBuilder } = require('broccoli-test-helper'); const { stripIndent } = require('common-tags'); @@ -120,7 +120,7 @@ describe('ColocatedTemplateCompiler', function() { 'application.hbs': `{{outlet}}`, components: { 'foo.hbs': `{{yield}}`, - } + }, }, }, }); From fb2808a947f48047867dda96c6fdef798e221320 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 5 Sep 2019 15:40:26 -0400 Subject: [PATCH 13/29] Extract helper method to build merged component JS contents. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes testing easier (at least it makes my mental overhead somewhat less while testing 😀) --- lib/colocated-broccoli-plugin.js | 32 ++++++++++++++++++++------------ package.json | 2 +- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/lib/colocated-broccoli-plugin.js b/lib/colocated-broccoli-plugin.js index 8f154224..58b67f19 100644 --- a/lib/colocated-broccoli-plugin.js +++ b/lib/colocated-broccoli-plugin.js @@ -6,6 +6,7 @@ const copyFileSync = require('fs-copy-file-sync'); const path = require('path'); const walkSync = require('walk-sync'); const Plugin = require('broccoli-plugin'); +const { stripIndents } = require('common-tags'); module.exports = class ColocatedTemplateProcessor extends Plugin { constructor(tree, options) { @@ -14,6 +15,24 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { this.options = options; } + _transformExistingComponent(filePath, jsContents, templateContents) { + // TODO: deal with hygiene + if (!jsContents.includes('export default')) { + let message = `${filePath}\` does not contain a \`default export\`. Did you forget to export the component class?`; + return `${jsContents}\nthrow new Error(${JSON.stringify(message)})`; + } + + let modifiedJS = jsContents.replace('export default', 'const CLASS ='); + + let output = stripIndents` + ${modifiedJS} + const setComponentTemplate = Ember._setComponentTemplate; + const TEMPLATE = ${this.options.precompile(templateContents)}; + export default setComponentTemplate(TEMPLATE, CLASS);`; + + return output; + } + build() { // TODO: do we need to pass through all files, or only template files? let files = walkSync(this.inputPaths[0], { directories: false }); @@ -52,7 +71,6 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { let templateContents = fs.readFileSync(inputPath, { encoding: 'utf8' }); let jsContents = null; - // TODO: deal with hygiene if (hasJSFile) { // add the template, call setComponentTemplate @@ -60,17 +78,7 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { encoding: 'utf8', }); - if (jsContents.includes('export default')) { - jsContents = jsContents.replace('export default', 'const CLASS ='); - } else { - let message = `${filePath}\` does not contain a \`default export\`. Did you forget to export the component class?`; - jsContents = `${jsContents}\nthrow new Error(${JSON.stringify(message)})`; - } - - jsContents = `${jsContents} -const setComponentTemplate = Ember._setComponentTemplate; -const TEMPLATE = ${this.options.precompile(templateContents)}; -export default setComponentTemplate(TEMPLATE, CLASS);`; + jsContents = this._transformExistingComponent(filePath, jsContents, templateContents); } else { // create JS file, use null component pattern jsContents = `const templateOnlyComponent = Ember._templateOnlyComponent; diff --git a/package.json b/package.json index 4490ff1f..330da819 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "broccoli-debug": "^0.6.5", "broccoli-persistent-filter": "^2.3.1", "broccoli-plugin": "^2.0.0", + "common-tags": "^1.8.0", "fs-copy-file-sync": "^1.1.1", "hash-for-dep": "^1.5.1", "heimdalljs-logger": "^0.1.10", @@ -48,7 +49,6 @@ "broccoli-test-helper": "^2.0.0", "chai": "^4.2.0", "co": "^4.6.0", - "common-tags": "^1.8.0", "ember-cli": "~3.12.0", "ember-cli-app-version": "^3.2.0", "ember-cli-babel": "^7.11.0", From f5a0b01cae00d9a8529157d49dcab6821b11584b Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 6 Sep 2019 09:15:48 -0400 Subject: [PATCH 14/29] Add TODO comments for additional tasks. --- lib/ember-addon-main.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/ember-addon-main.js b/lib/ember-addon-main.js index 16bccaa6..95f5b5e5 100644 --- a/lib/ember-addon-main.js +++ b/lib/ember-addon-main.js @@ -11,6 +11,13 @@ module.exports = { parentRegistry: null, + _shouldColocateTemplates() { + //TODO: only do colocated processing when using: + // * ember-cli-babel@7.11+ + // * ember-cli@3.12+ + return true; + }, + _getDebugTree() { if (!this._cachedDebugTree) { // when this.parent === this.project, `this.parent.name` is a function 😭 @@ -29,6 +36,7 @@ module.exports = { // ensure that broccoli-ember-hbs-template-compiler is not processing hbs files registry.remove('template', 'broccoli-ember-hbs-template-compiler'); + // TODO: pass through options into precompiler (e.g. `moduleName`, `parserOptions: { srcName }`, etc) let precompile = string => { let htmlbarsOptions = this.htmlbarsOptions(); let templateCompiler = htmlbarsOptions.templateCompiler; @@ -37,6 +45,8 @@ module.exports = { let debugTree = this._getDebugTree(); + let shouldColocateTemplates = this._shouldColocateTemplates(); + registry.add('template', { name: 'ember-cli-htmlbars', ext: 'hbs', @@ -45,16 +55,16 @@ module.exports = { let inputTree = debugTree(tree, '01-input'); let htmlbarsOptions = this._addon.htmlbarsOptions(); - let unifiedColocatedTemplates = debugTree( - new ColocatedTemplateProcessor(inputTree, { precompile }), - '02-colocated-output' - ); + + if (shouldColocateTemplates) { + inputTree = debugTree( + new ColocatedTemplateProcessor(inputTree, { precompile }), + '02-colocated-output' + ); + } let TemplateCompiler = require('./template-compiler-plugin'); - return debugTree( - new TemplateCompiler(unifiedColocatedTemplates, htmlbarsOptions), - '03-output' - ); + return debugTree(new TemplateCompiler(inputTree, htmlbarsOptions), '03-output'); }, precompile, From 6de52e522b09127f499cdbc2d3a0da175289f8e1 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 6 Sep 2019 09:24:18 -0400 Subject: [PATCH 15/29] Flesh out more tests. --- lib/colocated-broccoli-plugin.js | 4 +- node-tests/colocated-plugin-test.js | 79 +++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/lib/colocated-broccoli-plugin.js b/lib/colocated-broccoli-plugin.js index 58b67f19..a2122365 100644 --- a/lib/colocated-broccoli-plugin.js +++ b/lib/colocated-broccoli-plugin.js @@ -18,8 +18,8 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { _transformExistingComponent(filePath, jsContents, templateContents) { // TODO: deal with hygiene if (!jsContents.includes('export default')) { - let message = `${filePath}\` does not contain a \`default export\`. Did you forget to export the component class?`; - return `${jsContents}\nthrow new Error(${JSON.stringify(message)})`; + let message = `\`${filePath}\` does not contain a \`default export\`. Did you forget to export the component class?`; + return `${jsContents}\nthrow new Error(${JSON.stringify(message)});`; } let modifiedJS = jsContents.replace('export default', 'const CLASS ='); diff --git a/node-tests/colocated-plugin-test.js b/node-tests/colocated-plugin-test.js index 16476e9e..59ccc097 100644 --- a/node-tests/colocated-plugin-test.js +++ b/node-tests/colocated-plugin-test.js @@ -136,4 +136,83 @@ describe('ColocatedTemplateCompiler', function() { assert.deepStrictEqual(output.read(), input.read()); }); + + it('it works if input is manually using setComponentTemplate - no colocated template exists', async function() { + input.write({ + 'app-name-here': { + components: { + 'foo.js': stripIndent` + import Component from '@glimmer/component'; + import { setComponentTemplate } from '@ember/component'; + import hbs from 'ember-cli-htmlbars-inline-precompile'; + + export default class FooComponent extends Component {} + setComponentTemplate(FooComponent, hbs\`sometemplate\`); + `, + }, + templates: { + 'application.hbs': `{{outlet}}`, + }, + }, + }); + + let tree = new ColocatedTemplateCompiler(input.path(), { + precompile(template) { + return JSON.stringify({ template }); + }, + }); + + output = createBuilder(tree); + await output.build(); + + assert.deepStrictEqual(output.read(), { + 'app-name-here': { + components: { + 'foo.js': stripIndent` + import Component from '@glimmer/component'; + import { setComponentTemplate } from '@ember/component'; + import hbs from 'ember-cli-htmlbars-inline-precompile'; + + export default class FooComponent extends Component {} + setComponentTemplate(FooComponent, hbs\`sometemplate\`); + `, + }, + templates: { + 'application.hbs': '{{outlet}}', + }, + }, + }); + }); + + it('emits an error when a default export is not present in a component JS file', async function() { + input.write({ + 'app-name-here': { + components: { + 'foo.hbs': `{{yield}}`, + 'foo.js': stripIndent` + export function whatever() {} + `, + }, + }, + }); + + let tree = new ColocatedTemplateCompiler(input.path(), { + precompile(template) { + return JSON.stringify({ template }); + }, + }); + + output = createBuilder(tree); + await output.build(); + + assert.deepStrictEqual(output.read(), { + 'app-name-here': { + components: { + 'foo.js': stripIndent` + export function whatever() {}\nthrow new Error("\`app-name-here/components/foo.hbs\` does not contain a \`default export\`. Did you forget to export the component class?"); + `, + }, + }, + }); + }); }); From 5709c0fca85e4a8a7c9a955eb7ba13938436d21c Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 6 Sep 2019 15:10:52 -0400 Subject: [PATCH 16/29] Avoid adding the import for setComponentTemplate. This will be done by an AST plugin instead. --- lib/colocated-broccoli-plugin.js | 23 +++++++++++------------ node-tests/colocated-plugin-test.js | 10 ++++++---- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/colocated-broccoli-plugin.js b/lib/colocated-broccoli-plugin.js index a2122365..ee55b688 100644 --- a/lib/colocated-broccoli-plugin.js +++ b/lib/colocated-broccoli-plugin.js @@ -16,19 +16,16 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { } _transformExistingComponent(filePath, jsContents, templateContents) { - // TODO: deal with hygiene if (!jsContents.includes('export default')) { let message = `\`${filePath}\` does not contain a \`default export\`. Did you forget to export the component class?`; return `${jsContents}\nthrow new Error(${JSON.stringify(message)});`; } - let modifiedJS = jsContents.replace('export default', 'const CLASS ='); - + // TODO: deal with hygiene? let output = stripIndents` - ${modifiedJS} - const setComponentTemplate = Ember._setComponentTemplate; - const TEMPLATE = ${this.options.precompile(templateContents)}; - export default setComponentTemplate(TEMPLATE, CLASS);`; + import hbs from 'ember-cli-htmlbars-inline-precompile'; + const __COLOCATED_TEMPLATE__ = hbs\`${templateContents}\`; + ${jsContents}`; return output; } @@ -81,11 +78,13 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { jsContents = this._transformExistingComponent(filePath, jsContents, templateContents); } else { // create JS file, use null component pattern - jsContents = `const templateOnlyComponent = Ember._templateOnlyComponent; -const setComponentTemplate = Ember._setComponentTemplate; -const TEMPLATE = ${this.options.precompile(templateContents)}; -const CLASS = templateOnlyComponent(); -export default setComponentTemplate(TEMPLATE, CLASS);`; + + jsContents = stripIndents` + import templateOnly from '@ember/component/template-only'; + import hbs from 'ember-cli-htmlbars-inline-precompile'; + const __COLOCATED_TEMPLATE__ = hbs\`${templateContents}\`; + + export default templateOnly();` } let outputPath = path.join(this.outputPath, possibleJSPath); diff --git a/node-tests/colocated-plugin-test.js b/node-tests/colocated-plugin-test.js index 59ccc097..0b3bd00f 100644 --- a/node-tests/colocated-plugin-test.js +++ b/node-tests/colocated-plugin-test.js @@ -91,12 +91,12 @@ describe('ColocatedTemplateCompiler', function() { 'app-name-here': { components: { 'foo.js': stripIndent` + import { setComponentTemplate } from '@ember/component'; + import hbs from 'ember-cli-htmlbars-inline-precompile'; + const __COLOCATED_TEMPLATE__ = hbs\`{{yield}}\`; import Component from '@glimmer/component'; - const CLASS = class FooComponent extends Component {} - const setComponentTemplate = Ember._setComponentTemplate; - const TEMPLATE = {"template":"{{yield}}"}; - export default setComponentTemplate(TEMPLATE, CLASS); + export default class FooComponent extends Component {} `, }, templates: { @@ -215,4 +215,6 @@ describe('ColocatedTemplateCompiler', function() { }, }); }); + + it('does not break class decorator usage'); }); From b44e14be265aefec3c4f85698817ac842738e426 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 8 Sep 2019 22:00:21 -0400 Subject: [PATCH 17/29] yarn lint:js --fix --- lib/colocated-broccoli-plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/colocated-broccoli-plugin.js b/lib/colocated-broccoli-plugin.js index ee55b688..f29a7edd 100644 --- a/lib/colocated-broccoli-plugin.js +++ b/lib/colocated-broccoli-plugin.js @@ -84,7 +84,7 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { import hbs from 'ember-cli-htmlbars-inline-precompile'; const __COLOCATED_TEMPLATE__ = hbs\`${templateContents}\`; - export default templateOnly();` + export default templateOnly();`; } let outputPath = path.join(this.outputPath, possibleJSPath); From bb4ad58b08d9c20817b5860b89628353d21eaaa4 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 8 Sep 2019 22:16:09 -0400 Subject: [PATCH 18/29] Fix colocated-broccoli-plugin tests --- lib/colocated-broccoli-plugin.js | 15 ++++++--------- node-tests/colocated-plugin-test.js | 13 ++++++------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/lib/colocated-broccoli-plugin.js b/lib/colocated-broccoli-plugin.js index f29a7edd..b89aa89e 100644 --- a/lib/colocated-broccoli-plugin.js +++ b/lib/colocated-broccoli-plugin.js @@ -6,7 +6,7 @@ const copyFileSync = require('fs-copy-file-sync'); const path = require('path'); const walkSync = require('walk-sync'); const Plugin = require('broccoli-plugin'); -const { stripIndents } = require('common-tags'); +const { stripIndent } = require('common-tags'); module.exports = class ColocatedTemplateProcessor extends Plugin { constructor(tree, options) { @@ -22,12 +22,9 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { } // TODO: deal with hygiene? - let output = stripIndents` - import hbs from 'ember-cli-htmlbars-inline-precompile'; - const __COLOCATED_TEMPLATE__ = hbs\`${templateContents}\`; - ${jsContents}`; + let prefix = `import { hbs } from 'ember-cli-htmlbars';\nconst __COLOCATED_TEMPLATE__ = hbs\`${templateContents}\`;\n`; - return output; + return prefix + jsContents; } build() { @@ -79,12 +76,12 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { } else { // create JS file, use null component pattern - jsContents = stripIndents` + jsContents = stripIndent` import templateOnly from '@ember/component/template-only'; - import hbs from 'ember-cli-htmlbars-inline-precompile'; + import { hbs } from 'ember-cli-htmlbars'; const __COLOCATED_TEMPLATE__ = hbs\`${templateContents}\`; - export default templateOnly();`; + export default templateOnly();\n`; } let outputPath = path.join(this.outputPath, possibleJSPath); diff --git a/node-tests/colocated-plugin-test.js b/node-tests/colocated-plugin-test.js index 0b3bd00f..18ab75e7 100644 --- a/node-tests/colocated-plugin-test.js +++ b/node-tests/colocated-plugin-test.js @@ -47,11 +47,11 @@ describe('ColocatedTemplateCompiler', function() { 'app-name-here': { components: { 'foo.js': stripIndent` - const templateOnlyComponent = Ember._templateOnlyComponent; - const setComponentTemplate = Ember._setComponentTemplate; - const TEMPLATE = {"template":"{{yield}}"}; - const CLASS = templateOnlyComponent(); - export default setComponentTemplate(TEMPLATE, CLASS); + import templateOnly from '@ember/component/template-only'; + import { hbs } from 'ember-cli-htmlbars'; + const __COLOCATED_TEMPLATE__ = hbs\`{{yield}}\`; + + export default templateOnly(); `, }, templates: { @@ -91,8 +91,7 @@ describe('ColocatedTemplateCompiler', function() { 'app-name-here': { components: { 'foo.js': stripIndent` - import { setComponentTemplate } from '@ember/component'; - import hbs from 'ember-cli-htmlbars-inline-precompile'; + import { hbs } from 'ember-cli-htmlbars'; const __COLOCATED_TEMPLATE__ = hbs\`{{yield}}\`; import Component from '@glimmer/component'; From 9362a4cbec024db1f11e0532c98b2f59a8326afa Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 8 Sep 2019 22:39:06 -0400 Subject: [PATCH 19/29] Add babel plugin to add setComponentTemplate usage. --- lib/colocated-babel-plugin.js | 61 +++++++++++++++++++++++++++++++++++ lib/ember-addon-main.js | 13 ++++++-- package.json | 1 + 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 lib/colocated-babel-plugin.js diff --git a/lib/colocated-babel-plugin.js b/lib/colocated-babel-plugin.js new file mode 100644 index 00000000..3fb56da7 --- /dev/null +++ b/lib/colocated-babel-plugin.js @@ -0,0 +1,61 @@ +// For ease of debuggin / tweaking: +// https://astexplorer.net/#/gist/bcca584efdab6c981a75618642c76a22/1e1d262eaeb47b7da66150e0781a02b96e597b25 +module.exports = function(babel) { + let t = babel.types; + + return { + name: 'ember-cli-htmlbars-colocation-template', + + visitor: { + VariableDeclarator(path, state) { + if (path.node.id.name === '__COLOCATED_TEMPLATE__') { + state.colocatedTemplateFound = true; + } + }, + + ExportDefaultDeclaration(path, state) { + if (!state.colocatedTemplateFound) { + return; + } + + let defaultExportDeclaration = path.node.declaration; + let setComponentTemplateMemberExpression = t.memberExpression( + t.identifier('Ember'), + t.identifier('_setComponentTemplate') + ); + let colocatedTemplateIdentifier = t.identifier('__COLOCATED_TEMPLATE__'); + + if (defaultExportDeclaration.type === 'ClassDeclaration') { + // when the default export is a ClassDeclaration with an `id`, + // wrapping it in a CallExpression would remove that class from the + // local scope which would cause issues for folks using the declared + // name _after_ the export + if (defaultExportDeclaration.id !== null) { + path.parent.body.push( + t.expressionStatement( + t.callExpression(setComponentTemplateMemberExpression, [ + defaultExportDeclaration.id, + colocatedTemplateIdentifier, + ]) + ) + ); + } else { + path.node.declaration = t.callExpression(setComponentTemplateMemberExpression, [ + colocatedTemplateIdentifier, + t.classExpression( + null, + defaultExportDeclaration.superClass, + defaultExportDeclaration.body + ), + ]); + } + } else { + path.node.declaration = t.callExpression(setComponentTemplateMemberExpression, [ + colocatedTemplateIdentifier, + defaultExportDeclaration, + ]); + } + }, + }, + }; +}; diff --git a/lib/ember-addon-main.js b/lib/ember-addon-main.js index 95f5b5e5..3424b0dd 100644 --- a/lib/ember-addon-main.js +++ b/lib/ember-addon-main.js @@ -5,6 +5,7 @@ const utils = require('./utils'); const ColocatedTemplateProcessor = require('./colocated-broccoli-plugin'); const debugGenerator = require('heimdalljs-logger'); const logger = debugGenerator('ember-cli-htmlbars'); +const { hasPlugin, addPlugin } = require('ember-cli-babel-plugin-helpers'); module.exports = { name: require('../package').name, @@ -85,7 +86,7 @@ module.exports = { // add the babel-plugin-htmlbars-inline-precompile to the list of plugins // used by `ember-cli-babel` addon - if (!this._isBabelPluginRegistered(babelPlugins)) { + if (!this._isInlinePrecompileBabelPluginRegistered(babelPlugins)) { let pluginWrappers = this.astPlugins(); let templateCompilerPath = this.templateCompilerPath(); let pluginInfo = utils.setupPlugins(pluginWrappers); @@ -149,6 +150,14 @@ module.exports = { babelPlugins.push(htmlBarsPlugin); } } + + if (this._shouldColocateTemplates()) { + let colocatedPluginPath = require.resolve('./colocated-babel-plugin'); + + if (!hasPlugin(babelPlugins, colocatedPluginPath)) { + addPlugin(babelPlugins, colocatedPluginPath); + } + } }, /** @@ -158,7 +167,7 @@ module.exports = { * For non parallel api, check the 'modules' to see if it contains the babel plugin * @param {*} plugins */ - _isBabelPluginRegistered(plugins) { + _isInlinePrecompileBabelPluginRegistered(plugins) { return plugins.some(plugin => { if (Array.isArray(plugin)) { return plugin[0] === require.resolve('babel-plugin-htmlbars-inline-precompile'); diff --git a/package.json b/package.json index 330da819..8cf06459 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "broccoli-persistent-filter": "^2.3.1", "broccoli-plugin": "^2.0.0", "common-tags": "^1.8.0", + "ember-cli-babel-plugin-helpers": "^1.1.0", "fs-copy-file-sync": "^1.1.1", "hash-for-dep": "^1.5.1", "heimdalljs-logger": "^0.1.10", From 952287b9a91e31a98758c18ae39f07ee744f7941 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 9 Sep 2019 08:53:42 -0400 Subject: [PATCH 20/29] Simplify implementation / reduce duplication. --- lib/colocated-broccoli-plugin.js | 31 ++++++++++------------------- node-tests/colocated-plugin-test.js | 8 ++++---- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/lib/colocated-broccoli-plugin.js b/lib/colocated-broccoli-plugin.js index b89aa89e..8432a422 100644 --- a/lib/colocated-broccoli-plugin.js +++ b/lib/colocated-broccoli-plugin.js @@ -6,7 +6,6 @@ const copyFileSync = require('fs-copy-file-sync'); const path = require('path'); const walkSync = require('walk-sync'); const Plugin = require('broccoli-plugin'); -const { stripIndent } = require('common-tags'); module.exports = class ColocatedTemplateProcessor extends Plugin { constructor(tree, options) { @@ -15,18 +14,6 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { this.options = options; } - _transformExistingComponent(filePath, jsContents, templateContents) { - if (!jsContents.includes('export default')) { - let message = `\`${filePath}\` does not contain a \`default export\`. Did you forget to export the component class?`; - return `${jsContents}\nthrow new Error(${JSON.stringify(message)});`; - } - - // TODO: deal with hygiene? - let prefix = `import { hbs } from 'ember-cli-htmlbars';\nconst __COLOCATED_TEMPLATE__ = hbs\`${templateContents}\`;\n`; - - return prefix + jsContents; - } - build() { // TODO: do we need to pass through all files, or only template files? let files = walkSync(this.inputPaths[0], { directories: false }); @@ -65,6 +52,9 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { let templateContents = fs.readFileSync(inputPath, { encoding: 'utf8' }); let jsContents = null; + // TODO: deal with hygiene? + let prefix = `import { hbs } from 'ember-cli-htmlbars';\nconst __COLOCATED_TEMPLATE__ = hbs\`${templateContents}\`;\n`; + if (hasJSFile) { // add the template, call setComponentTemplate @@ -72,18 +62,19 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { encoding: 'utf8', }); - jsContents = this._transformExistingComponent(filePath, jsContents, templateContents); + if (!jsContents.includes('export default')) { + let message = `\`${filePath}\` does not contain a \`default export\`. Did you forget to export the component class?`; + jsContents = `${jsContents}\nthrow new Error(${JSON.stringify(message)});`; + prefix = ''; + } } else { // create JS file, use null component pattern - jsContents = stripIndent` - import templateOnly from '@ember/component/template-only'; - import { hbs } from 'ember-cli-htmlbars'; - const __COLOCATED_TEMPLATE__ = hbs\`${templateContents}\`; - - export default templateOnly();\n`; + jsContents = `import templateOnly from '@ember/component/template-only';\n\nexport default templateOnly();\n`; } + jsContents = prefix + jsContents; + let outputPath = path.join(this.outputPath, possibleJSPath); // TODO: don't speculatively mkdirSync (likely do in a try/catch with ENOENT) diff --git a/node-tests/colocated-plugin-test.js b/node-tests/colocated-plugin-test.js index 18ab75e7..9a97b453 100644 --- a/node-tests/colocated-plugin-test.js +++ b/node-tests/colocated-plugin-test.js @@ -46,13 +46,13 @@ describe('ColocatedTemplateCompiler', function() { assert.deepStrictEqual(output.read(), { 'app-name-here': { components: { - 'foo.js': stripIndent` - import templateOnly from '@ember/component/template-only'; + 'foo.js': + stripIndent` import { hbs } from 'ember-cli-htmlbars'; const __COLOCATED_TEMPLATE__ = hbs\`{{yield}}\`; + import templateOnly from '@ember/component/template-only'; - export default templateOnly(); - `, + export default templateOnly();` + '\n', }, templates: { 'application.hbs': '{{outlet}}', From cfa93e364e20d94818de66e00eee29de574b14fa Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 9 Sep 2019 09:11:05 -0400 Subject: [PATCH 21/29] Make requires more lazy. No need to require / load build related things when not building... --- lib/ember-addon-main.js | 10 +++++----- lib/utils.js | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/ember-addon-main.js b/lib/ember-addon-main.js index 3424b0dd..7cb7803c 100644 --- a/lib/ember-addon-main.js +++ b/lib/ember-addon-main.js @@ -2,10 +2,7 @@ const path = require('path'); const utils = require('./utils'); -const ColocatedTemplateProcessor = require('./colocated-broccoli-plugin'); -const debugGenerator = require('heimdalljs-logger'); -const logger = debugGenerator('ember-cli-htmlbars'); -const { hasPlugin, addPlugin } = require('ember-cli-babel-plugin-helpers'); +const logger = require('heimdalljs-logger')('ember-cli-htmlbars'); module.exports = { name: require('../package').name, @@ -58,13 +55,15 @@ module.exports = { let htmlbarsOptions = this._addon.htmlbarsOptions(); if (shouldColocateTemplates) { + const ColocatedTemplateProcessor = require('./colocated-broccoli-plugin'); + inputTree = debugTree( new ColocatedTemplateProcessor(inputTree, { precompile }), '02-colocated-output' ); } - let TemplateCompiler = require('./template-compiler-plugin'); + const TemplateCompiler = require('./template-compiler-plugin'); return debugTree(new TemplateCompiler(inputTree, htmlbarsOptions), '03-output'); }, @@ -152,6 +151,7 @@ module.exports = { } if (this._shouldColocateTemplates()) { + const { hasPlugin, addPlugin } = require('ember-cli-babel-plugin-helpers'); let colocatedPluginPath = require.resolve('./colocated-babel-plugin'); if (!hasPlugin(babelPlugins, colocatedPluginPath)) { diff --git a/lib/utils.js b/lib/utils.js index 12e9b790..3391042a 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -2,7 +2,6 @@ const fs = require('fs'); const path = require('path'); -const HTMLBarsInlinePrecompilePlugin = require.resolve('babel-plugin-htmlbars-inline-precompile'); const hashForDep = require('hash-for-dep'); const debugGenerator = require('heimdalljs-logger'); const logger = debugGenerator('ember-cli-htmlbars'); @@ -136,12 +135,13 @@ function setup(pluginInfo, options) { precompile.baseDir = () => path.resolve(__dirname, '..'); precompile.cacheKey = () => cacheKey; - let precompileInlineHTMLBarsPlugin = [ - HTMLBarsInlinePrecompilePlugin, + let plugin = [ + require.resolve('babel-plugin-htmlbars-inline-precompile'), { precompile, modules: options.modules }, + 'ember-cli-htmlbars:inline-precompile', ]; - return precompileInlineHTMLBarsPlugin; + return plugin; } function makeCacheKey(templateCompilerPath, pluginInfo, extra) { From eba43a7b63e0fcb3d96b4d7d34179a48164a1dad Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 9 Sep 2019 09:11:38 -0400 Subject: [PATCH 22/29] Add proper guard for using colocation. --- lib/ember-addon-main.js | 26 ++++++++++++++++++++++---- package.json | 1 + 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/ember-addon-main.js b/lib/ember-addon-main.js index 7cb7803c..a58927ae 100644 --- a/lib/ember-addon-main.js +++ b/lib/ember-addon-main.js @@ -10,10 +10,28 @@ module.exports = { parentRegistry: null, _shouldColocateTemplates() { - //TODO: only do colocated processing when using: - // * ember-cli-babel@7.11+ - // * ember-cli@3.12+ - return true; + if (this._cachedShouldColocateTemplates) { + return this._cachedShouldColocateTemplates; + } + + const semver = require('semver'); + + let babel = this.parent.addons.find(a => a.name === 'ember-cli-babel'); + let hasBabel = babel !== undefined; + let babelVersion = hasBabel && babel.pkg.version; + + // using this.project.emberCLIVersion() allows us to avoid issues when `npm + // link` is used; if this addon were linked and we did something like + // `require('ember-cli/package').version` we would get our own ember-cli + // version **not** the one in use currently + let emberCLIVersion = this.project.emberCLIVersion(); + + let hasValidBabelVersion = hasBabel && semver.gte(babelVersion, '7.11.0'); + let hasValidEmberCLIVersion = semver.gte(emberCLIVersion, '3.12.0-beta.2'); + + this._cachedShouldColocateTemplates = hasValidBabelVersion && hasValidEmberCLIVersion; + + return this._cachedShouldColocateTemplates; }, _getDebugTree() { diff --git a/package.json b/package.json index 8cf06459..2eff41b3 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "heimdalljs-logger": "^0.1.10", "json-stable-stringify": "^1.0.1", "mkdirp": "^0.5.1", + "semver": "^6.3.0", "strip-bom": "^3.0.0", "walk-sync": "^1.1.3" }, From 99ac97dcb92150957bf170256698239951966a64 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 9 Sep 2019 09:16:56 -0400 Subject: [PATCH 23/29] Refactor registry toTree setup. --- lib/colocated-broccoli-plugin.js | 2 -- lib/ember-addon-main.js | 29 +++++++++++------------------ 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/lib/colocated-broccoli-plugin.js b/lib/colocated-broccoli-plugin.js index 8432a422..bb285da5 100644 --- a/lib/colocated-broccoli-plugin.js +++ b/lib/colocated-broccoli-plugin.js @@ -10,8 +10,6 @@ const Plugin = require('broccoli-plugin'); module.exports = class ColocatedTemplateProcessor extends Plugin { constructor(tree, options) { super([tree], options); - - this.options = options; } build() { diff --git a/lib/ember-addon-main.js b/lib/ember-addon-main.js index a58927ae..a9827fc7 100644 --- a/lib/ember-addon-main.js +++ b/lib/ember-addon-main.js @@ -52,40 +52,33 @@ module.exports = { // ensure that broccoli-ember-hbs-template-compiler is not processing hbs files registry.remove('template', 'broccoli-ember-hbs-template-compiler'); - // TODO: pass through options into precompiler (e.g. `moduleName`, `parserOptions: { srcName }`, etc) - let precompile = string => { - let htmlbarsOptions = this.htmlbarsOptions(); - let templateCompiler = htmlbarsOptions.templateCompiler; - return utils.template(templateCompiler, string); - }; - - let debugTree = this._getDebugTree(); - - let shouldColocateTemplates = this._shouldColocateTemplates(); - registry.add('template', { name: 'ember-cli-htmlbars', ext: 'hbs', _addon: this, toTree(tree) { - let inputTree = debugTree(tree, '01-input'); - + let debugTree = this._addon._getDebugTree(); + let shouldColocateTemplates = this._addon._shouldColocateTemplates(); let htmlbarsOptions = this._addon.htmlbarsOptions(); + let inputTree = debugTree(tree, '01-input'); + if (shouldColocateTemplates) { const ColocatedTemplateProcessor = require('./colocated-broccoli-plugin'); - inputTree = debugTree( - new ColocatedTemplateProcessor(inputTree, { precompile }), - '02-colocated-output' - ); + inputTree = debugTree(new ColocatedTemplateProcessor(inputTree), '02-colocated-output'); } const TemplateCompiler = require('./template-compiler-plugin'); return debugTree(new TemplateCompiler(inputTree, htmlbarsOptions), '03-output'); }, - precompile, + precompile(string, options) { + let htmlbarsOptions = this._addon.htmlbarsOptions(); + let templateCompiler = htmlbarsOptions.templateCompiler; + + return utils.template(templateCompiler, string, options); + }, }); if (type === 'parent') { From 60b8ae925377d37ee057b63a462d185bd9a65f04 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 9 Sep 2019 11:15:28 -0400 Subject: [PATCH 24/29] Tweak comments in colocated-broccoli-plugin. --- lib/colocated-broccoli-plugin.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/colocated-broccoli-plugin.js b/lib/colocated-broccoli-plugin.js index bb285da5..dcc49baf 100644 --- a/lib/colocated-broccoli-plugin.js +++ b/lib/colocated-broccoli-plugin.js @@ -13,7 +13,6 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { } build() { - // TODO: do we need to pass through all files, or only template files? let files = walkSync(this.inputPaths[0], { directories: false }); let filesToCopy = []; @@ -24,6 +23,8 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { // TODO: why are these different? // Apps: my-app/components/foo.hbs, my-app/templates/components/foo.hbs // Addons: components/foo.js, templates/components/foo.hbs + // + // will be fixed by https://github.com/ember-cli/ember-cli/pull/8834 // TODO: make this more robust let isInsideComponentsFolder = From 2d58f11c0f2ec153a7747c98aae798da39c0cf17 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 9 Sep 2019 11:15:59 -0400 Subject: [PATCH 25/29] Ensure debugTree's are not "merged" for different invocations. --- lib/ember-addon-main.js | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/lib/ember-addon-main.js b/lib/ember-addon-main.js index a9827fc7..2a88f8ba 100644 --- a/lib/ember-addon-main.js +++ b/lib/ember-addon-main.js @@ -4,6 +4,8 @@ const path = require('path'); const utils = require('./utils'); const logger = require('heimdalljs-logger')('ember-cli-htmlbars'); +let registryInvocationCounter = 0; + module.exports = { name: require('../package').name, @@ -34,30 +36,22 @@ module.exports = { return this._cachedShouldColocateTemplates; }, - _getDebugTree() { - if (!this._cachedDebugTree) { - // when this.parent === this.project, `this.parent.name` is a function 😭 - let parentName = - typeof this.parent.name === 'function' ? this.parent.name() : this.parent.name; - - this._cachedDebugTree = require('broccoli-debug').buildDebugCallback( - `ember-cli-htmlbars:${parentName}` - ); - } - - return this._cachedDebugTree; - }, - setupPreprocessorRegistry(type, registry) { // ensure that broccoli-ember-hbs-template-compiler is not processing hbs files registry.remove('template', 'broccoli-ember-hbs-template-compiler'); + // when this.parent === this.project, `this.parent.name` is a function 😭 + let parentName = typeof this.parent.name === 'function' ? this.parent.name() : this.parent.name; + registry.add('template', { name: 'ember-cli-htmlbars', ext: 'hbs', _addon: this, toTree(tree) { - let debugTree = this._addon._getDebugTree(); + let debugTree = require('broccoli-debug').buildDebugCallback( + `ember-cli-htmlbars:${parentName}:tree-${registryInvocationCounter++}` + ); + let shouldColocateTemplates = this._addon._shouldColocateTemplates(); let htmlbarsOptions = this._addon.htmlbarsOptions(); From 9972294ece6de79d6c146fe3c4cb73cb001fd2ad Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 9 Sep 2019 11:27:37 -0400 Subject: [PATCH 26/29] Add tests for scoped addons. --- node-tests/colocated-plugin-test.js | 91 +++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/node-tests/colocated-plugin-test.js b/node-tests/colocated-plugin-test.js index 9a97b453..bd4a1f7d 100644 --- a/node-tests/colocated-plugin-test.js +++ b/node-tests/colocated-plugin-test.js @@ -105,6 +105,97 @@ describe('ColocatedTemplateCompiler', function() { }); }); + it('works for scoped addon using template only component', async function() { + input.write({ + '@scope-name': { + 'addon-name-here': { + components: { + 'foo.hbs': `{{yield}}`, + }, + templates: { + 'application.hbs': `{{outlet}}`, + }, + }, + }, + }); + + let tree = new ColocatedTemplateCompiler(input.path(), { + precompile(template) { + return JSON.stringify({ template }); + }, + }); + + output = createBuilder(tree); + await output.build(); + + assert.deepStrictEqual(output.read(), { + '@scope-name': { + 'addon-name-here': { + components: { + 'foo.js': + stripIndent` + import { hbs } from 'ember-cli-htmlbars'; + const __COLOCATED_TEMPLATE__ = hbs\`{{yield}}\`; + import templateOnly from '@ember/component/template-only'; + + export default templateOnly();` + '\n', + }, + templates: { + 'application.hbs': '{{outlet}}', + }, + }, + }, + }); + }); + + it('works for scoped addon using component with template and class', async function() { + input.write({ + '@scope-name': { + 'addon-name-here': { + components: { + 'foo.hbs': `{{yield}}`, + 'foo.js': stripIndent` + import Component from '@glimmer/component'; + + export default class FooComponent extends Component {} + `, + }, + templates: { + 'application.hbs': `{{outlet}}`, + }, + }, + }, + }); + + let tree = new ColocatedTemplateCompiler(input.path(), { + precompile(template) { + return JSON.stringify({ template }); + }, + }); + + output = createBuilder(tree); + await output.build(); + + assert.deepStrictEqual(output.read(), { + '@scope-name': { + 'addon-name-here': { + components: { + 'foo.js': stripIndent` + import { hbs } from 'ember-cli-htmlbars'; + const __COLOCATED_TEMPLATE__ = hbs\`{{yield}}\`; + import Component from '@glimmer/component'; + + export default class FooComponent extends Component {} + `, + }, + templates: { + 'application.hbs': '{{outlet}}', + }, + }, + }, + }); + }); + it('does nothing for "classic" location components', async function() { input.write({ 'app-name-here': { From db7e5f298a78e80cc6861c1a1777d1403419815a Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 9 Sep 2019 11:42:05 -0400 Subject: [PATCH 27/29] Only process colocated files from /components/ --- lib/colocated-broccoli-plugin.js | 33 +++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/colocated-broccoli-plugin.js b/lib/colocated-broccoli-plugin.js index dcc49baf..85d337a8 100644 --- a/lib/colocated-broccoli-plugin.js +++ b/lib/colocated-broccoli-plugin.js @@ -7,6 +7,24 @@ const path = require('path'); const walkSync = require('walk-sync'); const Plugin = require('broccoli-plugin'); +function detectRootName(files) { + let [first] = files; + let parts = first.split('/'); + + let root; + if (parts[0].startsWith('@')) { + root = parts.slice(0, 2).join('/'); + } else { + root = parts[0]; + } + + if (!files.every(f => f.startsWith(root))) { + root = null; + } + + return root; +} + module.exports = class ColocatedTemplateProcessor extends Plugin { constructor(tree, options) { super([tree], options); @@ -15,8 +33,17 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { build() { let files = walkSync(this.inputPaths[0], { directories: false }); + let root = detectRootName(files); + let filesToCopy = []; files.forEach(filePath => { + if (root === null) { + // do nothing, we cannot detect the proper root path for the app/addon + // being processed + filesToCopy.push(filePath); + return; + } + let filePathParts = path.parse(filePath); let inputPath = path.join(this.inputPaths[0], filePath); @@ -26,11 +53,7 @@ module.exports = class ColocatedTemplateProcessor extends Plugin { // // will be fixed by https://github.com/ember-cli/ember-cli/pull/8834 - // TODO: make this more robust - let isInsideComponentsFolder = - (filePath.includes('/components/') || filePath.startsWith('components/')) && - !filePath.includes('/templates/components/') && - !filePath.startsWith('templates/components'); + let isInsideComponentsFolder = filePath.startsWith(`${root}/components/`); // copy forward non-hbs files // TODO: don't copy .js files that will ultimately be overridden From 791bde491de84987e1b1f6c24931ca6a13a0632b Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sat, 14 Sep 2019 18:35:15 -0400 Subject: [PATCH 28/29] Fix setComponentTemplate argument ordering for native classes. --- lib/colocated-babel-plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/colocated-babel-plugin.js b/lib/colocated-babel-plugin.js index 3fb56da7..5f6dbf26 100644 --- a/lib/colocated-babel-plugin.js +++ b/lib/colocated-babel-plugin.js @@ -34,8 +34,8 @@ module.exports = function(babel) { path.parent.body.push( t.expressionStatement( t.callExpression(setComponentTemplateMemberExpression, [ - defaultExportDeclaration.id, colocatedTemplateIdentifier, + defaultExportDeclaration.id, ]) ) ); From 253503f1cda5bce173d65fd7b15de1f447cfa5e7 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 15 Sep 2019 13:13:22 -0400 Subject: [PATCH 29/29] Only opt-in to colocation when using octane edition. --- lib/ember-addon-main.js | 5 ++++- package.json | 1 + yarn.lock | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/ember-addon-main.js b/lib/ember-addon-main.js index 2a88f8ba..1c1a412f 100644 --- a/lib/ember-addon-main.js +++ b/lib/ember-addon-main.js @@ -3,6 +3,7 @@ const path = require('path'); const utils = require('./utils'); const logger = require('heimdalljs-logger')('ember-cli-htmlbars'); +const hasEdition = require('@ember/edition-utils').has; let registryInvocationCounter = 0; @@ -30,8 +31,10 @@ module.exports = { let hasValidBabelVersion = hasBabel && semver.gte(babelVersion, '7.11.0'); let hasValidEmberCLIVersion = semver.gte(emberCLIVersion, '3.12.0-beta.2'); + let hasOctane = hasEdition('octane'); - this._cachedShouldColocateTemplates = hasValidBabelVersion && hasValidEmberCLIVersion; + this._cachedShouldColocateTemplates = + hasOctane && hasValidBabelVersion && hasValidEmberCLIVersion; return this._cachedShouldColocateTemplates; }, diff --git a/package.json b/package.json index 2eff41b3..36c7a726 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "test:node:debug": "mocha debug node-tests/*.js" }, "dependencies": { + "@ember/edition-utils": "^1.1.1", "babel-plugin-htmlbars-inline-precompile": "^2.1.0", "broccoli-debug": "^0.6.5", "broccoli-persistent-filter": "^2.3.1", diff --git a/yarn.lock b/yarn.lock index ce5bdb18..52364551 100644 --- a/yarn.lock +++ b/yarn.lock @@ -727,6 +727,11 @@ resolved "https://registry.yarnpkg.com/@ember-data/rfc395-data/-/rfc395-data-0.0.4.tgz#ecb86efdf5d7733a76ff14ea651a1b0ed1f8a843" integrity sha512-tGRdvgC9/QMQSuSuJV45xoyhI0Pzjm7A9o/MVVA3HakXIImJbbzx/k/6dO9CUEQXIyS2y0fW6C1XaYOG7rY0FQ== +"@ember/edition-utils@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@ember/edition-utils/-/edition-utils-1.1.1.tgz#d5732c3da593f202e6e1ac6dbee56a758242403f" + integrity sha512-GEhri78jdQp/xxPpM6z08KlB0wrHfnfrJ9dmQk7JeQ4XCiMzXsJci7yooQgg/IcTKCM/PxE/IkGCQAo80adMkw== + "@ember/optional-features@^0.7.0": version "0.7.0" resolved "https://registry.yarnpkg.com/@ember/optional-features/-/optional-features-0.7.0.tgz#f65a858007020ddfb8342f586112750c32abd2d9"