Skip to content

Commit ca60073

Browse files
committed
fix(compiler): full qualified exports
fixes #1352
1 parent b375e65 commit ca60073

File tree

13 files changed

+93
-87
lines changed

13 files changed

+93
-87
lines changed

src/compiler/transformers/decorators-to-static/component-decorator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import * as d from '../../../declarations';
22
import { convertValueToLiteral, createStaticGetter, getDeclarationParameters, removeDecorators } from '../transform-utils';
33
import ts from 'typescript';
44
import { DEFAULT_STYLE_MODE, augmentDiagnosticWithNode, buildError, validateComponentTag } from '@utils';
5+
import { CLASS_DECORATORS_TO_REMOVE } from '../remove-stencil-import';
56

67

78
export function componentDecoratorToStatic(config: d.Config, diagnostics: d.Diagnostic[], cmpNode: ts.ClassDeclaration, newMembers: ts.ClassElement[], componentDecorator: ts.Decorator) {
8-
removeDecorators(cmpNode, ['Component']);
9+
removeDecorators(cmpNode, CLASS_DECORATORS_TO_REMOVE);
910

1011
const [ componentOptions ] = getDeclarationParameters<d.ComponentOptions>(componentDecorator);
1112
if (!componentOptions) {

src/compiler/transformers/decorators-to-static/convert-decorators.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1+
import { methodDecoratorsToStatic } from './method-decorator';
12
import * as d from '../../../declarations';
2-
import { isDecoratorNamed, removeDecorators } from '../transform-utils';
33
import { componentDecoratorToStatic } from './component-decorator';
44
import { elementDecoratorsToStatic } from './element-decorator';
55
import { eventDecoratorsToStatic } from './event-decorator';
66
import { listenDecoratorsToStatic } from './listen-decorator';
7-
import { methodDecoratorsToStatic } from './method-decorator';
7+
import { isDecoratorNamed, removeDecorators } from '../transform-utils';
88
import { propDecoratorsToStatic } from './prop-decorator';
99
import { stateDecoratorsToStatic } from './state-decorator';
1010
import { watchDecoratorsToStatic } from './watch-decorator';
11-
import { removeStencilImport } from '../remove-stencil-import';
11+
import { MEMBER_DECORATORS_TO_REMOVE, removeStencilImport } from '../remove-stencil-import';
1212
import ts from 'typescript';
1313

1414

@@ -74,17 +74,6 @@ function visitClass(config: d.Config, diagnostics: d.Diagnostic[], typeChecker:
7474
}
7575

7676
function removeStencilDecorators(classMembers: ts.ClassElement[]) {
77-
classMembers.forEach(member => removeDecorators(member, STENCIL_MEMBER_DECORATORS));
77+
classMembers.forEach(member => removeDecorators(member, MEMBER_DECORATORS_TO_REMOVE));
7878
}
7979

80-
const STENCIL_MEMBER_DECORATORS = [
81-
'Element',
82-
'Event',
83-
'Listen',
84-
'Method',
85-
'Prop',
86-
'PropDidChange',
87-
'PropWillChange',
88-
'State',
89-
'Watch',
90-
];

src/compiler/transformers/decorators-to-static/event-decorator.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as d from '../../../declarations';
22
import { augmentDiagnosticWithNode, buildWarn } from '@utils';
3-
import { convertValueToLiteral, createStaticGetter, getAttributeTypeInfo, getDeclarationParameters, isDecoratorNamed, resolveType, serializeSymbol } from '../transform-utils';
3+
import { convertValueToLiteral, createStaticGetter, getAttributeTypeInfo, getDeclarationParameters, isDecoratorNamed, resolveType, serializeSymbol, validateReferences } from '../transform-utils';
44
import ts from 'typescript';
55

66

@@ -35,7 +35,7 @@ function parseEventDecorator(config: d.Config, diagnostics: d.Diagnostic[], type
3535

3636
validateEventEmitterMemberName(config, diagnostics, prop.name, memberName);
3737

38-
return {
38+
const eventMeta = {
3939
method: memberName,
4040
name,
4141
bubbles: opts && typeof opts.bubbles === 'boolean' ? opts.bubbles : true,
@@ -44,6 +44,8 @@ function parseEventDecorator(config: d.Config, diagnostics: d.Diagnostic[], type
4444
docs: serializeSymbol(typeChecker, symbol),
4545
complexType: getComplexType(typeChecker, prop)
4646
};
47+
validateReferences(config, diagnostics, eventMeta.complexType.references, prop.type);
48+
return eventMeta;
4749
}
4850

4951
export function getEventName(eventOptions: d.EventOptions, memberName: string) {

src/compiler/transformers/decorators-to-static/method-decorator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as d from '../../../declarations';
2-
import { convertValueToLiteral, createStaticGetter, getAttributeTypeInfo, isDecoratorNamed, isMemberPrivate, serializeSymbol, typeToString } from '../transform-utils';
2+
import { convertValueToLiteral, createStaticGetter, getAttributeTypeInfo, isDecoratorNamed, isMemberPrivate, serializeSymbol, typeToString, validateReferences } from '../transform-utils';
33
import { augmentDiagnosticWithNode, buildError, buildWarn } from '@utils';
44
import { validatePublicName } from '../reserved-public-members';
55
import ts from 'typescript';
@@ -78,6 +78,7 @@ function parseMethodDecorator(config: d.Config, diagnostics: d.Diagnostic[], sou
7878
tags: signature.getJsDocTags()
7979
}
8080
};
81+
validateReferences(config, diagnostics, methodMeta.complexType.references, method.type);
8182

8283
const staticProp = ts.createPropertyAssignment(
8384
ts.createLiteral(methodName),

src/compiler/transformers/decorators-to-static/prop-decorator.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as d from '../../../declarations';
22
import { augmentDiagnosticWithNode, buildError, catchError, toDashCase } from '@utils';
3-
import { convertValueToLiteral, createStaticGetter, getAttributeTypeInfo, isDecoratorNamed, isMemberPrivate, resolveType, serializeSymbol, typeToString } from '../transform-utils';
3+
import { convertValueToLiteral, createStaticGetter, getAttributeTypeInfo, isDecoratorNamed, isMemberPrivate, resolveType, serializeSymbol, typeToString, validateReferences } from '../transform-utils';
44
import ts from 'typescript';
55
import { validatePublicName } from '../reserved-public-members';
66

@@ -71,6 +71,7 @@ function parsePropDecorator(config: d.Config, diagnostics: d.Diagnostic[], typeC
7171
optional: prop.questionToken !== undefined,
7272
docs: serializeSymbol(typeChecker, symbol)
7373
};
74+
validateReferences(config, diagnostics, propMeta.complexType.references, prop.type);
7475

7576
// prop can have an attribute if type is NOT "unknown"
7677
if (typeStr !== 'unknown') {
@@ -142,12 +143,11 @@ function getPropOptions(propDecorator: ts.Decorator, diagnostics: d.Diagnostic[]
142143

143144

144145
function getComplexType(typeChecker: ts.TypeChecker, node: ts.PropertyDeclaration, type: ts.Type): d.ComponentCompilerPropertyComplexType {
145-
const sourceFile = node.getSourceFile();
146146
const nodeType = node.type;
147147
return {
148148
original: nodeType ? nodeType.getText() : typeToString(typeChecker, type),
149149
resolved: resolveType(typeChecker, type),
150-
references: getAttributeTypeInfo(node, sourceFile)
150+
references: getAttributeTypeInfo(node, node.getSourceFile())
151151
};
152152
}
153153

src/compiler/transformers/remove-stencil-import.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,17 @@ const KEEP_IMPORTS = new Set([
4242
'readTask',
4343
'getElement'
4444
]);
45+
46+
export const CLASS_DECORATORS_TO_REMOVE = new Set(['Component']);
47+
export const MEMBER_DECORATORS_TO_REMOVE = new Set([
48+
'Element',
49+
'Event',
50+
'Listen',
51+
'Method',
52+
'Prop',
53+
'PropDidChange',
54+
'PropWillChange',
55+
'State',
56+
'Watch'
57+
]);
58+

src/compiler/transformers/transform-utils.ts

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as d from '../../declarations';
2-
import { normalizePath } from '@utils';
2+
import { augmentDiagnosticWithNode, buildError, normalizePath } from '@utils';
33
import ts from 'typescript';
4+
import { MEMBER_DECORATORS_TO_REMOVE } from './remove-stencil-import';
45

56

67
export const LegacyScriptTarget = ts.ScriptTarget.ES5;
@@ -112,22 +113,21 @@ export function evalText(text: string) {
112113
}
113114

114115

115-
export function removeDecorators(node: ts.Node, decoratorNames: string[]) {
116+
export function removeDecorators(node: ts.Node, decoratorNames: Set<string>) {
116117
if (node.decorators) {
117118
const updatedDecoratorList = node.decorators.filter(dec => {
118119
const name = (
119120
ts.isCallExpression(dec.expression) &&
120121
ts.isIdentifier(dec.expression.expression) &&
121122
dec.expression.expression.text
122123
);
123-
return !decoratorNames.includes(name);
124+
return !decoratorNames.has(name);
124125
});
125126

126-
if (updatedDecoratorList.length !== node.decorators.length) {
127+
if (updatedDecoratorList.length === 0) {
128+
node.decorators = undefined;
129+
} else if (updatedDecoratorList.length !== node.decorators.length) {
127130
node.decorators = ts.createNodeArray(updatedDecoratorList);
128-
if (node.decorators.length === 0) {
129-
node.decorators = undefined;
130-
}
131131
}
132132
}
133133
}
@@ -281,22 +281,27 @@ export class ObjectMap {
281281
}
282282

283283
export function getAttributeTypeInfo(baseNode: ts.Node, sourceFile: ts.SourceFile) {
284-
return getAllTypeReferences(baseNode)
285-
.reduce((allReferences, rt) => {
286-
allReferences[rt] = getTypeReferenceLocation(rt, sourceFile);
287-
return allReferences;
288-
}, {} as d.ComponentCompilerTypeReferences);
284+
const allReferences: d.ComponentCompilerTypeReferences = {};
285+
getAllTypeReferences(baseNode).forEach(rt => {
286+
allReferences[rt] = getTypeReferenceLocation(rt, sourceFile);
287+
});
288+
return allReferences;
289+
}
290+
291+
function getEntityName(entity: ts.EntityName): string {
292+
if (ts.isIdentifier(entity)) {
293+
return entity.escapedText.toString();
294+
} else {
295+
return getEntityName(entity.left);
296+
}
289297
}
290298

291299
function getAllTypeReferences(node: ts.Node): string[] {
292300
const referencedTypes: string[] = [];
293301

294302
function visit(node: ts.Node): ts.VisitResult<ts.Node> {
295303
if (ts.isTypeReferenceNode(node)) {
296-
if (ts.isIdentifier(node.typeName)) {
297-
const typeName = node.typeName as ts.Identifier;
298-
referencedTypes.push(typeName.escapedText.toString());
299-
}
304+
referencedTypes.push(getEntityName(node.typeName));
300305
if (node.typeArguments) {
301306
node.typeArguments
302307
.filter(ta => ts.isTypeReferenceNode(ta))
@@ -314,6 +319,16 @@ function getAllTypeReferences(node: ts.Node): string[] {
314319
return referencedTypes;
315320
}
316321

322+
export function validateReferences(config: d.Config, diagnostics: d.Diagnostic[], references: d.ComponentCompilerTypeReferences, node: ts.Node) {
323+
Object.keys(references).forEach(refName => {
324+
const ref = references[refName];
325+
if (ref.path === '@stencil/core' && MEMBER_DECORATORS_TO_REMOVE.has(refName) ) {
326+
const err = buildError(diagnostics);
327+
augmentDiagnosticWithNode(config, err, node);
328+
}
329+
});
330+
}
331+
317332
function getTypeReferenceLocation(typeName: string, sourceFile: ts.SourceFile): d.ComponentCompilerTypeReference {
318333
const sourceFileObj = sourceFile.getSourceFile();
319334

@@ -330,10 +345,10 @@ function getTypeReferenceLocation(typeName: string, sourceFile: ts.SourceFile):
330345
return false;
331346
}
332347
return true;
333-
});
348+
}) as ts.ImportDeclaration;
334349

335350
if (importTypeDeclaration) {
336-
const localImportPath = (<ts.StringLiteral>(<ts.ImportDeclaration>importTypeDeclaration).moduleSpecifier).text;
351+
const localImportPath = (<ts.StringLiteral>importTypeDeclaration.moduleSpecifier).text;
337352
return {
338353
location: 'import',
339354
path: localImportPath

src/compiler/transformers/validate-types-transform.ts

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,7 @@
1-
import { removeStencilImport } from './remove-stencil-import';
2-
import { } from './transform-utils';
1+
import { removeStencilImport, MEMBER_DECORATORS_TO_REMOVE, CLASS_DECORATORS_TO_REMOVE } from './remove-stencil-import';
2+
import { removeDecorators } from './transform-utils';
33
import ts from 'typescript';
44

5-
const CLASS_DECORATORS_TO_REMOVE = new Set(['Component']);
6-
const DECORATORS_TO_REMOVE = new Set([
7-
'Element',
8-
'Event',
9-
'Listen',
10-
'Method',
11-
'Prop',
12-
'PropDidChange',
13-
'PropWillChange',
14-
'State',
15-
'Watch'
16-
]);
17-
18-
195
export function removeStencilDecorators(): ts.TransformerFactory<ts.SourceFile> {
206

217
return transformCtx => {
@@ -32,38 +18,18 @@ export function removeStencilDecorators(): ts.TransformerFactory<ts.SourceFile>
3218

3319

3420
function visitComponentClass(classNode: ts.ClassDeclaration): ts.ClassDeclaration {
35-
classNode.decorators = removeDecoratorsByName(classNode.decorators, CLASS_DECORATORS_TO_REMOVE);
21+
removeDecorators(classNode, CLASS_DECORATORS_TO_REMOVE);
3622

3723
classNode.members.forEach((member) => {
3824
if (Array.isArray(member.decorators)) {
39-
member.decorators = removeDecoratorsByName(member.decorators, DECORATORS_TO_REMOVE);
25+
removeDecorators(member, MEMBER_DECORATORS_TO_REMOVE);
4026
}
4127
});
4228

4329
return classNode;
4430
}
4531

4632

47-
function removeDecoratorsByName(decoratorList: ts.NodeArray<ts.Decorator>, names: Set<string>): ts.NodeArray<ts.Decorator> {
48-
const updatedDecoratorList = decoratorList.filter(dec => {
49-
const toRemove = ts.isCallExpression(dec.expression) &&
50-
ts.isIdentifier(dec.expression.expression) &&
51-
names.has(dec.expression.expression.text);
52-
return !toRemove;
53-
});
54-
55-
if (updatedDecoratorList.length === 0 && decoratorList.length > 0) {
56-
return undefined;
57-
}
58-
59-
if (updatedDecoratorList.length !== decoratorList.length) {
60-
return ts.createNodeArray(updatedDecoratorList);
61-
}
62-
63-
return decoratorList;
64-
}
65-
66-
6733
export function removeStencilImports(): ts.TransformerFactory<ts.SourceFile> {
6834

6935
return transformCtx => {

src/compiler/types/generate-app-types.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,7 @@ export { LocalJSX as JSX };
8787
${jsxAugmentation}
8888
`;
8989

90-
const typeImportString = Object.keys(typeImportData).reduce((finalString: string, filePath: string) => {
91-
90+
const typeImportString = Object.keys(typeImportData).map(filePath => {
9291
const typeData = typeImportData[filePath];
9392
let importFilePath: string;
9493
if (config.sys.path.isAbsolute(filePath)) {
@@ -98,19 +97,20 @@ ${jsxAugmentation}
9897
} else {
9998
importFilePath = filePath;
10099
}
101-
finalString +=
102-
`import {
100+
101+
return `import {
103102
${typeData.sort(sortImportNames).map(td => {
104103
if (td.localName === td.importName) {
105104
return `${td.importName},`;
106105
} else {
107106
return `${td.localName} as ${td.importName},`;
108107
}
109-
}).join('\n')}
110-
} from '${importFilePath}';\n`;
108+
})
109+
.join('\n')
110+
}
111+
} from '${importFilePath}';`;
111112

112-
return finalString;
113-
}, '');
113+
}).join('\n');
114114

115115
const code = `
116116
import { HTMLStencilElement, JSXBase } from '@stencil/core/internal';

test/karma/test-app/attribute-complex/cmp.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Component, Prop, Method } from '@stencil/core';
2+
import { SomeTypes } from '../util';
23

34
@Component({
45
tag: 'attribute-complex'
@@ -7,13 +8,15 @@ export class AttributeComplex {
78

89
@Prop() nu0 = 1;
910
@Prop() nu1?: number;
11+
@Prop() nu2?: SomeTypes.Number;
1012

1113
@Prop() bool0 = true;
1214
@Prop() bool1?: boolean;
1315
@Prop() bool2?: boolean;
1416

1517
@Prop() str0 = 'hello';
1618
@Prop() str1?: string;
19+
@Prop() str2?: SomeTypes.String;
1720

1821
@Method()
1922
async getInstance() {

0 commit comments

Comments
 (0)