@stencil/angular-output-target 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,18 @@
1
1
  import type { ComponentCompilerEvent, ComponentCompilerProperty } from '@stencil/core/internal';
2
- import type { OutputType } from './types';
2
+ import type { ComponentInputProperty, OutputType } from './types';
3
3
  /**
4
4
  * Creates an Angular component declaration from formatted Stencil compiler metadata.
5
5
  *
6
6
  * @param tagName The tag name of the component.
7
- * @param inputs The inputs of the Stencil component (e.g. ['myInput']).
8
- * @param outputs The outputs/events of the Stencil component. (e.g. ['myOutput']).
7
+ * @param inputs The inputs of the Stencil component (e.g. [{name: 'myInput', required: true]).
9
8
  * @param methods The methods of the Stencil component. (e.g. ['myMethod']).
10
9
  * @param includeImportCustomElements Whether to define the component as a custom element.
11
10
  * @param standalone Whether to define the component as a standalone component.
12
11
  * @param inlineComponentProps List of properties that should be inlined into the component definition.
12
+ * @param events The events of the Stencil component for generating outputs.
13
13
  * @returns The component declaration as a string.
14
14
  */
15
- export declare const createAngularComponentDefinition: (tagName: string, inputs: readonly string[], outputs: readonly string[], methods: readonly string[], includeImportCustomElements?: boolean, standalone?: boolean, inlineComponentProps?: readonly ComponentCompilerProperty[]) => string;
15
+ export declare const createAngularComponentDefinition: (tagName: string, inputs: readonly ComponentInputProperty[], methods: readonly string[], includeImportCustomElements?: boolean, standalone?: boolean, inlineComponentProps?: readonly ComponentCompilerProperty[], events?: readonly ComponentCompilerEvent[]) => string;
16
16
  /**
17
17
  * Creates the component interface type definition.
18
18
  * @param outputType The output type.
@@ -1,4 +1,4 @@
1
- import { createComponentEventTypeImports, dashToPascalCase, formatToQuotedList } from './utils';
1
+ import { createComponentEventTypeImports, dashToPascalCase, formatToQuotedList, mapPropName } from './utils';
2
2
  /**
3
3
  * Creates a property declaration.
4
4
  *
@@ -24,25 +24,48 @@ function createPropertyDeclaration(prop, type, inlinePropertyAsSetter = false) {
24
24
  ${eventName}: ${type};`;
25
25
  }
26
26
  }
27
+ /**
28
+ * Creates a formatted inputs text with required declaration.
29
+ *
30
+ * @param prop A ComponentCompilerEvent or ComponentCompilerProperty to turn into a property declaration.
31
+ * @param inputs The inputs of the Stencil component (e.g. [{name: 'myInput', required: true]).
32
+ * @returns The inputs list declaration as a string.
33
+ */
34
+ function formatInputs(inputs) {
35
+ return inputs
36
+ .map((item) => {
37
+ if (item.required) {
38
+ return `{ name: '${item.name}', required: true }`;
39
+ }
40
+ else {
41
+ return `'${item.name}'`;
42
+ }
43
+ })
44
+ .join(', ');
45
+ }
27
46
  /**
28
47
  * Creates an Angular component declaration from formatted Stencil compiler metadata.
29
48
  *
30
49
  * @param tagName The tag name of the component.
31
- * @param inputs The inputs of the Stencil component (e.g. ['myInput']).
32
- * @param outputs The outputs/events of the Stencil component. (e.g. ['myOutput']).
50
+ * @param inputs The inputs of the Stencil component (e.g. [{name: 'myInput', required: true]).
33
51
  * @param methods The methods of the Stencil component. (e.g. ['myMethod']).
34
52
  * @param includeImportCustomElements Whether to define the component as a custom element.
35
53
  * @param standalone Whether to define the component as a standalone component.
36
54
  * @param inlineComponentProps List of properties that should be inlined into the component definition.
55
+ * @param events The events of the Stencil component for generating outputs.
37
56
  * @returns The component declaration as a string.
38
57
  */
