Skip to content

Commit

Permalink
Merge pull request #1340 from void-mAlex/staticHelpers-and-staticModi…
Browse files Browse the repository at this point in the history
…fiers-transform-fixes

Static helpers and static modifiers transform fixes
  • Loading branch information
ef4 committed Jan 27, 2023
2 parents d94051e + 31e7e25 commit c2dd82e
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 28 deletions.
35 changes: 28 additions & 7 deletions packages/compat/src/resolver-transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
ResolutionFail,
Resolution,
ResolvedDep,
HelperResolution,
ModifierResolution,
} from './resolver';
import type { ASTv1, ASTPluginBuilder, ASTPluginEnvironment, WalkerPath } from '@glimmer/syntax';
import type { WithJSUtils } from 'babel-plugin-ember-template-compilation';
Expand Down Expand Up @@ -241,11 +243,17 @@ export default function makeResolverTransform({ resolver, patchHelpersBug }: Opt
return;
}
if (node.path.original === 'helper' && node.params.length > 0) {
handleDynamicHelper(node.params[0], resolver, filename);
let resolution = handleDynamicHelper(node.params[0], resolver, filename);
emit(path, resolution, (node, newId) => {
node.params[0] = newId;
});
return;
}
if (node.path.original === 'modifier' && node.params.length > 0) {
handleDynamicModifier(node.params[0], resolver, filename);
let resolution = handleDynamicModifier(node.params[0], resolver, filename);
emit(path, resolution, (node, newId) => {
node.params[0] = newId;
});
return;
}
let resolution = resolver.resolveSubExpression(node.path.original, filename, node.path.loc);
Expand Down Expand Up @@ -288,7 +296,10 @@ export default function makeResolverTransform({ resolver, patchHelpersBug }: Opt
return;
}
if (node.path.original === 'helper' && node.params.length > 0) {
handleDynamicHelper(node.params[0], resolver, filename);
let resolution = handleDynamicHelper(node.params[0], resolver, filename);
emit(path, resolution, (node, newIdentifier) => {
node.params[0] = newIdentifier;
});
return;
}
let hasArgs = node.params.length > 0 || node.hash.pairs.length > 0;
Expand Down Expand Up @@ -520,20 +531,30 @@ function handleComponentHelper(
return resolver.resolveComponentHelper(locator, moduleName, param.loc, impliedBecause);
}

