Skip to content

Commit 8f9528e

Browse files
committed
[FEATURE] generate signature in component blueprints
Since [RFC 0748][0748], Glimmer components support a `Signature` type which specifies any arguments they accept, any blocks they yield, and the element types to which `...attributes` are applied. Incorporate the signature when generating TS blueprints for Glimmer components, including template-only components. Do *not* generate them for Ember (classic) components, since there are severe limitations in using classic components that way, and since we only support the Octane programming model in our TypeScript support per [RFC 0800][0800]. [0748]: https://rfcs.emberjs.com/id/https://rfcs.emberjs.com/id/0748-glimmer-component-signature/ [0800]: https://rfcs.emberjs.com/id/https://rfcs.emberjs.com/id/0800-ts-adoption-plan/
1 parent 999619d commit 8f9528e

File tree

2 files changed

+37
-10
lines changed

2 files changed

+37
-10
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
<%= importComponent %>
22
<%= importTemplate %>
3+
<%= componentSignature %>
34
export default <%= defaultExport %>

blueprints/component/index.js

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -227,15 +227,8 @@ module.exports = {
227227
},
228228

229229
locals(options) {
230-
let sanitizedModuleName = options.entity.name.replace(/\//g, '-');
231-
let classifiedModuleName = stringUtil.classify(sanitizedModuleName);
232-
233-
let templatePath = '';
234-
let importComponent = '';
235-
let importTemplate = '';
236-
let defaultExport = '';
237-
238230
// if we're in an addon, build import statement
231+
let templatePath = '';
239232
if (options.project.isEmberCLIAddon() || (options.inRepoAddon && !options.inDummy)) {
240233
if (options.pod) {
241234
templatePath = './template';
@@ -251,6 +244,14 @@ module.exports = {
251244
? options.componentClass
252245
: '@ember/component';
253246

247+
let sanitizedModuleName = options.entity.name.replace(/\//g, '-');
248+
let classifiedModuleName = stringUtil.classify(sanitizedModuleName);
249+
250+
let importComponent = '';
251+
let importTemplate = '';
252+
let defaultExport = '';
253+
let componentSignature = '';
254+
254255
switch (componentClass) {
255256
case '@ember/component':
256257
importComponent = `import Component from '@ember/component';`;
@@ -263,20 +264,45 @@ module.exports = {
263264
break;
264265
case '@glimmer/component':
265266
importComponent = `import Component from '@glimmer/component';`;
266-
defaultExport = `class ${classifiedModuleName}Component extends Component {}`;
267+
componentSignature = signatureFor(classifiedModuleName);
268+
defaultExport = `class ${classifiedModuleName}Component extends Component<${classifiedModuleName}Signature> {}`;
267269
break;
268270
case '@ember/component/template-only':
269271
importComponent = `import templateOnly from '@ember/component/template-only';`;
270-
defaultExport = `templateOnly();`;
272+
componentSignature = signatureFor(classifiedModuleName);
273+
defaultExport = `templateOnly<${classifiedModuleName}Signature>();`;
271274
break;
272275
}
273276

274277
return {
275278
importTemplate,
276279
importComponent,
280+
componentSignature,
277281
defaultExport,
278282
path: getPathOption(options),
279283
componentClass: options.componentClass,
280284
};
281285
},
282286
};
287+
288+
function signatureFor(classifiedModuleName) {
289+
let args = ` // The arguments accepted by the component${EOL} Args: {};`;
290+
291+
let blocks =
292+
` // Any blocks yielded by the component${EOL}` +
293+
` Blocks: {${EOL}` +
294+
` default: []${EOL}` +
295+
` };`;
296+
297+
let element =
298+
` // The element to which \`...attributes\` is applied in the component template${EOL}` +
299+
` Element: null;`;
300+
301+
return (
302+
`interface ${classifiedModuleName}Signature {${EOL}` +
303+
`${args}${EOL}` +
304+
`${blocks}${EOL}` +
305+
`${element}${EOL}` +
306+
`}${EOL}`
307+
);
308+
}

0 commit comments

Comments
 (0)