-
-
Notifications
You must be signed in to change notification settings - Fork 204
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support First Class Component Templates --
<template>
- Loading branch information
1 parent
139dcc8
commit 84f716e
Showing
7 changed files
with
831 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
'use strict'; | ||
|
||
const { getTemplateLocals } = require('@glimmer/syntax'); | ||
const { | ||
preprocessEmbeddedTemplates, | ||
} = require('ember-template-imports/lib/preprocess-embedded-templates'); | ||
const util = require('ember-template-imports/src/util'); | ||
|
||
function gjs(text, filename) { | ||
const isGlimmerFile = filename.endsWith('.gjs') || filename.endsWith('.gts'); | ||
|
||
if (!isGlimmerFile) { | ||
return [ | ||
{ | ||
filename, | ||
text, | ||
}, | ||
]; | ||
} | ||
|
||
const preprocessed = preprocessEmbeddedTemplates(text, { | ||
getTemplateLocals, | ||
relativePath: filename, | ||
|
||
templateTag: util.TEMPLATE_TAG_NAME, | ||
templateTagReplacement: util.TEMPLATE_TAG_PLACEHOLDER, | ||
|
||
includeSourceMaps: false, | ||
includeTemplateTokens: true, | ||
}); | ||
|
||
return [ | ||
{ | ||
filename, | ||
text: preprocessed.output, | ||
}, | ||
]; | ||
} | ||
|
||
module.exports = { | ||
preprocess: gjs, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
'use strict'; | ||
|
||
/** | ||
* Because this test needs the preprocessor, we can't use the normal | ||
* RuleTester api doesn't support preprocessors. | ||
* | ||
* @typedef {import('eslint/lib/cli-engine/cli-engine').CLIEngineOptions} CLIEngineOptions | ||
*/ | ||
|
||
const { ESLint } = require('eslint'); | ||
const plugin = require('../../../lib'); | ||
|
||
/** | ||
* Helper function which creates ESLint instance with enabled/disabled autofix feature. | ||
* | ||
* @param {CLIEngineOptions} [options={}] Whether to enable autofix feature. | ||
* @returns {ESLint} ESLint instance to execute in tests. | ||
*/ | ||
function initESLint(options) { | ||
// tests must be run with ESLint 7+ | ||
return new ESLint({ | ||
ignore: false, | ||
useEslintrc: false, | ||
plugins: { ember: plugin }, | ||
overrideConfig: { | ||
root: true, | ||
env: { | ||
browser: true, | ||
}, | ||
parser: '@babel/eslint-parser', | ||
parserOptions: { | ||
ecmaVersion: 2020, | ||
sourceType: 'module', | ||
}, | ||
plugins: ['ember'], | ||
extends: ['plugin:ember/base'], | ||
rules: { | ||
'no-undef': 'error', | ||
}, | ||
}, | ||
...options, | ||
}); | ||
} | ||
|
||
const valid = [ | ||
{ | ||
filename: 'my-component.js', | ||
code: ` | ||
import Component from '@glimmer/component'; | ||
export default class MyComponent extends Component { | ||
} | ||
`, | ||
}, | ||
{ | ||
filename: 'my-component.gjs', | ||
code: ` | ||
import { on } from '@ember/modifier'; | ||
const noop = () => {}; | ||
<template> | ||
<div {{on 'click' noop}} /> | ||
</template> | ||
`, | ||
}, | ||
{ | ||
filename: 'my-component.gjs', | ||
code: ` | ||
import { on } from '@ember/modifier'; | ||
const noop = () => {}; | ||
export default <template> | ||
<div {{on 'click' noop}} /> | ||
</template> | ||
`, | ||
}, | ||
{ | ||
filename: 'my-component.gjs', | ||
code: ` | ||
const Foo = <template>hi</template> | ||
<template> | ||
<Foo /> | ||
</template> | ||
`, | ||
}, | ||
]; | ||
|
||
const invalid = [ | ||
{ | ||
filename: 'my-component.gjs', | ||
code: ` | ||
const noop = () => {}; | ||
<template> | ||
{{on 'click' noop}} | ||
</template> | ||
`, | ||
errors: [ | ||
{ | ||
message: "'on' is not defined.", | ||
}, | ||
], | ||
}, | ||
{ | ||
filename: 'my-component.gjs', | ||
code: ` | ||
<template> | ||
{{noop}} | ||
</template> | ||
`, | ||
errors: [ | ||
{ | ||
message: "'noop' is not defined.", | ||
}, | ||
], | ||
}, | ||
{ | ||
filename: 'my-component.gjs', | ||
code: ` | ||
<template> | ||
<Foo /> | ||
</template> | ||
`, | ||
errors: [ | ||
{ | ||
message: "'Foo' is not defined.", | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
describe('template-vars', () => { | ||
describe('valid', () => { | ||
for (const scenario of valid) { | ||
const { code, filename } = scenario; | ||
|
||
// eslint-disable-next-line jest/valid-title | ||
it(code, async () => { | ||
const eslint = initESLint(); | ||
const results = await eslint.lintText(code, { filePath: filename }); | ||
const resultErrors = results.map((result) => result.messages).flat(); | ||
|
||
// This gives more meaningful information than | ||
// checking if results is empty / length === 0 | ||
expect(results?.[0]?.messages?.[0]?.message || '').toStrictEqual(''); | ||
expect(resultErrors).toHaveLength(0); | ||
}); | ||
} | ||
}); | ||
|
||
describe('invalid', () => { | ||
for (const scenario of invalid) { | ||
const { code, filename, errors } = scenario; | ||
|
||
// eslint-disable-next-line jest/valid-title | ||
it(code, async () => { | ||
const eslint = initESLint(); | ||
const results = await eslint.lintText(code, { filePath: filename }); | ||
|
||
const resultErrors = results.map((result) => result.messages).flat(); | ||
expect(resultErrors).toHaveLength(errors.length); | ||
|
||
for (const [index, error] of resultErrors.entries()) { | ||
const expected = errors[index]; | ||
|
||
for (const key of Object.keys(expected)) { | ||
expect(error[key]).toStrictEqual(expected[key]); | ||
} | ||
} | ||
}); | ||
} | ||
}); | ||
}); |
Oops, something went wrong.