Skip to content

Commit 1118df1

Browse files
authored
Merge pull request #20356 from emberjs/blueprint-component-signature
[FEATURE] generate signature in component blueprints
2 parents 999619d + eebfa28 commit 1118df1

File tree

3 files changed

+57
-12
lines changed

3 files changed

+57
-12
lines changed

blueprints/-maybe-polyfill-typescript-blueprints.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ function canEmitTypeScript() {
88
}
99

1010
module.exports = function (context) {
11-
if (canEmitTypeScript()) {
11+
let canUseTypeScript = canEmitTypeScript();
12+
if (canUseTypeScript) {
1213
typescriptBlueprintPolyfill(context);
1314
} else {
1415
// Use the plain old JS templates from before
1516
context.path = context.path.replace('blueprints', 'blueprints-js');
1617
}
18+
return canUseTypeScript;
1719
};
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: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,17 @@ module.exports = {
5353
},
5454
],
5555

56+
/**
57+
Flag to let us correctly handle the case where we are running against a
58+
version of Ember CLI which does not support TS-based emit, and where we
59+
therefore *must* not emit a `defaultExport` local which includes a type
60+
parameter in the exported function call or class definition.
61+
*/
62+
_isUsingTS: false,
63+
5664
init() {
5765
this._super && this._super.init.apply(this, arguments);
58-
maybePolyfillTypeScriptBlueprints(this);
66+
this._isUsingTS = maybePolyfillTypeScriptBlueprints(this);
5967
let isOctane = has('octane');
6068

6169
this.availableOptions.forEach((option) => {
@@ -227,15 +235,8 @@ module.exports = {
227235
},
228236

229237
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-
238238
// if we're in an addon, build import statement
239+
let templatePath = '';
239240
if (options.project.isEmberCLIAddon() || (options.inRepoAddon && !options.inDummy)) {
240241
if (options.pod) {
241242
templatePath = './template';
@@ -251,6 +252,14 @@ module.exports = {
251252
? options.componentClass
252253
: '@ember/component';
253254

255+
let sanitizedModuleName = options.entity.name.replace(/\//g, '-');
256+
let classifiedModuleName = stringUtil.classify(sanitizedModuleName);
257+
258+
let importComponent = '';
259+
let importTemplate = '';
260+
let defaultExport = '';
261+
let componentSignature = '';
262+
254263
switch (componentClass) {
255264
case '@ember/component':
256265
importComponent = `import Component from '@ember/component';`;
@@ -263,20 +272,53 @@ module.exports = {
263272
break;
264273
case '@glimmer/component':
265274
importComponent = `import Component from '@glimmer/component';`;
266-
defaultExport = `class ${classifiedModuleName}Component extends Component {}`;
275+
if (this._isUsingTS) {
276+
componentSignature = signatureFor(classifiedModuleName);
277+
defaultExport = `class ${classifiedModuleName}Component extends Component<${classifiedModuleName}Signature> {}`;
278+
} else {
279+
defaultExport = `class ${classifiedModuleName}Component extends Component {}`;
280+
}
267281
break;
268282
case '@ember/component/template-only':
269283
importComponent = `import templateOnly from '@ember/component/template-only';`;
270-
defaultExport = `templateOnly();`;
284+
if (this._isUsingTS) {
285+
componentSignature = signatureFor(classifiedModuleName);
286+
defaultExport = `templateOnly<${classifiedModuleName}Signature>();`;
287+
} else {
288+
defaultExport = `templateOnly();`;
289+
}
271290
break;
272291
}
273292

274293
return {
275294
importTemplate,
276295
importComponent,
296+
componentSignature,
277297
defaultExport,
278298
path: getPathOption(options),
279299
componentClass: options.componentClass,
280300
};
281301
},
282302
};
303+
304+
function signatureFor(classifiedModuleName) {
305+
let args = ` // The arguments accepted by the component${EOL} Args: {};`;
306+
307+
let blocks =
308+
` // Any blocks yielded by the component${EOL}` +
309+
` Blocks: {${EOL}` +
310+
` default: []${EOL}` +
311+
` };`;
312+
313+
let element =
314+
` // The element to which \`...attributes\` is applied in the component template${EOL}` +
315+
` Element: null;`;
316+
317+
return (
318+
`interface ${classifiedModuleName}Signature {${EOL}` +
319+
`${args}${EOL}` +
320+
`${blocks}${EOL}` +
321+
`${element}${EOL}` +
322+
`}${EOL}`
323+
);
324+
}

0 commit comments

Comments
 (0)