Skip to content

Commit 3377bc8

Browse files
committed
feat(angular): emit proxies utils in a different file
1 parent 4321cf0 commit 3377bc8

3 files changed

Lines changed: 90 additions & 127 deletions

File tree

src/compiler/config/validate-outputs-angular.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ export function validateOutputTargetAngular(config: d.Config) {
99

1010
distOutputTargets.forEach(outputTarget => {
1111
outputTarget.excludeComponents = outputTarget.excludeComponents || [];
12-
outputTarget.useDirectives = !!outputTarget.useDirectives;
1312

1413
if (!path.isAbsolute(outputTarget.directivesProxyFile)) {
1514
outputTarget.directivesProxyFile = normalizePath(path.join(config.rootDir, outputTarget.directivesProxyFile));
1615
}
1716

18-
if (!path.isAbsolute(outputTarget.directivesArrayFile)) {
17+
if (outputTarget.directivesArrayFile && !path.isAbsolute(outputTarget.directivesArrayFile)) {
1918
outputTarget.directivesArrayFile = normalizePath(path.join(config.rootDir, outputTarget.directivesArrayFile));
2019
}
20+
21+
if (outputTarget.directivesUtilsFile && !path.isAbsolute(outputTarget.directivesUtilsFile)) {
22+
outputTarget.directivesUtilsFile = normalizePath(path.join(config.rootDir, outputTarget.directivesUtilsFile));
23+
}
2124
});
2225
}

src/compiler/distribution/dist-angular.ts

Lines changed: 84 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as d from '../../declarations';
22
import { dashToPascalCase } from '../../util/helpers';
33
import { MEMBER_TYPE } from '../../util/constants';
44
import { isDocsPublic } from '../util';
5+
import { OutputTargetAngular } from '../../declarations';
56

67

78
export async function generateAngularProxies(config: d.Config, compilerCtx: d.CompilerCtx, cmpRegistry: d.ComponentRegistry) {
@@ -13,6 +14,17 @@ export async function generateAngularProxies(config: d.Config, compilerCtx: d.Co
1314
}));
1415
}
1516

17+
async function angularDirectiveProxyOutput(config: d.Config, compilerCtx: d.CompilerCtx, outputTarget: d.OutputTargetAngular, cmpRegistry: d.ComponentRegistry) {
18+
const components = getComponents(outputTarget.excludeComponents, cmpRegistry);
19+
20+
await Promise.all([
21+
generateProxies(config, compilerCtx, components, outputTarget),
22+
generateAngularArray(config, compilerCtx, components, outputTarget),
23+
generateAngularUtils(compilerCtx, outputTarget)
24+
]);
25+
26+
config.logger.debug(`generated angular directives: ${outputTarget.directivesProxyFile}`);
27+
}
1628

1729
function getComponents(excludeComponents: string[], cmpRegistry: d.ComponentRegistry): d.ComponentMeta[] {
1830
return Object.keys(cmpRegistry)
@@ -25,124 +37,34 @@ function getComponents(excludeComponents: string[], cmpRegistry: d.ComponentRegi
2537
});
2638
}
2739

