@stencil/angular-output-target 0.6.1-dev.11662577182.1c45c8de → 0.6.1-dev.11667512184.13935f80

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.
package/README.md CHANGED
@@ -27,7 +27,7 @@ export const config: Config = {
27
27
  outputTargets: [
28
28
  angularOutputTarget({
29
29
  componentCorePackage: 'component-library',
30
- proxyDeclarationFile: '../component-library-angular/src/directives/proxies.ts',
30
+ directivesProxyFile: '../component-library-angular/src/directives/proxies.ts',
31
31
  directivesArrayFile: '../component-library-angular/src/directives/index.ts',
32
32
  }),
33
33
  {
@@ -43,7 +43,7 @@ export const config: Config = {
43
43
  | Property | Description |
44
44
  | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
45
45
  | `componentCorePackage` | The NPM package name of your Stencil component library. This package is used as a dependency for your Angular wrappers. |
46
- | `proxyDeclarationFile` | The output file of all the component wrappers generated by the output target. This file path should point to a location within your Angular library/project. |
46
+ | `directivesProxyFile` | The output file of all the component wrappers generated by the output target. This file path should point to a location within your Angular library/project. |
47
47
  | `directivesArrayFile` | The output file of a constant of all the generated component wrapper classes. Used for easily declaring and exporting the generated components from an `NgModule`. This file path should point to a location within your Angular library/project. |
48
48
  | `valueAccessorConfigs` | The configuration object for how individual web components behave with Angular control value accessors. |
49
49
  | `excludeComponents` | An array of tag names to exclude from generating component wrappers for. This is helpful when have a custom framework implementation of a specific component or need to extend the base component wrapper behavior. |
@@ -36,6 +36,28 @@ export const defineCustomElement = (tagName: string, customElement: any) => {
36
36
  }
37
37
  };
38
38
 
39
+ /**
40
+ * The Angular property name that contains the object of metadata properties
41
+ * for the component added by the Angular compiler.
42
+ */
43
+ const NG_COMP_DEF = 'ɵcmp';
44
+
45
+ export const clearAngularOutputBindings = (cls: any) => {
46
+ if (typeof cls === 'function' && cls !== null) {
47
+ if (cls.prototype.constructor) {
48
+ const instance = cls.prototype.constructor;
49
+ if (instance[NG_COMP_DEF]) {
50
+ /**
51
+ * With the output targets generating @Output() proxies, we need to
52
+ * clear the metadata (ɵcmp.outputs) so that Angular does not add its own event listener
53
+ * and cause duplicate event emissions for the web component events.
54
+ */
55
+ instance[NG_COMP_DEF].outputs = {};
56
+ }
57
+ }
58
+ }
59
+ };
60
+
39
61
  // tslint:disable-next-line: only-arrow-functions
40
62
  export function ProxyCmp(opts: { defineCustomElementFn?: () => void; inputs?: any; methods?: any }) {
41
63
  const decorator = function (cls: any) {
@@ -45,6 +67,8 @@ export function ProxyCmp(opts: { defineCustomElementFn?: () => void; inputs?: an
45
67
  defineCustomElementFn();
46
68
  }
47
69
 
70
+ clearAngularOutputBindings(cls);
71
+
48
72
  if (inputs) {
49
73
  proxyInputs(cls, inputs);
50
74
  }
@@ -9,7 +9,7 @@ import type { ComponentCompilerEvent } from '@stencil/core/internal';
9
9
  * @param includeImportCustomElements Whether to define the component as a custom element.
10
10
  * @returns The component declaration as a string.
11
11
  */
12
- export declare const createAngularComponentDefinition: (tagName: string, inputs: readonly string[], outputs: readonly string[], methods: readonly string[], includeImportCustomElements?: boolean) => string;
12
+ export declare const createAngularComponentDefinition: (tagName: string, inputs: readonly string[], outputs: readonly ComponentCompilerEvent[], methods: readonly string[], includeImportCustomElements?: boolean) => string;
13
13
  /**
14
14
  * Creates the component interface type definition.
15
15
  * @param tagNameAsPascal The tag name as PascalCase.
@@ -17,9 +17,11 @@ export const createAngularComponentDefinition = (tagName, inputs, outputs, metho
17
17
  // Formats the input strings into comma separated, single quoted values.
18
18
  const formattedInputs = formatToQuotedList(inputs);
19
19
  // Formats the output strings into comma separated, single quoted values.
20
- const formattedOutputs = formatToQuotedList(outputs);
20
+ const formattedOutputs = formatToQuotedList(outputs.map((event) => event.name));
21
21
  // Formats the method strings into comma separated, single quoted values.
22
22
  const formattedMethods = formatToQuotedList(methods);
23
+ // The collection of @Output() decorators for the component.
24
+ const outputDecorators = outputs.map((event) => createAngularOutputDecorator(tagName, event));
23
25
  const proxyCmpOptions = [];
24
26
  if (includeImportCustomElements) {
25
27
  const defineCustomElementFn = `define${tagNameAsPascal}`;
@@ -31,32 +33,54 @@ export const createAngularComponentDefinition = (tagName, inputs, outputs, metho
31
33
  if (hasMethods) {
32
34
  proxyCmpOptions.push(`\n methods: [${formattedMethods}]`);
33
35
  }
34
- /**
35
- * Notes on the generated output:
36
- * - We disable @angular-eslint/no-inputs-metadata-property, so that
37
- * Angular does not complain about the inputs property. The output target
38
- * uses the inputs property to define the inputs of the component instead of
39
- * having to use the @Input decorator (and manually define the type and default value).
40
- */
41
- const output = `@ProxyCmp({${proxyCmpOptions.join(',')}\n})
42
- @Component({
43
- selector: '${tagName}',
44
- changeDetection: ChangeDetectionStrategy.OnPush,
45
- template: '<ng-content></ng-content>',
46
- // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
47
- inputs: [${formattedInputs}],
48
- })
49
- export class ${tagNameAsPascal} {
50
- protected el: HTMLElement;
51
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
52
- c.detach();
53
- this.el = r.nativeElement;${hasOutputs
54
- ? `
55
- proxyOutputs(this, this.el, [${formattedOutputs}]);`
56
- : ''}
57
- }
58
- }`;
59
- return output;
36
+ const output = [
37
+ `@ProxyCmp({${proxyCmpOptions.join(',')}\n})`,
38
+ `@Component({`,
39
+ ` selector: '${tagName}',`,
40
+ ` changeDetection: ChangeDetectionStrategy.OnPush,`,
41
+ ` template: '<ng-content></ng-content>',`,
42
+ /**
43
+ * We disable @angular-eslint/no-inputs-metadata-property, so that
44
+ * Angular does not complain about the inputs property. The output target
45
+ * uses the inputs property to define the inputs of the component instead of
46
+ * having to use the @Input decorator (and manually define the type and default value).
47
+ */
48
+ ` // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property`,
49
+ ` inputs: [${formattedInputs}],`,
50
+ `})`,
51
+ `export class ${tagNameAsPascal} {`,
52
+ ];
53
+ if (outputDecorators.length > 0) {
54
+ for (let outputDecorator of outputDecorators) {
55
+ output.push(` ${outputDecorator}`);
56
+ }
57
+ }
58
+ output.push(` protected el: HTMLElement;`);
59
+ output.push(` constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {`);
60
+ output.push(` c.detach();`);
61
+ output.push(` this.el = r.nativeElement;`);
62
+ if (hasOutputs) {
63
+ output.push(` proxyOutputs(this, this.el, [${formattedOutputs}]);`);
64
+ }
65
+ output.push(` }`);
66
+ output.push(`}`);
67
+ return output.join('\n');
68
+ };
69
+ /**
70
+ * Creates an `@Output()` decorator for a custom event on a Stencil component.
71
+ * @param tagName The tag name of the component.
72
+ * @param event The Stencil component event.
73
+ * @returns The `@Output()` decorator as a string.
74
+ */
75
+ const createAngularOutputDecorator = (tagName, event) => {
76
+ const tagNameAsPascal = dashToPascalCase(tagName);
77
+ // When updating to Stencil 3.0, the component custom event generic will be
78
+ // exported by default and can be referenced here with:
79
+ // const customEvent = `${tagNameAsPascal}CustomEvent`;
80
+ const customEventType = `CustomEvent`;
81
+ const eventType = formatOutputType(tagNameAsPascal, event);
82
+ const outputType = `${customEventType}<${eventType}>`;
83
+ return `@Output() ${event.name}: EventEmitter<${outputType}> = new EventEmitter();`;
60
84
  };
61
85
  /**
62
86
  * Sanitizes and formats the component event type.
@@ -74,9 +98,10 @@ const formatOutputType = (componentClassName, event) => {
74
98
  .filter(([_, refObject]) => refObject.location === 'local' || refObject.location === 'import')
75
99
  .reduce((type, [src, dst]) => {
76
100
  const renamedType = `I${componentClassName}${type}`;
77
- return renamedType
101
+ return (renamedType
78
102
  .replace(new RegExp(`^${src}$`, 'g'), `${dst}`)
79
- .replace(new RegExp(`([^\\w])${src}([^\\w])`, 'g'), (v, p1, p2) => [p1, dst, p2].join(''));
103
+ // Capture all instances of the `src` field surrounded by non-word characters on each side and join them.
104
+ .replace(new RegExp(`([^\\w])${src}([^\\w])`, 'g'), (v, p1, p2) => [p1, dst, p2].join('')));
80
105
  }, event.complexType.original
81
106
  .replace(/\n/g, ' ')
82
107
  .replace(/\s{2,}/g, ' ')
@@ -105,21 +130,22 @@ const createDocComment = (doc) => {
105
130
  * @returns The component interface type definition as a string.
106
131
  */
107
132
  export const createComponentTypeDefinition = (tagNameAsPascal, events, componentCorePackage, includeImportCustomElements = false, customElementsDir) => {
108
- const publicEvents = events.filter(ev => !ev.internal);
133
+ const publicEvents = events.filter((ev) => !ev.internal);
109
134
  const eventTypeImports = createComponentEventTypeImports(tagNameAsPascal, publicEvents, {
110
135
  componentCorePackage,
111
136
  includeImportCustomElements,
112
137
  customElementsDir,
113
138
  });
114
- const eventTypes = publicEvents
115
- .map((event) => {
139
+ const eventTypes = publicEvents.map((event) => {
116
140
  const comment = createDocComment(event.docs);
117
141
  return `${comment.length > 0 ? ` ${comment}` : ''}
118
142
  ${event.name}: EventEmitter<CustomEvent<${formatOutputType(tagNameAsPascal, event)}>>;`;
119
143
  });
120
144
  const interfaceDeclaration = `export declare interface ${tagNameAsPascal} extends Components.${tagNameAsPascal} {`;
121
- const typeDefinition = (eventTypeImports.length > 0 ? `${eventTypeImports + '\n\n'}` : '')
122
- + `${interfaceDeclaration}${eventTypes.length === 0 ? '}' : `
145
+ const typeDefinition = (eventTypeImports.length > 0 ? `${eventTypeImports + '\n\n'}` : '') +
146
+ `${interfaceDeclaration}${eventTypes.length === 0
147
+ ? '}'
148
+ : `
123
149
  ${eventTypes.join('\n')}
124
150
  }`}`;
125
151
  return typeDefinition;
@@ -4,7 +4,7 @@ export function generateAngularDirectivesFile(compilerCtx, components, outputTar
4
4
  if (!outputTarget.directivesArrayFile) {
5
5
  return Promise.resolve();
6
6
  }
7
- const proxyPath = relativeImport(outputTarget.directivesArrayFile, outputTarget.proxyDeclarationFile, '.ts');
7
+ const proxyPath = relativeImport(outputTarget.directivesArrayFile, outputTarget.directivesProxyFile, '.ts');
8
8
  const directives = components
9
9
  .map((cmpMeta) => dashToPascalCase(cmpMeta.tagName))
10
10
  .map((className) => `d.${className}`)
@@ -4,7 +4,7 @@ export default async function generateValueAccessors(compilerCtx, components, ou
4
4
  if (!Array.isArray(outputTarget.valueAccessorConfigs) || outputTarget.valueAccessorConfigs.length === 0) {
5
5
  return;
6
6
  }
7
- const targetDir = path.dirname(outputTarget.proxyDeclarationFile);
7
+ const targetDir = path.dirname(outputTarget.directivesProxyFile);
8
8
  const normalizedValueAccessors = outputTarget.valueAccessorConfigs.reduce((allAccessors, va) => {
9
9
  const elementSelectors = Array.isArray(va.elementSelectors) ? va.elementSelectors : [va.elementSelectors];
10
10
  const type = va.type;
package/dist/index.cjs.js CHANGED
@@ -148,9 +148,11 @@ const createAngularComponentDefinition = (tagName, inputs, outputs, methods, inc
148
148
  // Formats the input strings into comma separated, single quoted values.
149
149
  const formattedInputs = formatToQuotedList(inputs);
150
150
  // Formats the output strings into comma separated, single quoted values.
151
- const formattedOutputs = formatToQuotedList(outputs);
151
+ const formattedOutputs = formatToQuotedList(outputs.map((event) => event.name));
152
152
  // Formats the method strings into comma separated, single quoted values.
153
153
  const formattedMethods = formatToQuotedList(methods);
154
+ // The collection of @Output() decorators for the component.
155
+ const outputDecorators = outputs.map((event) => createAngularOutputDecorator(tagName, event));
154
156
  const proxyCmpOptions = [];
155
157
  if (includeImportCustomElements) {
156
158
  const defineCustomElementFn = `define${tagNameAsPascal}`;
@@ -162,32 +164,54 @@ const createAngularComponentDefinition = (tagName, inputs, outputs, methods, inc
162
164
  if (hasMethods) {
163
165
  proxyCmpOptions.push(`\n methods: [${formattedMethods}]`);
164
166
  }
165
- /**
166
- * Notes on the generated output:
167
- * - We disable @angular-eslint/no-inputs-metadata-property, so that
168
- * Angular does not complain about the inputs property. The output target
169
- * uses the inputs property to define the inputs of the component instead of
170
- * having to use the @Input decorator (and manually define the type and default value).
171
- */
172
- const output = `@ProxyCmp({${proxyCmpOptions.join(',')}\n})
173
- @Component({
174
- selector: '${tagName}',
175
- changeDetection: ChangeDetectionStrategy.OnPush,
176
- template: '<ng-content></ng-content>',
177
- // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
178
- inputs: [${formattedInputs}],
179
- })
180
- export class ${tagNameAsPascal} {
181
- protected el: HTMLElement;
182
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
183
- c.detach();
184
- this.el = r.nativeElement;${hasOutputs
185
- ? `
186
- proxyOutputs(this, this.el, [${formattedOutputs}]);`
187
- : ''}
188
- }
189
- }`;
190
- return output;
167
+ const output = [
168
+ `@ProxyCmp({${proxyCmpOptions.join(',')}\n})`,
169
+ `@Component({`,
170
+ ` selector: '${tagName}',`,
171
+ ` changeDetection: ChangeDetectionStrategy.OnPush,`,
172
+ ` template: '<ng-content></ng-content>',`,
173
+ /**
174
+ * We disable @angular-eslint/no-inputs-metadata-property, so that
175
+ * Angular does not complain about the inputs property. The output target
176
+ * uses the inputs property to define the inputs of the component instead of
177
+ * having to use the @Input decorator (and manually define the type and default value).
178
+ */
179
+ ` // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property`,
180
+ ` inputs: [${formattedInputs}],`,
181
+ `})`,
182
+ `export class ${tagNameAsPascal} {`,
183
+ ];
184
+ if (outputDecorators.length > 0) {
185
+ for (let outputDecorator of outputDecorators) {
186
+ output.push(` ${outputDecorator}`);
187
+ }
188
+ }
189
+ output.push(` protected el: HTMLElement;`);
190
+ output.push(` constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {`);
191
+ output.push(` c.detach();`);
192
+ output.push(` this.el = r.nativeElement;`);
193
+ if (hasOutputs) {
194
+ output.push(` proxyOutputs(this, this.el, [${formattedOutputs}]);`);
195
+ }
196
+ output.push(` }`);
197
+ output.push(`}`);
198
+ return output.join('\n');
199
+ };
200
+ /**
201
+ * Creates an `@Output()` decorator for a custom event on a Stencil component.
202
+ * @param tagName The tag name of the component.
203
+ * @param event The Stencil component event.
204
+ * @returns The `@Output()` decorator as a string.
205
+ */
206
+ const createAngularOutputDecorator = (tagName, event) => {
207
+ const tagNameAsPascal = dashToPascalCase(tagName);
208
+ // When updating to Stencil 3.0, the component custom event generic will be
209
+ // exported by default and can be referenced here with:
210
+ // const customEvent = `${tagNameAsPascal}CustomEvent`;
211
+ const customEventType = `CustomEvent`;
212
+ const eventType = formatOutputType(tagNameAsPascal, event);
213
+ const outputType = `${customEventType}<${eventType}>`;
214
+ return `@Output() ${event.name}: EventEmitter<${outputType}> = new EventEmitter();`;
191
215
  };
192
216
  /**
193
217
  * Sanitizes and formats the component event type.
@@ -205,9 +229,10 @@ const formatOutputType = (componentClassName, event) => {
205
229
  .filter(([_, refObject]) => refObject.location === 'local' || refObject.location === 'import')
206
230
  .reduce((type, [src, dst]) => {
207
231
  const renamedType = `I${componentClassName}${type}`;
208
- return renamedType
232
+ return (renamedType
209
233
  .replace(new RegExp(`^${src}$`, 'g'), `${dst}`)
210
- .replace(new RegExp(`([^\\w])${src}([^\\w])`, 'g'), (v, p1, p2) => [p1, dst, p2].join(''));
234
+ // Capture all instances of the `src` field surrounded by non-word characters on each side and join them.
235
+ .replace(new RegExp(`([^\\w])${src}([^\\w])`, 'g'), (v, p1, p2) => [p1, dst, p2].join('')));
211
236
  }, event.complexType.original
212
237
  .replace(/\n/g, ' ')
213
238
  .replace(/\s{2,}/g, ' ')
@@ -236,21 +261,22 @@ const createDocComment = (doc) => {
236
261
  * @returns The component interface type definition as a string.
237
262
  */
238
263
  const createComponentTypeDefinition = (tagNameAsPascal, events, componentCorePackage, includeImportCustomElements = false, customElementsDir) => {
239
- const publicEvents = events.filter(ev => !ev.internal);
264
+ const publicEvents = events.filter((ev) => !ev.internal);
240
265
  const eventTypeImports = createComponentEventTypeImports(tagNameAsPascal, publicEvents, {
241
266
  componentCorePackage,
242
267
  includeImportCustomElements,
243
268
  customElementsDir,
244
269
  });
245
- const eventTypes = publicEvents
246
- .map((event) => {
270
+ const eventTypes = publicEvents.map((event) => {
247
271
  const comment = createDocComment(event.docs);
248
272
  return `${comment.length > 0 ? ` ${comment}` : ''}
249
273
  ${event.name}: EventEmitter<CustomEvent<${formatOutputType(tagNameAsPascal, event)}>>;`;
250
274
  });
251
275
  const interfaceDeclaration = `export declare interface ${tagNameAsPascal} extends Components.${tagNameAsPascal} {`;
252
- const typeDefinition = (eventTypeImports.length > 0 ? `${eventTypeImports + '\n\n'}` : '')
253
- + `${interfaceDeclaration}${eventTypes.length === 0 ? '}' : `
276
+ const typeDefinition = (eventTypeImports.length > 0 ? `${eventTypeImports + '\n\n'}` : '') +
277
+ `${interfaceDeclaration}${eventTypes.length === 0
278
+ ? '}'
279
+ : `
254
280
  ${eventTypes.join('\n')}
255
281
  }`}`;
256
282
  return typeDefinition;
@@ -261,7 +287,7 @@ function generateAngularDirectivesFile(compilerCtx, components, outputTarget) {
261
287
  if (!outputTarget.directivesArrayFile) {
262
288
  return Promise.resolve();
263
289
  }
264
- const proxyPath = relativeImport(outputTarget.directivesArrayFile, outputTarget.proxyDeclarationFile, '.ts');
290
+ const proxyPath = relativeImport(outputTarget.directivesArrayFile, outputTarget.directivesProxyFile, '.ts');
265
291
  const directives = components
266
292
  .map((cmpMeta) => dashToPascalCase(cmpMeta.tagName))
267
293
  .map((className) => `d.${className}`)
@@ -280,7 +306,7 @@ async function generateValueAccessors(compilerCtx, components, outputTarget, con
280
306
  if (!Array.isArray(outputTarget.valueAccessorConfigs) || outputTarget.valueAccessorConfigs.length === 0) {
281
307
  return;
282
308
  }
283
- const targetDir = path__default['default'].dirname(outputTarget.proxyDeclarationFile);
309
+ const targetDir = path__default['default'].dirname(outputTarget.directivesProxyFile);
284
310
  const normalizedValueAccessors = outputTarget.valueAccessorConfigs.reduce((allAccessors, va) => {
285
311
  const elementSelectors = Array.isArray(va.elementSelectors) ? va.elementSelectors : [va.elementSelectors];
286
312
  const type = va.type;
@@ -331,30 +357,13 @@ const VALUE_ACCESSOR_EVENT = `<VALUE_ACCESSOR_EVENT>`;
331
357
  const VALUE_ACCESSOR_TARGETATTR = '<VALUE_ACCESSOR_TARGETATTR>';
332
358
  const VALUE_ACCESSOR_EVENTTARGETS = ` '(<VALUE_ACCESSOR_EVENT>)': 'handleChangeEvent($event.target.<VALUE_ACCESSOR_TARGETATTR>)'`;
333
359
 
334
- /**
335
- * Creates an Angular module declaration for a component wrapper.
336
- * @param componentTagName The tag name of the Stencil component.
337
- * @returns The Angular module declaration as a string.
338
- */
339
- const generateAngularModuleForComponent = (componentTagName) => {
340
- const tagNameAsPascal = dashToPascalCase(componentTagName);
341
- const componentClassName = `${tagNameAsPascal}`;
342
- const moduleClassName = `${tagNameAsPascal}Module`;
343
- const moduleDefinition = `@NgModule({
344
- declarations: [${componentClassName}],
345
- exports: [${componentClassName}]
346
- })
347
- export class ${moduleClassName} { }`;
348
- return moduleDefinition;
349
- };
350
-
351
360
  async function angularDirectiveProxyOutput(compilerCtx, outputTarget, components, config) {
352
361
  const filteredComponents = getFilteredComponents(outputTarget.excludeComponents, components);
353
362
  const rootDir = config.rootDir;
354
363
  const pkgData = await readPackageJson(config, rootDir);
355
364
  const finalText = generateProxies(filteredComponents, pkgData, outputTarget, config.rootDir);
356
365
  await Promise.all([
357
- compilerCtx.fs.writeFile(outputTarget.proxyDeclarationFile, finalText),
366
+ compilerCtx.fs.writeFile(outputTarget.directivesProxyFile, finalText),
358
367
  copyResources$1(config, outputTarget),
359
368
  generateAngularDirectivesFile(compilerCtx, filteredComponents, outputTarget),
360
369
  generateValueAccessors(compilerCtx, filteredComponents, outputTarget, config),
@@ -368,7 +377,7 @@ async function copyResources$1(config, outputTarget) {
368
377
  throw new Error('stencil is not properly initialized at this step. Notify the developer');
369
378
  }
370
379
  const srcDirectory = path__default['default'].join(__dirname, '..', 'angular-component-lib');
371
- const destDirectory = path__default['default'].join(path__default['default'].dirname(outputTarget.proxyDeclarationFile), 'angular-component-lib');
380
+ const destDirectory = path__default['default'].join(path__default['default'].dirname(outputTarget.directivesProxyFile), 'angular-component-lib');
372
381
  return config.sys.copy([
373
382
  {
374
383
  src: srcDirectory,
@@ -379,11 +388,9 @@ async function copyResources$1(config, outputTarget) {
379
388
  ], srcDirectory);
380
389
  }
381
390
  function generateProxies(components, pkgData, outputTarget, rootDir) {
382
- var _a;
383
391
  const distTypesDir = path__default['default'].dirname(pkgData.types);
384
392
  const dtsFilePath = path__default['default'].join(rootDir, distTypesDir, GENERATED_DTS);
385
- const componentsTypeFile = relativeImport(outputTarget.proxyDeclarationFile, dtsFilePath, '.d.ts');
386
- const createSingleComponentAngularModules = (_a = outputTarget.createSingleComponentAngularModules) !== null && _a !== void 0 ? _a : false;
393
+ const componentsTypeFile = relativeImport(outputTarget.directivesProxyFile, dtsFilePath, '.d.ts');
387
394
  /**
388
395
  * The collection of named imports from @angular/core.
389
396
  */
@@ -394,14 +401,12 @@ function generateProxies(components, pkgData, outputTarget, rootDir) {
394
401
  'ElementRef',
395
402
  'EventEmitter',
396
403
  'NgZone',
404
+ 'Output',
397
405
  ];
398
406
  /**
399
407
  * The collection of named imports from the angular-component-lib/utils.
400
408
  */
401
409
  const componentLibImports = ['ProxyCmp', 'proxyOutputs'];
402
- if (createSingleComponentAngularModules) {
403
- angularCoreImports.push('NgModule');
404
- }
405
410
  const imports = `/* tslint:disable */
406
411
  /* auto-generated angular directive proxies */
407
412
  ${createImportStatement(angularCoreImports, '@angular/core')}
@@ -437,12 +442,6 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
437
442
  });
438
443
  sourceImports = cmpImports.join('\n');
439
444
  }
440
- if (createSingleComponentAngularModules) {
441
- // Generating Angular modules is only supported in the dist-custom-elements build
442
- if (!outputTarget.includeImportCustomElements) {
443
- throw new Error('Generating single component Angular modules requires the "includeImportCustomElements" option to be set to true.');
444
- }
445
- }
446
445
  const proxyFileOutput = [];
447
446
  const filterInternalProps = (prop) => !prop.internal;
448
447
  const mapPropName = (prop) => prop.name;
@@ -459,7 +458,7 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
459
458
  inputs.sort();
460
459
  const outputs = [];
461
460
  if (cmpMeta.events) {
462
- outputs.push(...cmpMeta.events.filter(filterInternalProps).map(mapPropName));
461
+ outputs.push(...cmpMeta.events.filter(filterInternalProps));
463
462
  }
464
463
  const methods = [];
465
464
  if (cmpMeta.methods) {
@@ -468,16 +467,11 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
468
467
  /**
469
468
  * For each component, we need to generate:
470
469
  * 1. The @Component decorated class
471
- * 2. Optionally the @NgModule decorated class (if createSingleComponentAngularModules is true)
472
- * 3. The component interface (using declaration merging for types).
470
+ * 2. The component interface (using declaration merging for types).
473
471
  */
474
472
  const componentDefinition = createAngularComponentDefinition(cmpMeta.tagName, inputs, outputs, methods, includeImportCustomElements);
475
- const moduleDefinition = generateAngularModuleForComponent(cmpMeta.tagName);
476
473
  const componentTypeDefinition = createComponentTypeDefinition(tagNameAsPascal, cmpMeta.events, componentCorePackage, includeImportCustomElements, customElementsDir);
477
474
  proxyFileOutput.push(componentDefinition, '\n');
478
- if (createSingleComponentAngularModules) {
479
- proxyFileOutput.push(moduleDefinition, '\n');
480
- }
481
475
  proxyFileOutput.push(componentTypeDefinition, '\n');
482
476
  }
483
477
  const final = [imports, typeImports, sourceImports, ...proxyFileOutput];
@@ -503,14 +497,11 @@ function normalizeOutputTarget(config, outputTarget) {
503
497
  if (config.rootDir == null) {
504
498
  throw new Error('rootDir is not set and it should be set by stencil itself');
505
499
  }
506
- if (outputTarget.directivesProxyFile !== undefined) {
507
- throw new Error('directivesProxyFile has been removed. Use proxyDeclarationFile instead.');
508
- }
509
- if (outputTarget.proxyDeclarationFile == null) {
510
- throw new Error('proxyDeclarationFile is required. Please set it in the Stencil config.');
500
+ if (outputTarget.directivesProxyFile == null) {
501
+ throw new Error('directivesProxyFile is required. Please set it in the Stencil config.');
511
502
  }
512
- if (outputTarget.proxyDeclarationFile && !path__default['default'].isAbsolute(outputTarget.proxyDeclarationFile)) {
513
- results.proxyDeclarationFile = normalizePath(path__default['default'].join(config.rootDir, outputTarget.proxyDeclarationFile));
503
+ if (outputTarget.directivesProxyFile && !path__default['default'].isAbsolute(outputTarget.directivesProxyFile)) {
504
+ results.directivesProxyFile = normalizePath(path__default['default'].join(config.rootDir, outputTarget.directivesProxyFile));
514
505
  }
515
506
  if (outputTarget.directivesArrayFile && !path__default['default'].isAbsolute(outputTarget.directivesArrayFile)) {
516
507
  results.directivesArrayFile = normalizePath(path__default['default'].join(config.rootDir, outputTarget.directivesArrayFile));
package/dist/index.js CHANGED
@@ -140,9 +140,11 @@ const createAngularComponentDefinition = (tagName, inputs, outputs, methods, inc
140
140
  // Formats the input strings into comma separated, single quoted values.
141
141
  const formattedInputs = formatToQuotedList(inputs);
142
142
  // Formats the output strings into comma separated, single quoted values.
143
- const formattedOutputs = formatToQuotedList(outputs);
143
+ const formattedOutputs = formatToQuotedList(outputs.map((event) => event.name));
144
144
  // Formats the method strings into comma separated, single quoted values.
145
145
  const formattedMethods = formatToQuotedList(methods);
146
+ // The collection of @Output() decorators for the component.
147
+ const outputDecorators = outputs.map((event) => createAngularOutputDecorator(tagName, event));
146
148
  const proxyCmpOptions = [];
147
149
  if (includeImportCustomElements) {
148
150
  const defineCustomElementFn = `define${tagNameAsPascal}`;
@@ -154,32 +156,54 @@ const createAngularComponentDefinition = (tagName, inputs, outputs, methods, inc
154
156
  if (hasMethods) {
155
157
  proxyCmpOptions.push(`\n methods: [${formattedMethods}]`);
156
158
  }
157
- /**
158
- * Notes on the generated output:
159
- * - We disable @angular-eslint/no-inputs-metadata-property, so that
160
- * Angular does not complain about the inputs property. The output target
161
- * uses the inputs property to define the inputs of the component instead of
162
- * having to use the @Input decorator (and manually define the type and default value).
163
- */
164
- const output = `@ProxyCmp({${proxyCmpOptions.join(',')}\n})
165
- @Component({
166
- selector: '${tagName}',
167
- changeDetection: ChangeDetectionStrategy.OnPush,
168
- template: '<ng-content></ng-content>',
169
- // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
170
- inputs: [${formattedInputs}],
171
- })
172
- export class ${tagNameAsPascal} {
173
- protected el: HTMLElement;
174
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
175
- c.detach();
176
- this.el = r.nativeElement;${hasOutputs
177
- ? `
178
- proxyOutputs(this, this.el, [${formattedOutputs}]);`
179
- : ''}
180
- }
181
- }`;
182
- return output;
159
+ const output = [
160
+ `@ProxyCmp({${proxyCmpOptions.join(',')}\n})`,
161
+ `@Component({`,
162
+ ` selector: '${tagName}',`,
163
+ ` changeDetection: ChangeDetectionStrategy.OnPush,`,
164
+ ` template: '<ng-content></ng-content>',`,
165
+ /**
166
+ * We disable @angular-eslint/no-inputs-metadata-property, so that
167
+ * Angular does not complain about the inputs property. The output target
168
+ * uses the inputs property to define the inputs of the component instead of
169
+ * having to use the @Input decorator (and manually define the type and default value).
170
+ */
171
+ ` // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property`,
172
+ ` inputs: [${formattedInputs}],`,
173
+ `})`,
174
+ `export class ${tagNameAsPascal} {`,
175
+ ];
176
+ if (outputDecorators.length > 0) {
177
+ for (let outputDecorator of outputDecorators) {
178
+ output.push(` ${outputDecorator}`);
179
+ }
180
+ }
181
+ output.push(` protected el: HTMLElement;`);
182
+ output.push(` constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {`);
183
+ output.push(` c.detach();`);
184
+ output.push(` this.el = r.nativeElement;`);
185
+ if (hasOutputs) {
186
+ output.push(` proxyOutputs(this, this.el, [${formattedOutputs}]);`);
187
+ }
188
+ output.push(` }`);
189
+ output.push(`}`);
190
+ return output.join('\n');
191
+ };
192
+ /**
193
+ * Creates an `@Output()` decorator for a custom event on a Stencil component.
194
+ * @param tagName The tag name of the component.
195
+ * @param event The Stencil component event.
196
+ * @returns The `@Output()` decorator as a string.
197
+ */
198
+ const createAngularOutputDecorator = (tagName, event) => {
199
+ const tagNameAsPascal = dashToPascalCase(tagName);
200
+ // When updating to Stencil 3.0, the component custom event generic will be
201
+ // exported by default and can be referenced here with:
202
+ // const customEvent = `${tagNameAsPascal}CustomEvent`;
203
+ const customEventType = `CustomEvent`;
204
+ const eventType = formatOutputType(tagNameAsPascal, event);
205
+ const outputType = `${customEventType}<${eventType}>`;
206
+ return `@Output() ${event.name}: EventEmitter<${outputType}> = new EventEmitter();`;
183
207
  };
184
208
  /**
185
209
  * Sanitizes and formats the component event type.
@@ -197,9 +221,10 @@ const formatOutputType = (componentClassName, event) => {
197
221
  .filter(([_, refObject]) => refObject.location === 'local' || refObject.location === 'import')
198
222
  .reduce((type, [src, dst]) => {
199
223
  const renamedType = `I${componentClassName}${type}`;
200
- return renamedType
224
+ return (renamedType
201
225
  .replace(new RegExp(`^${src}$`, 'g'), `${dst}`)
202
- .replace(new RegExp(`([^\\w])${src}([^\\w])`, 'g'), (v, p1, p2) => [p1, dst, p2].join(''));
226
+ // Capture all instances of the `src` field surrounded by non-word characters on each side and join them.
227
+ .replace(new RegExp(`([^\\w])${src}([^\\w])`, 'g'), (v, p1, p2) => [p1, dst, p2].join('')));
203
228
  }, event.complexType.original
204
229
  .replace(/\n/g, ' ')
205
230
  .replace(/\s{2,}/g, ' ')
@@ -228,21 +253,22 @@ const createDocComment = (doc) => {
228
253
  * @returns The component interface type definition as a string.
229
254
  */
230
255
  const createComponentTypeDefinition = (tagNameAsPascal, events, componentCorePackage, includeImportCustomElements = false, customElementsDir) => {
231
- const publicEvents = events.filter(ev => !ev.internal);
256
+ const publicEvents = events.filter((ev) => !ev.internal);
232
257
  const eventTypeImports = createComponentEventTypeImports(tagNameAsPascal, publicEvents, {
233
258
  componentCorePackage,
234
259
  includeImportCustomElements,
235
260
  customElementsDir,
236
261
  });
237
- const eventTypes = publicEvents
238
- .map((event) => {
262
+ const eventTypes = publicEvents.map((event) => {
239
263
  const comment = createDocComment(event.docs);
240
264
  return `${comment.length > 0 ? ` ${comment}` : ''}
241
265
  ${event.name}: EventEmitter<CustomEvent<${formatOutputType(tagNameAsPascal, event)}>>;`;
242
266
  });
243
267
  const interfaceDeclaration = `export declare interface ${tagNameAsPascal} extends Components.${tagNameAsPascal} {`;
244
- const typeDefinition = (eventTypeImports.length > 0 ? `${eventTypeImports + '\n\n'}` : '')
245
- + `${interfaceDeclaration}${eventTypes.length === 0 ? '}' : `
268
+ const typeDefinition = (eventTypeImports.length > 0 ? `${eventTypeImports + '\n\n'}` : '') +
269
+ `${interfaceDeclaration}${eventTypes.length === 0
270
+ ? '}'
271
+ : `
246
272
  ${eventTypes.join('\n')}
247
273
  }`}`;
248
274
  return typeDefinition;
@@ -253,7 +279,7 @@ function generateAngularDirectivesFile(compilerCtx, components, outputTarget) {
253
279
  if (!outputTarget.directivesArrayFile) {
254
280
  return Promise.resolve();
255
281
  }
256
- const proxyPath = relativeImport(outputTarget.directivesArrayFile, outputTarget.proxyDeclarationFile, '.ts');
282
+ const proxyPath = relativeImport(outputTarget.directivesArrayFile, outputTarget.directivesProxyFile, '.ts');
257
283
  const directives = components
258
284
  .map((cmpMeta) => dashToPascalCase(cmpMeta.tagName))
259
285
  .map((className) => `d.${className}`)
@@ -272,7 +298,7 @@ async function generateValueAccessors(compilerCtx, components, outputTarget, con
272
298
  if (!Array.isArray(outputTarget.valueAccessorConfigs) || outputTarget.valueAccessorConfigs.length === 0) {
273
299
  return;
274
300
  }
275
- const targetDir = path.dirname(outputTarget.proxyDeclarationFile);
301
+ const targetDir = path.dirname(outputTarget.directivesProxyFile);
276
302
  const normalizedValueAccessors = outputTarget.valueAccessorConfigs.reduce((allAccessors, va) => {
277
303
  const elementSelectors = Array.isArray(va.elementSelectors) ? va.elementSelectors : [va.elementSelectors];
278
304
  const type = va.type;
@@ -323,30 +349,13 @@ const VALUE_ACCESSOR_EVENT = `<VALUE_ACCESSOR_EVENT>`;
323
349
  const VALUE_ACCESSOR_TARGETATTR = '<VALUE_ACCESSOR_TARGETATTR>';
324
350
  const VALUE_ACCESSOR_EVENTTARGETS = ` '(<VALUE_ACCESSOR_EVENT>)': 'handleChangeEvent($event.target.<VALUE_ACCESSOR_TARGETATTR>)'`;
325
351
 
326
- /**
327
- * Creates an Angular module declaration for a component wrapper.
328
- * @param componentTagName The tag name of the Stencil component.
329
- * @returns The Angular module declaration as a string.
330
- */
331
- const generateAngularModuleForComponent = (componentTagName) => {
332
- const tagNameAsPascal = dashToPascalCase(componentTagName);
333
- const componentClassName = `${tagNameAsPascal}`;
334
- const moduleClassName = `${tagNameAsPascal}Module`;
335
- const moduleDefinition = `@NgModule({
336
- declarations: [${componentClassName}],
337
- exports: [${componentClassName}]
338
- })
339
- export class ${moduleClassName} { }`;
340
- return moduleDefinition;
341
- };
342
-
343
352
  async function angularDirectiveProxyOutput(compilerCtx, outputTarget, components, config) {
344
353
  const filteredComponents = getFilteredComponents(outputTarget.excludeComponents, components);
345
354
  const rootDir = config.rootDir;
346
355
  const pkgData = await readPackageJson(config, rootDir);
347
356
  const finalText = generateProxies(filteredComponents, pkgData, outputTarget, config.rootDir);
348
357
  await Promise.all([
349
- compilerCtx.fs.writeFile(outputTarget.proxyDeclarationFile, finalText),
358
+ compilerCtx.fs.writeFile(outputTarget.directivesProxyFile, finalText),
350
359
  copyResources$1(config, outputTarget),
351
360
  generateAngularDirectivesFile(compilerCtx, filteredComponents, outputTarget),
352
361
  generateValueAccessors(compilerCtx, filteredComponents, outputTarget, config),
@@ -360,7 +369,7 @@ async function copyResources$1(config, outputTarget) {
360
369
  throw new Error('stencil is not properly initialized at this step. Notify the developer');
361
370
  }
362
371
  const srcDirectory = path.join(__dirname, '..', 'angular-component-lib');
363
- const destDirectory = path.join(path.dirname(outputTarget.proxyDeclarationFile), 'angular-component-lib');
372
+ const destDirectory = path.join(path.dirname(outputTarget.directivesProxyFile), 'angular-component-lib');
364
373
  return config.sys.copy([
365
374
  {
366
375
  src: srcDirectory,
@@ -371,11 +380,9 @@ async function copyResources$1(config, outputTarget) {
371
380
  ], srcDirectory);
372
381
  }
373
382
  function generateProxies(components, pkgData, outputTarget, rootDir) {
374
- var _a;
375
383
  const distTypesDir = path.dirname(pkgData.types);
376
384
  const dtsFilePath = path.join(rootDir, distTypesDir, GENERATED_DTS);
377
- const componentsTypeFile = relativeImport(outputTarget.proxyDeclarationFile, dtsFilePath, '.d.ts');
378
- const createSingleComponentAngularModules = (_a = outputTarget.createSingleComponentAngularModules) !== null && _a !== void 0 ? _a : false;
385
+ const componentsTypeFile = relativeImport(outputTarget.directivesProxyFile, dtsFilePath, '.d.ts');
379
386
  /**
380
387
  * The collection of named imports from @angular/core.
381
388
  */
@@ -386,14 +393,12 @@ function generateProxies(components, pkgData, outputTarget, rootDir) {
386
393
  'ElementRef',
387
394
  'EventEmitter',
388
395
  'NgZone',
396
+ 'Output',
389
397
  ];
390
398
  /**
391
399
  * The collection of named imports from the angular-component-lib/utils.
392
400
  */
393
401
  const componentLibImports = ['ProxyCmp', 'proxyOutputs'];
394
- if (createSingleComponentAngularModules) {
395
- angularCoreImports.push('NgModule');
396
- }
397
402
  const imports = `/* tslint:disable */
398
403
  /* auto-generated angular directive proxies */
399
404
  ${createImportStatement(angularCoreImports, '@angular/core')}
@@ -429,12 +434,6 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
429
434
  });
430
435
  sourceImports = cmpImports.join('\n');
431
436
  }
432
- if (createSingleComponentAngularModules) {
433
- // Generating Angular modules is only supported in the dist-custom-elements build
434
- if (!outputTarget.includeImportCustomElements) {
435
- throw new Error('Generating single component Angular modules requires the "includeImportCustomElements" option to be set to true.');
436
- }
437
- }
438
437
  const proxyFileOutput = [];
439
438
  const filterInternalProps = (prop) => !prop.internal;
440
439
  const mapPropName = (prop) => prop.name;
@@ -451,7 +450,7 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
451
450
  inputs.sort();
452
451
  const outputs = [];
453
452
  if (cmpMeta.events) {
454
- outputs.push(...cmpMeta.events.filter(filterInternalProps).map(mapPropName));
453
+ outputs.push(...cmpMeta.events.filter(filterInternalProps));
455
454
  }
456
455
  const methods = [];
457
456
  if (cmpMeta.methods) {
@@ -460,16 +459,11 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
460
459
  /**
461
460
  * For each component, we need to generate:
462
461
  * 1. The @Component decorated class
463
- * 2. Optionally the @NgModule decorated class (if createSingleComponentAngularModules is true)
464
- * 3. The component interface (using declaration merging for types).
462
+ * 2. The component interface (using declaration merging for types).
465
463
  */
466
464
  const componentDefinition = createAngularComponentDefinition(cmpMeta.tagName, inputs, outputs, methods, includeImportCustomElements);
467
- const moduleDefinition = generateAngularModuleForComponent(cmpMeta.tagName);
468
465
  const componentTypeDefinition = createComponentTypeDefinition(tagNameAsPascal, cmpMeta.events, componentCorePackage, includeImportCustomElements, customElementsDir);
469
466
  proxyFileOutput.push(componentDefinition, '\n');
470
- if (createSingleComponentAngularModules) {
471
- proxyFileOutput.push(moduleDefinition, '\n');
472
- }
473
467
  proxyFileOutput.push(componentTypeDefinition, '\n');
474
468
  }
475
469
  const final = [imports, typeImports, sourceImports, ...proxyFileOutput];
@@ -495,14 +489,11 @@ function normalizeOutputTarget(config, outputTarget) {
495
489
  if (config.rootDir == null) {
496
490
  throw new Error('rootDir is not set and it should be set by stencil itself');
497
491
  }
498
- if (outputTarget.directivesProxyFile !== undefined) {
499
- throw new Error('directivesProxyFile has been removed. Use proxyDeclarationFile instead.');
500
- }
501
- if (outputTarget.proxyDeclarationFile == null) {
502
- throw new Error('proxyDeclarationFile is required. Please set it in the Stencil config.');
492
+ if (outputTarget.directivesProxyFile == null) {
493
+ throw new Error('directivesProxyFile is required. Please set it in the Stencil config.');
503
494
  }
504
- if (outputTarget.proxyDeclarationFile && !path.isAbsolute(outputTarget.proxyDeclarationFile)) {
505
- results.proxyDeclarationFile = normalizePath(path.join(config.rootDir, outputTarget.proxyDeclarationFile));
495
+ if (outputTarget.directivesProxyFile && !path.isAbsolute(outputTarget.directivesProxyFile)) {
496
+ results.directivesProxyFile = normalizePath(path.join(config.rootDir, outputTarget.directivesProxyFile));
506
497
  }
507
498
  if (outputTarget.directivesArrayFile && !path.isAbsolute(outputTarget.directivesArrayFile)) {
508
499
  results.directivesArrayFile = normalizePath(path.join(config.rootDir, outputTarget.directivesArrayFile));
@@ -3,14 +3,13 @@ import { relativeImport, normalizePath, sortBy, readPackageJson, dashToPascalCas
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';
6
- import { generateAngularModuleForComponent } from './generate-angular-modules';
7
6
  export async function angularDirectiveProxyOutput(compilerCtx, outputTarget, components, config) {
8
7
  const filteredComponents = getFilteredComponents(outputTarget.excludeComponents, components);
9
8
  const rootDir = config.rootDir;
10
9
  const pkgData = await readPackageJson(config, rootDir);
11
10
  const finalText = generateProxies(filteredComponents, pkgData, outputTarget, config.rootDir);
12
11
  await Promise.all([
13
- compilerCtx.fs.writeFile(outputTarget.proxyDeclarationFile, finalText),
12
+ compilerCtx.fs.writeFile(outputTarget.directivesProxyFile, finalText),
14
13
  copyResources(config, outputTarget),
15
14
  generateAngularDirectivesFile(compilerCtx, filteredComponents, outputTarget),
16
15
  generateValueAccessors(compilerCtx, filteredComponents, outputTarget, config),
@@ -24,7 +23,7 @@ async function copyResources(config, outputTarget) {
24
23
  throw new Error('stencil is not properly initialized at this step. Notify the developer');
25
24
  }
26
25
  const srcDirectory = path.join(__dirname, '..', 'angular-component-lib');
27
- const destDirectory = path.join(path.dirname(outputTarget.proxyDeclarationFile), 'angular-component-lib');
26
+ const destDirectory = path.join(path.dirname(outputTarget.directivesProxyFile), 'angular-component-lib');
28
27
  return config.sys.copy([
29
28
  {
30
29
  src: srcDirectory,
@@ -35,11 +34,9 @@ async function copyResources(config, outputTarget) {
35
34
  ], srcDirectory);
36
35
  }
37
36
  export function generateProxies(components, pkgData, outputTarget, rootDir) {
38
- var _a;
39
37
  const distTypesDir = path.dirname(pkgData.types);
40
38
  const dtsFilePath = path.join(rootDir, distTypesDir, GENERATED_DTS);
41
- const componentsTypeFile = relativeImport(outputTarget.proxyDeclarationFile, dtsFilePath, '.d.ts');
42
- const createSingleComponentAngularModules = (_a = outputTarget.createSingleComponentAngularModules) !== null && _a !== void 0 ? _a : false;
39
+ const componentsTypeFile = relativeImport(outputTarget.directivesProxyFile, dtsFilePath, '.d.ts');
43
40
  /**
44
41
  * The collection of named imports from @angular/core.
45
42
  */
@@ -50,14 +47,12 @@ export function generateProxies(components, pkgData, outputTarget, rootDir) {
50
47
  'ElementRef',
51
48
  'EventEmitter',
52
49
  'NgZone',
50
+ 'Output',
53
51
  ];
54
52
  /**
55
53
  * The collection of named imports from the angular-component-lib/utils.
56
54
  */
57
55
  const componentLibImports = ['ProxyCmp', 'proxyOutputs'];
58
- if (createSingleComponentAngularModules) {
59
- angularCoreImports.push('NgModule');
60
- }
61
56
  const imports = `/* tslint:disable */
62
57
  /* auto-generated angular directive proxies */
63
58
  ${createImportStatement(angularCoreImports, '@angular/core')}
@@ -93,12 +88,6 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
93
88
  });
94
89
  sourceImports = cmpImports.join('\n');
95
90
  }
96
- if (createSingleComponentAngularModules) {
97
- // Generating Angular modules is only supported in the dist-custom-elements build
98
- if (!outputTarget.includeImportCustomElements) {
99
- throw new Error('Generating single component Angular modules requires the "includeImportCustomElements" option to be set to true.');
100
- }
101
- }
102
91
  const proxyFileOutput = [];
103
92
  const filterInternalProps = (prop) => !prop.internal;
104
93
  const mapPropName = (prop) => prop.name;
@@ -115,7 +104,7 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
115
104
  inputs.sort();
116
105
  const outputs = [];
117
106
  if (cmpMeta.events) {
118
- outputs.push(...cmpMeta.events.filter(filterInternalProps).map(mapPropName));
107
+ outputs.push(...cmpMeta.events.filter(filterInternalProps));
119
108
  }
120
109
  const methods = [];
121
110
  if (cmpMeta.methods) {
@@ -124,16 +113,11 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
124
113
  /**
125
114
  * For each component, we need to generate:
126
115
  * 1. The @Component decorated class
127
- * 2. Optionally the @NgModule decorated class (if createSingleComponentAngularModules is true)
128
- * 3. The component interface (using declaration merging for types).
116
+ * 2. The component interface (using declaration merging for types).
129
117
  */
130
118
  const componentDefinition = createAngularComponentDefinition(cmpMeta.tagName, inputs, outputs, methods, includeImportCustomElements);
131
- const moduleDefinition = generateAngularModuleForComponent(cmpMeta.tagName);
132
119
  const componentTypeDefinition = createComponentTypeDefinition(tagNameAsPascal, cmpMeta.events, componentCorePackage, includeImportCustomElements, customElementsDir);
133
120
  proxyFileOutput.push(componentDefinition, '\n');
134
- if (createSingleComponentAngularModules) {
135
- proxyFileOutput.push(moduleDefinition, '\n');
136
- }
137
121
  proxyFileOutput.push(componentTypeDefinition, '\n');
138
122
  }
139
123
  const final = [imports, typeImports, sourceImports, ...proxyFileOutput];
package/dist/plugin.js CHANGED
@@ -18,14 +18,11 @@ export function normalizeOutputTarget(config, outputTarget) {
18
18
  if (config.rootDir == null) {
19
19
  throw new Error('rootDir is not set and it should be set by stencil itself');
20
20
  }
21
- if (outputTarget.directivesProxyFile !== undefined) {
22
- throw new Error('directivesProxyFile has been removed. Use proxyDeclarationFile instead.');
21
+ if (outputTarget.directivesProxyFile == null) {
22
+ throw new Error('directivesProxyFile is required. Please set it in the Stencil config.');
23
23
  }
24
- if (outputTarget.proxyDeclarationFile == null) {
25
- throw new Error('proxyDeclarationFile is required. Please set it in the Stencil config.');
26
- }
27
- if (outputTarget.proxyDeclarationFile && !path.isAbsolute(outputTarget.proxyDeclarationFile)) {
28
- results.proxyDeclarationFile = normalizePath(path.join(config.rootDir, outputTarget.proxyDeclarationFile));
24
+ if (outputTarget.directivesProxyFile && !path.isAbsolute(outputTarget.directivesProxyFile)) {
25
+ results.directivesProxyFile = normalizePath(path.join(config.rootDir, outputTarget.directivesProxyFile));
29
26
  }
30
27
  if (outputTarget.directivesArrayFile && !path.isAbsolute(outputTarget.directivesArrayFile)) {
31
28
  results.directivesArrayFile = normalizePath(path.join(config.rootDir, outputTarget.directivesArrayFile));
package/dist/types.d.ts CHANGED
@@ -4,25 +4,17 @@ export interface OutputTargetAngular {
4
4
  * This is used to generate the import statements.
5
5
  */
6
6
  componentCorePackage: string;
7
- /**
8
- * @deprecated Use `proxyDeclarationFile` instead. This property has been replaced.
9
- */
10
- directivesProxyFile?: string;
11
- directivesArrayFile?: string;
12
- directivesUtilsFile?: string;
13
7
  /**
14
8
  * The path to the proxy file that will be generated. This can be an absolute path
15
9
  * or a relative path from the root directory of the Stencil library.
16
10
  */
17
- proxyDeclarationFile: string;
11
+ directivesProxyFile: string;
12
+ directivesArrayFile?: string;
13
+ directivesUtilsFile?: string;
18
14
  valueAccessorConfigs?: ValueAccessorConfig[];
19
15
  excludeComponents?: string[];
20
16
  includeImportCustomElements?: boolean;
21
17
  customElementsDir?: string;
22
- /**
23
- * `true` to generate a single component Angular module for each component.
24
- */
25
- createSingleComponentAngularModules?: boolean;
26
18
  }
27
19
  export declare type ValueAccessorTypes = 'text' | 'radio' | 'select' | 'number' | 'boolean';
28
20
  export interface ValueAccessorConfig {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stencil/angular-output-target",
3
- "version": "0.6.1-dev.11662577182.1c45c8de",
3
+ "version": "0.6.1-dev.11667512184.13935f80",
4
4
  "description": "Angular output target for @stencil/core components.",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.js",
@@ -58,5 +58,5 @@
58
58
  ],
59
59
  "testURL": "http://localhost"
60
60
  },
61
- "gitHead": "c45c8deb595afb1d5321159783c838fb7131f087"
61
+ "gitHead": "3935f8069bb24eea156c4c5901c94357b302f1f5"
62
62
  }
@@ -1,6 +0,0 @@
1
- /**
2
- * Creates an Angular module declaration for a component wrapper.
3
- * @param componentTagName The tag name of the Stencil component.
4
- * @returns The Angular module declaration as a string.
5
- */
6
- export declare const generateAngularModuleForComponent: (componentTagName: string) => string;
@@ -1,17 +0,0 @@
1
- import { dashToPascalCase } from './utils';
2
- /**
3
- * Creates an Angular module declaration for a component wrapper.
4
- * @param componentTagName The tag name of the Stencil component.
5
- * @returns The Angular module declaration as a string.
6
- */
7
- export const generateAngularModuleForComponent = (componentTagName) => {
8
- const tagNameAsPascal = dashToPascalCase(componentTagName);
9
- const componentClassName = `${tagNameAsPascal}`;
10
- const moduleClassName = `${tagNameAsPascal}Module`;
11
- const moduleDefinition = `@NgModule({
12
- declarations: [${componentClassName}],
13
- exports: [${componentClassName}]
14
- })
15
- export class ${moduleClassName} { }`;
16
- return moduleDefinition;
17
- };