-
Notifications
You must be signed in to change notification settings - Fork 24.7k
/
metadata_spec.ts
127 lines (110 loc) 路 4.47 KB
/
metadata_spec.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript';
import {absoluteFrom, getSourceFileOrError} from '../../file_system';
import {TestFile, runInEachFileSystem} from '../../file_system/testing';
import {NOOP_DEFAULT_IMPORT_RECORDER, NoopImportRewriter} from '../../imports';
import {TypeScriptReflectionHost} from '../../reflection';
import {getDeclaration, makeProgram} from '../../testing';
import {ImportManager, translateStatement} from '../../translator';
import {generateSetClassMetadataCall} from '../src/metadata';
runInEachFileSystem(() => {
describe('ngtsc setClassMetadata converter', () => {
it('should convert decorated class metadata', () => {
const res = compileAndPrint(`
import {Component} from '@angular/core';
@Component('metadata') class Target {}
`);
expect(res).toEqual(
`/*@__PURE__*/ (function () { i0.傻setClassMetadata(Target, [{ type: Component, args: ['metadata'] }], null, null); })();`);
});
it('should convert namespaced decorated class metadata', () => {
const res = compileAndPrint(`
import * as core from '@angular/core';
@core.Component('metadata') class Target {}
`);
expect(res).toEqual(
`/*@__PURE__*/ (function () { i0.傻setClassMetadata(Target, [{ type: core.Component, args: ['metadata'] }], null, null); })();`);
});
it('should convert decorated class constructor parameter metadata', () => {
const res = compileAndPrint(`
import {Component, Inject, Injector} from '@angular/core';
const FOO = 'foo';
@Component('metadata') class Target {
constructor(@Inject(FOO) foo: any, bar: Injector) {}
}
`);
expect(res).toContain(
`function () { return [{ type: undefined, decorators: [{ type: Inject, args: [FOO] }] }, { type: i0.Injector }]; }, null);`);
});
it('should convert decorated field metadata', () => {
const res = compileAndPrint(`
import {Component, Input} from '@angular/core';
@Component('metadata') class Target {
@Input() foo: string;
@Input('value') bar: string;
notDecorated: string;
}
`);
expect(res).toContain(`{ foo: [{ type: Input }], bar: [{ type: Input, args: ['value'] }] })`);
});
it('should convert decorated field getter/setter metadata', () => {
const res = compileAndPrint(`
import {Component, Input} from '@angular/core';
@Component('metadata') class Target {
@Input() get foo() { return this._foo; }
set foo(value: string) { this._foo = value; }
private _foo: string;
get bar() { return this._bar; }
@Input('value') set bar(value: string) { this._bar = value; }
private _bar: string;
}
`);
expect(res).toContain(`{ foo: [{ type: Input }], bar: [{ type: Input, args: ['value'] }] })`);
});
it('should not convert non-angular decorators to metadata', () => {
const res = compileAndPrint(`
declare function NotAComponent(...args: any[]): any;
@NotAComponent('metadata') class Target {}
`);
expect(res).toBe('');
});
});
function compileAndPrint(contents: string): string {
const _ = absoluteFrom;
const CORE: TestFile = {
name: _('/node_modules/@angular/core/index.d.ts'),
contents: `
export declare function Input(...args: any[]): any;
export declare function Inject(...args: any[]): any;
export declare function Component(...args: any[]): any;
export declare class Injector {}
`
};
const {program} = makeProgram(
[
CORE, {
name: _('/index.ts'),
contents,
}
],
{target: ts.ScriptTarget.ES2015});
const host = new TypeScriptReflectionHost(program.getTypeChecker());
const target = getDeclaration(program, _('/index.ts'), 'Target', ts.isClassDeclaration);
const call = generateSetClassMetadataCall(target, host, NOOP_DEFAULT_IMPORT_RECORDER, false);
if (call === null) {
return '';
}
const sf = getSourceFileOrError(program, _('/index.ts'));
const im = new ImportManager(new NoopImportRewriter(), 'i');
const tsStatement =
translateStatement(call, im, NOOP_DEFAULT_IMPORT_RECORDER, ts.ScriptTarget.ES2015);
const res = ts.createPrinter().printNode(ts.EmitHint.Unspecified, tsStatement, sf);
return res.replace(/\s+/g, ' ');
}
});