@typespec/emitter-framework 0.8.0-dev.2 → 0.8.0-dev.3
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.
- package/CHANGELOG.md +11 -0
- package/dist/src/typescript/components/enum-declaration.d.ts +1 -0
- package/dist/src/typescript/components/enum-declaration.d.ts.map +1 -1
- package/dist/src/typescript/components/enum-declaration.js +7 -0
- package/dist/src/typescript/components/function-declaration.d.ts.map +1 -1
- package/dist/src/typescript/components/function-declaration.js +8 -3
- package/dist/src/typescript/components/interface-declaration.d.ts.map +1 -1
- package/dist/src/typescript/components/interface-declaration.js +3 -0
- package/dist/src/typescript/components/interface-member.d.ts +3 -1
- package/dist/src/typescript/components/interface-member.d.ts.map +1 -1
- package/dist/src/typescript/components/interface-member.js +2 -0
- package/dist/src/typescript/components/interface-method.d.ts +3 -1
- package/dist/src/typescript/components/interface-method.d.ts.map +1 -1
- package/dist/src/typescript/components/interface-method.js +9 -2
- package/dist/src/typescript/components/type-alias-declaration.d.ts.map +1 -1
- package/dist/src/typescript/components/type-alias-declaration.js +4 -1
- package/dist/src/typescript/components/type-declaration.d.ts.map +1 -1
- package/dist/src/typescript/components/type-declaration.js +10 -0
- package/dist/src/typescript/components/union-declaration.d.ts +3 -1
- package/dist/src/typescript/components/union-declaration.d.ts.map +1 -1
- package/dist/src/typescript/components/union-declaration.js +4 -1
- package/dist/src/typescript/components/union-expression.d.ts.map +1 -1
- package/dist/src/typescript/components/union-expression.js +103 -10
- package/dist/src/typescript/utils/operation.d.ts.map +1 -1
- package/dist/src/typescript/utils/operation.js +5 -0
- package/dist/test/typescript/components/enum-declaration.test.js +79 -0
- package/dist/test/typescript/components/function-declaration.test.js +81 -0
- package/dist/test/typescript/components/interface-declaration.test.js +232 -9
- package/dist/test/typescript/components/type-alias-declaration.test.js +75 -0
- package/dist/test/typescript/components/union-declaration.test.js +358 -106
- package/package.json +1 -1
- package/src/typescript/components/enum-declaration.tsx +12 -1
- package/src/typescript/components/function-declaration.tsx +6 -1
- package/src/typescript/components/interface-declaration.tsx +3 -1
- package/src/typescript/components/interface-member.tsx +4 -0
- package/src/typescript/components/interface-method.tsx +7 -1
- package/src/typescript/components/type-alias-declaration.tsx +2 -1
- package/src/typescript/components/type-declaration.tsx +8 -6
- package/src/typescript/components/union-declaration.tsx +4 -1
- package/src/typescript/components/union-expression.tsx +100 -7
- package/src/typescript/utils/operation.ts +3 -0
- package/test/typescript/components/enum-declaration.test.tsx +72 -0
- package/test/typescript/components/function-declaration.test.tsx +78 -0
- package/test/typescript/components/interface-declaration.test.tsx +223 -9
- package/test/typescript/components/type-alias-declaration.test.tsx +72 -0
- package/test/typescript/components/union-declaration.test.tsx +330 -102
|
@@ -1,182 +1,410 @@
|
|
|
1
1
|
import { render } from "@alloy-js/core";
|
|
2
|
+
import { d } from "@alloy-js/core/testing";
|
|
2
3
|
import { SourceFile } from "@alloy-js/typescript";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { Enum, Model, Union } from "@typespec/compiler";
|
|
5
|
+
import { BasicTestRunner } from "@typespec/compiler/testing";
|
|
6
|
+
import { beforeEach, describe, it } from "vitest";
|
|
6
7
|
import { Output } from "../../../src/core/components/output.jsx";
|
|
7
8
|
import { UnionDeclaration } from "../../../src/typescript/components/union-declaration.js";
|
|
8
9
|
import { UnionExpression } from "../../../src/typescript/components/union-expression.js";
|
|
9
|
-
import {
|
|
10
|
+
import { InterfaceDeclaration } from "../../../src/typescript/index.js";
|
|
11
|
+
import { assertFileContents } from "../../utils.js";
|
|
12
|
+
import { createEmitterFrameworkTestRunner } from "../test-host.js";
|
|
10
13
|
|
|
11
14
|
describe("Typescript Union Declaration", () => {
|
|
15
|
+
let runner: BasicTestRunner;
|
|
16
|
+
|
|
17
|
+
beforeEach(async () => {
|
|
18
|
+
runner = await createEmitterFrameworkTestRunner();
|
|
19
|
+
});
|
|
20
|
+
|
|
12
21
|
describe("Union not bound to Typespec Types", () => {
|
|
13
22
|
it("creates a union declaration", async () => {
|
|
14
|
-
|
|
23
|
+
await runner.compile(``);
|
|
15
24
|
const res = render(
|
|
16
|
-
<Output program={program}>
|
|
25
|
+
<Output program={runner.program}>
|
|
17
26
|
<SourceFile path="test.ts">
|
|
18
27
|
<UnionDeclaration name="MyUnion">"red" | "blue"</UnionDeclaration>
|
|
19
28
|
</SourceFile>
|
|
20
29
|
</Output>,
|
|
21
30
|
);
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
expect(actualContent).toBe(expectedContent);
|
|
32
|
+
assertFileContents(
|
|
33
|
+
res,
|
|
34
|
+
d`
|
|
35
|
+
type MyUnion = "red" | "blue";
|
|
36
|
+
`,
|
|
37
|
+
);
|
|
30
38
|
});
|
|
31
39
|
});
|
|
32
40
|
|
|
33
41
|
describe("Union bound to Typespec Types", () => {
|
|
34
42
|
describe("Bound to Union", () => {
|
|
35
43
|
it("creates a union declaration", async () => {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
`);
|
|
44
|
+
const { TestUnion } = (await runner.compile(`
|
|
45
|
+
namespace DemoService;
|
|
46
|
+
@test union TestUnion {
|
|
47
|
+
one: "one",
|
|
48
|
+
two: "two"
|
|
49
|
+
}
|
|
50
|
+
`)) as { TestUnion: Union };
|
|
43
51
|
|
|
44
|
-
const
|
|
45
|
-
|
|
52
|
+
const res = render(
|
|
53
|
+
<Output program={runner.program}>
|
|
54
|
+
<SourceFile path="test.ts">
|
|
55
|
+
<UnionDeclaration type={TestUnion} />
|
|
56
|
+
</SourceFile>
|
|
57
|
+
</Output>,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
assertFileContents(
|
|
61
|
+
res,
|
|
62
|
+
d`
|
|
63
|
+
type TestUnion = "one" | "two";
|
|
64
|
+
`,
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("creates a union declaration with JSDoc", async () => {
|
|
69
|
+
const { TestUnion } = (await runner.compile(`
|
|
70
|
+
namespace DemoService;
|
|
71
|
+
/**
|
|
72
|
+
* Test Union
|
|
73
|
+
*/
|
|
74
|
+
@test union TestUnion {
|
|
75
|
+
one: "one",
|
|
76
|
+
two: "two"
|
|
77
|
+
}
|
|
78
|
+
`)) as { TestUnion: Union };
|
|
46
79
|
|
|
47
80
|
const res = render(
|
|
48
|
-
<Output program={program}>
|
|
81
|
+
<Output program={runner.program}>
|
|
49
82
|
<SourceFile path="test.ts">
|
|
50
|
-
<UnionDeclaration type={
|
|
83
|
+
<UnionDeclaration type={TestUnion} />
|
|
51
84
|
</SourceFile>
|
|
52
85
|
</Output>,
|
|
53
86
|
);
|
|
54
87
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
88
|
+
assertFileContents(
|
|
89
|
+
res,
|
|
90
|
+
d`
|
|
91
|
+
/**
|
|
92
|
+
* Test Union
|
|
93
|
+
*/
|
|
94
|
+
type TestUnion = "one" | "two";
|
|
95
|
+
`,
|
|
96
|
+
);
|
|
62
97
|
});
|
|
63
98
|
|
|
64
99
|
it("creates a union declaration with name override", async () => {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
`);
|
|
72
|
-
|
|
73
|
-
const [namespace] = program.resolveTypeReference("DemoService");
|
|
74
|
-
const union = Array.from((namespace as Namespace).unions.values())[0];
|
|
100
|
+
const { TestUnion } = (await runner.compile(`
|
|
101
|
+
namespace DemoService;
|
|
102
|
+
@test union TestUnion {
|
|
103
|
+
one: "one",
|
|
104
|
+
two: "two"
|
|
105
|
+
}
|
|
106
|
+
`)) as { TestUnion: Union };
|
|
75
107
|
|
|
76
108
|
const res = render(
|
|
77
|
-
<Output program={program}>
|
|
109
|
+
<Output program={runner.program}>
|
|
78
110
|
<SourceFile path="test.ts">
|
|
79
|
-
<UnionDeclaration export type={
|
|
111
|
+
<UnionDeclaration export type={TestUnion} name="MyUnion" />
|
|
80
112
|
</SourceFile>
|
|
81
113
|
</Output>,
|
|
82
114
|
);
|
|
83
115
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
expect(actualContent).toBe(expectedContent);
|
|
116
|
+
assertFileContents(
|
|
117
|
+
res,
|
|
118
|
+
d`
|
|
119
|
+
export type MyUnion = "one" | "two";
|
|
120
|
+
`,
|
|
121
|
+
);
|
|
91
122
|
});
|
|
92
123
|
|
|
93
124
|
it("creates a union declaration with extra children", async () => {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
`);
|
|
101
|
-
|
|
102
|
-
const [namespace] = program.resolveTypeReference("DemoService");
|
|
103
|
-
const union = Array.from((namespace as Namespace).unions.values())[0];
|
|
125
|
+
const { TestUnion } = (await runner.compile(`
|
|
126
|
+
namespace DemoService;
|
|
127
|
+
@test union TestUnion {
|
|
128
|
+
one: "one",
|
|
129
|
+
two: "two"
|
|
130
|
+
}
|
|
131
|
+
`)) as { TestUnion: Union };
|
|
104
132
|
|
|
105
133
|
const res = render(
|
|
106
|
-
<Output program={program}>
|
|
134
|
+
<Output program={runner.program}>
|
|
107
135
|
<SourceFile path="test.ts">
|
|
108
|
-
<UnionDeclaration type={
|
|
136
|
+
<UnionDeclaration type={TestUnion}>"three"</UnionDeclaration>
|
|
109
137
|
</SourceFile>
|
|
110
138
|
</Output>,
|
|
111
139
|
);
|
|
112
140
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
expect(actualContent).toBe(expectedContent);
|
|
141
|
+
assertFileContents(
|
|
142
|
+
res,
|
|
143
|
+
d`
|
|
144
|
+
type TestUnion = "one" | "two" | "three";
|
|
145
|
+
`,
|
|
146
|
+
);
|
|
120
147
|
});
|
|
121
148
|
|
|
122
|
-
it("renders
|
|
123
|
-
const
|
|
149
|
+
it("renders a union expression", async () => {
|
|
150
|
+
const { TestUnion } = (await runner.compile(`
|
|
124
151
|
namespace DemoService;
|
|
125
|
-
union TestUnion {
|
|
152
|
+
@test union TestUnion {
|
|
126
153
|
one: "one",
|
|
127
154
|
two: "two"
|
|
128
155
|
}
|
|
129
|
-
|
|
156
|
+
`)) as { TestUnion: Union };
|
|
157
|
+
|
|
158
|
+
const res = render(
|
|
159
|
+
<Output program={runner.program}>
|
|
160
|
+
<SourceFile path="test.ts">
|
|
161
|
+
let x: <UnionExpression type={TestUnion} /> = "one";
|
|
162
|
+
</SourceFile>
|
|
163
|
+
</Output>,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
assertFileContents(
|
|
167
|
+
res,
|
|
168
|
+
d`
|
|
169
|
+
let x: "one" | "two" = "one";
|
|
170
|
+
`,
|
|
171
|
+
);
|
|
172
|
+
});
|
|
130
173
|
|
|
131
|
-
|
|
132
|
-
|
|
174
|
+
describe("Discriminated Union", () => {
|
|
175
|
+
it("renders a discriminated union", async () => {
|
|
176
|
+
const { TestUnion } = (await runner.compile(`
|
|
177
|
+
namespace DemoService;
|
|
178
|
+
@discriminated
|
|
179
|
+
@test union TestUnion {
|
|
180
|
+
one: { oneItem: true },
|
|
181
|
+
two: true
|
|
182
|
+
}
|
|
183
|
+
`)) as { TestUnion: Union };
|
|
184
|
+
|
|
185
|
+
const res = render(
|
|
186
|
+
<Output program={runner.program}>
|
|
187
|
+
<SourceFile path="test.ts">
|
|
188
|
+
<UnionDeclaration type={TestUnion} />
|
|
189
|
+
</SourceFile>
|
|
190
|
+
</Output>,
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
assertFileContents(
|
|
194
|
+
res,
|
|
195
|
+
d`
|
|
196
|
+
type TestUnion = {
|
|
197
|
+
kind: "one";
|
|
198
|
+
value: {
|
|
199
|
+
oneItem: true;
|
|
200
|
+
};
|
|
201
|
+
} | {
|
|
202
|
+
kind: "two";
|
|
203
|
+
value: true;
|
|
204
|
+
};
|
|
205
|
+
`,
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("renders a discriminated union with custom properties", async () => {
|
|
211
|
+
const { TestUnion } = (await runner.compile(`
|
|
212
|
+
namespace DemoService;
|
|
213
|
+
@discriminated(#{ discriminatorPropertyName: "dataKind", envelopePropertyName: "data" })
|
|
214
|
+
@test union TestUnion {
|
|
215
|
+
one: { oneItem: true },
|
|
216
|
+
two: true
|
|
217
|
+
}
|
|
218
|
+
`)) as { TestUnion: Union };
|
|
133
219
|
|
|
134
220
|
const res = render(
|
|
135
|
-
<Output program={program}>
|
|
221
|
+
<Output program={runner.program}>
|
|
136
222
|
<SourceFile path="test.ts">
|
|
137
|
-
|
|
223
|
+
<UnionDeclaration type={TestUnion} />
|
|
138
224
|
</SourceFile>
|
|
139
225
|
</Output>,
|
|
140
226
|
);
|
|
227
|
+
assertFileContents(
|
|
228
|
+
res,
|
|
229
|
+
d`
|
|
230
|
+
type TestUnion = {
|
|
231
|
+
dataKind: "one";
|
|
232
|
+
data: {
|
|
233
|
+
oneItem: true;
|
|
234
|
+
};
|
|
235
|
+
} | {
|
|
236
|
+
dataKind: "two";
|
|
237
|
+
data: true;
|
|
238
|
+
};
|
|
239
|
+
`,
|
|
240
|
+
);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it("renders a discriminated union with named models", async () => {
|
|
244
|
+
const { Pet, Cat, Dog } = (await runner.compile(`
|
|
245
|
+
namespace DemoService;
|
|
246
|
+
@test model Cat {
|
|
247
|
+
name: string;
|
|
248
|
+
meow: boolean;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
@test model Dog {
|
|
252
|
+
name: string;
|
|
253
|
+
bark: boolean;
|
|
254
|
+
}
|
|
141
255
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
256
|
+
@discriminated
|
|
257
|
+
@test union Pet {
|
|
258
|
+
cat: Cat,
|
|
259
|
+
dog: Dog,
|
|
260
|
+
}
|
|
261
|
+
`)) as { Pet: Union; Cat: Model; Dog: Model };
|
|
262
|
+
|
|
263
|
+
const res = render(
|
|
264
|
+
<Output program={runner.program}>
|
|
265
|
+
<SourceFile path="test.ts">
|
|
266
|
+
<InterfaceDeclaration type={Cat} />
|
|
267
|
+
<hbr />
|
|
268
|
+
<InterfaceDeclaration type={Dog} />
|
|
269
|
+
<hbr />
|
|
270
|
+
<UnionDeclaration type={Pet} />
|
|
271
|
+
</SourceFile>
|
|
272
|
+
</Output>,
|
|
273
|
+
);
|
|
274
|
+
assertFileContents(
|
|
275
|
+
res,
|
|
276
|
+
d`
|
|
277
|
+
interface Cat {
|
|
278
|
+
name: string;
|
|
279
|
+
meow: boolean;
|
|
280
|
+
}
|
|
281
|
+
interface Dog {
|
|
282
|
+
name: string;
|
|
283
|
+
bark: boolean;
|
|
284
|
+
}
|
|
285
|
+
type Pet = {
|
|
286
|
+
kind: "cat";
|
|
287
|
+
value: Cat;
|
|
288
|
+
} | {
|
|
289
|
+
kind: "dog";
|
|
290
|
+
value: Dog;
|
|
291
|
+
};
|
|
292
|
+
`,
|
|
293
|
+
);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
describe("Discriminated Union with no envelope", () => {
|
|
297
|
+
it("renders named discriminated union", async () => {
|
|
298
|
+
const { Pet, Cat, Dog } = (await runner.compile(`
|
|
299
|
+
namespace DemoService;
|
|
300
|
+
|
|
301
|
+
@test model Cat {
|
|
302
|
+
name: string;
|
|
303
|
+
meow: boolean;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
@test model Dog {
|
|
307
|
+
name: string;
|
|
308
|
+
bark: boolean;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
@discriminated(#{ envelope: "none", discriminatorPropertyName: "dataKind" })
|
|
312
|
+
@test union Pet {
|
|
313
|
+
cat: Cat,
|
|
314
|
+
dog: Dog,
|
|
315
|
+
}
|
|
316
|
+
`)) as { Pet: Union; Cat: Model; Dog: Model };
|
|
317
|
+
|
|
318
|
+
const res = render(
|
|
319
|
+
<Output program={runner.program}>
|
|
320
|
+
<SourceFile path="test.ts">
|
|
321
|
+
<InterfaceDeclaration type={Cat} />
|
|
322
|
+
<hbr />
|
|
323
|
+
<InterfaceDeclaration type={Dog} />
|
|
324
|
+
<hbr />
|
|
325
|
+
<UnionDeclaration type={Pet} />
|
|
326
|
+
</SourceFile>
|
|
327
|
+
</Output>,
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
assertFileContents(
|
|
331
|
+
res,
|
|
332
|
+
d`
|
|
333
|
+
interface Cat {
|
|
334
|
+
name: string;
|
|
335
|
+
meow: boolean;
|
|
336
|
+
}
|
|
337
|
+
interface Dog {
|
|
338
|
+
name: string;
|
|
339
|
+
bark: boolean;
|
|
340
|
+
}
|
|
341
|
+
type Pet = {
|
|
342
|
+
dataKind: "cat"
|
|
343
|
+
} & Cat | {
|
|
344
|
+
dataKind: "dog"
|
|
345
|
+
} & Dog;
|
|
346
|
+
`,
|
|
347
|
+
);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it("renders anonymous discriminated union", async () => {
|
|
351
|
+
const { TestUnion } = (await runner.compile(`
|
|
352
|
+
namespace DemoService;
|
|
353
|
+
@discriminated(#{ envelope: "none", discriminatorPropertyName: "dataKind" })
|
|
354
|
+
@test union TestUnion {
|
|
355
|
+
one: { oneItem: true },
|
|
356
|
+
two: { secondItem: false }
|
|
357
|
+
}
|
|
358
|
+
`)) as { TestUnion: Union };
|
|
359
|
+
|
|
360
|
+
const res = render(
|
|
361
|
+
<Output program={runner.program}>
|
|
362
|
+
<SourceFile path="test.ts">
|
|
363
|
+
<UnionDeclaration type={TestUnion} />
|
|
364
|
+
</SourceFile>
|
|
365
|
+
</Output>,
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
assertFileContents(
|
|
369
|
+
res,
|
|
370
|
+
d`
|
|
371
|
+
type TestUnion = {
|
|
372
|
+
dataKind: "one";
|
|
373
|
+
oneItem: true;
|
|
374
|
+
} | {
|
|
375
|
+
dataKind: "two";
|
|
376
|
+
secondItem: false;
|
|
377
|
+
};
|
|
378
|
+
`,
|
|
379
|
+
);
|
|
147
380
|
});
|
|
148
|
-
expect(actualContent).toBe(expectedContent);
|
|
149
381
|
});
|
|
150
382
|
});
|
|
151
383
|
|
|
152
384
|
describe("Bound to Enum", () => {
|
|
153
385
|
it("creates a union declaration", async () => {
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
`);
|
|
161
|
-
|
|
162
|
-
const [namespace] = program.resolveTypeReference("DemoService");
|
|
163
|
-
const union = Array.from((namespace as Namespace).enums.values())[0];
|
|
386
|
+
const { TestEnum } = (await runner.compile(`
|
|
387
|
+
namespace DemoService;
|
|
388
|
+
@test enum TestEnum {
|
|
389
|
+
one: "one",
|
|
390
|
+
two: "two"
|
|
391
|
+
}
|
|
392
|
+
`)) as { TestEnum: Enum };
|
|
164
393
|
|
|
165
394
|
const res = render(
|
|
166
|
-
<Output program={program}>
|
|
395
|
+
<Output program={runner.program}>
|
|
167
396
|
<SourceFile path="test.ts">
|
|
168
|
-
<UnionDeclaration type={
|
|
397
|
+
<UnionDeclaration type={TestEnum} />
|
|
169
398
|
</SourceFile>
|
|
170
399
|
</Output>,
|
|
171
400
|
);
|
|
172
401
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
expect(actualContent).toBe(expectedContent);
|
|
402
|
+
assertFileContents(
|
|
403
|
+
res,
|
|
404
|
+
d`
|
|
405
|
+
type TestEnum = "one" | "two";
|
|
406
|
+
`,
|
|
407
|
+
);
|
|
180
408
|
});
|
|
181
409
|
});
|
|
182
410
|
});
|