function handleDynamicHelper(param: ASTv1.Expression, resolver: Resolver, moduleName: string): void {
function handleDynamicHelper(
param: ASTv1.Expression,
resolver: Resolver,
moduleName: string
): HelperResolution | ResolutionFail | null {
// We only need to handle StringLiterals since Ember already throws an error if unsupported values
// are passed to the helper keyword.
// If a helper reference is passed in we don't need to do anything since it's either the result of a previous
// helper keyword invocation, or a helper reference that was imported somewhere.
if (param.type === 'StringLiteral') {
resolver.resolveDynamicHelper({ type: 'literal', path: param.value }, moduleName, param.loc);
return resolver.resolveDynamicHelper({ type: 'literal', path: param.value }, moduleName, param.loc);
}
return null;
}

function handleDynamicModifier(param: ASTv1.Expression, resolver: Resolver, moduleName: string): void {
function handleDynamicModifier(
param: ASTv1.Expression,
resolver: Resolver,
moduleName: string
): ModifierResolution | ResolutionFail | null {
if (param.type === 'StringLiteral') {
resolver.resolveDynamicModifier({ type: 'literal', path: param.value }, moduleName, param.loc);
return resolver.resolveDynamicModifier({ type: 'literal', path: param.value }, moduleName, param.loc);
}
return null;
}

function extendPath<N extends ASTv1.Node, K extends keyof N>(
Expand Down
116 changes: 95 additions & 21 deletions packages/compat/tests/resolver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ describe('compat-resolver', function () {
`);
});

test.skip('string literal passed to "helper" keyword in content position', function () {
test('string literal passed to "helper" keyword in content position', function () {
let transform = configure({
staticHelpers: true,
});
Expand All @@ -705,11 +705,14 @@ describe('compat-resolver', function () {
import helloWorld from "../helpers/hello-world.js";
import { precompileTemplate } from "@ember/template-compilation";
export default precompileTemplate("{{helper helloWorld}}", {
moduleName: "my-app/templates/application.hbs"
moduleName: "my-app/templates/application.hbs",
scope: () => ({
helloWorld,
}),
});
`);
});
test.skip('string literal passed to "modifier" keyword in content position', function () {
test('string literal passed to "modifier" keyword in content position', function () {
let transform = configure({
staticModifiers: true,
});
Expand All @@ -723,11 +726,70 @@ describe('compat-resolver', function () {
import addListener from "../modifiers/add-listener.js";
import { precompileTemplate } from "@ember/template-compilation";
export default precompileTemplate("<button {{(modifier addListener \\"click\\" this.handleClick)}}>Test</button>", {
moduleName: "my-app/templates/application.hbs"
moduleName: "my-app/templates/application.hbs",
scope: () => ({
addListener
})
});
`);
});
test('modifier in bare mustache, no args', function () {
let transform = configure({
staticModifiers: false,
});
givenFile('modifiers/scroll-top.js');
expect(transform('templates/application.hbs', `<div {{scroll-top}}>Test</div>`)).toEqualCode(`
import { precompileTemplate } from "@ember/template-compilation";
export default precompileTemplate("<div {{scroll-top}}>Test</div>", {
moduleName: "my-app/templates/application.hbs",
});
`);
});
test('modifier in bare mustache, with args', function () {
let transform = configure({
staticModifiers: false,
});
givenFile('modifiers/scroll-top.js');
expect(transform('templates/application.hbs', `<div {{scroll-top @scrollTopPosition}}>Test</div>`)).toEqualCode(`
import { precompileTemplate } from "@ember/template-compilation";
export default precompileTemplate("<div {{scroll-top @scrollTopPosition}}>Test</div>", {
moduleName: "my-app/templates/application.hbs",
});
`);
});
test('modifier in bare mustache, no args', function () {
let transform = configure({
staticModifiers: true,
});
givenFile('modifiers/scroll-top.js');
expect(transform('templates/application.hbs', `<div {{scroll-top}}>Test</div>`)).toEqualCode(`
import scrollTop from "../modifiers/scroll-top.js";
import { precompileTemplate } from "@ember/template-compilation";
export default precompileTemplate("<div {{scrollTop}}>Test</div>", {
moduleName: "my-app/templates/application.hbs",
scope: () => ({
scrollTop
})
});
`);
});
test.skip('modifier currying using the "modifier" keyword', function () {
test('modifier in bare mustache, with args', function () {
let transform = configure({
staticModifiers: true,
});
givenFile('modifiers/scroll-top.js');
expect(transform('templates/application.hbs', `<div {{scroll-top @scrollTopPosition}}>Test</div>`)).toEqualCode(`
import scrollTop from "../modifiers/scroll-top.js";
import { precompileTemplate } from "@ember/template-compilation";
export default precompileTemplate("<div {{scrollTop @scrollTopPosition}}>Test</div>", {
moduleName: "my-app/templates/application.hbs",
scope: () => ({
scrollTop
})
});
`);
});
test('modifier currying using the "modifier" keyword', function () {
let transform = configure({ staticModifiers: true });
givenFile('modifiers/add-listener.js');
expect(
Expand All @@ -743,7 +805,10 @@ describe('compat-resolver', function () {
import addListener from "../modifiers/add-listener.js";
import { precompileTemplate } from "@ember/template-compilation";
export default precompileTemplate("{{#let (modifier addListener) as |addListener|}}\\n {{#let (modifier addListener \\"click\\") as |addClickListener|}}\\n <button {{addClickListener this.handleClick}}>Test</button>\\n {{/let}}\\n {{/let}}", {
moduleName: "my-app/templates/application.hbs"
moduleName: "my-app/templates/application.hbs",
scope: () => ({
addListener
})
});
`);
});
Expand Down Expand Up @@ -970,7 +1035,7 @@ describe('compat-resolver', function () {
`);
});

test.skip('string literal passed to "helper" keyword in helper position', function () {
test('string literal passed to "helper" keyword in helper position', function () {
let transform = configure({ staticHelpers: true });
givenFile('helpers/hello-world.js');
expect(
Expand All @@ -983,14 +1048,17 @@ describe('compat-resolver', function () {
`
)
).toEqualCode(`
import HelloWorld from "../helpers/hello-world.js";
import helloWorld from "../helpers/hello-world.js";
import { precompileTemplate } from "@ember/template-compilation";
export default precompileTemplate("\\n {{#let (helper HelloWorld) as |helloWorld|}}\\n {{helloWorld}}\\n {{/let}}\\n ", {
moduleName: "my-app/templates/application.hbs"
export default precompileTemplate("\\n {{#let (helper helloWorld) as |helloWorld|}}\\n {{helloWorld}}\\n {{/let}}\\n ", {
moduleName: "my-app/templates/application.hbs",
scope: () => ({
helloWorld,
}),
});
`);
});
test.skip('helper currying using the "helper" keyword', function () {
test('helper currying using the "helper" keyword', function () {
let transform = configure({ staticHelpers: true });
givenFile('helpers/hello-world.js');
expect(
Expand All @@ -1005,14 +1073,17 @@ describe('compat-resolver', function () {
`
)
).toEqualCode(`
import HelloWorld from "../helpers/hello-world.js";
import helloWorld from "../helpers/hello-world.js";
import { precompileTemplate } from "@ember/template-compilation";
export default precompileTemplate("\\n {{#let (helper HelloWorld name=\\"World\\") as |hello|}}\\n {{#let (helper hello name=\\"Tomster\\") as |helloTomster|}}\\n {{helloTomster name=\\"Zoey\\"}}\\n {{/let}}\\n {{/let}}\\n ", {
moduleName: "my-app/templates/application.hbs"
export default precompileTemplate("\\n {{#let (helper helloWorld name=\\"World\\") as |hello|}}\\n {{#let (helper hello name=\\"Tomster\\") as |helloTomster|}}\\n {{helloTomster name=\\"Zoey\\"}}\\n {{/let}}\\n {{/let}}\\n ", {
moduleName: "my-app/templates/application.hbs",
scope: () => ({
helloWorld,
}),
});
`);
});
test.skip('string literal passed to "modifier" keyword in helper position', function () {
test('string literal passed to "modifier" keyword in helper position', function () {
let transform = configure({ staticModifiers: true });
givenFile('modifiers/add-listener.js');
expect(
Expand All @@ -1024,11 +1095,14 @@ describe('compat-resolver', function () {
{{/let}}
`
)
).toEqual(`
import AddListener from ../modifiers/add-listener.js;
).toEqualCode(`
import addListener from "../modifiers/add-listener.js";
import { precompileTemplate } from "@ember/template-compilation";
export default precompileTemplate("\\n {{#let (modifier AddListener \\"click\\") as |addClickListener|}}\\n <button {{addClickListener this.handleClick}}>Test</button>\\n {{/let}}\\n ", {
moduleName: "my-app/templates/application.hbs"
export default precompileTemplate("\\n {{#let (modifier addListener \\"click\\") as |addClickListener|}}\\n <button {{addClickListener this.handleClick}}>Test</button>\\n {{/let}}\\n ", {
moduleName: "my-app/templates/application.hbs",
scope: () => ({
addListener
}),
});
`);
});
Expand All @@ -1039,13 +1113,13 @@ describe('compat-resolver', function () {
transform('templates/application.hbs', `{{my-thing header=(component "hello-world") }}`);
}).toThrow(new RegExp(`Missing component: hello-world in templates/application.hbs`));
});
test.skip('string literal passed to "helper" keyword fails to resolve', function () {
test('string literal passed to "helper" keyword fails to resolve', function () {
let transform = configure({ staticHelpers: true });
expect(() => {
transform('templates/application.hbs', `{{helper "hello-world"}}`);
}).toThrow(new RegExp(`Missing helper: hello-world in templates/application.hbs`));
});
test.skip('string literal passed to "modifier" keyword fails to resolve', function () {
test('string literal passed to "modifier" keyword fails to resolve', function () {
let transform = configure({ staticModifiers: true });
expect(() => {
transform(
Expand Down

0 comments on commit c2dd82e

Please sign in to comment.