@travetto/web 6.0.2 → 7.0.0-rc.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,212 +0,0 @@
1
- import ts from 'typescript';
2
-
3
- import {
4
- TransformerState, OnClass, OnMethod, DocUtil, DecoratorUtil, DecoratorMeta, LiteralUtil, AnyType,
5
- OnProperty
6
- } from '@travetto/transformer';
7
-
8
- import { SchemaTransformUtil } from '@travetto/schema/support/transformer/util.ts';
9
-
10
- const PARAM_DEC_IMPORT = '@travetto/web/src/decorator/param.ts';
11
- const COMMON_DEC_IMPORT = '@travetto/web/src/decorator/common.ts';
12
- const ENDPOINT_DEC_IMPORT = '@travetto/web/src/decorator/endpoint.ts';
13
-
14
- /**
15
- * Handle @Controller, @Endpoint
16
- */
17
- export class WebTransformer {
18
-
19
- /**
20
- * Handle endpoint parameter
21
- */
22
- static handleEndpointParameter(state: TransformerState, node: ts.ParameterDeclaration, epDec: DecoratorMeta, idx: number): ts.ParameterDeclaration {
23
- const pDec = state.findDecorator(this, node, 'Param');
24
- let pDecArg = DecoratorUtil.getPrimaryArgument(pDec)!;
25
- if (pDecArg && ts.isStringLiteral(pDecArg)) {
26
- pDecArg = state.fromLiteral({ name: pDecArg });
27
- }
28
-
29
- const paramType = state.resolveType(node);
30
- let name = node.name.getText();
31
- if (/[{}\[\]]/.test(name)) { // Destructured
32
- name = `param__${idx + 1}`;
33
- }
34
-
35
- let detectedParamType: string | undefined;
36
-
37
- const config: { type: AnyType, name?: string } = { type: paramType };
38
-
39
- // Detect default behavior
40
- // If primitive
41
- if (paramType.key !== 'managed' && paramType.key !== 'shape') {
42
- // Get path of endpoint
43
- const arg = DecoratorUtil.getPrimaryArgument(epDec.dec);
44
- // If non-regex
45
- if (arg && ts.isStringLiteral(arg)) {
46
- const literal = LiteralUtil.toLiteral(arg);
47
- // If param name matches path param, default to @PathParam
48
- detectedParamType = new RegExp(`:${name}\\b`).test(literal) ? 'PathParam' : 'QueryParam';
49
- } else {
50
- // Default to query for empty or regex endpoints
51
- detectedParamType = 'QueryParam';
52
- }
53
- } else {
54
- // Treat as schema, and see if endpoint supports a body for default behavior on untyped
55
- detectedParamType = epDec.targets?.includes('@travetto/web:HttpRequestBody') ? 'Body' : 'QueryParam';
56
- config.name = '';
57
- }
58
-
59
- if (paramType.key === 'managed' && paramType.importName.startsWith('@travetto/')) {
60
- if (paramType.name === 'WebResponse') {
61
- throw new Error(`${paramType.name} must be registered using @ContextParam`);
62
- } else if (paramType.name === 'WebRequest') {
63
- throw new Error(`${paramType.name} is an invalid endpoint parameter`);
64
- }
65
- }
66
-
67
- node = SchemaTransformUtil.computeField(state, node, config);
68
-
69
- const modifiers = (node.modifiers ?? []).filter(x => x !== pDec);
70
- const conf = state.extendObjectLiteral({ name, sourceText: node.name.getText() }, pDecArg);
71
-
72
- if (!pDec) { // Handle default, missing
73
- modifiers.push(state.createDecorator(PARAM_DEC_IMPORT, detectedParamType ?? 'QueryParam', conf));
74
- } else if (ts.isCallExpression(pDec.expression)) { // if it does exist, update
75
- modifiers.push(state.factory.createDecorator(
76
- state.factory.createCallExpression(
77
- pDec.expression.expression,
78
- [],
79
- [conf, ...pDec.expression.arguments.slice(1)]
80
- )
81
- ));
82
- }
83
-
84
- return state.factory.updateParameterDeclaration(
85
- node,
86
- modifiers,
87
- node.dotDotDotToken,
88
- node.name,
89
- node.questionToken,
90
- node.type,
91
- node.initializer
92
- );
93
- }
94
-
95
- /**
96
- * On @Endpoint method
97
- */
98
- @OnMethod('Endpoint')
99
- static handleEndpoint(state: TransformerState, node: ts.MethodDeclaration, dec?: DecoratorMeta): ts.MethodDeclaration {
100
-
101
- const modifiers = (node.modifiers ?? []).slice(0);
102
- const newDecls: ts.ModifierLike[] = [];
103
-
104
- const comments = DocUtil.describeDocs(node);
105
-
106
- // Handle description/title/summary w/e
107
- if (comments.description) {
108
- newDecls.push(state.createDecorator(COMMON_DEC_IMPORT, 'Describe', state.fromLiteral({
109
- title: comments.description
110
- })));
111
- }
112
-
113
- let nParams = node.parameters;
114
-
115
- // Handle parameters
116
- if (node.parameters.length) {
117
- const params: ts.ParameterDeclaration[] = [];
118
- // If there are parameters to process
119
- let i = 0;
120
- for (const p of node.parameters) {
121
- params.push(this.handleEndpointParameter(state, p, dec!, i));
122
- i += 1;
123
- }
124
-
125
- nParams = state.factory.createNodeArray(params);
126
- }
127
-
128
- // If we have a valid response type, declare it
129
- const nodeType = state.resolveReturnType(node);
130
- let targetType = nodeType;
131
-
132
- if (nodeType.key === 'literal' && nodeType.typeArguments?.length && nodeType.name === 'Promise') {
133
- targetType = nodeType.typeArguments[0];
134
- }
135
-
136
- let inner: AnyType | undefined;
137
- if (targetType.key === 'managed' && targetType.name === 'WebResponse' && targetType.importName.startsWith('@travetto/web')) {
138
- inner = state.getApparentTypeOfField(targetType.original!, 'body');
139
- }
140
-
141
- const returnType = SchemaTransformUtil.ensureType(state, inner ?? nodeType, node);
142
- if (returnType.type) {
143
- newDecls.push(state.createDecorator(ENDPOINT_DEC_IMPORT, 'ResponseType', state.fromLiteral({
144
- ...returnType,
145
- title: comments.return
146
- })));
147
- }
148
-
149
- if (newDecls.length || nParams !== node.parameters) {
150
- return state.factory.updateMethodDeclaration(
151
- node,
152
- [...modifiers, ...newDecls],
153
- node.asteriskToken,
154
- node.name,
155
- node.questionToken,
156
- node.typeParameters,
157
- nParams,
158
- node.type,
159
- node.body
160
- );
161
- } else {
162
- return node;
163
- }
164
- }
165
-
166
- /**
167
- * Handle @Controller
168
- */
169
- @OnClass('Controller')
170
- static handleController(state: TransformerState, node: ts.ClassDeclaration): ts.ClassDeclaration {
171
- // Read title/description/summary from jsdoc on class
172
- const comments = DocUtil.describeDocs(node);
173
-
174
- if (!comments.description) {
175
- return node;
176
- } else {
177
- return state.factory.updateClassDeclaration(
178
- node,
179
- [
180
- ...(node.modifiers ?? []),
181
- state.createDecorator(COMMON_DEC_IMPORT, 'Describe', state.fromLiteral({
182
- title: comments.description
183
- }))
184
- ],
185
- node.name,
186
- node.typeParameters,
187
- node.heritageClauses,
188
- node.members
189
- );
190
- }
191
- }
192
-
193
- /**
194
- * Handle ContextParam annotation
195
- */
196
- @OnProperty('ContextParam')
197
- static registerContextParam(state: TransformerState, node: ts.PropertyDeclaration): typeof node {
198
- const decl = state.findDecorator(this, node, 'ContextParam', PARAM_DEC_IMPORT);
199
-
200
- // Doing decls
201
- return state.factory.updatePropertyDeclaration(
202
- node,
203
- DecoratorUtil.spliceDecorators(node, decl, [
204
- state.createDecorator(PARAM_DEC_IMPORT, 'ContextParam', state.fromLiteral({ target: state.getConcreteType(node) }))
205
- ], 0),
206
- node.name,
207
- node.questionToken,
208
- node.type,
209
- node.initializer
210
- );
211
- }
212
- }