@stencil/angular-output-target 0.0.6 → 0.2.1-0

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,36 +1,39 @@
1
+ /* eslint-disable */
2
+ /* tslint:disable */
1
3
  import { fromEvent } from 'rxjs';
2
4
 
3
5
  export const proxyInputs = (Cmp: any, inputs: string[]) => {
4
6
  const Prototype = Cmp.prototype;
5
- inputs.forEach((item) => {
7
+ inputs.forEach(item => {
6
8
  Object.defineProperty(Prototype, item, {
7
9
  get() {
8
10
  return this.el[item];
9
11
  },
10
12
  set(val: any) {
11
13
  this.z.runOutsideAngular(() => (this.el[item] = val));
12
- },
14
+ }
13
15
  });
14
16
  });
15
17
  };
16
18
 
17
19
  export const proxyMethods = (Cmp: any, methods: string[]) => {
18
20
  const Prototype = Cmp.prototype;
19
- methods.forEach((methodName) => {
21
+ methods.forEach(methodName => {
20
22
  Prototype[methodName] = function () {
21
23
  const args = arguments;
22
- return this.z.runOutsideAngular(() => this.el[methodName].apply(this.el, args));
24
+ return this.z.runOutsideAngular(() =>
25
+ this.el[methodName].apply(this.el, args)
26
+ );
23
27
  };
24
28
  });
25
29
  };
26
30
 
27
31
  export const proxyOutputs = (instance: any, el: any, events: string[]) => {
28
- events.forEach((eventName) => (instance[eventName] = fromEvent(el, eventName)));
29
- };
32
+ events.forEach(eventName => instance[eventName] = fromEvent(el, eventName));
33
+ }
30
34
 
31
- // tslint:disable-next-line: only-arrow-functions
32
35
  export function ProxyCmp(opts: { inputs?: any; methods?: any }) {
33
- const decorator = function (cls: any) {
36
+ const decorator = function(cls: any) {
34
37
  if (opts.inputs) {
35
38
  proxyInputs(cls, opts.inputs);
36
39
  }
@@ -1,5 +1,4 @@
1
- import path from 'path';
2
- import { dashToPascalCase, normalizePath } from './utils';
1
+ import { dashToPascalCase } from './utils';
3
2
  export const createComponentDefinition = (componentCorePackage, distTypesDir, rootDir) => (cmpMeta) => {
4
3
  // Collect component meta
5
4
  const inputs = [
@@ -19,30 +18,59 @@ export const createComponentDefinition = (componentCorePackage, distTypesDir, ro
19
18
  if (inputs.length > 0) {
20
19
  directiveOpts.push(`inputs: ['${inputs.join(`', '`)}']`);
21
20
  }
22
- if (outputs.length > 0) {
23
- directiveOpts.push(`outputs: ['${outputs.map((output) => output.name).join(`', '`)}']`);
24
- }
25
21
  const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
26
- const typePath = path.parse(path.join(componentCorePackage, path.join(cmpMeta.sourceFilePath, '').replace(path.join(rootDir, 'src'), distTypesDir)));
27
- const importPath = normalizePath(path.join(typePath.dir, typePath.name));
28
- const outputsInterface = outputs.length > 0
29
- ? `import { ${cmpMeta.componentClassName} as I${cmpMeta.componentClassName} } from '${importPath}';`
30
- : '';
22
+ const outputsInterface = new Set();
23
+ const outputReferenceRemap = {};
24
+ outputs.forEach((output) => {
25
+ Object.entries(output.complexType.references).forEach(([reference, refObject]) => {
26
+ // Add import line for each local/import reference, and add new mapping name.
27
+ // `outputReferenceRemap` should be updated only if the import interface is set in outputsInterface,
28
+ // this will prevent global types to be remapped.
29
+ const remappedReference = `I${cmpMeta.componentClassName}${reference}`;
30
+ if (refObject.location === 'local' || refObject.location === 'import') {
31
+ outputReferenceRemap[reference] = remappedReference;
32
+ outputsInterface.add(`import { ${reference} as ${remappedReference} } from '${componentCorePackage}';`);
33
+ }
34
+ });
35
+ });
36
+ const componentEvents = [
37
+ '' // Empty first line
38
+ ];
39
+ // Generate outputs
40
+ outputs.forEach((output, index) => {
41
+ componentEvents.push(` /**
42
+ * ${output.docs.text} ${output.docs.tags.map((tag) => `@${tag.name} ${tag.text}`)}
43
+ */`);
44
+ /**
45
+ * The original attribute contains the original type defined by the devs.
46
+ * This regexp normalizes the reference, by removing linebreaks,
47
+ * replacing consecutive spaces with a single space, and adding a single space after commas.
48
+ **/
49
+ const outputTypeRemapped = Object.entries(outputReferenceRemap).reduce((type, [src, dst]) => {
50
+ return type
51
+ .replace(new RegExp(`^${src}$`, 'g'), `${dst}`)
52
+ .replace(new RegExp(`([^\\w])${src}([^\\w])`, 'g'), (v, p1, p2) => [p1, dst, p2].join(''));
53
+ }, output.complexType.original
54
+ .replace(/\n/g, ' ')
55
+ .replace(/\s{2,}/g, ' ')
56
+ .replace(/,\s*/g, ', '));
57
+ componentEvents.push(` ${output.name}: EventEmitter<CustomEvent<${outputTypeRemapped.trim()}>>;`);
58
+ if (index === outputs.length - 1) {
59
+ // Empty line to push end `}` to new line
60
+ componentEvents.push('\n');
61
+ }
62
+ });
31
63
  const lines = [
32
- `
33
- ${outputsInterface}
34
- export declare interface ${tagNameAsPascal} extends Components.${tagNameAsPascal} {}
64
+ '',
65
+ `${[...outputsInterface].join('\n')}
66
+ export declare interface ${tagNameAsPascal} extends Components.${tagNameAsPascal} {${componentEvents.length > 1 ? componentEvents.join('\n') : ''}}
67
+
35
68
  ${getProxyCmp(inputs, methods)}
36
69
  @Component({
37
70
  ${directiveOpts.join(',\n ')}
38
71
  })
39
72
  export class ${tagNameAsPascal} {`,
40
73
  ];
41
- // Generate outputs
42
- outputs.forEach((output) => {
43
- lines.push(` /** ${output.docs.text} ${output.docs.tags.map((tag) => `@${tag.name} ${tag.text}`)}*/`);
44
- lines.push(` ${output.name}!: I${cmpMeta.componentClassName}['${output.method}'];`);
45
- });
46
74
  lines.push(' protected el: HTMLElement;');
47
75
  lines.push(` constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
48
76
  c.detach();
@@ -13,7 +13,7 @@ export function generateAngularDirectivesFile(compilerCtx, components, outputTar
13
13
  import * as d from '${proxyPath}';
14
14
 
15
15
  export const DIRECTIVES = [
16
- ${directives}
16
+ ${directives}
17
17
  ];
18
18
  `;
19
19
  return compilerCtx.fs.writeFile(outputTarget.directivesArrayFile, c);
@@ -1,3 +1,8 @@
1
1
  import type { OutputTargetAngular } from './types';
2
2
  import type { CompilerCtx, ComponentCompilerMeta, Config } from '@stencil/core/internal';
3
+ export interface ValueAccessor {
4
+ elementSelectors: string[];
5
+ eventTargets: [string, string][];
6
+ }
3
7
  export default function generateValueAccessors(compilerCtx: CompilerCtx, components: ComponentCompilerMeta[], outputTarget: OutputTargetAngular, config: Config): Promise<void>;
8
+ export declare function createValueAccessor(srcFileContents: string, valueAccessor: ValueAccessor): string;
@@ -1,3 +1,4 @@
1
+ import { EOL } from 'os';
1
2
  import path from 'path';
2
3
  export default async function generateValueAccessors(compilerCtx, components, outputTarget, config) {
3
4
  if (!Array.isArray(outputTarget.valueAccessorConfigs) ||
@@ -32,11 +33,11 @@ export default async function generateValueAccessors(compilerCtx, components, ou
32
33
  }));
33
34
  await copyResources(config, ['value-accessor.ts'], targetDir);
34
35
  }
35
- function createValueAccessor(srcFileContents, valueAccessor) {
36
+ export function createValueAccessor(srcFileContents, valueAccessor) {
36
37
  const hostContents = valueAccessor.eventTargets.map((listItem) => VALUE_ACCESSOR_EVENTTARGETS.replace(VALUE_ACCESSOR_EVENT, listItem[0]).replace(VALUE_ACCESSOR_TARGETATTR, listItem[1]));
37
38
  return srcFileContents
38
39
  .replace(VALUE_ACCESSOR_SELECTORS, valueAccessor.elementSelectors.join(', '))
39
- .replace(VALUE_ACCESSOR_EVENTTARGETS, hostContents.join('\n'));
40
+ .replace(VALUE_ACCESSOR_EVENTTARGETS, hostContents.join(`,${EOL}`));
40
41
  }
41
42
  function copyResources(config, resourcesFilesToCopy, directory) {
42
43
  if (!config.sys || !config.sys.copy) {
package/dist/index.cjs.js CHANGED
@@ -2,13 +2,17 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
-
7
- var path = _interopDefault(require('path'));
5
+ var path = require('path');
8
6
  var util = require('util');
9
- var fs = _interopDefault(require('fs'));
7
+ var fs = require('fs');
8
+ var os = require('os');
9
+
10
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
11
 
11
- const readFile = util.promisify(fs.readFile);
12
+ var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
13
+ var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
14
+
15
+ const readFile = util.promisify(fs__default['default'].readFile);
12
16
  const toLowerCase = (str) => str.toLowerCase();
13
17
  const dashToPascalCase = (str) => toLowerCase(str)
14
18
  .split('-')
@@ -53,17 +57,17 @@ function normalizePath(str) {
53
57
  return str;
54
58
  }
55
59
  function relativeImport(pathFrom, pathTo, ext) {
56
- let relativePath = path.relative(path.dirname(pathFrom), path.dirname(pathTo));
60
+ let relativePath = path__default['default'].relative(path__default['default'].dirname(pathFrom), path__default['default'].dirname(pathTo));
57
61
  if (relativePath === '') {
58
62
  relativePath = '.';
59
63
  }
60
64
  else if (relativePath[0] !== '.') {
61
65
  relativePath = './' + relativePath;
62
66
  }
63
- return normalizePath(`${relativePath}/${path.basename(pathTo, ext)}`);
67
+ return normalizePath(`${relativePath}/${path__default['default'].basename(pathTo, ext)}`);
64
68
  }
65
69
  async function readPackageJson(rootDir) {
66
- const pkgJsonPath = path.join(rootDir, 'package.json');
70
+ const pkgJsonPath = path__default['default'].join(rootDir, 'package.json');
67
71
  let pkgJson;
68
72
  try {
69
73
  pkgJson = await readFile(pkgJsonPath, 'utf8');
@@ -103,30 +107,59 @@ const createComponentDefinition = (componentCorePackage, distTypesDir, rootDir)
103
107
  if (inputs.length > 0) {
104
108
  directiveOpts.push(`inputs: ['${inputs.join(`', '`)}']`);
105
109
  }
106
- if (outputs.length > 0) {
107
- directiveOpts.push(`outputs: ['${outputs.map((output) => output.name).join(`', '`)}']`);
108
- }
109
110
  const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
110
- const typePath = path.parse(path.join(componentCorePackage, path.join(cmpMeta.sourceFilePath, '').replace(path.join(rootDir, 'src'), distTypesDir)));
111
- const importPath = normalizePath(path.join(typePath.dir, typePath.name));
112
- const outputsInterface = outputs.length > 0
113
- ? `import { ${cmpMeta.componentClassName} as I${cmpMeta.componentClassName} } from '${importPath}';`
114
- : '';
111
+ const outputsInterface = new Set();
112
+ const outputReferenceRemap = {};
113
+ outputs.forEach((output) => {
114
+ Object.entries(output.complexType.references).forEach(([reference, refObject]) => {
115
+ // Add import line for each local/import reference, and add new mapping name.
116
+ // `outputReferenceRemap` should be updated only if the import interface is set in outputsInterface,
117
+ // this will prevent global types to be remapped.
118
+ const remappedReference = `I${cmpMeta.componentClassName}${reference}`;
119
+ if (refObject.location === 'local' || refObject.location === 'import') {
120
+ outputReferenceRemap[reference] = remappedReference;
121
+ outputsInterface.add(`import { ${reference} as ${remappedReference} } from '${componentCorePackage}';`);
122
+ }
123
+ });
124
+ });
125
+ const componentEvents = [
126
+ '' // Empty first line
127
+ ];
128
+ // Generate outputs
129
+ outputs.forEach((output, index) => {
130
+ componentEvents.push(` /**
131
+ * ${output.docs.text} ${output.docs.tags.map((tag) => `@${tag.name} ${tag.text}`)}
132
+ */`);
133
+ /**
134
+ * The original attribute contains the original type defined by the devs.
135
+ * This regexp normalizes the reference, by removing linebreaks,
136
+ * replacing consecutive spaces with a single space, and adding a single space after commas.
137
+ **/
138
+ const outputTypeRemapped = Object.entries(outputReferenceRemap).reduce((type, [src, dst]) => {
139
+ return type
140
+ .replace(new RegExp(`^${src}$`, 'g'), `${dst}`)
141
+ .replace(new RegExp(`([^\\w])${src}([^\\w])`, 'g'), (v, p1, p2) => [p1, dst, p2].join(''));
142
+ }, output.complexType.original
143
+ .replace(/\n/g, ' ')
144
+ .replace(/\s{2,}/g, ' ')
145
+ .replace(/,\s*/g, ', '));
146
+ componentEvents.push(` ${output.name}: EventEmitter<CustomEvent<${outputTypeRemapped.trim()}>>;`);
147
+ if (index === outputs.length - 1) {
148
+ // Empty line to push end `}` to new line
149
+ componentEvents.push('\n');
150
+ }
151
+ });
115
152
  const lines = [
116
- `
117
- ${outputsInterface}
118
- export declare interface ${tagNameAsPascal} extends Components.${tagNameAsPascal} {}
153
+ '',
154
+ `${[...outputsInterface].join('\n')}
155
+ export declare interface ${tagNameAsPascal} extends Components.${tagNameAsPascal} {${componentEvents.length > 1 ? componentEvents.join('\n') : ''}}
156
+
119
157
  ${getProxyCmp(inputs, methods)}
120
158
  @Component({
121
159
  ${directiveOpts.join(',\n ')}
122
160
  })
123
161
  export class ${tagNameAsPascal} {`,
124
162
  ];
125
- // Generate outputs
126
- outputs.forEach((output) => {
127
- lines.push(` /** ${output.docs.text} ${output.docs.tags.map((tag) => `@${tag.name} ${tag.text}`)}*/`);
128
- lines.push(` ${output.name}!: I${cmpMeta.componentClassName}['${output.method}'];`);
129
- });
130
163
  lines.push(' protected el: HTMLElement;');
131
164
  lines.push(` constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
132
165
  c.detach();
@@ -166,7 +199,7 @@ function generateAngularDirectivesFile(compilerCtx, components, outputTarget) {
166
199
  import * as d from '${proxyPath}';
167
200
 
168
201
  export const DIRECTIVES = [
169
- ${directives}
202
+ ${directives}
170
203
  ];
171
204
  `;
172
205
  return compilerCtx.fs.writeFile(outputTarget.directivesArrayFile, c);
@@ -177,7 +210,7 @@ async function generateValueAccessors(compilerCtx, components, outputTarget, con
177
210
  outputTarget.valueAccessorConfigs.length === 0) {
178
211
  return;
179
212
  }
180
- const targetDir = path.dirname(outputTarget.directivesProxyFile);
213
+ const targetDir = path__default['default'].dirname(outputTarget.directivesProxyFile);
181
214
  const normalizedValueAccessors = outputTarget.valueAccessorConfigs.reduce((allAccessors, va) => {
182
215
  const elementSelectors = Array.isArray(va.elementSelectors)
183
216
  ? va.elementSelectors
@@ -197,8 +230,8 @@ async function generateValueAccessors(compilerCtx, components, outputTarget, con
197
230
  await Promise.all(Object.keys(normalizedValueAccessors).map(async (type) => {
198
231
  const valueAccessorType = type; // Object.keys converts to string
199
232
  const targetFileName = `${type}-value-accessor.ts`;
200
- const targetFilePath = path.join(targetDir, targetFileName);
201
- const srcFilePath = path.join(__dirname, '../resources/control-value-accessors/', targetFileName);
233
+ const targetFilePath = path__default['default'].join(targetDir, targetFileName);
234
+ const srcFilePath = path__default['default'].join(__dirname, '../resources/control-value-accessors/', targetFileName);
202
235
  const srcFileContents = await compilerCtx.fs.readFile(srcFilePath);
203
236
  const finalText = createValueAccessor(srcFileContents, normalizedValueAccessors[valueAccessorType]);
204
237
  await compilerCtx.fs.writeFile(targetFilePath, finalText);
@@ -209,7 +242,7 @@ function createValueAccessor(srcFileContents, valueAccessor) {
209
242
  const hostContents = valueAccessor.eventTargets.map((listItem) => VALUE_ACCESSOR_EVENTTARGETS.replace(VALUE_ACCESSOR_EVENT, listItem[0]).replace(VALUE_ACCESSOR_TARGETATTR, listItem[1]));
210
243
  return srcFileContents
211
244
  .replace(VALUE_ACCESSOR_SELECTORS, valueAccessor.elementSelectors.join(', '))
212
- .replace(VALUE_ACCESSOR_EVENTTARGETS, hostContents.join('\n'));
245
+ .replace(VALUE_ACCESSOR_EVENTTARGETS, hostContents.join(`,${os.EOL}`));
213
246
  }
214
247
  function copyResources(config, resourcesFilesToCopy, directory) {
215
248
  if (!config.sys || !config.sys.copy) {
@@ -217,13 +250,13 @@ function copyResources(config, resourcesFilesToCopy, directory) {
217
250
  }
218
251
  const copyTasks = resourcesFilesToCopy.map((rf) => {
219
252
  return {
220
- src: path.join(__dirname, '../resources/control-value-accessors/', rf),
221
- dest: path.join(directory, rf),
253
+ src: path__default['default'].join(__dirname, '../resources/control-value-accessors/', rf),
254
+ dest: path__default['default'].join(directory, rf),
222
255
  keepDirStructure: false,
223
256
  warn: false,
224
257
  };
225
258
  });
226
- return config.sys.copy(copyTasks, path.join(directory));
259
+ return config.sys.copy(copyTasks, path__default['default'].join(directory));
227
260
  }
228
261
  const VALUE_ACCESSOR_SELECTORS = `<VALUE_ACCESSOR_SELECTORS>`;
229
262
  const VALUE_ACCESSOR_EVENT = `<VALUE_ACCESSOR_EVENT>`;
@@ -249,8 +282,8 @@ async function copyResources$1(config, outputTarget) {
249
282
  if (!config.sys || !config.sys.copy || !config.sys.glob) {
250
283
  throw new Error('stencil is not properly initialized at this step. Notify the developer');
251
284
  }
252
- const srcDirectory = path.join(__dirname, '..', 'angular-component-lib');
253
- const destDirectory = path.join(path.dirname(outputTarget.directivesProxyFile), 'angular-component-lib');
285
+ const srcDirectory = path__default['default'].join(__dirname, '..', 'angular-component-lib');
286
+ const destDirectory = path__default['default'].join(path__default['default'].dirname(outputTarget.directivesProxyFile), 'angular-component-lib');
254
287
  return config.sys.copy([
255
288
  {
256
289
  src: srcDirectory,
@@ -261,12 +294,12 @@ async function copyResources$1(config, outputTarget) {
261
294
  ], srcDirectory);
262
295
  }
263
296
  function generateProxies(components, pkgData, outputTarget, rootDir) {
264
- const distTypesDir = path.dirname(pkgData.types);
265
- const dtsFilePath = path.join(rootDir, distTypesDir, GENERATED_DTS);
297
+ const distTypesDir = path__default['default'].dirname(pkgData.types);
298
+ const dtsFilePath = path__default['default'].join(rootDir, distTypesDir, GENERATED_DTS);
266
299
  const componentsTypeFile = relativeImport(outputTarget.directivesProxyFile, dtsFilePath, '.d.ts');
267
300
  const imports = `/* tslint:disable */
268
301
  /* auto-generated angular directive proxies */
269
- import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, NgZone } from '@angular/core';
302
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, NgZone } from '@angular/core';
270
303
  import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';\n`;
271
304
  const typeImports = !outputTarget.componentCorePackage
272
305
  ? `import { ${IMPORT_TYPES} } from '${normalizePath(componentsTypeFile)}';`
@@ -275,7 +308,7 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';\n`;
275
308
  imports,
276
309
  typeImports,
277
310
  components
278
- .map(createComponentDefinition(outputTarget.componentCorePackage, distTypesDir, rootDir))
311
+ .map(createComponentDefinition(outputTarget.componentCorePackage))
279
312
  .join('\n'),
280
313
  ];
281
314
  return final.join('\n') + '\n';
@@ -303,14 +336,14 @@ function normalizeOutputTarget(config, outputTarget) {
303
336
  if (outputTarget.directivesProxyFile == null) {
304
337
  throw new Error('directivesProxyFile is required');
305
338
  }
306
- if (outputTarget.directivesProxyFile && !path.isAbsolute(outputTarget.directivesProxyFile)) {
307
- results.directivesProxyFile = normalizePath(path.join(config.rootDir, outputTarget.directivesProxyFile));
339
+ if (outputTarget.directivesProxyFile && !path__default['default'].isAbsolute(outputTarget.directivesProxyFile)) {
340
+ results.directivesProxyFile = normalizePath(path__default['default'].join(config.rootDir, outputTarget.directivesProxyFile));
308
341
  }
309
- if (outputTarget.directivesArrayFile && !path.isAbsolute(outputTarget.directivesArrayFile)) {
310
- results.directivesArrayFile = normalizePath(path.join(config.rootDir, outputTarget.directivesArrayFile));
342
+ if (outputTarget.directivesArrayFile && !path__default['default'].isAbsolute(outputTarget.directivesArrayFile)) {
343
+ results.directivesArrayFile = normalizePath(path__default['default'].join(config.rootDir, outputTarget.directivesArrayFile));
311
344
  }
312
- if (outputTarget.directivesUtilsFile && !path.isAbsolute(outputTarget.directivesUtilsFile)) {
313
- results.directivesUtilsFile = normalizePath(path.join(config.rootDir, outputTarget.directivesUtilsFile));
345
+ if (outputTarget.directivesUtilsFile && !path__default['default'].isAbsolute(outputTarget.directivesUtilsFile)) {
346
+ results.directivesUtilsFile = normalizePath(path__default['default'].join(config.rootDir, outputTarget.directivesUtilsFile));
314
347
  }
315
348
  return results;
316
349
  }
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import path from 'path';
2
2
  import { promisify } from 'util';
3
3
  import fs from 'fs';
4
+ import { EOL } from 'os';
4
5
 
5
6
  const readFile = promisify(fs.readFile);
6
7
  const toLowerCase = (str) => str.toLowerCase();
@@ -97,30 +98,59 @@ const createComponentDefinition = (componentCorePackage, distTypesDir, rootDir)
97
98
  if (inputs.length > 0) {
98
99
  directiveOpts.push(`inputs: ['${inputs.join(`', '`)}']`);
99
100
  }
100
- if (outputs.length > 0) {
101
- directiveOpts.push(`outputs: ['${outputs.map((output) => output.name).join(`', '`)}']`);
102
- }
103
101
  const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
104
- const typePath = path.parse(path.join(componentCorePackage, path.join(cmpMeta.sourceFilePath, '').replace(path.join(rootDir, 'src'), distTypesDir)));
105
- const importPath = normalizePath(path.join(typePath.dir, typePath.name));
106
- const outputsInterface = outputs.length > 0
107
- ? `import { ${cmpMeta.componentClassName} as I${cmpMeta.componentClassName} } from '${importPath}';`
108
- : '';
102
+ const outputsInterface = new Set();
103
+ const outputReferenceRemap = {};
104
+ outputs.forEach((output) => {
105
+ Object.entries(output.complexType.references).forEach(([reference, refObject]) => {
106
+ // Add import line for each local/import reference, and add new mapping name.
107
+ // `outputReferenceRemap` should be updated only if the import interface is set in outputsInterface,
108
+ // this will prevent global types to be remapped.
109
+ const remappedReference = `I${cmpMeta.componentClassName}${reference}`;
110
+ if (refObject.location === 'local' || refObject.location === 'import') {
111
+ outputReferenceRemap[reference] = remappedReference;
112
+ outputsInterface.add(`import { ${reference} as ${remappedReference} } from '${componentCorePackage}';`);
113
+ }
114
+ });
115
+ });
116
+ const componentEvents = [
117
+ '' // Empty first line
118
+ ];
119
+ // Generate outputs
120
+ outputs.forEach((output, index) => {
121
+ componentEvents.push(` /**
122
+ * ${output.docs.text} ${output.docs.tags.map((tag) => `@${tag.name} ${tag.text}`)}
123
+ */`);
124
+ /**
125
+ * The original attribute contains the original type defined by the devs.
126
+ * This regexp normalizes the reference, by removing linebreaks,
127
+ * replacing consecutive spaces with a single space, and adding a single space after commas.
128
+ **/
129
+ const outputTypeRemapped = Object.entries(outputReferenceRemap).reduce((type, [src, dst]) => {
130
+ return type
131
+ .replace(new RegExp(`^${src}$`, 'g'), `${dst}`)
132
+ .replace(new RegExp(`([^\\w])${src}([^\\w])`, 'g'), (v, p1, p2) => [p1, dst, p2].join(''));
133
+ }, output.complexType.original
134
+ .replace(/\n/g, ' ')
135
+ .replace(/\s{2,}/g, ' ')
136
+ .replace(/,\s*/g, ', '));
137
+ componentEvents.push(` ${output.name}: EventEmitter<CustomEvent<${outputTypeRemapped.trim()}>>;`);
138
+ if (index === outputs.length - 1) {
139
+ // Empty line to push end `}` to new line
140
+ componentEvents.push('\n');
141
+ }
142
+ });
109
143
  const lines = [
110
- `
111
- ${outputsInterface}
112
- export declare interface ${tagNameAsPascal} extends Components.${tagNameAsPascal} {}
144
+ '',
145
+ `${[...outputsInterface].join('\n')}
146
+ export declare interface ${tagNameAsPascal} extends Components.${tagNameAsPascal} {${componentEvents.length > 1 ? componentEvents.join('\n') : ''}}
147
+
113
148
  ${getProxyCmp(inputs, methods)}
114
149
  @Component({
115
150
  ${directiveOpts.join(',\n ')}
116
151
  })
117
152
  export class ${tagNameAsPascal} {`,
118
153
  ];
119
- // Generate outputs
120
- outputs.forEach((output) => {
121
- lines.push(` /** ${output.docs.text} ${output.docs.tags.map((tag) => `@${tag.name} ${tag.text}`)}*/`);
122
- lines.push(` ${output.name}!: I${cmpMeta.componentClassName}['${output.method}'];`);
123
- });
124
154
  lines.push(' protected el: HTMLElement;');
125
155
  lines.push(` constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
126
156
  c.detach();
@@ -160,7 +190,7 @@ function generateAngularDirectivesFile(compilerCtx, components, outputTarget) {
160
190
  import * as d from '${proxyPath}';
161
191
 
162
192
  export const DIRECTIVES = [
163
- ${directives}
193
+ ${directives}
164
194
  ];
165
195
  `;
166
196
  return compilerCtx.fs.writeFile(outputTarget.directivesArrayFile, c);
@@ -203,7 +233,7 @@ function createValueAccessor(srcFileContents, valueAccessor) {
203
233
  const hostContents = valueAccessor.eventTargets.map((listItem) => VALUE_ACCESSOR_EVENTTARGETS.replace(VALUE_ACCESSOR_EVENT, listItem[0]).replace(VALUE_ACCESSOR_TARGETATTR, listItem[1]));
204
234
  return srcFileContents
205
235
  .replace(VALUE_ACCESSOR_SELECTORS, valueAccessor.elementSelectors.join(', '))
206
- .replace(VALUE_ACCESSOR_EVENTTARGETS, hostContents.join('\n'));
236
+ .replace(VALUE_ACCESSOR_EVENTTARGETS, hostContents.join(`,${EOL}`));
207
237
  }
208
238
  function copyResources(config, resourcesFilesToCopy, directory) {
209
239
  if (!config.sys || !config.sys.copy) {
@@ -260,7 +290,7 @@ function generateProxies(components, pkgData, outputTarget, rootDir) {
260
290
  const componentsTypeFile = relativeImport(outputTarget.directivesProxyFile, dtsFilePath, '.d.ts');
261
291
  const imports = `/* tslint:disable */
262
292
  /* auto-generated angular directive proxies */
263
- import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, NgZone } from '@angular/core';
293
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, NgZone } from '@angular/core';
264
294
  import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';\n`;
265
295
  const typeImports = !outputTarget.componentCorePackage
266
296
  ? `import { ${IMPORT_TYPES} } from '${normalizePath(componentsTypeFile)}';`
@@ -269,7 +299,7 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';\n`;
269
299
  imports,
270
300
  typeImports,
271
301
  components
272
- .map(createComponentDefinition(outputTarget.componentCorePackage, distTypesDir, rootDir))
302
+ .map(createComponentDefinition(outputTarget.componentCorePackage))
273
303
  .join('\n'),
274
304
  ];
275
305
  return final.join('\n') + '\n';
@@ -39,7 +39,7 @@ export function generateProxies(components, pkgData, outputTarget, rootDir) {
39
39
  const componentsTypeFile = relativeImport(outputTarget.directivesProxyFile, dtsFilePath, '.d.ts');
40
40
  const imports = `/* tslint:disable */
41
41
  /* auto-generated angular directive proxies */
42
- import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, NgZone } from '@angular/core';
42
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, NgZone } from '@angular/core';
43
43
  import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';\n`;
44
44
  const typeImports = !outputTarget.componentCorePackage
45
45
  ? `import { ${IMPORT_TYPES} } from '${normalizePath(componentsTypeFile)}';`
package/dist/utils.d.ts CHANGED
@@ -4,4 +4,5 @@ export declare const dashToPascalCase: (str: string) => string;
4
4
  export declare function sortBy<T>(array: T[], prop: (item: T) => string): T[];
5
5
  export declare function normalizePath(str: string): string;
6
6
  export declare function relativeImport(pathFrom: string, pathTo: string, ext?: string): string;
7
+ export declare function isRelativePath(path: string): boolean | "";
7
8
  export declare function readPackageJson(rootDir: string): Promise<PackageJSON>;
package/dist/utils.js CHANGED
@@ -55,6 +55,9 @@ export function relativeImport(pathFrom, pathTo, ext) {
55
55
  }
56
56
  return normalizePath(`${relativePath}/${path.basename(pathTo, ext)}`);
57
57
  }
58
+ export function isRelativePath(path) {
59
+ return path && path.startsWith('.');
60
+ }
58
61
  export async function readPackageJson(rootDir) {
59
62
  const pkgJsonPath = path.join(rootDir, 'package.json');
60
63
  let pkgJson;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stencil/angular-output-target",
3
- "version": "0.0.6",
3
+ "version": "0.2.1-0",
4
4
  "description": "Angular output target for @stencil/core components.",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.js",