39
- export const createAngularComponentDefinition = (tagName, inputs, outputs, methods, includeImportCustomElements = false, standalone = false, inlineComponentProps = []) => {
58
+ export const createAngularComponentDefinition = (tagName, inputs, methods, includeImportCustomElements = false, standalone = false, inlineComponentProps = [], events = []) => {
40
59
  const tagNameAsPascal = dashToPascalCase(tagName);
60
+ const outputs = events.filter((event) => !event.internal).map((event) => event.name);
41
61
  const hasInputs = inputs.length > 0;
42
62
  const hasOutputs = outputs.length > 0;
43
63
  const hasMethods = methods.length > 0;
44
64
  // Formats the input strings into comma separated, single quoted values.
45
- const formattedInputs = formatToQuotedList(inputs);
65
+ const proxyCmpFormattedInputs = formatToQuotedList(inputs.map(mapPropName));
66
+ // Formats the input strings into comma separated, single quoted values if optional.
67
+ // Formats the required input strings into comma separated {name, required} objects.
68
+ const formattedInputs = formatInputs(inputs);
46
69
  // Formats the output strings into comma separated, single quoted values.
47
70
  const formattedOutputs = formatToQuotedList(outputs);
48
71
  // Formats the method strings into comma separated, single quoted values.
@@ -53,7 +76,7 @@ export const createAngularComponentDefinition = (tagName, inputs, outputs, metho
53
76
  proxyCmpOptions.push(`\n defineCustomElementFn: ${defineCustomElementFn}`);
54
77
  }
55
78
  if (hasInputs) {
56
- proxyCmpOptions.push(`\n inputs: [${formattedInputs}]`);
79
+ proxyCmpOptions.push(`\n inputs: [${proxyCmpFormattedInputs}]`);
57
80
  }
58
81
  if (hasMethods) {
59
82
  proxyCmpOptions.push(`\n methods: [${formattedMethods}]`);
@@ -63,7 +86,18 @@ export const createAngularComponentDefinition = (tagName, inputs, outputs, metho
63
86
  standaloneOption = `\n standalone: false`;
64
87
  }
65
88
  const propertyDeclarations = inlineComponentProps.map((m) => createPropertyDeclaration(m, `Components.${tagNameAsPascal}['${m.name}']`, true));
66
- const propertiesDeclarationText = [`protected el: HTML${tagNameAsPascal}Element;`, ...propertyDeclarations].join('\n ');
89
+ const outputDeclarations = events
90
+ .filter((event) => !event.internal)
91
+ .map((event) => {
92
+ const camelCaseOutput = event.name.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
93
+ const outputType = `EventEmitter<CustomEvent<${formatOutputType(tagNameAsPascal, event)}>>`;
94
+ return `@Output() ${camelCaseOutput} = new ${outputType}();`;
95
+ });
96
+ const propertiesDeclarationText = [
97
+ `protected el: HTML${tagNameAsPascal}Element;`,
98
+ ...propertyDeclarations,
99
+ ...outputDeclarations,
100
+ ].join('\n ');
67
101
  /**
68
102
  * Notes on the generated output:
69
103
  * - We disable @angular-eslint/no-inputs-metadata-property, so that
@@ -77,16 +111,13 @@ export const createAngularComponentDefinition = (tagName, inputs, outputs, metho
77
111
  changeDetection: ChangeDetectionStrategy.OnPush,
78
112
  template: '<ng-content></ng-content>',
79
113
  // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
80
- inputs: [${formattedInputs}],${standaloneOption}
114
+ inputs: [${formattedInputs}],${hasOutputs ? `\n outputs: [${formattedOutputs}],` : ''}${standaloneOption}
81
115
  })
82
116
  export class ${tagNameAsPascal} {
83
117
  ${propertiesDeclarationText}
84
118
  constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
85
119
  c.detach();
86
- this.el = r.nativeElement;${hasOutputs
87
- ? `
88
- proxyOutputs(this, this.el, [${formattedOutputs}]);`
89
- : ''}
120
+ this.el = r.nativeElement;
90
121
  }
91
122
  }`;
92
123
  return output;
package/dist/index.cjs.js CHANGED
@@ -15,6 +15,7 @@ const OutputTypes = {
15
15
  Standalone: 'standalone',
16
16
  };
17
17
  const toLowerCase = (str) => str.toLowerCase();
18
+ const mapPropName = (prop) => prop.name;
18
19
  const dashToPascalCase = (str) => toLowerCase(str)
19
20
  .split('-')
20
21
  .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
@@ -169,25 +170,48 @@ function createPropertyDeclaration(prop, type, inlinePropertyAsSetter = false) {
169
170
  ${eventName}: ${type};`;
170
171
  }
171
172
  }
173
+ /**
174
+ * Creates a formatted inputs text with required declaration.
175
+ *
176
+ * @param prop A ComponentCompilerEvent or ComponentCompilerProperty to turn into a property declaration.
177
+ * @param inputs The inputs of the Stencil component (e.g. [{name: 'myInput', required: true]).
178
+ * @returns The inputs list declaration as a string.
179
+ */
180
+ function formatInputs(inputs) {
181
+ return inputs
182
+ .map((item) => {
183
+ if (item.required) {
184
+ return `{ name: '${item.name}', required: true }`;
185
+ }
186
+ else {
187
+ return `'${item.name}'`;
188
+ }
189
+ })
190
+ .join(', ');
191
+ }
172
192
  /**
173
193
  * Creates an Angular component declaration from formatted Stencil compiler metadata.
174
194
  *
175
195
  * @param tagName The tag name of the component.
176
- * @param inputs The inputs of the Stencil component (e.g. ['myInput']).
177
- * @param outputs The outputs/events of the Stencil component. (e.g. ['myOutput']).
196
+ * @param inputs The inputs of the Stencil component (e.g. [{name: 'myInput', required: true]).
178
197
  * @param methods The methods of the Stencil component. (e.g. ['myMethod']).
179
198
  * @param includeImportCustomElements Whether to define the component as a custom element.
180
199
  * @param standalone Whether to define the component as a standalone component.
181
200
  * @param inlineComponentProps List of properties that should be inlined into the component definition.
201
+ * @param events The events of the Stencil component for generating outputs.
182
202
  * @returns The component declaration as a string.
183
203
  */
184
- const createAngularComponentDefinition = (tagName, inputs, outputs, methods, includeImportCustomElements = false, standalone = false, inlineComponentProps = []) => {
204
+ const createAngularComponentDefinition = (tagName, inputs, methods, includeImportCustomElements = false, standalone = false, inlineComponentProps = [], events = []) => {
185
205
  const tagNameAsPascal = dashToPascalCase(tagName);
206
+ const outputs = events.filter((event) => !event.internal).map((event) => event.name);
186
207
  const hasInputs = inputs.length > 0;
187
208
  const hasOutputs = outputs.length > 0;
188
209
  const hasMethods = methods.length > 0;
189
210
  // Formats the input strings into comma separated, single quoted values.
190
- const formattedInputs = formatToQuotedList(inputs);
211
+ const proxyCmpFormattedInputs = formatToQuotedList(inputs.map(mapPropName));
212
+ // Formats the input strings into comma separated, single quoted values if optional.
213
+ // Formats the required input strings into comma separated {name, required} objects.
214
+ const formattedInputs = formatInputs(inputs);
191
215
  // Formats the output strings into comma separated, single quoted values.
192
216
  const formattedOutputs = formatToQuotedList(outputs);
193
217
  // Formats the method strings into comma separated, single quoted values.
@@ -198,7 +222,7 @@ const createAngularComponentDefinition = (tagName, inputs, outputs, methods, inc
198
222
  proxyCmpOptions.push(`\n defineCustomElementFn: ${defineCustomElementFn}`);
199
223
  }
200
224
  if (hasInputs) {
201
- proxyCmpOptions.push(`\n inputs: [${formattedInputs}]`);
225
+ proxyCmpOptions.push(`\n inputs: [${proxyCmpFormattedInputs}]`);
202
226
  }
203
227
  if (hasMethods) {
204
228
  proxyCmpOptions.push(`\n methods: [${formattedMethods}]`);
@@ -208,7 +232,18 @@ const createAngularComponentDefinition = (tagName, inputs, outputs, methods, inc
208
232
  standaloneOption = `\n standalone: false`;
209
233
  }
210
234
  const propertyDeclarations = inlineComponentProps.map((m) => createPropertyDeclaration(m, `Components.${tagNameAsPascal}['${m.name}']`, true));
211
- const propertiesDeclarationText = [`protected el: HTML${tagNameAsPascal}Element;`, ...propertyDeclarations].join('\n ');
235
+ const outputDeclarations = events
236
+ .filter((event) => !event.internal)
237
+ .map((event) => {
238
+ const camelCaseOutput = event.name.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
239
+ const outputType = `EventEmitter<CustomEvent<${formatOutputType(tagNameAsPascal, event)}>>`;
240
+ return `@Output() ${camelCaseOutput} = new ${outputType}();`;
241
+ });
242
+ const propertiesDeclarationText = [
243
+ `protected el: HTML${tagNameAsPascal}Element;`,
244
+ ...propertyDeclarations,
245
+ ...outputDeclarations,
246
+ ].join('\n ');
212
247
  /**
213
248
  * Notes on the generated output:
214
249
  * - We disable @angular-eslint/no-inputs-metadata-property, so that
@@ -222,16 +257,13 @@ const createAngularComponentDefinition = (tagName, inputs, outputs, methods, inc
222
257
  changeDetection: ChangeDetectionStrategy.OnPush,
223
258
  template: '<ng-content></ng-content>',
224
259
  // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
225
- inputs: [${formattedInputs}],${standaloneOption}
260
+ inputs: [${formattedInputs}],${hasOutputs ? `\n outputs: [${formattedOutputs}],` : ''}${standaloneOption}
226
261
  })
227
262
  export class ${tagNameAsPascal} {
228
263
  ${propertiesDeclarationText}
229
264
  constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
230
265
  c.detach();
231
- this.el = r.nativeElement;${hasOutputs
232
- ? `
233
- proxyOutputs(this, this.el, [${formattedOutputs}]);`
234
- : ''}
266
+ this.el = r.nativeElement;
235
267
  }
236
268
  }`;
237
269
  return output;
@@ -474,16 +506,13 @@ function generateProxies(components, pkgData, outputTarget, rootDir) {
474
506
  */
475
507
  const angularCoreImports = ['ChangeDetectionStrategy', 'ChangeDetectorRef', 'Component', 'ElementRef'];
476
508
  if (includeOutputImports) {
477
- angularCoreImports.push('EventEmitter');
509
+ angularCoreImports.push('EventEmitter', 'Output');
478
510
  }
479
511
  angularCoreImports.push('NgZone');
480
512
  /**
481
513
  * The collection of named imports from the angular-component-lib/utils.
482
514
  */
483
515
  const componentLibImports = ['ProxyCmp'];
484
- if (includeOutputImports) {
485
- componentLibImports.push('proxyOutputs');
486
- }
487
516
  if (includeSingleComponentAngularModules) {
488
517
  angularCoreImports.push('NgModule');
489
518
  }
@@ -522,7 +551,14 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
522
551
  }
523
552
  const proxyFileOutput = [];
524
553
  const filterInternalProps = (prop) => !prop.internal;
525
- const mapPropName = (prop) => prop.name;
554
+ // Ensure that virtual properties has required as false.
555
+ const mapInputProp = (prop) => {
556
+ var _a;
557
+ return ({
558
+ name: prop.name,
559
+ required: (_a = prop.required) !== null && _a !== void 0 ? _a : false,
560
+ });
561
+ };
526
562
  const { componentCorePackage, customElementsDir } = outputTarget;
527
563
  for (let cmpMeta of components) {
528
564
  const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
@@ -530,15 +566,11 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
530
566
  if (cmpMeta.properties) {
531
567
  internalProps.push(...cmpMeta.properties.filter(filterInternalProps));
532
568
  }
533
- const inputs = internalProps.map(mapPropName);
569
+ const inputs = internalProps.map(mapInputProp);
534
570
  if (cmpMeta.virtualProperties) {
535
- inputs.push(...cmpMeta.virtualProperties.map(mapPropName));
536
- }
537
- inputs.sort();
538
- const outputs = [];
539
- if (cmpMeta.events) {
540
- outputs.push(...cmpMeta.events.filter(filterInternalProps).map(mapPropName));
571
+ inputs.push(...cmpMeta.virtualProperties.map(mapInputProp));
541
572
  }
573
+ const orderedInputs = sortBy(inputs, (cip) => cip.name);
542
574
  const methods = [];
543
575
  if (cmpMeta.methods) {
544
576
  methods.push(...cmpMeta.methods.filter(filterInternalProps).map(mapPropName));
@@ -550,7 +582,7 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
550
582
  * 2. Optionally the @NgModule decorated class (if includeSingleComponentAngularModules is true)
551
583
  * 3. The component interface (using declaration merging for types).
552
584
  */
553
- const componentDefinition = createAngularComponentDefinition(cmpMeta.tagName, inputs, outputs, methods, isCustomElementsBuild, isStandaloneBuild, inlineComponentProps);
585
+ const componentDefinition = createAngularComponentDefinition(cmpMeta.tagName, orderedInputs, methods, isCustomElementsBuild, isStandaloneBuild, inlineComponentProps, cmpMeta.events || []);
554
586
  const moduleDefinition = generateAngularModuleForComponent(cmpMeta.tagName);
555
587
  const componentTypeDefinition = createComponentTypeDefinition(outputType, tagNameAsPascal, cmpMeta.events, componentCorePackage, customElementsDir);
556
588
  proxyFileOutput.push(componentDefinition, '\n');
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ const OutputTypes = {
7
7
  Standalone: 'standalone',
8
8
  };
9
9
  const toLowerCase = (str) => str.toLowerCase();
10
+ const mapPropName = (prop) => prop.name;
10
11
  const dashToPascalCase = (str) => toLowerCase(str)
11
12
  .split('-')
12
13
  .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
@@ -161,25 +162,48 @@ function createPropertyDeclaration(prop, type, inlinePropertyAsSetter = false) {
161
162
  ${eventName}: ${type};`;
162
163
  }
163
164
  }
165
+ /**
166
+ * Creates a formatted inputs text with required declaration.
167
+ *
168
+ * @param prop A ComponentCompilerEvent or ComponentCompilerProperty to turn into a property declaration.
169
+ * @param inputs The inputs of the Stencil component (e.g. [{name: 'myInput', required: true]).
170
+ * @returns The inputs list declaration as a string.
171
+ */
172
+ function formatInputs(inputs) {
173
+ return inputs
174
+ .map((item) => {
175
+ if (item.required) {
176
+ return `{ name: '${item.name}', required: true }`;
177
+ }
178
+ else {
179
+ return `'${item.name}'`;
180
+ }
181
+ })
182
+ .join(', ');
183
+ }
164
184
  /**
165
185
  * Creates an Angular component declaration from formatted Stencil compiler metadata.
166
186
  *
167
187
  * @param tagName The tag name of the component.
168
- * @param inputs The inputs of the Stencil component (e.g. ['myInput']).
169
- * @param outputs The outputs/events of the Stencil component. (e.g. ['myOutput']).
188
+ * @param inputs The inputs of the Stencil component (e.g. [{name: 'myInput', required: true]).
170
189
  * @param methods The methods of the Stencil component. (e.g. ['myMethod']).
171
190
  * @param includeImportCustomElements Whether to define the component as a custom element.
172
191
  * @param standalone Whether to define the component as a standalone component.
173
192
  * @param inlineComponentProps List of properties that should be inlined into the component definition.
193
+ * @param events The events of the Stencil component for generating outputs.
174
194
  * @returns The component declaration as a string.
175
195
  */
176
- const createAngularComponentDefinition = (tagName, inputs, outputs, methods, includeImportCustomElements = false, standalone = false, inlineComponentProps = []) => {
196
+ const createAngularComponentDefinition = (tagName, inputs, methods, includeImportCustomElements = false, standalone = false, inlineComponentProps = [], events = []) => {
177
197
  const tagNameAsPascal = dashToPascalCase(tagName);
198
+ const outputs = events.filter((event) => !event.internal).map((event) => event.name);
178
199
  const hasInputs = inputs.length > 0;
179
200
  const hasOutputs = outputs.length > 0;
180
201
  const hasMethods = methods.length > 0;
181
202
  // Formats the input strings into comma separated, single quoted values.
182
- const formattedInputs = formatToQuotedList(inputs);
203
+ const proxyCmpFormattedInputs = formatToQuotedList(inputs.map(mapPropName));
204
+ // Formats the input strings into comma separated, single quoted values if optional.
205
+ // Formats the required input strings into comma separated {name, required} objects.
206
+ const formattedInputs = formatInputs(inputs);
183
207
  // Formats the output strings into comma separated, single quoted values.
184
208
  const formattedOutputs = formatToQuotedList(outputs);
185
209
  // Formats the method strings into comma separated, single quoted values.
@@ -190,7 +214,7 @@ const createAngularComponentDefinition = (tagName, inputs, outputs, methods, inc
190
214
  proxyCmpOptions.push(`\n defineCustomElementFn: ${defineCustomElementFn}`);
191
215
  }
192
216
  if (hasInputs) {
193
- proxyCmpOptions.push(`\n inputs: [${formattedInputs}]`);
217
+ proxyCmpOptions.push(`\n inputs: [${proxyCmpFormattedInputs}]`);
194
218
  }
195
219
  if (hasMethods) {
196
220
  proxyCmpOptions.push(`\n methods: [${formattedMethods}]`);
@@ -200,7 +224,18 @@ const createAngularComponentDefinition = (tagName, inputs, outputs, methods, inc
200
224
  standaloneOption = `\n standalone: false`;
201
225
  }
202
226
  const propertyDeclarations = inlineComponentProps.map((m) => createPropertyDeclaration(m, `Components.${tagNameAsPascal}['${m.name}']`, true));
203
- const propertiesDeclarationText = [`protected el: HTML${tagNameAsPascal}Element;`, ...propertyDeclarations].join('\n ');
227
+ const outputDeclarations = events
228
+ .filter((event) => !event.internal)
229
+ .map((event) => {
230
+ const camelCaseOutput = event.name.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
231
+ const outputType = `EventEmitter<CustomEvent<${formatOutputType(tagNameAsPascal, event)}>>`;
232
+ return `@Output() ${camelCaseOutput} = new ${outputType}();`;
233
+ });
234
+ const propertiesDeclarationText = [
235
+ `protected el: HTML${tagNameAsPascal}Element;`,
236
+ ...propertyDeclarations,
237
+ ...outputDeclarations,
238
+ ].join('\n ');
204
239
  /**
205
240
  * Notes on the generated output:
206
241
  * - We disable @angular-eslint/no-inputs-metadata-property, so that
@@ -214,16 +249,13 @@ const createAngularComponentDefinition = (tagName, inputs, outputs, methods, inc
214
249
  changeDetection: ChangeDetectionStrategy.OnPush,
215
250
  template: '<ng-content></ng-content>',
216
251
  // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
217
- inputs: [${formattedInputs}],${standaloneOption}
252
+ inputs: [${formattedInputs}],${hasOutputs ? `\n outputs: [${formattedOutputs}],` : ''}${standaloneOption}
218
253
  })
219
254
  export class ${tagNameAsPascal} {
220
255
  ${propertiesDeclarationText}
221
256
  constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
222
257
  c.detach();
223
- this.el = r.nativeElement;${hasOutputs
224
- ? `
225
- proxyOutputs(this, this.el, [${formattedOutputs}]);`
226
- : ''}
258
+ this.el = r.nativeElement;
227
259
  }
228
260
  }`;
229
261
  return output;
@@ -466,16 +498,13 @@ function generateProxies(components, pkgData, outputTarget, rootDir) {
466
498
  */
467
499
  const angularCoreImports = ['ChangeDetectionStrategy', 'ChangeDetectorRef', 'Component', 'ElementRef'];
468
500
  if (includeOutputImports) {
469
- angularCoreImports.push('EventEmitter');
501
+ angularCoreImports.push('EventEmitter', 'Output');
470
502
  }
471
503
  angularCoreImports.push('NgZone');
472
504
  /**
473
505
  * The collection of named imports from the angular-component-lib/utils.
474
506
  */
475
507
  const componentLibImports = ['ProxyCmp'];
476
- if (includeOutputImports) {
477
- componentLibImports.push('proxyOutputs');
478
- }
479
508
  if (includeSingleComponentAngularModules) {
480
509
  angularCoreImports.push('NgModule');
481
510
  }
@@ -514,7 +543,14 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
514
543
  }
515
544
  const proxyFileOutput = [];
516
545
  const filterInternalProps = (prop) => !prop.internal;
517
- const mapPropName = (prop) => prop.name;
546
+ // Ensure that virtual properties has required as false.
547
+ const mapInputProp = (prop) => {
548
+ var _a;
549
+ return ({
550
+ name: prop.name,
551
+ required: (_a = prop.required) !== null && _a !== void 0 ? _a : false,
552
+ });
553
+ };
518
554
  const { componentCorePackage, customElementsDir } = outputTarget;
519
555
  for (let cmpMeta of components) {
520
556
  const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
@@ -522,15 +558,11 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
522
558
  if (cmpMeta.properties) {
523
559
  internalProps.push(...cmpMeta.properties.filter(filterInternalProps));
524
560
  }
525
- const inputs = internalProps.map(mapPropName);
561
+ const inputs = internalProps.map(mapInputProp);
526
562
  if (cmpMeta.virtualProperties) {
527
- inputs.push(...cmpMeta.virtualProperties.map(mapPropName));
528
- }
529
- inputs.sort();
530
- const outputs = [];
531
- if (cmpMeta.events) {
532
- outputs.push(...cmpMeta.events.filter(filterInternalProps).map(mapPropName));
563
+ inputs.push(...cmpMeta.virtualProperties.map(mapInputProp));
533
564
  }
565
+ const orderedInputs = sortBy(inputs, (cip) => cip.name);
534
566
  const methods = [];
535
567
  if (cmpMeta.methods) {
536
568
  methods.push(...cmpMeta.methods.filter(filterInternalProps).map(mapPropName));
@@ -542,7 +574,7 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
542
574
  * 2. Optionally the @NgModule decorated class (if includeSingleComponentAngularModules is true)
543
575
  * 3. The component interface (using declaration merging for types).
544
576
  */
545
- const componentDefinition = createAngularComponentDefinition(cmpMeta.tagName, inputs, outputs, methods, isCustomElementsBuild, isStandaloneBuild, inlineComponentProps);
577
+ const componentDefinition = createAngularComponentDefinition(cmpMeta.tagName, orderedInputs, methods, isCustomElementsBuild, isStandaloneBuild, inlineComponentProps, cmpMeta.events || []);
546
578
  const moduleDefinition = generateAngularModuleForComponent(cmpMeta.tagName);
547
579
  const componentTypeDefinition = createComponentTypeDefinition(outputType, tagNameAsPascal, cmpMeta.events, componentCorePackage, customElementsDir);
548
580
  proxyFileOutput.push(componentDefinition, '\n');
@@ -1,5 +1,5 @@
1
1
  import path from 'path';
2
- import { relativeImport, normalizePath, sortBy, readPackageJson, dashToPascalCase, createImportStatement, isOutputTypeCustomElementsBuild, OutputTypes, } from './utils';
2
+ import { relativeImport, normalizePath, sortBy, readPackageJson, dashToPascalCase, createImportStatement, isOutputTypeCustomElementsBuild, OutputTypes, mapPropName, } from './utils';
3
3
  import { createAngularComponentDefinition, createComponentTypeDefinition } from './generate-angular-component';
4
4
  import { generateAngularDirectivesFile } from './generate-angular-directives-file';
5
5
  import generateValueAccessors from './generate-value-accessors';
@@ -49,16 +49,13 @@ export function generateProxies(components, pkgData, outputTarget, rootDir) {
49
49
  */
50
50
  const angularCoreImports = ['ChangeDetectionStrategy', 'ChangeDetectorRef', 'Component', 'ElementRef'];
51
51
  if (includeOutputImports) {
52
- angularCoreImports.push('EventEmitter');
52
+ angularCoreImports.push('EventEmitter', 'Output');
53
53
  }
54
54
  angularCoreImports.push('NgZone');
55
55
  /**
56
56
  * The collection of named imports from the angular-component-lib/utils.
57
57
  */
58
58
  const componentLibImports = ['ProxyCmp'];
59
- if (includeOutputImports) {
60
- componentLibImports.push('proxyOutputs');
61
- }
62
59
  if (includeSingleComponentAngularModules) {
63
60
  angularCoreImports.push('NgModule');
64
61
  }
@@ -97,7 +94,14 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
97
94
  }
98
95
  const proxyFileOutput = [];
99
96
  const filterInternalProps = (prop) => !prop.internal;
100
- const mapPropName = (prop) => prop.name;
97
+ // Ensure that virtual properties has required as false.
98
+ const mapInputProp = (prop) => {
99
+ var _a;
100
+ return ({
101
+ name: prop.name,
102
+ required: (_a = prop.required) !== null && _a !== void 0 ? _a : false,
103
+ });
104
+ };
101
105
  const { componentCorePackage, customElementsDir } = outputTarget;
102
106
  for (let cmpMeta of components) {
103
107
  const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
@@ -105,15 +109,11 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
105
109
  if (cmpMeta.properties) {
106
110
  internalProps.push(...cmpMeta.properties.filter(filterInternalProps));
107
111
  }
108
- const inputs = internalProps.map(mapPropName);
112
+ const inputs = internalProps.map(mapInputProp);
109
113
  if (cmpMeta.virtualProperties) {
110
- inputs.push(...cmpMeta.virtualProperties.map(mapPropName));
111
- }
112
- inputs.sort();
113
- const outputs = [];
114
- if (cmpMeta.events) {
115
- outputs.push(...cmpMeta.events.filter(filterInternalProps).map(mapPropName));
114
+ inputs.push(...cmpMeta.virtualProperties.map(mapInputProp));
116
115
  }
116
+ const orderedInputs = sortBy(inputs, (cip) => cip.name);
117
117
  const methods = [];
118
118
  if (cmpMeta.methods) {
119
119
  methods.push(...cmpMeta.methods.filter(filterInternalProps).map(mapPropName));
@@ -125,7 +125,7 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
125
125
  * 2. Optionally the @NgModule decorated class (if includeSingleComponentAngularModules is true)
126
126
  * 3. The component interface (using declaration merging for types).
127
127
  */
128
- const componentDefinition = createAngularComponentDefinition(cmpMeta.tagName, inputs, outputs, methods, isCustomElementsBuild, isStandaloneBuild, inlineComponentProps);
128
+ const componentDefinition = createAngularComponentDefinition(cmpMeta.tagName, orderedInputs, methods, isCustomElementsBuild, isStandaloneBuild, inlineComponentProps, cmpMeta.events || []);
129
129
  const moduleDefinition = generateAngularModuleForComponent(cmpMeta.tagName);
130
130
  const componentTypeDefinition = createComponentTypeDefinition(outputType, tagNameAsPascal, cmpMeta.events, componentCorePackage, customElementsDir);
131
131
  proxyFileOutput.push(componentDefinition, '\n');
package/dist/types.d.ts CHANGED
@@ -44,3 +44,7 @@ export interface ValueAccessorConfig {
44
44
  export interface PackageJSON {
45
45
  types: string;
46
46
  }
47
+ export interface ComponentInputProperty {
48
+ name: string;
49
+ required: boolean;
50
+ }
package/dist/utils.d.ts CHANGED
@@ -4,6 +4,9 @@ export declare const OutputTypes: {
4
4
  [key: string]: OutputType;
5
5
  };
6
6
  export declare const toLowerCase: (str: string) => string;
7
+ export declare const mapPropName: (prop: {
8
+ name: string;
9
+ }) => string;
7
10
  export declare const dashToPascalCase: (str: string) => string;
8
11
  export declare function sortBy<T>(array: T[], prop: (item: T) => string): T[];
9
12
  export declare function normalizePath(str: string): string;
package/dist/utils.js CHANGED
@@ -5,6 +5,7 @@ export const OutputTypes = {
5
5
  Standalone: 'standalone',
6
6
  };
7
7
  export const toLowerCase = (str) => str.toLowerCase();
8
+ export const mapPropName = (prop) => prop.name;
8
9
  export const dashToPascalCase = (str) => toLowerCase(str)
9
10
  .split('-')
10
11
  .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stencil/angular-output-target",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Angular output target for @stencil/core components.",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.js",
@@ -50,7 +50,7 @@
50
50
  "devDependencies": {
51
51
  "@angular/core": "8.2.14",
52
52
  "@angular/forms": "8.2.14",
53
- "@stencil/core": "4.32.0",
53
+ "@stencil/core": "4.35.1",
54
54
  "@types/node": "^18.0.0",
55
55
  "npm-run-all2": "^6.2.4",
56
56
  "rimraf": "^5.0.0",