Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds the strict resolver as an option #837

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 88 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,106 @@ export default class App extends Application {
// ...snip...
```

## Strict

> **Note** This was originally developed as <https://github.com/stefanpenner/ember-strict-resolver>

in app/resolver.js

```js
export { default } from "ember-resolver/strict";
```

## Migration

Migrating to the `strict` resolver from the `classic` can be done piecemeal by supporting a sub-set of the old resolution formats.

> **Note** `normalize` is needed because without it you will get errors related to failing to be able to inject services that were never normalized in the registry.

```js
// app/resolver.js

import Resolver from "ember-resolver/strict";

export default class extends Resolver {
legacyMappings = {
"service:camelCaseNotSupported": "service:camel-case-not-supported",
};

resolve(_fullName) {
return super.resolve(this.legacyMappings[_fullName] || _fullName);
}

normalize(_fullName) {
return this.legacyMappings[_fullName] || _fullName;
}
}
```

This will allow you file PRs with libraries that currently do not support the strict resolver in its entirety.

If you have a component that is failing to resolve correctly with the error `Attempted to lookup "helper:nameOfVariable". Use "helper:name-of-variable" instead.`, please convert your template to use explicit-this (also required by Ember v4.0). The template lint can be enabled by turning on [no-implicit-this](https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/no-implicit-this.md).

An example of what this looks like is the following

```hbs
// addon/components/templates/foo.hbs

<div>
{{fullName}}
</div>
```

This will result in the error, `Attempted to lookup "helper:fullName". Use "helper:full-name" instead.`. The fix for this would be to decide if this is a argument being passed into foo or if this is a local property.

_fullName_ is coming from an invocation of _Foo_ like the following:

```
<Foo
@fullName="The Teamster"
/>
```

Then the fix for your template would be:

```hbs
// addon/components/templates/foo.hbs

<div>
{{@fullName}}
</div>
```

If _fullName_ is a property on your component the fix would be:

```hbs
// addon/components/templates/foo.hbs

<div>
{{this.fullName}}
</div>
```

## Addon Development

### Installation

* `git clone` this repository
* `npm install`
* `bower install`
- `git clone` this repository
- `npm install`
- `bower install`

### Running

* `ember server`
* Visit your app at http://localhost:4200.
- `ember server`
- Visit your app at http://localhost:4200.

### Running Tests

* `ember test`
* `ember test --server`
- `ember test`
- `ember test --server`

### Building

* `ember build`
- `ember build`

For more information on using ember-cli, visit [http://www.ember-cli.com/](http://www.ember-cli.com/).
130 changes: 130 additions & 0 deletions addon/addon/resolvers/strict/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/* globals requirejs */

import { warn } from '@ember/debug';
import { dasherize } from '@ember/string';
import { DEBUG } from '@glimmer/env';

import require from 'require';

export default class Resolver {
constructor(attrs) {
if (attrs) {
this.namespace = attrs.namespace;
}
// secret handshake with router to ensure substates are enabled
// see https://github.com/emberjs/ember.js/blob/a429dc327ee6ef97d948a83e727886c75c6fe043/packages/%40ember/-internals/routing/lib/system/router.ts#L344
this.moduleBasedResolver = true;
}

static create(args) {
return new this(args);
}

has(moduleName) {
return moduleName in (requirejs.entries || requirejs._eak_seen);
}

parseFullName(fullName) {
let prefix, type, name;

let fullNameParts = fullName.split('@');

if (fullNameParts.length === 3) {
if (fullNameParts[0].length === 0) {
// leading scoped namespace: `@scope/pkg@type:name`
prefix = `@${fullNameParts[1]}`;
let prefixParts = fullNameParts[2].split(':');
type = prefixParts[0];
name = prefixParts[1];
} else {
// interweaved scoped namespace: `type:@scope/pkg@name`
prefix = `@${fullNameParts[1]}`;
type = fullNameParts[0].slice(0, -1);
name = fullNameParts[2];
}

if (type === 'template:components') {
name = `components/${name}`;
type = 'template';
}
} else if (fullNameParts.length === 2) {
let prefixParts = fullNameParts[0].split(':');

if (prefixParts.length === 2) {
if (prefixParts[1].length === 0) {
type = prefixParts[0];
name = `@${fullNameParts[1]}`;
} else {
prefix = prefixParts[1];
type = prefixParts[0];
name = fullNameParts[1];
}
} else {
let nameParts = fullNameParts[1].split(':');

prefix = fullNameParts[0];
type = nameParts[0];
name = nameParts[1];
}

if (type === 'template' && prefix.lastIndexOf('components/', 0) === 0) {
name = `components/${name}`;
prefix = prefix.slice(11);
}
} else {
fullNameParts = fullName.split(':');

prefix = this.namespace.modulePrefix;
type = fullNameParts[0];
name = fullNameParts[1];
}

return {
prefix,
type,
name
}
}

moduleNameForFullName(fullName) {
let moduleName;

const { prefix, type, name } = this.parseFullName(fullName);

if (name === 'main') {
moduleName = `${prefix}/${type}`;
} else if (type === 'engine') {
moduleName = `${name}/engine`;
} else if (type === 'route-map') {
moduleName = `${name}/routes`;
} else if (type === 'config') {
moduleName = `${prefix}/${type}/${name.replace(/\./g, '/')}`;
} else {
moduleName = `${prefix}/${type}s/${name.replace(/\./g, '/')}`;
}

return moduleName;
}

resolve(fullName) {
const moduleName = this.moduleNameForFullName(fullName);

if (this.has(moduleName)) {
// hit
return require(moduleName)['default'];
}
// miss
}

normalize(fullName) {
if(DEBUG) {
const { type } = this.parseFullName(fullName);

if(['service'].includes(type)) {
warn(`Attempted to lookup "${fullName}". Use "${dasherize(fullName)}" instead.`, !fullName.match(/[a-z]+[A-Z]+/), { id: 'ember-strict-resolver.camelcase-names' });
}
}

return fullName;
}
}
10 changes: 6 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading