Skip to content

Commit

Permalink
Merge pull request #20356 from emberjs/blueprint-component-signature
Browse files Browse the repository at this point in the history
[FEATURE] generate signature in component blueprints
  • Loading branch information
chriskrycho committed Jan 20, 2023
2 parents 999619d + eebfa28 commit 1118df1
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 12 deletions.
4 changes: 3 additions & 1 deletion blueprints/-maybe-polyfill-typescript-blueprints.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ function canEmitTypeScript() {
}

module.exports = function (context) {
if (canEmitTypeScript()) {
let canUseTypeScript = canEmitTypeScript();
if (canUseTypeScript) {
typescriptBlueprintPolyfill(context);
} else {
// Use the plain old JS templates from before
context.path = context.path.replace('blueprints', 'blueprints-js');
}
return canUseTypeScript;
};
1 change: 1 addition & 0 deletions blueprints/component/files/__root__/__path__/__name__.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<%= importComponent %>
<%= importTemplate %>
<%= componentSignature %>
export default <%= defaultExport %>
64 changes: 53 additions & 11 deletions blueprints/component/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,17 @@ module.exports = {
},
],

/**
Flag to let us correctly handle the case where we are running against a
version of Ember CLI which does not support TS-based emit, and where we
therefore *must* not emit a `defaultExport` local which includes a type
parameter in the exported function call or class definition.
*/
_isUsingTS: false,

init() {
this._super && this._super.init.apply(this, arguments);
maybePolyfillTypeScriptBlueprints(this);
this._isUsingTS = maybePolyfillTypeScriptBlueprints(this);
let isOctane = has('octane');

this.availableOptions.forEach((option) => {
Expand Down Expand Up @@ -227,15 +235,8 @@ module.exports = {
},

locals(options) {
let sanitizedModuleName = options.entity.name.replace(/\//g, '-');
let classifiedModuleName = stringUtil.classify(sanitizedModuleName);

let templatePath = '';
let importComponent = '';
let importTemplate = '';
let defaultExport = '';

// if we're in an addon, build import statement
let templatePath = '';
if (options.project.isEmberCLIAddon() || (options.inRepoAddon && !options.inDummy)) {
if (options.pod) {
templatePath = './template';
Expand All @@ -251,6 +252,14 @@ module.exports = {
? options.componentClass
: '@ember/component';

let sanitizedModuleName = options.entity.name.replace(/\//g, '-');
let classifiedModuleName = stringUtil.classify(sanitizedModuleName);

let importComponent = '';
let importTemplate = '';
let defaultExport = '';
let componentSignature = '';

switch (componentClass) {
case '@ember/component':
importComponent = `import Component from '@ember/component';`;
Expand All @@ -263,20 +272,53 @@ module.exports = {
break;
case '@glimmer/component':
importComponent = `import Component from '@glimmer/component';`;
defaultExport = `class ${classifiedModuleName}Component extends Component {}`;
if (this._isUsingTS) {
componentSignature = signatureFor(classifiedModuleName);
defaultExport = `class ${classifiedModuleName}Component extends Component<${classifiedModuleName}Signature> {}`;
} else {
defaultExport = `class ${classifiedModuleName}Component extends Component {}`;
}
break;
case '@ember/component/template-only':
importComponent = `import templateOnly from '@ember/component/template-only';`;
defaultExport = `templateOnly();`;
if (this._isUsingTS) {
componentSignature = signatureFor(classifiedModuleName);
defaultExport = `templateOnly<${classifiedModuleName}Signature>();`;
} else {
defaultExport = `templateOnly();`;
}
break;
}

return {
importTemplate,
importComponent,
componentSignature,
defaultExport,
path: getPathOption(options),
componentClass: options.componentClass,
};
},
};

function signatureFor(classifiedModuleName) {
let args = ` // The arguments accepted by the component${EOL} Args: {};`;

let blocks =
` // Any blocks yielded by the component${EOL}` +
` Blocks: {${EOL}` +
` default: []${EOL}` +
` };`;

let element =
` // The element to which \`...attributes\` is applied in the component template${EOL}` +
` Element: null;`;

return (
`interface ${classifiedModuleName}Signature {${EOL}` +
`${args}${EOL}` +
`${blocks}${EOL}` +
`${element}${EOL}` +
`}${EOL}`
);
}

0 comments on commit 1118df1

Please sign in to comment.