1
- import { Enum , Interface , Model , Operation , Union } from "@typespec/compiler" ;
1
+ import { Model } from "@typespec/compiler" ;
2
2
import {
3
3
AssetEmitter ,
4
4
Context ,
5
- EmittedSourceFile ,
6
5
EmitterOutput ,
7
- Scope ,
8
- SourceFile ,
9
6
TypeSpecDeclaration ,
10
7
createAssetEmitter ,
11
8
} from "@typespec/compiler/emitter-framework" ;
12
9
13
10
import assert from "assert" ;
14
- import * as prettier from "prettier" ;
15
11
import { describe , it } from "vitest" ;
16
12
17
13
import {
@@ -22,28 +18,36 @@ import { EmitterOptions } from "../src/lib.js";
22
18
import { emitTypeSpec , getHostForTypeSpecFile } from "./host.js" ;
23
19
24
20
const testCode = `
21
+ namespace Root;
22
+
25
23
model Basic { x: string }
26
24
model RefsOtherModel { x: Basic, y: UnionDecl }
27
25
model HasNestedLiteral { x: { y: string } }
28
26
model HasArrayProperty { x: string[], y: Basic[] }
29
27
model IsArray is Array<string>;
30
- model Derived extends Basic { }
31
28
32
- @doc("Has a doc")
33
- model HasDoc { @doc("an x property") x: string }
29
+ namespace WrappedModels {
30
+ model Derived extends Basic { }
31
+
32
+ @doc("Has a doc")
33
+ model HasDoc { @doc("an x property") x: string }
34
+ }
34
35
35
36
model Template<T> { prop: T }
36
37
model HasTemplates { x: Template<Basic> }
37
38
model IsTemplate is Template<Basic>;
38
39
model HasRef {
39
40
x: Basic.x;
40
41
y: RefsOtherModel.x;
42
+ z: Operations.SomeOp;
41
43
}
42
44
43
- op SomeOp(x: string): string;
45
+ namespace Operations {
46
+ op SomeOp(x: string): string;
44
47
45
- interface MyInterface {
46
- op get(): string;
48
+ interface MyInterface {
49
+ op get(): string;
50
+ }
47
51
}
48
52
49
53
union UnionDecl {
@@ -58,11 +62,6 @@ enum MyEnum {
58
62
` ;
59
63
60
64
class SingleFileTestEmitter extends SingleFileTypescriptEmitter {
61
- programContext ( ) : Context {
62
- const outputFile = this . emitter . createSourceFile ( "output.ts" ) ;
63
- return { scope : outputFile . globalScope } ;
64
- }
65
-
66
65
operationReturnTypeReferenceContext ( ) : Context {
67
66
return {
68
67
fromOperation : true ,
@@ -351,39 +350,7 @@ describe("emitter-framework: typescript emitter", () => {
351
350
const host = await getHostForTypeSpecFile ( testCode ) ;
352
351
353
352
class ClassPerFileEmitter extends TypescriptEmitter {
354
- modelDeclarationContext ( model : Model ) : Context {
355
- return this . #declarationContext( model ) ;
356
- }
357
-
358
- modelInstantiationContext ( model : Model ) : Context {
359
- return this . #declarationContext( model ) ;
360
- }
361
-
362
- unionDeclarationContext ( union : Union ) : Context {
363
- return this . #declarationContext( union ) ;
364
- }
365
-
366
- unionInstantiationContext ( union : Union ) : Context {
367
- return this . #declarationContext( union ) ;
368
- }
369
-
370
- enumDeclarationContext ( en : Enum ) : Context {
371
- return this . #declarationContext( en ) ;
372
- }
373
-
374
- arrayDeclarationContext ( array : Model ) : Context {
375
- return this . #declarationContext( array ) ;
376
- }
377
-
378
- interfaceDeclarationContext ( iface : Interface ) : Context {
379
- return this . #declarationContext( iface ) ;
380
- }
381
-
382
- operationDeclarationContext ( operation : Operation ) : Context {
383
- return this . #declarationContext( operation ) ;
384
- }
385
-
386
- #declarationContext( decl : TypeSpecDeclaration ) {
353
+ declarationContext ( decl : TypeSpecDeclaration ) {
387
354
const name = this . emitter . emitDeclarationName ( decl ) ;
388
355
const outputFile = this . emitter . createSourceFile ( `${ name } .ts` ) ;
389
356
@@ -422,77 +389,11 @@ describe("emitter-framework: typescript emitter", () => {
422
389
} ) ;
423
390
424
391
it ( "emits to namespaces" , async ( ) => {
425
- const host = await getHostForTypeSpecFile ( testCode ) ;
426
-
427
- class NamespacedEmitter extends SingleFileTypescriptEmitter {
428
- private nsByName : Map < string , Scope < string > > = new Map ( ) ;
429
-
430
- modelDeclarationContext ( model : Model ) : Context {
431
- const name = this . emitter . emitDeclarationName ( model ) ;
432
- if ( ! name ) return { } ;
433
- const nsName = name . slice ( 0 , 1 ) ;
434
- let nsScope = this . nsByName . get ( nsName ) ;
435
- if ( ! nsScope ) {
436
- nsScope = this . emitter . createScope (
437
- { } ,
438
- nsName ,
439
- this . emitter . getContext ( ) . scope
440
- ) ;
441
- this . nsByName . set ( nsName , nsScope ) ;
442
- }
443
-
444
- return {
445
- scope : nsScope ,
446
- } ;
447
- }
448
-
449
- async sourceFile (
450
- sourceFile : SourceFile < string >
451
- ) : Promise < EmittedSourceFile > {
452
- const emittedSourceFile = await super . sourceFile ( sourceFile ) ;
453
- emittedSourceFile . contents += emitNamespaces ( sourceFile . globalScope ) ;
454
- emittedSourceFile . contents = await prettier . format (
455
- emittedSourceFile . contents ,
456
- {
457
- parser : "typescript" ,
458
- }
459
- ) ;
460
- return emittedSourceFile ;
461
-
462
- function emitNamespaces ( scope : Scope < string > ) {
463
- let res = "" ;
464
- for ( const childScope of scope . childScopes ) {
465
- res += emitNamespace ( childScope ) ;
466
- }
467
- return res ;
468
- }
469
- function emitNamespace ( scope : Scope < string > ) {
470
- let ns = `namespace ${ scope . name } {\n` ;
471
- ns += emitNamespaces ( scope ) ;
472
- for ( const decl of scope . declarations ) {
473
- ns += decl . value + "\n" ;
474
- }
475
- ns += `}\n` ;
476
-
477
- return ns ;
478
- }
479
- }
480
- }
481
- const emitter = createAssetEmitter ( host . program , NamespacedEmitter , {
482
- emitterOutputDir : host . program . compilerOptions . outputDir ! ,
483
- options : { } ,
484
- } as any ) ;
485
- emitter . emitProgram ( ) ;
486
- await emitter . writeOutput ( ) ;
487
- const contents = ( await host . compilerHost . readFile ( "tsp-output/output.ts" ) )
488
- . text ;
489
- assert . match ( contents , / n a m e s p a c e B / ) ;
490
- assert . match ( contents , / n a m e s p a c e R / ) ;
491
- assert . match ( contents , / n a m e s p a c e H / ) ;
492
- assert . match ( contents , / n a m e s p a c e I / ) ;
493
- assert . match ( contents , / n a m e s p a c e D / ) ;
494
- assert . match ( contents , / B \. B a s i c / ) ;
495
- assert . match ( contents , / B \. B a s i c / ) ;
392
+ const contents = await emitTypeSpecToTs ( testCode ) ;
393
+ assert . match ( contents , / n a m e s p a c e R o o t / ) ;
394
+ assert . match ( contents , / n a m e s p a c e O p e r a t i o n s / ) ;
395
+ assert . match ( contents , / n a m e s p a c e W r a p p e d M o d e l s / ) ;
396
+ assert . match ( contents , / O p e r a t i o n s \. S o m e O p / ) ;
496
397
} ) ;
497
398
498
399
it ( "handles circular references" , async ( ) => {
0 commit comments