@typespec/compiler 0.68.0-dev.1 → 0.68.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.
Files changed (44) hide show
  1. package/dist/manifest.js +2 -2
  2. package/package.json +1 -5
  3. package/templates/__snapshots__/rest/main.tsp +1 -1
  4. package/templates/rest/main.tsp +1 -1
  5. package/dist/src/emitter-framework/asset-emitter.d.ts +0 -6
  6. package/dist/src/emitter-framework/asset-emitter.d.ts.map +0 -1
  7. package/dist/src/emitter-framework/asset-emitter.js +0 -740
  8. package/dist/src/emitter-framework/asset-emitter.js.map +0 -1
  9. package/dist/src/emitter-framework/builders/array-builder.d.ts +0 -7
  10. package/dist/src/emitter-framework/builders/array-builder.d.ts.map +0 -1
  11. package/dist/src/emitter-framework/builders/array-builder.js +0 -35
  12. package/dist/src/emitter-framework/builders/array-builder.js.map +0 -1
  13. package/dist/src/emitter-framework/builders/object-builder.d.ts +0 -12
  14. package/dist/src/emitter-framework/builders/object-builder.d.ts.map +0 -1
  15. package/dist/src/emitter-framework/builders/object-builder.js +0 -52
  16. package/dist/src/emitter-framework/builders/object-builder.js.map +0 -1
  17. package/dist/src/emitter-framework/builders/string-builder.d.ts +0 -13
  18. package/dist/src/emitter-framework/builders/string-builder.d.ts.map +0 -1
  19. package/dist/src/emitter-framework/builders/string-builder.js +0 -90
  20. package/dist/src/emitter-framework/builders/string-builder.js.map +0 -1
  21. package/dist/src/emitter-framework/index.d.ts +0 -75
  22. package/dist/src/emitter-framework/index.d.ts.map +0 -1
  23. package/dist/src/emitter-framework/index.js +0 -33
  24. package/dist/src/emitter-framework/index.js.map +0 -1
  25. package/dist/src/emitter-framework/placeholder.d.ts +0 -12
  26. package/dist/src/emitter-framework/placeholder.d.ts.map +0 -1
  27. package/dist/src/emitter-framework/placeholder.js +0 -18
  28. package/dist/src/emitter-framework/placeholder.js.map +0 -1
  29. package/dist/src/emitter-framework/ref-scope.d.ts +0 -14
  30. package/dist/src/emitter-framework/ref-scope.d.ts.map +0 -1
  31. package/dist/src/emitter-framework/ref-scope.js +0 -30
  32. package/dist/src/emitter-framework/ref-scope.js.map +0 -1
  33. package/dist/src/emitter-framework/reference-cycle.d.ts +0 -23
  34. package/dist/src/emitter-framework/reference-cycle.d.ts.map +0 -1
  35. package/dist/src/emitter-framework/reference-cycle.js +0 -32
  36. package/dist/src/emitter-framework/reference-cycle.js.map +0 -1
  37. package/dist/src/emitter-framework/type-emitter.d.ts +0 -349
  38. package/dist/src/emitter-framework/type-emitter.d.ts.map +0 -1
  39. package/dist/src/emitter-framework/type-emitter.js +0 -721
  40. package/dist/src/emitter-framework/type-emitter.js.map +0 -1
  41. package/dist/src/emitter-framework/types.d.ts +0 -140
  42. package/dist/src/emitter-framework/types.d.ts.map +0 -1
  43. package/dist/src/emitter-framework/types.js +0 -42
  44. package/dist/src/emitter-framework/types.js.map +0 -1
