From a8a2010c9b0c0d1ef29f208a4ec9a9a16971d8e4 Mon Sep 17 00:00:00 2001 From: Chris LoPresto Date: Sun, 24 Jun 2018 17:24:44 -0400 Subject: [PATCH 1/5] Sketch out broccoli plugin to discover freestyle usage https://github.com/chrislopresto/ember-freestyle/issues/176 --- index.js | 83 ++++++++++++++++++- tests/acceptance/auto-discover-test.js | 16 ++++ .../components/x-bar/freestyle/component.js | 3 + .../components/x-bar/freestyle/template.hbs | 9 ++ 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 tests/acceptance/auto-discover-test.js create mode 100644 tests/dummy/app/components/x-bar/freestyle/component.js create mode 100644 tests/dummy/app/components/x-bar/freestyle/template.hbs diff --git a/index.js b/index.js index ce26769d..b2f20fe9 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,50 @@ 'use strict'; var mergeTrees = require('broccoli-merge-trees'); -var fs = require('fs'); +var fs = require('fs'); var flatiron = require('broccoli-flatiron'); var freestyleUsageSnippetFinder = require('./freestyle-usage-snippet-finder'); +var Funnel = require('broccoli-funnel'); +var Writer = require('broccoli-writer'); +var path = require('path'); +var glob = require('glob'); + +FreestyleDiscovery.prototype = Object.create(Writer.prototype); +FreestyleDiscovery.prototype.constructor = FreestyleDiscovery; + +function FreestyleDiscovery(inputTree, options) { + if (!(this instanceof FreestyleDiscovery)) { + return new FreestyleDiscovery(inputTree, options); + } + + this.inputTree = inputTree; + this.options = { + outputFile: options.outputFile, + componentNamePattern: `${options.appName}\/components\/(.*)\/component\.js$` + }; +} + +FreestyleDiscovery.prototype.write = function(readTree, destDir) { + var _this = this; + var componentPathPattern = '**/freestyle/component.js'; + var componentRegex = new RegExp(this.options.componentNamePattern); + + return readTree(this.inputTree).then(function(srcDir) { + var files = glob.sync(path.join(srcDir, componentPathPattern)); + var components = files.map((componentPath) => { + // Extract a freestyle component name that looks like: + // x-bar/freestyle + // from a componentPath that looks like: + // /Users/xxxxx/p/xxxxx/ember-freestyle/tmp/broccoli_merge_trees-output_path-7BiiNpHw.tmp/dummy/components/x-bar/freestyle/component.js + return componentRegex.exec(componentPath)[1]; + }); + + var output = `export default ${JSON.stringify(components)};`; + fs.mkdirSync(path.join(destDir, path.dirname(_this.options.outputFile))); + fs.writeFileSync(path.join(destDir, _this.options.outputFile), output); + }); +} + module.exports = { name: 'ember-freestyle', @@ -27,6 +68,24 @@ module.exports = { return mergeTrees(treesToMerge); }, + preprocessTree: function(type, tree) { + if (type === 'js') { + var treesToMerge = [tree]; + let discoveredComponents = FreestyleDiscovery(tree, { + appName: this.app.name, + outputFile: '/-freestyle/discovered-components.js' + }); + + discoveredComponents = new Funnel(discoveredComponents, { + destDir: this.app.name + }); + + treesToMerge.push(discoveredComponents); + tree = mergeTrees(treesToMerge); + } + return tree; + }, + snippetPaths: function() { if (this.app) { var freestyleOptions = this.app.options.freestyle || {}; @@ -43,8 +102,28 @@ module.exports = { return ['app']; }, - included: function(/*app, parentAddon*/) { + included: function(app, parentAddon) { this._super.included.apply(this, arguments); + + // Quick fix for add-on nesting + // https://github.com/aexmachina/ember-cli-sass/blob/v5.3.0/index.js#L73-L75 + // see: https://github.com/ember-cli/ember-cli/issues/3718 + while (typeof app.import !== 'function' && (app.app || app.parent)) { + app = app.app || app.parent; + } + + // if app.import and parentAddon are blank, we're probably being consumed by an in-repo-addon + // or engine, for which the "bust through" technique above does not work. + if (typeof app.import !== 'function' && !parentAddon) { + if (app.registry && app.registry.app) { + app = app.registry.app; + } + } + + // Per the ember-cli documentation + // http://ember-cli.com/extending/#broccoli-build-options-for-in-repo-addons + let target = (parentAddon || app); + this.options = target.options || {}; }, isDevelopingAddon: function() { diff --git a/tests/acceptance/auto-discover-test.js b/tests/acceptance/auto-discover-test.js new file mode 100644 index 00000000..6b63181b --- /dev/null +++ b/tests/acceptance/auto-discover-test.js @@ -0,0 +1,16 @@ +import { test } from 'qunit'; +import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; +import freestyleGuide from '../pages/freestyle-guide'; +import discoveredComponents from 'dummy/-freestyle/discovered-components'; + +moduleForAcceptance('Acceptance | section rendering', { + beforeEach() { + freestyleGuide.visit(); + } +}); + +test('verifying guide sections', (assert) => { + andThen(() => { + assert.ok(discoveredComponents.includes('x-bar/freestyle'), 'includes discovered component'); + }); +}); diff --git a/tests/dummy/app/components/x-bar/freestyle/component.js b/tests/dummy/app/components/x-bar/freestyle/component.js new file mode 100644 index 00000000..cbfd5011 --- /dev/null +++ b/tests/dummy/app/components/x-bar/freestyle/component.js @@ -0,0 +1,3 @@ +import Component from '@ember/component'; + +export default Component.extend(); diff --git a/tests/dummy/app/components/x-bar/freestyle/template.hbs b/tests/dummy/app/components/x-bar/freestyle/template.hbs new file mode 100644 index 00000000..84cf53a3 --- /dev/null +++ b/tests/dummy/app/components/x-bar/freestyle/template.hbs @@ -0,0 +1,9 @@ +{{x-bar + title='Just a static title' + size=10 + showBorder=true + rank=2 + isVisible=true + isTasteful=true + innerBorderThickness=3 +}} From a119499919f3740c9f90dd11685b207ff1aa940e Mon Sep 17 00:00:00 2001 From: Chris LoPresto Date: Sun, 24 Jun 2018 18:10:47 -0400 Subject: [PATCH 2/5] Appease eslint --- index.js | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index b2f20fe9..6990f4d5 100644 --- a/index.js +++ b/index.js @@ -20,7 +20,7 @@ function FreestyleDiscovery(inputTree, options) { this.inputTree = inputTree; this.options = { outputFile: options.outputFile, - componentNamePattern: `${options.appName}\/components\/(.*)\/component\.js$` + componentNamePattern: `${options.appName}/components/(.*)/component.js$` }; } diff --git a/package.json b/package.json index ead4d94e..e560a094 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ }, "dependencies": { "broccoli-flatiron": "0.1.2", + "broccoli-funnel": "^2.0.1", "broccoli-merge-trees": "^2.0.0", "broccoli-writer": "^0.1.1", "ember-cli-babel": "^6.6.0", From ff3d8a2511cb4711216c023f8c35ff9801633f25 Mon Sep 17 00:00:00 2001 From: Luke Melia Date: Tue, 26 Jun 2018 01:08:18 -0400 Subject: [PATCH 3/5] Add component and service code to output the discovered freestyle components --- addon/components/freestyle-auto.js | 10 ++++ addon/templates/components/freestyle-auto.hbs | 3 ++ app/components/freestyle-auto.js | 1 + app/services/ember-freestyle.js | 7 ++- ember-cli-build.js | 6 ++- package.json | 5 +- tests/acceptance/auto-discover-test.js | 9 ++-- tests/acceptance/section-navigation-test.js | 11 ++-- tests/acceptance/section-rendering-test.js | 53 ++++++++----------- tests/dummy/app/components/x-baz/component.js | 12 +++++ .../{x-bar => x-baz}/freestyle/component.js | 0 .../{x-bar => x-baz}/freestyle/template.hbs | 4 +- tests/dummy/app/components/x-baz/template.hbs | 13 +++++ tests/dummy/app/templates/acceptance.hbs | 4 ++ tests/dummy/app/templates/documentation.hbs | 10 ++++ yarn.lock | 13 +++-- 16 files changed, 112 insertions(+), 49 deletions(-) create mode 100644 addon/components/freestyle-auto.js create mode 100644 addon/templates/components/freestyle-auto.hbs create mode 100644 app/components/freestyle-auto.js create mode 100644 tests/dummy/app/components/x-baz/component.js rename tests/dummy/app/components/{x-bar => x-baz}/freestyle/component.js (100%) rename tests/dummy/app/components/{x-bar => x-baz}/freestyle/template.hbs (69%) create mode 100644 tests/dummy/app/components/x-baz/template.hbs diff --git a/addon/components/freestyle-auto.js b/addon/components/freestyle-auto.js new file mode 100644 index 00000000..6d1452bc --- /dev/null +++ b/addon/components/freestyle-auto.js @@ -0,0 +1,10 @@ +import Component from '@ember/component'; +import layout from '../templates/components/freestyle-auto'; +import { inject as service } from '@ember/service'; +import { readOnly } from '@ember/object/computed'; + +export default Component.extend({ + layout, + emberFreestyle: service(), + components: readOnly('emberFreestyle.discoveredComponents') +}); diff --git a/addon/templates/components/freestyle-auto.hbs b/addon/templates/components/freestyle-auto.hbs new file mode 100644 index 00000000..52b71b11 --- /dev/null +++ b/addon/templates/components/freestyle-auto.hbs @@ -0,0 +1,3 @@ +{{#each components as |c|}} + {{component c}} +{{/each}} diff --git a/app/components/freestyle-auto.js b/app/components/freestyle-auto.js new file mode 100644 index 00000000..00451fbf --- /dev/null +++ b/app/components/freestyle-auto.js @@ -0,0 +1 @@ +export { default } from 'ember-freestyle/components/freestyle-auto'; diff --git a/app/services/ember-freestyle.js b/app/services/ember-freestyle.js index ac384ccd..4aed95bc 100644 --- a/app/services/ember-freestyle.js +++ b/app/services/ember-freestyle.js @@ -1 +1,6 @@ -export { default } from 'ember-freestyle/services/ember-freestyle'; \ No newline at end of file +import Service from 'ember-freestyle/services/ember-freestyle'; +import discoveredComponents from '../-freestyle/discovered-components'; + +export default Service.extend({ + discoveredComponents +}); diff --git a/ember-cli-build.js b/ember-cli-build.js index 1b017138..ff286ac1 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -11,7 +11,11 @@ module.exports = function(defaults) { }, freestyle: { snippetSearchPaths: ["tests/dummy/app", "addon/styles"] - } + }, + "ember-cli-babel": { + includePolyfill: true + }, + es3Safe: false, }); if (defaults.project.findAddonByName("ember-native-dom-event-dispatcher")) { diff --git a/package.json b/package.json index e560a094..6830bc39 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "ember-cli-github-pages": "0.2.0", "ember-cli-htmlbars-inline-precompile": "^1.0.0", "ember-cli-inject-live-reload": "^1.4.1", - "ember-cli-page-object": "^1.13.0-alpha.1", + "ember-cli-page-object": "^1.14.0", "ember-cli-qunit": "^4.1.1", "ember-cli-release": "v1.0.0-beta.2", "ember-cli-sass-lint": "^1.0.3", @@ -56,7 +56,8 @@ "eslint-config-ember": "0.3.0", "eslint-plugin-ember": "^5.0.0", "eslint-plugin-node": "^6.0.0", - "loader.js": "^4.2.3" + "loader.js": "^4.2.3", + "qunit-dom": "^0.6.3" }, "engines": { "node": "^4.5 || 6.* || >= 7.*" diff --git a/tests/acceptance/auto-discover-test.js b/tests/acceptance/auto-discover-test.js index 6b63181b..93716cca 100644 --- a/tests/acceptance/auto-discover-test.js +++ b/tests/acceptance/auto-discover-test.js @@ -3,14 +3,13 @@ import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; import freestyleGuide from '../pages/freestyle-guide'; import discoveredComponents from 'dummy/-freestyle/discovered-components'; -moduleForAcceptance('Acceptance | section rendering', { +moduleForAcceptance('Acceptance | auto-discover', { beforeEach() { freestyleGuide.visit(); } }); -test('verifying guide sections', (assert) => { - andThen(() => { - assert.ok(discoveredComponents.includes('x-bar/freestyle'), 'includes discovered component'); - }); +test('verifying auto discovery', async function(assert) { + assert.ok(discoveredComponents.includes('x-baz/freestyle'), 'includes discovered component'); + assert.dom('.x-Baz-title').hasText('Just a static x-baz title'); }); diff --git a/tests/acceptance/section-navigation-test.js b/tests/acceptance/section-navigation-test.js index 4cce5217..b8b4dbcc 100644 --- a/tests/acceptance/section-navigation-test.js +++ b/tests/acceptance/section-navigation-test.js @@ -17,13 +17,14 @@ test('verifying header', (assert) => { }); test('verifying menu sections', (assert) => { - assert.expect(5); + assert.expect(6); andThen(() => { - assert.equal(freestyleGuide.menu.sections.length, 4); + assert.equal(freestyleGuide.menu.sections.length, 5); assert.equal(freestyleGuide.menu.sections.objectAt(0).text, 'All'); assert.equal(freestyleGuide.menu.sections.objectAt(1).text, 'Foo Things'); - assert.equal(freestyleGuide.menu.sections.objectAt(2).text, 'Dynamic Properties'); - assert.equal(freestyleGuide.menu.sections.objectAt(3).text, 'Visual Style'); + assert.equal(freestyleGuide.menu.sections.objectAt(2).text, 'Auto-Discovered'); + assert.equal(freestyleGuide.menu.sections.objectAt(3).text, 'Dynamic Properties'); + assert.equal(freestyleGuide.menu.sections.objectAt(4).text, 'Visual Style'); }); }); @@ -35,7 +36,7 @@ test('navigating directly to a subsection', function(assert) { assert.equal(sectionFooThings.subsections.objectAt(0).text, 'Foo Subsection A'); assert.equal(sectionFooThings.subsections.objectAt(1).text, 'Foo Subsection B'); - let sectionVisualStyle = freestyleGuide.menu.sections.objectAt(3); + let sectionVisualStyle = freestyleGuide.menu.sections.objectAt(4); assert.equal(sectionVisualStyle.subsections.length, 2); assert.equal(sectionVisualStyle.subsections.objectAt(0).text, 'Typography'); assert.equal(sectionVisualStyle.subsections.objectAt(1).text, 'Color'); diff --git a/tests/acceptance/section-rendering-test.js b/tests/acceptance/section-rendering-test.js index 0eb25516..f548a97e 100644 --- a/tests/acceptance/section-rendering-test.js +++ b/tests/acceptance/section-rendering-test.js @@ -3,43 +3,36 @@ import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; import freestyleGuide from '../pages/freestyle-guide'; moduleForAcceptance('Acceptance | section rendering', { - beforeEach() { - freestyleGuide.visit(); + async beforeEach() { + await freestyleGuide.visit(); } }); -test('verifying guide sections', (assert) => { - assert.expect(4); - andThen(() => { - assert.equal(freestyleGuide.content.sections.length, 3); - assert.equal(freestyleGuide.content.sections.objectAt(0).text, 'Foo Things'); - assert.equal(freestyleGuide.content.sections.objectAt(1).text, 'Dynamic Properties'); - assert.equal(freestyleGuide.content.sections.objectAt(2).text, 'Visual Style'); - }); +test('verifying guide sections', async function(assert) { + assert.expect(5); + assert.equal(freestyleGuide.content.sections.length, 4, '4 sections rendered'); + assert.equal(freestyleGuide.content.sections.objectAt(0).text, 'Foo Things'); + assert.equal(freestyleGuide.content.sections.objectAt(1).text, 'Auto-Discovered'); + assert.equal(freestyleGuide.content.sections.objectAt(2).text, 'Dynamic Properties'); + assert.equal(freestyleGuide.content.sections.objectAt(3).text, 'Visual Style'); }); -test('verifying guide subsections', (assert) => { +test('verifying guide subsections', async function(assert) { assert.expect(6); - andThen(() => { - let sectionFooThings = freestyleGuide.content.sections.objectAt(0); - assert.equal(sectionFooThings.subsections.length, 2); - assert.equal(sectionFooThings.subsections.objectAt(0).text, 'Foo Subsection A'); - assert.equal(sectionFooThings.subsections.objectAt(1).text, 'Foo Subsection B'); - - let sectionVisualStyle = freestyleGuide.content.sections.objectAt(2); - assert.equal(sectionVisualStyle.subsections.length, 2); - assert.equal(sectionVisualStyle.subsections.objectAt(0).text, 'Typography'); - assert.equal(sectionVisualStyle.subsections.objectAt(1).text, 'Color'); - }); + let sectionFooThings = freestyleGuide.content.sections.objectAt(0); + assert.equal(sectionFooThings.subsections.length, 2, '2 subsections in first section'); + assert.equal(sectionFooThings.subsections.objectAt(0).text, 'Foo Subsection A'); + assert.equal(sectionFooThings.subsections.objectAt(1).text, 'Foo Subsection B'); + let sectionVisualStyle = freestyleGuide.content.sections.objectAt(3); + assert.equal(sectionVisualStyle.subsections.length, 2, '2 subsections in fourth section'); + assert.equal(sectionVisualStyle.subsections.objectAt(0).text, 'Typography'); + assert.equal(sectionVisualStyle.subsections.objectAt(1).text, 'Color'); }); -test('freestyle notes show up', (assert) => { +test('freestyle notes show up', async function(assert) { assert.expect(1); - andThen(() => { - let sectionFooThings = freestyleGuide.content.sections.objectAt(0); - let note = sectionFooThings.subsections.objectAt(0).collections.objectAt(0).variants.objectAt(0).noteContent[1]; - - assert.ok(note.includes('Another Note About Normal')); - }) -}) + let sectionFooThings = freestyleGuide.content.sections.objectAt(0); + let note = sectionFooThings.subsections.objectAt(0).collections.objectAt(0).variants.objectAt(0).noteContent[1]; + assert.ok(note.includes('Another Note About Normal')); +}); diff --git a/tests/dummy/app/components/x-baz/component.js b/tests/dummy/app/components/x-baz/component.js new file mode 100644 index 00000000..3795f6d1 --- /dev/null +++ b/tests/dummy/app/components/x-baz/component.js @@ -0,0 +1,12 @@ +import Component from '@ember/component'; +import layout from './template'; + +export default Component.extend({ + layout, + title: 'Default Title', + description: 'Default Description', + size: 'medium', + showBorder: true, + isVisible: true, + isTasteful: false, +}); diff --git a/tests/dummy/app/components/x-bar/freestyle/component.js b/tests/dummy/app/components/x-baz/freestyle/component.js similarity index 100% rename from tests/dummy/app/components/x-bar/freestyle/component.js rename to tests/dummy/app/components/x-baz/freestyle/component.js diff --git a/tests/dummy/app/components/x-bar/freestyle/template.hbs b/tests/dummy/app/components/x-baz/freestyle/template.hbs similarity index 69% rename from tests/dummy/app/components/x-bar/freestyle/template.hbs rename to tests/dummy/app/components/x-baz/freestyle/template.hbs index 84cf53a3..25f28b33 100644 --- a/tests/dummy/app/components/x-bar/freestyle/template.hbs +++ b/tests/dummy/app/components/x-baz/freestyle/template.hbs @@ -1,5 +1,5 @@ -{{x-bar - title='Just a static title' +{{x-baz + title='Just a static x-baz title' size=10 showBorder=true rank=2 diff --git a/tests/dummy/app/components/x-baz/template.hbs b/tests/dummy/app/components/x-baz/template.hbs new file mode 100644 index 00000000..e9d50bc2 --- /dev/null +++ b/tests/dummy/app/components/x-baz/template.hbs @@ -0,0 +1,13 @@ +
+
+ {{title}} +
+

