diff --git a/.travis.yml b/.travis.yml index dc4acc7a..2f33bc1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,7 @@ env: matrix: fast_finish: true allow_failures: + - env: EMBER_TRY_SCENARIO=ember-beta - env: EMBER_TRY_SCENARIO=ember-canary before_install: diff --git a/mu-trees/addon/resolvers/fallback/index.js b/mu-trees/addon/resolvers/fallback/index.js index d19f5ebf..389d4139 100644 --- a/mu-trees/addon/resolvers/fallback/index.js +++ b/mu-trees/addon/resolvers/fallback/index.js @@ -9,8 +9,8 @@ export default Resolver.extend({ namespace: { modulePrefix: this.config.app.name } }, options)); }, - resolve(name, referrer) { - let result = this._super(name, referrer); + resolve(name, referrer, rawString) { + let result = this._super(name, referrer, rawString); return result || this._fallback.resolve(name); } }); diff --git a/mu-trees/addon/resolvers/glimmer-wrapper/index.js b/mu-trees/addon/resolvers/glimmer-wrapper/index.js index b68c62ff..1639152c 100644 --- a/mu-trees/addon/resolvers/glimmer-wrapper/index.js +++ b/mu-trees/addon/resolvers/glimmer-wrapper/index.js @@ -30,7 +30,22 @@ const Resolver = DefaultResolver.extend({ normalize: null, - resolve(lookupString, referrer) { + resolve(lookupString, referrer, rawString) { + /* + * Ember namespaces are part of the raw invocation passed as a third + * argument, for example other-addon::some-service + */ + let rootName = this._configRootName; + let rawStringName = null; + if (rawString) { + let [namespace, name] = rawString.split('::'); + rootName = namespace; + rawStringName = name; + } + + let [type, lookupStringName] = lookupString.split(':'); + let name = lookupStringName; + /* * Ember components require their lookupString to be massaged. Make this * as "pay-go" as possible. @@ -38,13 +53,22 @@ const Resolver = DefaultResolver.extend({ if (referrer) { // make absolute let parts = referrer.split(':src/ui/'); - referrer = `${parts[0]}:/${this._configRootName}/${parts[1]}`; + referrer = `${parts[0]}:/${rootName}/${parts[1]}`; referrer = referrer.split('/template.hbs')[0]; + } else if (rawString) { + // This is only required because: + // https://github.com/glimmerjs/glimmer-di/issues/45 + referrer = `${type}:/${rootName}/`; } - let [type, name] = lookupString.split(':'); + /* If there is no name, fallback to the name passed in the rawString */ + if (!name) { + name = rawStringName; + } if (name) { - if (type === 'service') { + if (type === 'component' && rawString && name) { + lookupString = `${type}:${name}`; + } else if (type === 'service') { /* Services may be camelCased */ lookupString = `service:${dasherize(name)}`; } else if (type === 'route') { @@ -54,8 +78,9 @@ const Resolver = DefaultResolver.extend({ /* Controllers may have.dot.paths */ lookupString = `controller:${slasherize(name)}`; } else if (type === 'template') { - if (name.indexOf('components/') === 0) { - lookupString = `template:${name.slice(11)}`; + if (lookupStringName && lookupStringName.indexOf('components/') === 0) { + let sliced = lookupStringName.slice(11); + lookupString = `template:${sliced.length ? sliced : rawStringName}`; } else { /* * Ember partials are looked up as templates. Here we replace the template @@ -77,7 +102,7 @@ const Resolver = DefaultResolver.extend({ * have dots.in.paths */ lookupString = `template`; - referrer = `route:/${this._configRootName}/routes/${slasherize(name)}`; + referrer = `route:/${rootName}/routes/${slasherize(name)}`; } } } diff --git a/mu-trees/tests/unit/resolvers/glimmer-wrapper/basic-test.js b/mu-trees/tests/unit/resolvers/glimmer-wrapper/basic-test.js index 8f79ba88..740d88c8 100644 --- a/mu-trees/tests/unit/resolvers/glimmer-wrapper/basic-test.js +++ b/mu-trees/tests/unit/resolvers/glimmer-wrapper/basic-test.js @@ -723,3 +723,82 @@ test('Can resolve a local helper for another component', function(assert) { 'helper not resolved at global levelt' ); }); + +// Namespaces + +test('Can resolve a namespaced service lookup', function(assert) { + let service = {}; + let resolver = this.resolverForEntries({ + app: { + name: 'example-app' + }, + types: { + service: { definitiveCollection: 'services' } + }, + collections: { + services: { + types: [ 'service' ] + } + } + }, { + 'service:/other-namespace/services/i18n': service + }); + + assert.equal( + resolver.resolve('service', null, 'other-namespace::i18n'), + service, + 'namespaced resolution resolved' + ); +}); + +test('Can resolve a namespaced component template', function(assert) { + let template = {}; + let resolver = this.resolverForEntries({ + app: { + name: 'example-app' + }, + types: { + template: { definitiveCollection: 'components' } + }, + collections: { + components: { + group: 'ui', + types: [ 'template' ] + } + } + }, { + 'template:/other-namespace/components/my-component': template + }); + + assert.equal( + resolver.resolve('template:components/', null, 'other-namespace::my-component'), + template, + 'namespaced resolution resolved' + ); +}); + +test('Can resolve a namespaced component object', function(assert) { + let component = {}; + let resolver = this.resolverForEntries({ + app: { + name: 'example-app' + }, + types: { + component: { definitiveCollection: 'components' } + }, + collections: { + components: { + group: 'ui', + types: [ 'component' ] + } + } + }, { + 'component:/other-namespace/components/my-component': component + }); + + assert.equal( + resolver.resolve('component', null, 'other-namespace::my-component'), + component, + 'namespaced resolution resolved' + ); +});