28-
async function angularDirectiveProxyOutput(config: d.Config, compilerCtx: d.CompilerCtx, outputTarget: d.OutputTargetAngular, cmpRegistry: d.ComponentRegistry) {
29-
const components = getComponents(outputTarget.excludeComponents, cmpRegistry);
30-
const useDirectives = outputTarget.useDirectives;
31-
const { hasOutputs, proxies } = generateProxies(components, useDirectives);
32-
33-
const auxFunctions: string[] = [
34-
inputsAuxFunction(),
35-
outputsAuxFunction(),
36-
methodsAuxFunction()
37-
];
38-
const angularImports = [
39-
'ElementRef'
40-
];
41-
42-
if (components.length > 0) {
43-
if (useDirectives) {
44-
angularImports.push('Directive');
45-
} else {
46-
angularImports.push('Component');
47-
angularImports.push('ChangeDetectorRef');
48-
}
49-
}
50-
51-
if (hasOutputs) {
52-
angularImports.push('EventEmitter');
53-
}
40+
async function generateProxies(config: d.Config, compilerCtx: d.CompilerCtx, components: d.ComponentMeta[], outputTarget: OutputTargetAngular) {
41+
const proxies = getProxies(components);
5442

55-
const imports = `
56-
${hasOutputs ? `import { fromEvent } from 'rxjs';` : '' }
57-
import { ${angularImports.sort().join(', ')} } from '@angular/core';
58-
`;
43+
const imports = `/* tslint:disable */
44+
/* auto-generated angular directive proxies */
45+
import { Component, ElementRef, ChangeDetectorRef, EventEmitter } from '@angular/core';`;
5946

6047
const sourceImports = !outputTarget.componentCorePackage ? ''
6148
: `type StencilComponents<T extends keyof StencilElementInterfaces> = StencilElementInterfaces[T];`;
6249

6350
const final: string[] = [
64-
'/* tslint:disable */',
65-
'/* auto-generated angular directive proxies */',
6651
imports,
52+
getProxyUtils(config, outputTarget),
6753
sourceImports,
68-
auxFunctions.join('\n'),
6954
proxies,
7055
];
7156

7257
const finalText = final.join('\n') + '\n';
7358
await compilerCtx.fs.writeFile(outputTarget.directivesProxyFile, finalText);
74-
if (outputTarget.directivesArrayFile) {
75-
const proxyPath = relativeImport(config, outputTarget.directivesArrayFile, outputTarget.directivesProxyFile);
76-
const a = angularArray(components, proxyPath);
77-
await compilerCtx.fs.writeFile(outputTarget.directivesArrayFile, a);
78-
}
79-
config.logger.debug(`generated angular directives: ${outputTarget.directivesProxyFile}`);
80-
}
81-
82-
function inputsAuxFunction() {
83-
return `
84-
export function proxyInputs(Cmp: any, inputs: string[]) {
85-
const Prototype = Cmp.prototype;
86-
inputs.forEach(item => {
87-
Object.defineProperty(Prototype, item, {
88-
get() { return this.el[item]; },
89-
set(val: any) { this.el[item] = val; },
90-
});
91-
});
92-
}`;
93-
}
94-
95-
96-
function outputsAuxFunction() {
97-
return `
98-
export function proxyOutputs(instance: any, el: any, events: string[]) {
99-
events.forEach(eventName => instance[eventName] = fromEvent(el, eventName));
100-
}`;
101-
}
102-
103-
104-
function methodsAuxFunction() {
105-
return `
106-
export function proxyMethods(Cmp: any, methods: string[]) {
107-
const Prototype = Cmp.prototype;
108-
methods.forEach(methodName => {
109-
Prototype[methodName] = function() {
110-
const args = arguments;
111-
return this.el.componentOnReady().then((el: any) => el[methodName].apply(el, args));
112-
};
113-
});
114-
}
115-
`;
11659
}
11760

118-
function generateProxies(components: d.ComponentMeta[], useDirectives: boolean) {
119-
let hasMethods = false;
120-
let hasOutputs = false;
121-
let hasInputs = false;
122-
123-
const lines = components.map(cmpMeta => {
124-
const proxy = generateProxy(cmpMeta, useDirectives);
125-
if (proxy.hasInputs) {
126-
hasInputs = true;
127-
}
128-
if (proxy.hasMethods) {
129-
hasMethods = true;
130-
}
131-
if (proxy.hasOutputs) {
132-
hasOutputs = true;
133-
}
134-
return proxy.text;
135-
});
136-
137-
return {
138-
proxies: lines.join('\n'),
139-
hasInputs,
140-
hasMethods,
141-
hasOutputs
142-
};
61+
function getProxies(components: d.ComponentMeta[]) {
62+
return components
63+
.map(getProxy)
64+
.join('\n');
14365
}
14466

145-
function generateProxy(cmpMeta: d.ComponentMeta, useDirectives: boolean) {
67+
function getProxy(cmpMeta: d.ComponentMeta) {
14668
// Collect component meta
14769
const inputs = getInputs(cmpMeta);
14870
const outputs = getOutputs(cmpMeta);
@@ -154,32 +76,27 @@ function generateProxy(cmpMeta: d.ComponentMeta, useDirectives: boolean) {
15476
const hasMethods = methods.length > 0;
15577

15678
// Generate Angular @Directive
157-
const decorator = useDirectives ? 'Directive' : 'Component';
15879
const directiveOpts = [
15980
`selector: \'${cmpMeta.tagNameMeta}\'`,
81+
`changeDetection: 0`,
82+
`template: '<ng-content></ng-content>'`
16083
];
161-
if (!useDirectives) {
162-
directiveOpts.push(
163-
`changeDetection: 0`,
164-
`template: '<ng-content></ng-content>'`
165-
);
166-
}
16784
if (inputs.length > 0) {
16885
directiveOpts.push(`inputs: ['${inputs.join(`', '`)}']`);
16986
}
17087

17188
const tagNameAsPascal = dashToPascalCase(cmpMeta.tagNameMeta);
17289
const lines = [`
17390
export declare interface ${tagNameAsPascal} extends StencilComponents<'${tagNameAsPascal}'> {}
174-
@${decorator}({ ${directiveOpts.join(', ')} })
91+
@Component({ ${directiveOpts.join(', ')} })
17592
export class ${tagNameAsPascal} {`];
17693

17794
// Generate outputs
17895
outputs.forEach(output => {
17996
lines.push(` ${output}!: EventEmitter<CustomEvent>;`);
18097
});
18198

182-
lines.push(' el: HTMLElement');
99+
lines.push(' el: HTMLElement;');
183100
lines.push(` constructor(c: ChangeDetectorRef, r: ElementRef) {
184101
c.detach();
185102
this.el = r.nativeElement;`);
@@ -196,12 +113,7 @@ export class ${tagNameAsPascal} {`];
196113
lines.push(`proxyInputs(${tagNameAsPascal}, ['${inputs.join(`', '`)}']);`);
197114
}
198115

199-
return {
200-
text: lines.join('\n'),
201-
hasInputs,
202-
hasMethods,
203-
hasOutputs
204-
};
116+
return lines.join('\n');
205117
}
206118

207119
function getInputs(cmpMeta: d.ComponentMeta) {
@@ -224,24 +136,72 @@ function getMethods(cmpMeta: d.ComponentMeta) {
224136
});
225137
}
226138

227-
228-
function relativeImport(config: d.Config, pathFrom: string, pathTo: string) {
229-
let relativePath = config.sys.path.relative(config.sys.path.dirname(pathFrom), config.sys.path.dirname(pathTo));
230-
relativePath = relativePath === '' ? '.' : relativePath;
231-
return `${relativePath}/${config.sys.path.basename(pathTo, '.ts')}`;
139+
function getProxyUtils(config: d.Config, outputTarget: OutputTargetAngular) {
140+
if (!outputTarget.directivesUtilsFile) {
141+
return PROXY_UTILS.replace(/export function/g, 'function');
142+
} else {
143+
const utilsPath = relativeImport(config, outputTarget.directivesProxyFile, outputTarget.directivesUtilsFile);
144+
return `import { proxyInputs, proxyMethods, proxyOutputs } from '${utilsPath}';\n`;
145+
}
232146
}
233147

234-
function angularArray(components: d.ComponentMeta[], proxyPath: string) {
148+
async function generateAngularArray(config: d.Config, compilerCtx: d.CompilerCtx, components: d.ComponentMeta[], outputTarget: OutputTargetAngular) {
149+
if (!outputTarget.directivesArrayFile) {
150+
return;
151+
}
152+
153+
const proxyPath = relativeImport(config, outputTarget.directivesArrayFile, outputTarget.directivesProxyFile);
235154
const directives = components
236155
.map(cmpMeta => dashToPascalCase(cmpMeta.tagNameMeta))
237156
.map(className => `d.${className}`)
238157
.join(',\n ');
239158

240-
return `
159+
const c = `
241160
import * as d from '${proxyPath}';
242161
243162
export const DIRECTIVES = [
244-
${directives}
163+
${directives}
245164
];
246165
`;
166+
await compilerCtx.fs.writeFile(outputTarget.directivesArrayFile, c);
167+
}
168+
169+
async function generateAngularUtils(compilerCtx: d.CompilerCtx, outputTarget: OutputTargetAngular) {
170+
if (outputTarget.directivesUtilsFile) {
171+
await compilerCtx.fs.writeFile(outputTarget.directivesUtilsFile, '/* tslint:disable */\n' + PROXY_UTILS);
172+
}
173+
}
174+
175+
function relativeImport(config: d.Config, pathFrom: string, pathTo: string) {
176+
let relativePath = config.sys.path.relative(config.sys.path.dirname(pathFrom), config.sys.path.dirname(pathTo));
177+
relativePath = relativePath === '' ? '.' : relativePath;
178+
return `${relativePath}/${config.sys.path.basename(pathTo, '.ts')}`;
247179
}
180+
181+
const PROXY_UTILS = `import { fromEvent } from 'rxjs';
182+
183+
export function proxyInputs(Cmp: any, inputs: string[]) {
184+
const Prototype = Cmp.prototype;
185+
inputs.forEach(item => {
186+
Object.defineProperty(Prototype, item, {
187+
get() { return this.el[item]; },
188+
set(val: any) { this.el[item] = val; },
189+
});
190+
});
191+
}
192+
193+
export function proxyMethods(Cmp: any, methods: string[]) {
194+
const Prototype = Cmp.prototype;
195+
methods.forEach(methodName => {
196+
Prototype[methodName] = function() {
197+
const args = arguments;
198+
return this.el.componentOnReady().then((el: any) => el[methodName].apply(el, args));
199+
};
200+
});
201+
}
202+
203+
export function proxyOutputs(instance: any, el: any, events: string[]) {
204+
events.forEach(eventName => instance[eventName] = fromEvent(el, eventName));
205+
}
206+
`;
207+

src/declarations/output-targets.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,8 @@ export interface OutputTargetAngular extends OutputTargetBase {
207207
componentCorePackage?: string;
208208
directivesProxyFile?: string;
209209
directivesArrayFile?: string;
210+
directivesUtilsFile?: string;
210211
excludeComponents?: string[];
211-
useDirectives?: boolean;
212212
}
213213

214214

0 commit comments

Comments
 (0)