@stencil/angular-output-target 0.6.1-dev.11657573317.16e0205c → 0.6.1-dev.11662151255.17ea4066

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/dist/index.cjs.js CHANGED
@@ -81,117 +81,185 @@ async function readPackageJson(config, rootDir) {
81
81
  }
82
82
  return pkgData;
83
83
  }
84
- const EXTENDED_PATH_REGEX = /^\\\\\?\\/;
85
- const NON_ASCII_REGEX = /[^\x00-\x80]+/;
86
- const SLASH_REGEX = /\\/g;
87
-
88
- const createComponentDefinition = (componentCorePackage, distTypesDir, rootDir, includeImportCustomElements = false, customElementsDir = 'components') => (cmpMeta) => {
89
- // Collect component meta
90
- const inputs = [
91
- ...cmpMeta.properties.filter((prop) => !prop.internal).map((prop) => prop.name),
92
- ...cmpMeta.virtualProperties.map((prop) => prop.name),
93
- ].sort();
94
- const outputs = cmpMeta.events.filter((ev) => !ev.internal).map((prop) => prop);
95
- const methods = cmpMeta.methods.filter((method) => !method.internal).map((prop) => prop.name);
96
- // Process meta
97
- const hasOutputs = outputs.length > 0;
98
- // Generate Angular @Directive
99
- const directiveOpts = [
100
- `selector: \'${cmpMeta.tagName}\'`,
101
- `changeDetection: ChangeDetectionStrategy.OnPush`,
102
- `template: '<ng-content></ng-content>'`,
103
- ];
104
- if (inputs.length > 0) {
105
- directiveOpts.push(`inputs: ['${inputs.join(`', '`)}']`);
84
+ /**
85
+ * Formats an array of strings to a string of quoted, comma separated values.
86
+ * @param list The list of unformatted strings to format
87
+ * @returns The formatted array of strings. (e.g. ['foo', 'bar']) => `'foo', 'bar'`
88
+ */
89
+ const formatToQuotedList = (list) => list.map((item) => `'${item}'`).join(', ');
90
+ /**
91
+ * Creates an import statement for a list of named imports from a module.
92
+ * @param imports The list of named imports.
93
+ * @param module The module to import from.
94
+ *
95
+ * @returns The import statement as a string.
96
+ */
97
+ const createImportStatement = (imports, module) => {
98
+ if (imports.length === 0) {
99
+ return '';
106
100
  }
107
- const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
108
- const outputsInterface = new Set();
109
- const outputReferenceRemap = {};
110
- outputs.forEach((output) => {
111
- Object.entries(output.complexType.references).forEach(([reference, refObject]) => {
112
- // Add import line for each local/import reference, and add new mapping name.
113
- // `outputReferenceRemap` should be updated only if the import interface is set in outputsInterface,
114
- // this will prevent global types to be remapped.
115
- const remappedReference = `I${cmpMeta.componentClassName}${reference}`;
101
+ return `import { ${imports.join(', ')} } from '${module}';`;
102
+ };
103
+ /**
104
+ * Creates the collection of import statements for a component based on the component's events type dependencies.
105
+ * @param componentTagName The tag name of the component (pascal case).
106
+ * @param events The events compiler metadata.
107
+ * @param options The options for generating the import statements (e.g. whether to import from the custom elements directory).
108
+ * @returns The import statements as an array of strings.
109
+ */
110
+ const createComponentEventTypeImports = (componentTagName, events, options) => {
111
+ const { componentCorePackage, includeImportCustomElements, customElementsDir } = options;
112
+ const imports = [];
113
+ const namedImports = new Set();
114
+ const importPathName = normalizePath(componentCorePackage) + (includeImportCustomElements ? `/${customElementsDir || 'components'}` : '');
115
+ events.forEach((event) => {
116
+ Object.entries(event.complexType.references).forEach(([typeName, refObject]) => {
116
117
  if (refObject.location === 'local' || refObject.location === 'import') {
117
- outputReferenceRemap[reference] = remappedReference;
118
- let importLocation = componentCorePackage;
119
- if (componentCorePackage !== undefined) {
120
- const dirPath = includeImportCustomElements ? `/${customElementsDir || 'components'}` : '';
121
- importLocation = `${normalizePath(componentCorePackage)}${dirPath}`;
118
+ const newTypeName = `I${componentTagName}${typeName}`;
119
+ // Prevents duplicate imports for the same type.
120
+ if (!namedImports.has(newTypeName)) {
121
+ imports.push(`import type { ${typeName} as ${newTypeName} } from '${importPathName}';`);
122
+ namedImports.add(newTypeName);
122
123
  }
123
- outputsInterface.add(`import type { ${reference} as ${remappedReference} } from '${importLocation}';`);
124
124
  }
125
125
  });
126
126
  });
127
- const componentEvents = [
128
- '' // Empty first line
129
- ];
130
- // Generate outputs
131
- outputs.forEach((output, index) => {
132
- componentEvents.push(` /**
133
- * ${output.docs.text} ${output.docs.tags.map((tag) => `@${tag.name} ${tag.text}`)}
134
- */`);
135
- /**
136
- * The original attribute contains the original type defined by the devs.
137
- * This regexp normalizes the reference, by removing linebreaks,
138
- * replacing consecutive spaces with a single space, and adding a single space after commas.
139
- **/
140
- const outputTypeRemapped = Object.entries(outputReferenceRemap).reduce((type, [src, dst]) => {
141
- return type
142
- .replace(new RegExp(`^${src}$`, 'g'), `${dst}`)
143
- .replace(new RegExp(`([^\\w])${src}([^\\w])`, 'g'), (v, p1, p2) => [p1, dst, p2].join(''));
144
- }, output.complexType.original
145
- .replace(/\n/g, ' ')
146
- .replace(/\s{2,}/g, ' ')
147
- .replace(/,\s*/g, ', '));
148
- componentEvents.push(` ${output.name}: EventEmitter<CustomEvent<${outputTypeRemapped.trim()}>>;`);
149
- if (index === outputs.length - 1) {
150
- // Empty line to push end `}` to new line
151
- componentEvents.push('\n');
152
- }
153
- });
154
- const lines = [
155
- '',
156
- `${[...outputsInterface].join('\n')}
157
- export declare interface ${tagNameAsPascal} extends Components.${tagNameAsPascal} {${componentEvents.length > 1 ? componentEvents.join('\n') : ''}}
127
+ return imports.join('\n');
128
+ };
129
+ const EXTENDED_PATH_REGEX = /^\\\\\?\\/;
130
+ const NON_ASCII_REGEX = /[^\x00-\x80]+/;
131
+ const SLASH_REGEX = /\\/g;
158
132
 
159
- ${getProxyCmp(cmpMeta.tagName, includeImportCustomElements, inputs, methods)}
133
+ /**
134
+ * Creates an Angular component declaration from formatted Stencil compiler metadata.
135
+ *
136
+ * @param tagName The tag name of the component.
137
+ * @param inputs The inputs of the Stencil component (e.g. ['myInput']).
138
+ * @param outputs The outputs/events of the Stencil component. (e.g. ['myOutput']).
139
+ * @param methods The methods of the Stencil component. (e.g. ['myMethod']).
140
+ * @param includeImportCustomElements Whether to define the component as a custom element.
141
+ * @returns The component declaration as a string.
142
+ */
143
+ const createAngularComponentDefinition = (tagName, inputs, outputs, methods, includeImportCustomElements = false) => {
144
+ const tagNameAsPascal = dashToPascalCase(tagName);
145
+ const hasInputs = inputs.length > 0;
146
+ const hasOutputs = outputs.length > 0;
147
+ const hasMethods = methods.length > 0;
148
+ // Formats the input strings into comma separated, single quoted values.
149
+ const formattedInputs = formatToQuotedList(inputs);
150
+ // Formats the output strings into comma separated, single quoted values.
151
+ const formattedOutputs = formatToQuotedList(outputs);
152
+ // Formats the method strings into comma separated, single quoted values.
153
+ const formattedMethods = formatToQuotedList(methods);
154
+ const proxyCmpOptions = [];
155
+ if (includeImportCustomElements) {
156
+ const defineCustomElementFn = `define${tagNameAsPascal}`;
157
+ proxyCmpOptions.push(`\n defineCustomElementFn: ${defineCustomElementFn}`);
158
+ }
159
+ if (hasInputs) {
160
+ proxyCmpOptions.push(`\n inputs: [${formattedInputs}]`);
161
+ }
162
+ if (hasMethods) {
163
+ proxyCmpOptions.push(`\n methods: [${formattedMethods}]`);
164
+ }
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})
160
173
  @Component({
161
- ${directiveOpts.join(',\n ')}
174
+ selector: '${tagName}',
175
+ template: '<ng-content></ng-content>',
176
+ changeDetection: ChangeDetectionStrategy.OnPush,
177
+ // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
178
+ inputs: [${formattedInputs}],
162
179
  })
163
- export class ${tagNameAsPascal} {`,
164
- ];
165
- lines.push(' protected el: HTMLElement;');
166
- lines.push(` constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
180
+ export class ${tagNameAsPascal} {
181
+ protected el: HTMLElement;
182
+ constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
167
183
  c.detach();
168
- this.el = r.nativeElement;`);
169
- if (hasOutputs) {
170
- lines.push(` proxyOutputs(this, this.el, ['${outputs.map((output) => output.name).join(`', '`)}']);`);
184
+ this.el = r.nativeElement;${hasOutputs
185
+ ? `
186
+ proxyOutputs(this, this.el, [${formattedOutputs}]);`
187
+ : ''}
188
+ }
189
+ }`;
190
+ return output;
191
+ };
192
+ /**
193
+ * Sanitizes and formats the component event type.
194
+ * @param componentClassName The class name of the component (e.g. 'MyComponent')
195
+ * @param event The Stencil component event.
196
+ * @returns The sanitized event type as a string.
197
+ */
198
+ const formatOutputType = (componentClassName, event) => {
199
+ /**
200
+ * The original attribute contains the original type defined by the devs.
201
+ * This regexp normalizes the reference, by removing linebreaks,
202
+ * replacing consecutive spaces with a single space, and adding a single space after commas.
203
+ */
204
+ return Object.entries(event.complexType.references)
205
+ .filter(([_, refObject]) => refObject.location === 'local' || refObject.location === 'import')
206
+ .reduce((type, [src, dst]) => {
207
+ const renamedType = `I${componentClassName}${type}`;
208
+ return renamedType
209
+ .replace(new RegExp(`^${src}$`, 'g'), `${dst}`)
210
+ .replace(new RegExp(`([^\\w])${src}([^\\w])`, 'g'), (v, p1, p2) => [p1, dst, p2].join(''));
211
+ }, event.complexType.original
212
+ .replace(/\n/g, ' ')
213
+ .replace(/\s{2,}/g, ' ')
214
+ .replace(/,\s*/g, ', '));
215
+ };
216
+ /**
217
+ * Creates a formatted comment block based on the JS doc comment.
218
+ * @param doc The compiler jsdoc.
219
+ * @returns The formatted comment block as a string.
220
+ */
221
+ const createDocComment = (doc) => {
222
+ if (doc.text.trim().length === 0 && doc.tags.length === 0) {
223
+ return '';
171
224
  }
172
- lines.push(` }`);
173
- lines.push(`}`);
174
- return lines.join('\n');
225
+ return `/**
226
+ * ${doc.text}${doc.tags.length > 0 ? ' ' : ''}${doc.tags.map((tag) => `@${tag.name} ${tag.text}`)}
227
+ */`;
228
+ };
229
+ /**
230
+ * Creates the component interface type definition.
231
+ * @param tagNameAsPascal The tag name as PascalCase.
232
+ * @param events The events to generate the interface properties for.
233
+ * @param componentCorePackage The component core package.
234
+ * @param includeImportCustomElements Whether to include the import for the custom element definition.
235
+ * @param customElementsDir The custom elements directory.
236
+ * @returns The component interface type definition as a string.
237
+ */
238
+ const createComponentTypeDefinition = (tagNameAsPascal, events, componentCorePackage, includeImportCustomElements = false, customElementsDir) => {
239
+ const typeDefinition = `${createComponentEventTypeImports(tagNameAsPascal, events, {
240
+ componentCorePackage,
241
+ includeImportCustomElements,
242
+ customElementsDir,
243
+ })}
244
+
245
+ export interface ${tagNameAsPascal} extends Components.${tagNameAsPascal} {
246
+ ${events
247
+ .map((event) => {
248
+ const comment = createDocComment(event.docs);
249
+ return `${comment.length > 0 ? ` ${comment}` : ''}
250
+ ${event.name}: EventEmitter<CustomEvent<${formatOutputType(tagNameAsPascal, event)}>>;`;
251
+ })
252
+ .join('\n')}
253
+ }`;
254
+ return typeDefinition;
175
255
  };
176
- function getProxyCmp(tagName, includeCustomElement, inputs, methods) {
177
- const hasInputs = inputs.length > 0;
178
- const hasMethods = methods.length > 0;
179
- const proxMeta = [
180
- `defineCustomElementFn: ${includeCustomElement ? 'define' + dashToPascalCase(tagName) : 'undefined'}`
181
- ];
182
- if (hasInputs)
183
- proxMeta.push(`inputs: ['${inputs.join(`', '`)}']`);
184
- if (hasMethods)
185
- proxMeta.push(`methods: ['${methods.join(`', '`)}']`);
186
- return `@ProxyCmp({\n ${proxMeta.join(',\n ')}\n})`;
187
- }
188
256
 
189
257
  function generateAngularDirectivesFile(compilerCtx, components, outputTarget) {
190
258
  // Only create the file if it is defined in the stencil configuration
191
259
  if (!outputTarget.directivesArrayFile) {
192
260
  return Promise.resolve();
193
261
  }
194
- const proxyPath = relativeImport(outputTarget.directivesArrayFile, outputTarget.directivesProxyFile, '.ts');
262
+ const proxyPath = relativeImport(outputTarget.directivesArrayFile, outputTarget.proxyDeclarationFile, '.ts');
195
263
  const directives = components
196
264
  .map((cmpMeta) => dashToPascalCase(cmpMeta.tagName))
197
265
  .map((className) => `d.${className}`)
@@ -207,15 +275,12 @@ export const DIRECTIVES = [
207
275
  }
208
276
 
209
277
  async function generateValueAccessors(compilerCtx, components, outputTarget, config) {
210
- if (!Array.isArray(outputTarget.valueAccessorConfigs) ||
211
- outputTarget.valueAccessorConfigs.length === 0) {
278
+ if (!Array.isArray(outputTarget.valueAccessorConfigs) || outputTarget.valueAccessorConfigs.length === 0) {
212
279
  return;
213
280
  }
214
- const targetDir = path__default['default'].dirname(outputTarget.directivesProxyFile);
281
+ const targetDir = path__default['default'].dirname(outputTarget.proxyDeclarationFile);
215
282
  const normalizedValueAccessors = outputTarget.valueAccessorConfigs.reduce((allAccessors, va) => {
216
- const elementSelectors = Array.isArray(va.elementSelectors)
217
- ? va.elementSelectors
218
- : [va.elementSelectors];
283
+ const elementSelectors = Array.isArray(va.elementSelectors) ? va.elementSelectors : [va.elementSelectors];
219
284
  const type = va.type;
220
285
  let allElementSelectors = [];
221
286
  let allEventTargets = [];
@@ -264,13 +329,30 @@ const VALUE_ACCESSOR_EVENT = `<VALUE_ACCESSOR_EVENT>`;
264
329
  const VALUE_ACCESSOR_TARGETATTR = '<VALUE_ACCESSOR_TARGETATTR>';
265
330
  const VALUE_ACCESSOR_EVENTTARGETS = ` '(<VALUE_ACCESSOR_EVENT>)': 'handleChangeEvent($event.target.<VALUE_ACCESSOR_TARGETATTR>)'`;
266
331
 
332
+ /**
333
+ * Creates an Angular module declaration for a component wrapper.
334
+ * @param componentTagName The tag name of the Stencil component.
335
+ * @returns The Angular module declaration as a string.
336
+ */
337
+ const generateAngularModuleForComponent = (componentTagName) => {
338
+ const tagNameAsPascal = dashToPascalCase(componentTagName);
339
+ const componentClassName = `${tagNameAsPascal}`;
340
+ const moduleClassName = `${tagNameAsPascal}Module`;
341
+ const moduleDefinition = `@NgModule({
342
+ declarations: [${componentClassName}],
343
+ exports: [${componentClassName}]
344
+ })
345
+ export class ${moduleClassName} { }`;
346
+ return moduleDefinition;
347
+ };
348
+
267
349
  async function angularDirectiveProxyOutput(compilerCtx, outputTarget, components, config) {
268
350
  const filteredComponents = getFilteredComponents(outputTarget.excludeComponents, components);
269
351
  const rootDir = config.rootDir;
270
352
  const pkgData = await readPackageJson(config, rootDir);
271
353
  const finalText = generateProxies(filteredComponents, pkgData, outputTarget, config.rootDir);
272
354
  await Promise.all([
273
- compilerCtx.fs.writeFile(outputTarget.directivesProxyFile, finalText),
355
+ compilerCtx.fs.writeFile(outputTarget.proxyDeclarationFile, finalText),
274
356
  copyResources$1(config, outputTarget),
275
357
  generateAngularDirectivesFile(compilerCtx, filteredComponents, outputTarget),
276
358
  generateValueAccessors(compilerCtx, filteredComponents, outputTarget, config),
@@ -284,7 +366,7 @@ async function copyResources$1(config, outputTarget) {
284
366
  throw new Error('stencil is not properly initialized at this step. Notify the developer');
285
367
  }
286
368
  const srcDirectory = path__default['default'].join(__dirname, '..', 'angular-component-lib');
287
- const destDirectory = path__default['default'].join(path__default['default'].dirname(outputTarget.directivesProxyFile), 'angular-component-lib');
369
+ const destDirectory = path__default['default'].join(path__default['default'].dirname(outputTarget.proxyDeclarationFile), 'angular-component-lib');
288
370
  return config.sys.copy([
289
371
  {
290
372
  src: srcDirectory,
@@ -295,13 +377,34 @@ async function copyResources$1(config, outputTarget) {
295
377
  ], srcDirectory);
296
378
  }
297
379
  function generateProxies(components, pkgData, outputTarget, rootDir) {
380
+ var _a;
298
381
  const distTypesDir = path__default['default'].dirname(pkgData.types);
299
382
  const dtsFilePath = path__default['default'].join(rootDir, distTypesDir, GENERATED_DTS);
300
- const componentsTypeFile = relativeImport(outputTarget.directivesProxyFile, dtsFilePath, '.d.ts');
383
+ const componentsTypeFile = relativeImport(outputTarget.proxyDeclarationFile, dtsFilePath, '.d.ts');
384
+ const createSingleComponentAngularModules = (_a = outputTarget.createSingleComponentAngularModules) !== null && _a !== void 0 ? _a : false;
385
+ /**
386
+ * The collection of named imports from @angular/core.
387
+ */
388
+ const angularCoreImports = [
389
+ 'ChangeDetectionStrategy',
390
+ 'ChangeDetectorRef',
391
+ 'Component',
392
+ 'ElementRef',
393
+ 'EventEmitter',
394
+ 'NgZone',
395
+ ];
396
+ /**
397
+ * The collection of named imports from the angular-component-lib/utils.
398
+ */
399
+ const componentLibImports = ['ProxyCmp', 'proxyOutputs'];
400
+ if (createSingleComponentAngularModules) {
401
+ angularCoreImports.push('NgModule');
402
+ }
301
403
  const imports = `/* tslint:disable */
302
404
  /* auto-generated angular directive proxies */
303
- import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, NgZone } from '@angular/core';
304
- import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';\n`;
405
+ ${createImportStatement(angularCoreImports, '@angular/core')}
406
+
407
+ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n`;
305
408
  /**
306
409
  * Generate JSX import type from correct location.
307
410
  * When using custom elements build, we need to import from
@@ -309,8 +412,12 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';\n`;
309
412
  * otherwise we risk bundlers pulling in lazy loaded imports.
310
413
  */
311
414
  const generateTypeImports = () => {
312
- let importLocation = outputTarget.componentCorePackage ? normalizePath(outputTarget.componentCorePackage) : normalizePath(componentsTypeFile);
313
- importLocation += outputTarget.includeImportCustomElements ? `/${outputTarget.customElementsDir || 'components'}` : '';
415
+ let importLocation = outputTarget.componentCorePackage
416
+ ? normalizePath(outputTarget.componentCorePackage)
417
+ : normalizePath(componentsTypeFile);
418
+ importLocation += outputTarget.includeImportCustomElements
419
+ ? `/${outputTarget.customElementsDir || 'components'}`
420
+ : '';
314
421
  return `import ${outputTarget.includeImportCustomElements ? 'type ' : ''}{ ${IMPORT_TYPES} } from '${importLocation}';\n`;
315
422
  };
316
423
  const typeImports = generateTypeImports();
@@ -322,21 +429,52 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';\n`;
322
429
  * IonButton React Component that takes in the Web Component as a parameter.
323
430
  */
324
431
  if (outputTarget.includeImportCustomElements && outputTarget.componentCorePackage !== undefined) {
325
- const cmpImports = components.map(component => {
432
+ const cmpImports = components.map((component) => {
326
433
  const pascalImport = dashToPascalCase(component.tagName);
327
- return `import { defineCustomElement as define${pascalImport} } from '${normalizePath(outputTarget.componentCorePackage)}/${outputTarget.customElementsDir ||
328
- 'components'}/${component.tagName}.js';`;
434
+ return `import { defineCustomElement as define${pascalImport} } from '${normalizePath(outputTarget.componentCorePackage)}/${outputTarget.customElementsDir || 'components'}/${component.tagName}.js';`;
329
435
  });
330
436
  sourceImports = cmpImports.join('\n');
331
437
  }
332
- const final = [
333
- imports,
334
- typeImports,
335
- sourceImports,
336
- components
337
- .map(createComponentDefinition(outputTarget.componentCorePackage, distTypesDir, rootDir, outputTarget.includeImportCustomElements, outputTarget.customElementsDir))
338
- .join('\n'),
339
- ];
438
+ if (createSingleComponentAngularModules) {
439
+ // Generating Angular modules is only supported in the dist-custom-elements build
440
+ if (!outputTarget.includeImportCustomElements) {
441
+ throw new Error('Generating single component Angular modules requires the "includeImportCustomElements" option to be set to true.');
442
+ }
443
+ }
444
+ const proxyFileOutput = [];
445
+ const filterInternalProps = (prop) => !prop.internal;
446
+ const mapPropName = (prop) => prop.name;
447
+ const { includeImportCustomElements, componentCorePackage, customElementsDir } = outputTarget;
448
+ for (let cmpMeta of components) {
449
+ const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
450
+ const inputs = [];
451
+ if (cmpMeta.properties) {
452
+ inputs.push(...cmpMeta.properties.filter(filterInternalProps).map(mapPropName));
453
+ }
454
+ if (cmpMeta.virtualProperties) {
455
+ inputs.push(...cmpMeta.virtualProperties.map(mapPropName));
456
+ }
457
+ inputs.sort();
458
+ const outputs = [];
459
+ if (cmpMeta.events) {
460
+ outputs.push(...cmpMeta.events.filter(filterInternalProps).map(mapPropName));
461
+ }
462
+ const methods = [];
463
+ if (cmpMeta.methods) {
464
+ methods.push(...cmpMeta.methods.filter(filterInternalProps).map(mapPropName));
465
+ }
466
+ /**
467
+ * For each component, we need to generate:
468
+ * 1. The @Component decorated class
469
+ * 2. Optionally the @NgModule decorated class (if createSingleComponentAngularModules is true)
470
+ * 3. The component interface (using declaration merging for types).
471
+ */
472
+ const componentDefinition = createAngularComponentDefinition(cmpMeta.tagName, inputs, outputs, methods, includeImportCustomElements);
473
+ const moduleDefinition = generateAngularModuleForComponent(cmpMeta.tagName);
474
+ const componentTypeDefinition = createComponentTypeDefinition(tagNameAsPascal, cmpMeta.events, componentCorePackage, includeImportCustomElements, customElementsDir);
475
+ proxyFileOutput.push(componentDefinition, '\n', createSingleComponentAngularModules ? moduleDefinition : '', '\n', componentTypeDefinition, '\n');
476
+ }
477
+ const final = [imports, typeImports, sourceImports, ...proxyFileOutput];
340
478
  return final.join('\n') + '\n';
341
479
  }
342
480
  const GENERATED_DTS = 'components.d.ts';
@@ -355,15 +493,18 @@ const angularOutputTarget = (outputTarget) => ({
355
493
  },
356
494
  });
357
495
  function normalizeOutputTarget(config, outputTarget) {
358
- const results = Object.assign(Object.assign({}, outputTarget), { excludeComponents: outputTarget.excludeComponents || [], valueAccessorConfig: outputTarget.valueAccessorConfig || [] });
496
+ const results = Object.assign(Object.assign({}, outputTarget), { excludeComponents: outputTarget.excludeComponents || [], valueAccessorConfigs: outputTarget.valueAccessorConfigs || [] });
359
497
  if (config.rootDir == null) {
360
498
  throw new Error('rootDir is not set and it should be set by stencil itself');
361
499
  }
362
- if (outputTarget.directivesProxyFile == null) {
363
- throw new Error('directivesProxyFile is required');
500
+ if (outputTarget.directivesProxyFile !== undefined) {
501
+ throw new Error('directivesProxyFile has been removed. Use proxyDeclarationFile instead.');
502
+ }
503
+ if (outputTarget.proxyDeclarationFile == null) {
504
+ throw new Error('proxyDeclarationFile is required. Please set it in the Stencil config.');
364
505
  }
365
- if (outputTarget.directivesProxyFile && !path__default['default'].isAbsolute(outputTarget.directivesProxyFile)) {
366
- results.directivesProxyFile = normalizePath(path__default['default'].join(config.rootDir, outputTarget.directivesProxyFile));
506
+ if (outputTarget.proxyDeclarationFile && !path__default['default'].isAbsolute(outputTarget.proxyDeclarationFile)) {
507
+ results.proxyDeclarationFile = normalizePath(path__default['default'].join(config.rootDir, outputTarget.proxyDeclarationFile));
367
508
  }
368
509
  if (outputTarget.directivesArrayFile && !path__default['default'].isAbsolute(outputTarget.directivesArrayFile)) {
369
510
  results.directivesArrayFile = normalizePath(path__default['default'].join(config.rootDir, outputTarget.directivesArrayFile));