Skip to content

Commit

Permalink
[FEAT] Add shouldParseScope and disableTemplateLiteral options
Browse files Browse the repository at this point in the history
This PR refactors `modules` to enable users to pass an options, with
three options currently supported:

1. `shouldParseScope`, which allows users to parse the `scope` parameter
   into a static format usable by the precompiler

    ```js
    {
      modules: {
        'ember-cli-htmlbars': 'default',
        '@ember/template-compilation': {
          export: 'precompileTemplate',
          shouldParseScope: true,
        }
      }
    }
    ```

    When enabled, the scope parameter is parsed, and then turned into an
    array of the keys on the object. If a non-object is passed, or any of
    the keys or values are not references, then an error is thrown.

2. `disableTemplateLiteral`, which disables using the precompile macro as a
   template tag. This should be used for `precompileTemplate` in
   `ember-cli-htmlbars`

3. `disableFunctionCall`, which disables using the precompile macro as
   a function call. This should be used by experimental template import
   syntaxes.

This PR also refactors the way that imports statements are processed.
They're now parsed in the beginning, in `Program`, ensuring that the
parse step is only done once, and that we can build a list of all
present imports in the file. This allows us to support more than one
module at once.

wip
  • Loading branch information
Chris Garrett committed Feb 22, 2021
1 parent 14e3488 commit 24ba661
Show file tree
Hide file tree
Showing 2 changed files with 276 additions and 57 deletions.
153 changes: 153 additions & 0 deletions __tests__/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,95 @@ describe('htmlbars-inline-precompile', function () {
expect(transformed).toEqual(expected, 'tagged template is replaced');
});

it('works with multiple imports from different modules', function () {
plugins = [
[
HTMLBarsInlinePrecompile,
{
precompile() {
return precompile.apply(this, arguments);
},

modules: {
'ember-cli-htmlbars': 'hbs',
'@ember/template-compilation': {
export: 'precompileTemplate',
},
},
},
],
];

let transformed = transform(`
import { hbs } from 'ember-cli-htmlbars';
import { precompileTemplate } from '@ember/template-compilation';
let a = hbs\`hello\`;
let b = precompileTemplate('hello');
`);

let expected = `let a = Ember.HTMLBars.template(\n/*\n hello\n*/\n"precompiled(hello)");\nlet b = Ember.HTMLBars.template(\n/*\n hello\n*/\n"precompiled(hello)");`;

expect(transformed).toEqual(expected, 'tagged template is replaced');
});

it('can disable template literal usage', function () {
plugins = [
[
HTMLBarsInlinePrecompile,
{
precompile() {
return precompile.apply(this, arguments);
},

modules: {
'@ember/template-compilation': {
export: 'precompileTemplate',
disableTemplateLiteral: true,
},
},
},
],
];

expect(() => {
transform(`
import { precompileTemplate } from '@ember/template-compilation';
let a = precompileTemplate\`hello\`;
`);
}).toThrow(
/Attempted to use `precompileTemplate` as a template tag, but it can only be called as a function with a string passed to it:/
);
});

it('can disable function call usage', function () {
plugins = [
[
HTMLBarsInlinePrecompile,
{
precompile() {
return precompile.apply(this, arguments);
},

modules: {
'ember-template-imports': {
export: 'hbs',
disableFunctionCall: true,
},
},
},
],
];

expect(() => {
transform(`
import { hbs } from 'ember-template-imports';
let a = hbs(\`hello\`);
`);
}).toThrow(
/Attempted to use `hbs` as a function call, but it can only be used as a template tag:/
);
});

it('works properly when used along with modules transform', function () {
plugins.push([TransformModules]);
let transformed = transform(
Expand Down Expand Up @@ -527,4 +616,68 @@ describe('htmlbars-inline-precompile', function () {
`);
});
});

describe('with transformScope: true', function () {
beforeEach(() => {
plugins = [
[
HTMLBarsInlinePrecompile,
{
precompile() {
return precompile.apply(this, arguments);
},

modules: {
'@ember/template-compilation': {
export: 'precompileTemplate',
shouldParseScope: true,
},
},
},
],
];
});

it('correctly handles scope', function () {
let source = 'hello';
transform(
`import { precompileTemplate } from '@ember/template-compilation';\nvar compiled = precompileTemplate('${source}', { scope: { foo, bar } });`
);

expect(optionsReceived).toEqual({
contents: source,
scope: ['foo', 'bar'],
});
});

it('errors if scope contains mismatched keys/values', function () {
expect(() => {
transform(
"import { precompileTemplate } from '@ember/template-compilation';\nvar compiled = precompileTemplate('hello', { scope: { foo: bar } });"
);
}).toThrow(
/Scope objects for `precompileTemplate` may only contain direct references to in-scope values, e.g. { foo } or { foo: foo }/
);
});

it('errors if scope is not an object', function () {
expect(() => {
transform(
"import { precompileTemplate } from '@ember/template-compilation';\nvar compiled = precompileTemplate('hello', { scope: ['foo', 'bar'] });"
);
}).toThrow(
/Scope objects for `precompileTemplate` must be an object expression containing only references to in-scope values/
);
});

it('errors if scope contains any non-reference values', function () {
expect(() => {
transform(
"import { precompileTemplate } from '@ember/template-compilation';\nvar compiled = precompileTemplate('hello', { scope: { foo, bar: 123 } });"
);
}).toThrow(
/Scope objects for `precompileTemplate` may only contain direct references to in-scope values, e.g. { bar } or { bar: bar }/
);
});
});
});
Loading

0 comments on commit 24ba661

Please sign in to comment.