@@ -1,740 +0,0 @@
1
- import { compilerAssert } from "../core/diagnostics.js";
2
- import { getTypeName } from "../core/helpers/type-name-utils.js";
3
- import { joinPaths } from "../core/path-utils.js";
4
- import { isTemplateDeclaration } from "../core/type-utils.js";
5
- import { CustomKeyMap } from "../utils/custom-key-map.js";
6
- import { Placeholder } from "./placeholder.js";
7
- import { resolveDeclarationReferenceScope } from "./ref-scope.js";
8
- import { ReferenceCycle } from "./reference-cycle.js";
9
- import { CircularEmit, Declaration, EmitterResult, NoEmit, RawCode, } from "./types.js";
10
- export function createAssetEmitter(program, TypeEmitterClass, emitContext) {
11
- const sourceFiles = [];
12
- const options = {
13
- noEmit: program.compilerOptions.dryRun ?? false,
14
- emitterOutputDir: emitContext.emitterOutputDir,
15
- ...emitContext.options,
16
- };
17
- const typeId = CustomKeyMap.objectKeyer();
18
- const contextId = CustomKeyMap.objectKeyer();
19
- const entryId = CustomKeyMap.objectKeyer();
20
- // This is effectively a seen set, ensuring that we don't emit the same
21
- // type with the same context twice. So the map stores a triple of:
22
- //
23
- // 1. the method of TypeEmitter we would call
24
- // 2. the tsp type we're emitting.
25
- // 3. the current context.
26
- //
27
- // Note that in order for this to work, context needs to be interned so
28
- // contexts with the same values inside are treated as identical in the
29
- // map. See createInterner for more details.
30
- const typeToEmitEntity = new CustomKeyMap(([method, type, context]) => {
31
- return `${method}-${typeId.getKey(type)}-${contextId.getKey(context)}`;
32
- });
33
- // When we encounter a circular reference, this map will hold a callback
34
- // that should be called when the circularly referenced type has completed
35
- // its emit.
36
- const waitingCircularRefs = new CustomKeyMap(([method, type, context]) => {
37
- return `${method}-${typeId.getKey(type)}-${contextId.getKey(context)}`;
38
- });
39
- // Similar to `typeToEmitEntity`, this ensures we don't recompute context
40
- // for types that we already have context for. Note that context is
41
- // dependent on the context of the context call, e.g. if a model is
42
- // referenced with reference context set we need to get its declaration
43
- // context again. So we use the context's context as a key. Context must
44
- // be interned, see createInterner for more details.
45
- const knownContexts = new CustomKeyMap(([entry, context]) => {
46
- return `${entryId.getKey(entry)}-${contextId.getKey(context)}`;
47
- });
48
- // The stack of types that the currently emitted type is lexically
49
- // contained in. This gets pushed to when we visit a type that is
50
- // lexically contained in the current type, and is reset when we jump via
51
- // reference to another type in a different lexical context. Note that
52
- // this does not correspond to tsp's lexical nesting, e.g. in the case of
53
- // an alias to a model expression, the alias is lexically outside the
54
- // model, but in the type graph we will consider it to be lexically inside
55
- // whatever references the alias.
56
- let lexicalTypeStack = [];
57
- let referenceTypeChain = [];
58
- // Internally, context is is split between lexicalContext and
59
- // referenceContext because when a reference is made, we carry over
60
- // referenceContext but leave lexical context behind. When context is
61
- // accessed by the user, they are merged by getContext().
62
- let context = {
63
- lexicalContext: {},
64
- referenceContext: {},
65
- };
66
- let programContext = null;
67
- // Incoming reference context is reference context that comes from emitting a
68
- // type reference. Incoming reference context is only set on the
69
- // incomingReferenceContextTarget and types lexically contained within it. For
70
- // example, when referencing a model with reference context set, we may need
71
- // to get context from the referenced model's namespaces, and such namespaces
72
- // will not see the reference context. However, the reference context will be
73
- // available for the model, its properties, and any types nested within it
74
- // (e.g. anonymous models).
75
- let incomingReferenceContext = null;
76
- let incomingReferenceContextTarget = null;
77
- const stateInterner = createInterner();
78
- const stackEntryInterner = createInterner();
79
- const assetEmitter = {
80
- getContext() {
81
- return {
82
- ...context.lexicalContext,
83
- ...context.referenceContext,
84
- };
85
- },
86
- getOptions() {
87
- return options;
88
- },
89
- getProgram() {
90
- return program;
91
- },
92
- result: {
93
- declaration(name, value) {
94
- const scope = currentScope();
95
- compilerAssert(scope, "Emit context must have a scope set in order to create declarations. Consider setting scope to a new source file's global scope in the `programContext` method of `TypeEmitter`.");
96
- return new Declaration(name, scope, value);
97
- },
98
- rawCode(value) {
99
- return new RawCode(value);
100
- },
101
- none() {
102
- return new NoEmit();
103
- },
104
- },
105
- createScope(block, name, parentScope = null) {
106
- let newScope;
107
- if (!parentScope) {
108
- // create source file scope
109
- newScope = {
110
- kind: "sourceFile",
111
- name,
112
- sourceFile: block,
113
- parentScope,
114
- childScopes: [],
115
- declarations: [],
116
- };
117
- }
118
- else {
119
- newScope = {
120
- kind: "namespace",
121
- name,
122
- namespace: block,
123
- childScopes: [],
124
- declarations: [],
125
- parentScope,
126
- };
127
- }
128
- parentScope?.childScopes.push(newScope);
129
- return newScope; // the overload of createScope causes type weirdness
130
- },
131
- createSourceFile(path) {
132
- const basePath = options.emitterOutputDir;
133
- const sourceFile = {
134
- globalScope: undefined,
135
- path: joinPaths(basePath, path),
136
- imports: new Map(),
137
- meta: {},
138
- };
139
- sourceFile.globalScope = this.createScope(sourceFile, "");
140
- sourceFiles.push(sourceFile);
141
- return sourceFile;
142
- },
143
- emitTypeReference(target, options) {
144
- return withPatchedReferenceContext(options?.referenceContext, () => {
145
- const oldIncomingReferenceContext = incomingReferenceContext;
146
- const oldIncomingReferenceContextTarget = incomingReferenceContextTarget;
147
- incomingReferenceContext = context.referenceContext ?? null;
148
- incomingReferenceContextTarget = incomingReferenceContext ? target : null;
149
- let result;
150
- if (target.kind === "ModelProperty") {
151
- result = invokeTypeEmitter("modelPropertyReference", target);
152
- }
153
- else if (target.kind === "EnumMember") {
154
- result = invokeTypeEmitter("enumMemberReference", target);
155
- }
156
- if (result) {
157
- incomingReferenceContext = oldIncomingReferenceContext;
158
- incomingReferenceContextTarget = oldIncomingReferenceContextTarget;
159
- return result;
160
- }
161
- const entity = this.emitType(target);
162
- incomingReferenceContext = oldIncomingReferenceContext;
163
- incomingReferenceContextTarget = oldIncomingReferenceContextTarget;
164
- let placeholder = null;
165
- if (entity.kind === "circular") {
166
- let waiting = waitingCircularRefs.get(entity.emitEntityKey);
167
- if (!waiting) {
168
- waiting = [];
169
- waitingCircularRefs.set(entity.emitEntityKey, waiting);
170
- }
171
- const typeChainSnapshot = referenceTypeChain;
172
- waiting.push({
173
- state: {
174
- lexicalTypeStack,
175
- context,
176
- },
177
- cb: (resolvedEntity) => invokeReference(this, resolvedEntity, true, resolveReferenceCycle(typeChainSnapshot, entity, typeToEmitEntity)),
178
- });
179
- placeholder = new Placeholder();
180
- return this.result.rawCode(placeholder);
181
- }
182
- else {
183
- return invokeReference(this, entity, false);
184
- }
185
- function invokeReference(assetEmitter, entity, circular, cycle) {
186
- let ref;
187
- const scope = currentScope();
188
- if (circular) {
189
- ref = typeEmitter.circularReference(entity, scope, cycle);
190
- }
191
- else {
192
- if (entity.kind !== "declaration") {
193
- return entity;
194
- }
195
- compilerAssert(scope, "Emit context must have a scope set in order to create references to declarations.");
196
- const { pathUp, pathDown, commonScope } = resolveDeclarationReferenceScope(entity, scope);
197
- ref = typeEmitter.reference(entity, pathUp, pathDown, commonScope);
198
- }
199
- if (!(ref instanceof EmitterResult)) {
200
- ref = assetEmitter.result.rawCode(ref);
201
- }
202
- if (placeholder) {
203
- // this should never happen as this function shouldn't be called until
204
- // the target declaration is finished being emitted.
205
- compilerAssert(ref.kind !== "circular", "TypeEmitter `reference` returned circular emit");
206
- // this could presumably be allowed if we want.
207
- compilerAssert(ref.kind === "none" || !(ref.value instanceof Placeholder), "TypeEmitter's `reference` method cannot return a placeholder.");
208
- switch (ref.kind) {
209
- case "code":
210
- case "declaration":
211
- placeholder.setValue(ref.value);
212
- break;
213
- case "none":
214
- // this cast is incorrect, think about what should happen
215
- // if reference returns noEmit...
216
- placeholder.setValue("");
217
- break;
218
- }
219
- }
220
- return ref;
221
- }
222
- });
223
- },
224
- emitDeclarationName(type) {
225
- return typeEmitter.declarationName(type);
226
- },
227
- async writeOutput() {
228
- return typeEmitter.writeOutput(sourceFiles);
229
- },
230
- getSourceFiles() {
231
- return sourceFiles;
232
- },
233
- emitType(type, context) {
234
- if (context?.referenceContext) {
235
- incomingReferenceContext = context?.referenceContext ?? incomingReferenceContext;
236
- incomingReferenceContextTarget = type ?? incomingReferenceContextTarget;
237
- }
238
- const declName = isDeclaration(type) && type.kind !== "Namespace" ? typeEmitter.declarationName(type) : null;
239
- const key = typeEmitterKey(type);
240
- let args;
241
- switch (key) {
242
- case "scalarDeclaration":
243
- case "scalarInstantiation":
244
- case "modelDeclaration":
245
- case "modelInstantiation":
246
- case "operationDeclaration":
247
- case "interfaceDeclaration":
248
- case "interfaceOperationDeclaration":
249
- case "enumDeclaration":
250
- case "unionDeclaration":
251
- case "unionInstantiation":
252
- args = [declName];
253
- break;
254
- case "arrayDeclaration":
255
- const arrayDeclElement = type.indexer.value;
256
- args = [declName, arrayDeclElement];
257
- break;
258
- case "arrayLiteral":
259
- const arrayLiteralElement = type.indexer.value;
260
- args = [arrayLiteralElement];
261
- break;
262
- case "intrinsic":
263
- args = [declName];
264
- break;
265
- default:
266
- args = [];
267
- }
268
- const result = invokeTypeEmitter(key, type, ...args);
269
- return result;
270
- },
271
- emitProgram(options) {
272
- const namespace = program.getGlobalNamespaceType();
273
- if (options?.emitGlobalNamespace) {
274
- this.emitType(namespace);
275
- return;
276
- }
277
- for (const ns of namespace.namespaces.values()) {
278
- if (ns.name === "TypeSpec" && !options?.emitTypeSpecNamespace)
279
- continue;
280
- this.emitType(ns);
281
- }
282
- for (const model of namespace.models.values()) {
283
- if (!isTemplateDeclaration(model)) {
284
- this.emitType(model);
285
- }
286
- }
287
- for (const operation of namespace.operations.values()) {
288
- if (!isTemplateDeclaration(operation)) {
289
- this.emitType(operation);
290
- }
291
- }
292
- for (const enumeration of namespace.enums.values()) {
293
- this.emitType(enumeration);
294
- }
295
- for (const union of namespace.unions.values()) {
296
- if (!isTemplateDeclaration(union)) {
297
- this.emitType(union);
298
- }
299
- }
300
- for (const iface of namespace.interfaces.values()) {
301
- if (!isTemplateDeclaration(iface)) {
302
- this.emitType(iface);
303
- }
304
- }
305
- for (const scalar of namespace.scalars.values()) {
306
- this.emitType(scalar);
307
- }
308
- },
309
- emitModelProperties(model) {
310
- const res = invokeTypeEmitter("modelProperties", model);
311
- if (res instanceof EmitterResult) {
312
- return res;
313
- }
314
- else {
315
- return this.result.rawCode(res);
316
- }
317
- },
318
- emitModelProperty(property) {
319
- return invokeTypeEmitter("modelPropertyLiteral", property);
320
- },
321
- emitOperationParameters(operation) {
322
- return invokeTypeEmitter("operationParameters", operation, operation.parameters);
323
- },
324
- emitOperationReturnType(operation) {
325
- return invokeTypeEmitter("operationReturnType", operation, operation.returnType);
326
- },
327
- emitInterfaceOperations(iface) {
328
- return invokeTypeEmitter("interfaceDeclarationOperations", iface);
329
- },
330
- emitInterfaceOperation(operation) {
331
- const name = typeEmitter.declarationName(operation);
332
- if (name === undefined) {
333
- // the general approach of invoking the expression form doesn't work here
334
- // because TypeSpec doesn't have operation expressions.
335
- compilerAssert(false, "Unnamed operations are not supported");
336
- }
337
- return invokeTypeEmitter("interfaceOperationDeclaration", operation, name);
338
- },
339
- emitEnumMembers(en) {
340
- return invokeTypeEmitter("enumMembers", en);
341
- },
342
- emitUnionVariants(union) {
343
- return invokeTypeEmitter("unionVariants", union);
344
- },
345
- emitTupleLiteralValues(tuple) {
346
- return invokeTypeEmitter("tupleLiteralValues", tuple);
347
- },
348
- async emitSourceFile(sourceFile) {
349
- return await typeEmitter.sourceFile(sourceFile);
350
- },
351
- };
352
- const typeEmitter = new TypeEmitterClass(assetEmitter);
353
- return assetEmitter;
354
- /**
355
- * This function takes care of calling a method on the TypeEmitter to
356
- * convert it to some emitted output. It will return a cached type if we
357
- * have seen it before (and the context is the same). It will establish
358
- * the emit context by calling the appropriate methods before getting the
359
- * emit result. Also if a type emitter returns just a T or a
360
- * Placeholder<T>, it will convert that to a RawCode result.
361
- */
362
- function invokeTypeEmitter(method, ...args) {
363
- const type = args[0];
364
- let entity;
365
- let emitEntityKey;
366
- let cached = false;
367
- withTypeContext(method, args, () => {
368
- emitEntityKey = [method, type, context];
369
- const seenEmitEntity = typeToEmitEntity.get(emitEntityKey);
370
- if (seenEmitEntity) {
371
- entity = seenEmitEntity;
372
- cached = true;
373
- return;
374
- }
375
- typeToEmitEntity.set(emitEntityKey, new CircularEmit(emitEntityKey));
376
- compilerAssert(typeEmitter[method], `TypeEmitter doesn't have a method named ${method}.`);
377
- entity = liftToRawCode(typeEmitter[method](...args));
378
- });
379
- if (cached) {
380
- return entity;
381
- }
382
- if (entity instanceof Placeholder) {
383
- entity.onValue((v) => handleCompletedEntity(v));
384
- return entity;
385
- }
386
- handleCompletedEntity(entity);
387
- return entity;
388
- function handleCompletedEntity(entity) {
389
- typeToEmitEntity.set(emitEntityKey, entity);
390
- const waitingRefCbs = waitingCircularRefs.get(emitEntityKey);
391
- if (waitingRefCbs) {
392
- for (const record of waitingRefCbs) {
393
- withContext(record.state, () => {
394
- record.cb(entity);
395
- });
396
- }
397
- waitingCircularRefs.set(emitEntityKey, []);
398
- }
399
- if (entity.kind === "declaration") {
400
- entity.scope.declarations.push(entity);
401
- }
402
- }
403
- function liftToRawCode(value) {
404
- if (value instanceof EmitterResult) {
405
- return value;
406
- }
407
- return assetEmitter.result.rawCode(value);
408
- }
409
- }
410
- function isInternalMethod(method) {
411
- return (method === "interfaceDeclarationOperations" ||
412
- method === "interfaceOperationDeclaration" ||
413
- method === "operationParameters" ||
414
- method === "operationReturnType" ||
415
- method === "modelProperties" ||
416
- method === "enumMembers" ||
417
- method === "tupleLiteralValues" ||
418
- method === "unionVariants");
419
- }
420
- /**
421
- * This helper takes a type and sets the `context` state to what it should
422
- * be in order to invoke the type emitter method for that type. This needs
423
- * to take into account the current context and any incoming reference
424
- * context.
425
- */
426
- function setContextForType(method, args) {
427
- const type = args[0];
428
- let newTypeStack;
429
- // if we've walked into a new declaration, reset the lexical type stack
430
- // to the lexical containers of the current type.
431
- if (isDeclaration(type) && type.kind !== "Intrinsic" && !isInternalMethod(method)) {
432
- newTypeStack = [stackEntryInterner.intern({ method, args: stackEntryInterner.intern(args) })];
433
- let ns = type.namespace;
434
- while (ns) {
435
- if (ns.name === "")
436
- break;
437
- newTypeStack.unshift(stackEntryInterner.intern({ method: "namespace", args: stackEntryInterner.intern([ns]) }));
438
- ns = ns.namespace;
439
- }
440
- }
441
- else {
442
- newTypeStack = [
443
- ...lexicalTypeStack,
444
- stackEntryInterner.intern({ method, args: stackEntryInterner.intern(args) }),
445
- ];
446
- }
447
- lexicalTypeStack = newTypeStack;
448
- if (!programContext) {
449
- programContext = stateInterner.intern({
450
- lexicalContext: typeEmitter.programContext(program),
451
- referenceContext: stateInterner.intern({}),
452
- });
453
- }
454
- // Establish our context by starting from program and walking up the type stack
455
- // and merging in context for each of the lexical containers.
456
- context = programContext;
457
- for (const entry of lexicalTypeStack) {
458
- if (incomingReferenceContext && entry.args[0] === incomingReferenceContextTarget) {
459
- // bring in any reference context so it is available for any types nested beneath this type.
460
- context = stateInterner.intern({
461
- lexicalContext: context.lexicalContext,
462
- referenceContext: stateInterner.intern({
463
- ...context.referenceContext,
464
- ...incomingReferenceContext,
465
- }),
466
- });
467
- }
468
- const seenContext = knownContexts.get([entry, context]);
469
- if (seenContext) {
470
- context = seenContext;
471
- continue;
472
- }
473
- const lexicalKey = entry.method + "Context";
474
- const referenceKey = entry.method + "ReferenceContext";
475
- if (keyHasContext(entry.method)) {
476
- compilerAssert(typeEmitter[lexicalKey], `TypeEmitter doesn't have a method named ${lexicalKey}`);
477
- }
478
- if (keyHasReferenceContext(entry.method)) {
479
- compilerAssert(typeEmitter[referenceKey], `TypeEmitter doesn't have a method named ${referenceKey}`);
480
- }
481
- const newContext = keyHasContext(entry.method)
482
- ? typeEmitter[lexicalKey](...entry.args)
483
- : {};
484
- const newReferenceContext = keyHasReferenceContext(entry.method)
485
- ? typeEmitter[referenceKey](...entry.args)
486
- : {};
487
- // assemble our new reference and lexical contexts.
488
- const newContextState = stateInterner.intern({
489
- lexicalContext: stateInterner.intern({
490
- ...context.lexicalContext,
491
- ...newContext,
492
- }),
493
- referenceContext: stateInterner.intern({
494
- ...context.referenceContext,
495
- ...newReferenceContext,
496
- }),
497
- });
498
- knownContexts.set([entry, context], newContextState);
499
- context = newContextState;
500
- }
501
- if (!isInternalMethod(method)) {
502
- referenceTypeChain = [
503
- ...referenceTypeChain,
504
- stackEntryInterner.intern({
505
- method,
506
- type,
507
- context,
508
- }),
509
- ];
510
- }
511
- }
512
- /**
513
- * Invoke the callback with the proper context for a given type.
514
- */
515
- function withTypeContext(method, args, cb) {
516
- const oldContext = context;
517
- const oldTypeStack = lexicalTypeStack;
518
- const oldRefTypeStack = referenceTypeChain;
519
- setContextForType(method, args);
520
- cb();
521
- context = oldContext;
522
- lexicalTypeStack = oldTypeStack;
523
- referenceTypeChain = oldRefTypeStack;
524
- }
525
- function withPatchedReferenceContext(referenceContext, cb) {
526
- if (referenceContext !== undefined) {
527
- const oldContext = context;
528
- context = stateInterner.intern({
529
- lexicalContext: context.lexicalContext,
530
- referenceContext: stateInterner.intern({
531
- ...context.referenceContext,
532
- ...referenceContext,
533
- }),
534
- });
535
- const result = cb();
536
- context = oldContext;
537
- return result;
538
- }
539
- else {
540
- return cb();
541
- }
542
- }
543
- /**
544
- * Invoke the callback with the given context.
545
- */
546
- function withContext(newContext, cb) {
547
- const oldContext = context;
548
- const oldTypeStack = lexicalTypeStack;
549
- context = newContext.context;
550
- lexicalTypeStack = newContext.lexicalTypeStack;
551
- cb();
552
- context = oldContext;
553
- lexicalTypeStack = oldTypeStack;
554
- }
555
- function typeEmitterKey(type) {
556
- switch (type.kind) {
557
- case "Model":
558
- if (program.checker.isStdType(type) && type.name === "Array") {
559
- // likely an array literal, though could be a bare reference to Array maybe?
560
- return "arrayLiteral";
561
- }
562
- if (type.name === "") {
563
- return "modelLiteral";
564
- }
565
- if (type.templateMapper) {
566
- return "modelInstantiation";
567
- }
568
- if (type.indexer && type.indexer.key.name === "integer") {
569
- return "arrayDeclaration";
570
- }
571
- return "modelDeclaration";
572
- case "Namespace":
573
- return "namespace";
574
- case "ModelProperty":
575
- return "modelPropertyLiteral";
576
- case "StringTemplate":
577
- return "stringTemplate";
578
- case "Boolean":
579
- return "booleanLiteral";
580
- case "String":
581
- return "stringLiteral";
582
- case "Number":
583
- return "numericLiteral";
584
- case "Operation":
585
- if (type.interface) {
586
- return "interfaceOperationDeclaration";
587
- }
588
- else {
589
- return "operationDeclaration";
590
- }
591
- case "Interface":
592
- return "interfaceDeclaration";
593
- case "Enum":
594
- return "enumDeclaration";
595
- case "EnumMember":
596
- return "enumMember";
597
- case "Union":
598
- if (!type.name) {
599
- return "unionLiteral";
600
- }
601
- if (type.templateMapper) {
602
- return "unionInstantiation";
603
- }
604
- return "unionDeclaration";
605
- case "UnionVariant":
606
- return "unionVariant";
607
- case "Tuple":
608
- return "tupleLiteral";
609
- case "Scalar":
610
- if (type.templateMapper) {
611
- return "scalarInstantiation";
612
- }
613
- else {
614
- return "scalarDeclaration";
615
- }
616
- case "Intrinsic":
617
- return "intrinsic";
618
- default:
619
- compilerAssert(false, `Encountered type ${type.kind} which we don't know how to emit.`);
620
- }
621
- }
622
- function currentScope() {
623
- return context.referenceContext?.scope ?? context.lexicalContext?.scope ?? null;
624
- }
625
- }
626
- /**
627
- * Returns true if the given type is a declaration or an instantiation of a declaration.
628
- * @param type
629
- * @returns
630
- */
631
- function isDeclaration(type) {
632
- switch (type.kind) {
633
- case "Namespace":
634
- case "Interface":
635
- case "Enum":
636
- case "Operation":
637
- case "Scalar":
638
- case "Intrinsic":
639
- return true;
640
- case "Model":
641
- return type.name ? type.name !== "" && type.name !== "Array" : false;
642
- case "Union":
643
- return type.name ? type.name !== "" : false;
644
- default:
645
- return false;
646
- }
647
- }
648
- /**
649
- * An interner takes an object and returns either that same object, or a
650
- * previously seen object that has the identical shape.
651
- *
652
- * This implementation is EXTREMELY non-optimal (O(n*m) where n = number of unique
653
- * state objects and m = the number of properties a state object contains). This
654
- * will very quickly be a bottleneck. That said, the common case is no state at
655
- * all, and also this is essentially implementing records and tuples, so could
656
- * probably adopt those when they are released. That that said, the records and
657
- * tuples are presently facing headwinds due to implementations facing exactly
658
- * these performance characteristics. Regardless, there are optimizations we
659
- * could consider.
660
- */
661
- function createInterner() {
662
- const emptyObject = {};
663
- const knownKeys = new Map();
664
- return {
665
- intern(object) {
666
- const keys = Object.keys(object);
667
- const keyLen = keys.length;
668
- if (keyLen === 0)
669
- return emptyObject;
670
- // Find an object set with minimum size by object keys
671
- let knownObjects = new Set();
672
- let minSize = Infinity;
673
- for (const objs of keys.map((key) => knownKeys.get(key))) {
674
- if (objs && objs.size < minSize) {
675
- knownObjects = objs;
676
- minSize = objs.size;
677
- }
678
- }
679
- // Now find a known object from the found smallest object set
680
- for (const ko of knownObjects) {
681
- const entries = Object.entries(ko);
682
- if (entries.length !== keyLen)
683
- continue;
684
- let found = true;
685
- for (const [key, value] of entries) {
686
- if (object[key] !== value) {
687
- found = false;
688
- break;
689
- }
690
- }
691
- if (found) {
692
- return ko;
693
- }
694
- }
695
- // If the object is not known, add all keys as known
696
- for (const key of keys) {
697
- const ko = knownKeys.get(key);
698
- if (ko) {
699
- ko.add(object);
700
- }
701
- else {
702
- knownKeys.set(key, new Set([object]));
703
- }
704
- }
705
- return object;
706
- },
707
- };
708
- }
709
- const noContext = new Set(["modelPropertyReference", "enumMemberReference"]);
710
- function keyHasContext(key) {
711
- return !noContext.has(key);
712
- }
713
- const noReferenceContext = new Set([
714
- ...noContext,
715
- "booleanLiteral",
716
- "stringTemplate",
717
- "stringLiteral",
718
- "numericLiteral",
719
- "scalarInstantiation",
720
- "enumMember",
721
- "enumMembers",
722
- "intrinsic",
723
- ]);
724
- function keyHasReferenceContext(key) {
725
- return !noReferenceContext.has(key);
726
- }
727
- function resolveReferenceCycle(stack, entity, typeToEmitEntity) {
728
- for (let i = stack.length - 1; i >= 0; i--) {
729
- if (stack[i].type === entity.emitEntityKey[1]) {
730
- return new ReferenceCycle(stack.slice(i).map((x) => {
731
- return {
732
- type: x.type,
733
- entity: typeToEmitEntity.get([x.method, x.type, x.context]),
734
- };
735
- }));
736
- }
737
- }
738
- throw new Error(`Couldn't resolve the circular reference stack for ${getTypeName(entity.emitEntityKey[1])}`);
739
- }
740
- //# sourceMappingURL=asset-emitter.js.map