{{description}}

+
+ {{yield}} +
+
diff --git a/tests/dummy/app/templates/acceptance.hbs b/tests/dummy/app/templates/acceptance.hbs index b114d067..edddc354 100644 --- a/tests/dummy/app/templates/acceptance.hbs +++ b/tests/dummy/app/templates/acceptance.hbs @@ -78,6 +78,10 @@ {{/freestyle-section}} + {{#freestyle-section name='Auto-Discovered' as |section|}} + {{freestyle-auto}} + {{/freestyle-section}} + {{#freestyle-section name='Dynamic Properties' as |section|}} {{#freestyle-dynamic 'dynamic-properties' dynamicProperties=dynamicProperties diff --git a/tests/dummy/app/templates/documentation.hbs b/tests/dummy/app/templates/documentation.hbs index 4c323b59..3537f3a6 100644 --- a/tests/dummy/app/templates/documentation.hbs +++ b/tests/dummy/app/templates/documentation.hbs @@ -172,6 +172,16 @@ Show Notes usage controls preference.

+

Automated discovery of components to include in your Freestyle guide

+ +

+\{{#freestyle-guide title="My Living Style Guide" subtitle="Showcasing My App's Components"}}
+  \{{freestyle-auto}}
+\{{/freestyle-guide}}
+  
+ + TODO: docs +

Removing Ember Freestyle from Your Production Payload

diff --git a/yarn.lock b/yarn.lock index 11eeddf5..fc79a5a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2287,9 +2287,9 @@ ember-cli-normalize-entity-name@^1.0.0: dependencies: silent-error "^1.0.0" -ember-cli-page-object@^1.13.0-alpha.1: - version "1.14.0" - resolved "https://registry.yarnpkg.com/ember-cli-page-object/-/ember-cli-page-object-1.14.0.tgz#fcf06b3b1ee6454196a29bc674abe8b65aa0adbd" +ember-cli-page-object@^1.14.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/ember-cli-page-object/-/ember-cli-page-object-1.14.1.tgz#2e3599c204c56440c6c8154fc686c603816f877a" dependencies: ceibo "~2.0.0" ember-cli-babel "^6.6.0" @@ -6192,6 +6192,13 @@ quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quic rimraf "^2.5.4" underscore.string "~3.3.4" +qunit-dom@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/qunit-dom/-/qunit-dom-0.6.3.tgz#f6d7563218179c4f0ef85f940bb79e10631c14ff" + dependencies: + broccoli-funnel "^2.0.0" + broccoli-merge-trees "^2.0.0" + qunit@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/qunit/-/qunit-2.5.0.tgz#64cbe30a1193ef02edc5b278efcdf1d0bae96b22" From 627c08801f736cff261d900ba82f3f8edac4599b Mon Sep 17 00:00:00 2001 From: Luke Melia Date: Tue, 26 Jun 2018 01:13:19 -0400 Subject: [PATCH 4/5] Wrap component in freestyle-usage --- .../components/x-baz/freestyle/template.hbs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/dummy/app/components/x-baz/freestyle/template.hbs b/tests/dummy/app/components/x-baz/freestyle/template.hbs index 25f28b33..42748b5e 100644 --- a/tests/dummy/app/components/x-baz/freestyle/template.hbs +++ b/tests/dummy/app/components/x-baz/freestyle/template.hbs @@ -1,9 +1,11 @@ -{{x-baz - title='Just a static x-baz title' - size=10 - showBorder=true - rank=2 - isVisible=true - isTasteful=true - innerBorderThickness=3 -}} +{{#freestyle-usage 'x-baz' title='x-baz'}} + {{x-baz + title='Just a static x-baz title' + size=10 + showBorder=true + rank=2 + isVisible=true + isTasteful=true + innerBorderThickness=3 + }} +{{/freestyle-usage}} From 367fc0d4a4bd93086119b204c1a46d7c2c305eec Mon Sep 17 00:00:00 2001 From: Luke Melia Date: Thu, 28 Jun 2018 01:24:30 -0400 Subject: [PATCH 5/5] Support more component paths, plus cleanup - Extract freestyle-discovery broccoli plugin to its own file - support additional component paths - allow broccoli plugin to receive options (prepping for configuration opts) - use a function instead of a regexp to extract the component name --- .eslintrc.js | 1 + index.js | 41 +------------ lib/freestyle-discovery.js | 58 +++++++++++++++++++ tests/acceptance/auto-discover-test.js | 6 +- .../components/freestyle/x-bay/component.js | 6 ++ .../components/freestyle/x-bay/template.hbs | 6 ++ tests/dummy/app/components/freestyle/x-qux.js | 3 + tests/dummy/app/components/x-bay/component.js | 12 ++++ tests/dummy/app/components/x-bay/template.hbs | 13 +++++ tests/dummy/app/components/x-qux/component.js | 12 ++++ tests/dummy/app/components/x-qux/template.hbs | 13 +++++ .../templates/components/freestyle/x-qux.hbs | 6 ++ 12 files changed, 136 insertions(+), 41 deletions(-) create mode 100644 lib/freestyle-discovery.js create mode 100644 tests/dummy/app/components/freestyle/x-bay/component.js create mode 100644 tests/dummy/app/components/freestyle/x-bay/template.hbs create mode 100644 tests/dummy/app/components/freestyle/x-qux.js create mode 100644 tests/dummy/app/components/x-bay/component.js create mode 100644 tests/dummy/app/components/x-bay/template.hbs create mode 100644 tests/dummy/app/components/x-qux/component.js create mode 100644 tests/dummy/app/components/x-qux/template.hbs create mode 100644 tests/dummy/app/templates/components/freestyle/x-qux.hbs diff --git a/.eslintrc.js b/.eslintrc.js index 57be4a65..99570c6b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -35,6 +35,7 @@ module.exports = { { files: [ 'index.js', + 'lib/freestyle-discovery.js', 'testem.js', 'ember-cli-build.js', 'config/**/*.js', diff --git a/index.js b/index.js index 6990f4d5..8cac10b1 100644 --- a/index.js +++ b/index.js @@ -3,47 +3,8 @@ var mergeTrees = require('broccoli-merge-trees'); var fs = require('fs'); var flatiron = require('broccoli-flatiron'); var freestyleUsageSnippetFinder = require('./freestyle-usage-snippet-finder'); - +var FreestyleDiscovery = require('./lib/freestyle-discovery'); var Funnel = require('broccoli-funnel'); -var Writer = require('broccoli-writer'); -var path = require('path'); -var glob = require('glob'); - -FreestyleDiscovery.prototype = Object.create(Writer.prototype); -FreestyleDiscovery.prototype.constructor = FreestyleDiscovery; - -function FreestyleDiscovery(inputTree, options) { - if (!(this instanceof FreestyleDiscovery)) { - return new FreestyleDiscovery(inputTree, options); - } - - this.inputTree = inputTree; - this.options = { - outputFile: options.outputFile, - componentNamePattern: `${options.appName}/components/(.*)/component.js$` - }; -} - -FreestyleDiscovery.prototype.write = function(readTree, destDir) { - var _this = this; - var componentPathPattern = '**/freestyle/component.js'; - var componentRegex = new RegExp(this.options.componentNamePattern); - - return readTree(this.inputTree).then(function(srcDir) { - var files = glob.sync(path.join(srcDir, componentPathPattern)); - var components = files.map((componentPath) => { - // Extract a freestyle component name that looks like: - // x-bar/freestyle - // from a componentPath that looks like: - // /Users/xxxxx/p/xxxxx/ember-freestyle/tmp/broccoli_merge_trees-output_path-7BiiNpHw.tmp/dummy/components/x-bar/freestyle/component.js - return componentRegex.exec(componentPath)[1]; - }); - - var output = `export default ${JSON.stringify(components)};`; - fs.mkdirSync(path.join(destDir, path.dirname(_this.options.outputFile))); - fs.writeFileSync(path.join(destDir, _this.options.outputFile), output); - }); -} module.exports = { name: 'ember-freestyle', diff --git a/lib/freestyle-discovery.js b/lib/freestyle-discovery.js new file mode 100644 index 00000000..eee9229e --- /dev/null +++ b/lib/freestyle-discovery.js @@ -0,0 +1,58 @@ +'use strict'; +var Writer = require('broccoli-writer'); +var path = require('path'); +var glob = require('glob'); +var fs = require('fs'); + +FreestyleDiscovery.prototype = Object.create(Writer.prototype); +FreestyleDiscovery.prototype.constructor = FreestyleDiscovery; + +function FreestyleDiscovery(inputTree, options) { + if (!(this instanceof FreestyleDiscovery)) { + return new FreestyleDiscovery(inputTree, options); + } + + this.inputTree = inputTree; + var freestyleComponentName = options.freestyleComponentName || 'freestyle'; + var defaultGlobPattern = `**/{${freestyleComponentName}/component.js,${options.appName}/components/${freestyleComponentName}/**/*.js}`; + this.options = { + outputFile: options.outputFile, + freestyleComponentName: freestyleComponentName, + componentPathGlobPattern: options.componentPathGlobPattern || defaultGlobPattern, + extractComponentName: options.extractComponentName || function extractComponentName(componentPath) { + // Extract a freestyle component name that looks like: + // x-bay/freestyle + // from a componentPath that looks like: + // /Users/xxxxx/p/xxxxx/ember-freestyle/tmp/broccoli_merge_trees-output_path-7BiiNpHw.tmp/dummy/components/x-bay/freestyle/component.js + // or + // /Users/xxxxx/p/xxxxx/ember-freestyle/tmp/broccoli_merge_trees-output_path-7BiiNpHw.tmp/dummy/components/x-bay/freestyle.js + var regexp = new RegExp(`${options.appName}/components/(.+/${freestyleComponentName})(?:/component)?.js$`); + var match = regexp.exec(componentPath); + if (!match) { + regexp = new RegExp(`${options.appName}/components/(${freestyleComponentName}/.+)(?:/component)?.js$`); + match = regexp.exec(componentPath); + } + if (match) { + return match[1].replace(/\/component$/,''); + } + } + }; +} + +FreestyleDiscovery.prototype.write = function(readTree, destDir) { + var _this = this; + var componentPathGlobPattern = this.options.componentPathGlobPattern; + var extractComponentName = this.options.extractComponentName; + + return readTree(this.inputTree).then(function(srcDir) { + var files = glob.sync(path.join(srcDir, componentPathGlobPattern)); + var components = files.map(extractComponentName).filter((name) => { + return name && !(/template$/.test(name)); + }); + var output = `export default ${JSON.stringify(components)};`; + fs.mkdirSync(path.join(destDir, path.dirname(_this.options.outputFile))); + fs.writeFileSync(path.join(destDir, _this.options.outputFile), output); + }); +} + +module.exports = FreestyleDiscovery; diff --git a/tests/acceptance/auto-discover-test.js b/tests/acceptance/auto-discover-test.js index 93716cca..34ce56e4 100644 --- a/tests/acceptance/auto-discover-test.js +++ b/tests/acceptance/auto-discover-test.js @@ -10,6 +10,10 @@ moduleForAcceptance('Acceptance | auto-discover', { }); test('verifying auto discovery', async function(assert) { - assert.ok(discoveredComponents.includes('x-baz/freestyle'), 'includes discovered component'); + assert.ok(discoveredComponents.includes('x-baz/freestyle'), 'includes discovered x-baz/freestyle component'); + assert.ok(discoveredComponents.includes('freestyle/x-bay'), 'includes discovered freestyle/x-bay component'); + assert.ok(discoveredComponents.includes('freestyle/x-qux'), 'includes discovered freestyle/x-qux component'); assert.dom('.x-Baz-title').hasText('Just a static x-baz title'); + assert.dom('.x-Bay-title').hasText('Just a static x-bay title'); + assert.dom('.x-Qux-title').hasText('Just a static x-qux title'); }); diff --git a/tests/dummy/app/components/freestyle/x-bay/component.js b/tests/dummy/app/components/freestyle/x-bay/component.js new file mode 100644 index 00000000..ab273cde --- /dev/null +++ b/tests/dummy/app/components/freestyle/x-bay/component.js @@ -0,0 +1,6 @@ +import Component from '@ember/component'; +import layout from './template'; + +export default Component.extend({ + layout +}); diff --git a/tests/dummy/app/components/freestyle/x-bay/template.hbs b/tests/dummy/app/components/freestyle/x-bay/template.hbs new file mode 100644 index 00000000..50c72b7a --- /dev/null +++ b/tests/dummy/app/components/freestyle/x-bay/template.hbs @@ -0,0 +1,6 @@ +{{#freestyle-usage 'x-bay' title='x-bay'}} + {{x-bay + title='Just a static x-bay title' + size=15 + }} +{{/freestyle-usage}} diff --git a/tests/dummy/app/components/freestyle/x-qux.js b/tests/dummy/app/components/freestyle/x-qux.js new file mode 100644 index 00000000..cbfd5011 --- /dev/null +++ b/tests/dummy/app/components/freestyle/x-qux.js @@ -0,0 +1,3 @@ +import Component from '@ember/component'; + +export default Component.extend(); diff --git a/tests/dummy/app/components/x-bay/component.js b/tests/dummy/app/components/x-bay/component.js new file mode 100644 index 00000000..3795f6d1 --- /dev/null +++ b/tests/dummy/app/components/x-bay/component.js @@ -0,0 +1,12 @@ +import Component from '@ember/component'; +import layout from './template'; + +export default Component.extend({ + layout, + title: 'Default Title', + description: 'Default Description', + size: 'medium', + showBorder: true, + isVisible: true, + isTasteful: false, +}); diff --git a/tests/dummy/app/components/x-bay/template.hbs b/tests/dummy/app/components/x-bay/template.hbs new file mode 100644 index 00000000..48c8488f --- /dev/null +++ b/tests/dummy/app/components/x-bay/template.hbs @@ -0,0 +1,13 @@ +

+
+ {{title}} +
+

{{description}}

+
+ {{yield}} +
+
diff --git a/tests/dummy/app/components/x-qux/component.js b/tests/dummy/app/components/x-qux/component.js new file mode 100644 index 00000000..3795f6d1 --- /dev/null +++ b/tests/dummy/app/components/x-qux/component.js @@ -0,0 +1,12 @@ +import Component from '@ember/component'; +import layout from './template'; + +export default Component.extend({ + layout, + title: 'Default Title', + description: 'Default Description', + size: 'medium', + showBorder: true, + isVisible: true, + isTasteful: false, +}); diff --git a/tests/dummy/app/components/x-qux/template.hbs b/tests/dummy/app/components/x-qux/template.hbs new file mode 100644 index 00000000..49fbaed3 --- /dev/null +++ b/tests/dummy/app/components/x-qux/template.hbs @@ -0,0 +1,13 @@ +
+
+ {{title}} +
+

{{description}}

+
+ {{yield}} +
+
diff --git a/tests/dummy/app/templates/components/freestyle/x-qux.hbs b/tests/dummy/app/templates/components/freestyle/x-qux.hbs new file mode 100644 index 00000000..94e9dbe0 --- /dev/null +++ b/tests/dummy/app/templates/components/freestyle/x-qux.hbs @@ -0,0 +1,6 @@ +{{#freestyle-usage 'x-qux' title='x-qux'}} + {{x-qux + title='Just a static x-qux title' + size=15 + }} +{{/freestyle-usage}}