An experimental TypeSpec syntax for Lexicon

fix types

authored by danabra.mov and committed by Tangled e9dc14c6 0c277f30

Changed files
+22 -10
packages
emitter
+22 -10
packages/emitter/src/emitter.ts
··· 48 LexCidLink, 49 LexRefVariant, 50 LexToken, 51 } from "./types.js"; 52 53 import { ··· 415 // Apply @default decorator if present 416 const rawDefault = getDefault(this.program, scalar); 417 const defaultValue = this.processDefaultValue(rawDefault); 418 - let defWithDefault: any = { ...scalarDef }; 419 420 if (defaultValue !== undefined) { 421 // Check if it's a Type (model reference for tokens) ··· 431 } else { 432 // Validate that the default value matches the type 433 this.assertValidValueForType(scalarDef.type, defaultValue, scalar); 434 - defWithDefault = { ...defWithDefault, default: defaultValue }; 435 } 436 } 437 ··· 439 if (scalarDef.type === "integer") { 440 const minValue = getMinValue(this.program, scalar); 441 if (minValue !== undefined) { 442 - (defWithDefault as any).minimum = minValue; 443 } 444 const maxValue = getMaxValue(this.program, scalar); 445 if (maxValue !== undefined) { 446 - (defWithDefault as any).maximum = maxValue; 447 } 448 } 449 ··· 474 // Apply @default decorator if present 475 const rawDefault = getDefault(this.program, union); 476 const defaultValue = this.processDefaultValue(rawDefault); 477 - let defWithDefault: any = { ...unionDef }; 478 479 if (defaultValue !== undefined) { 480 // Check if it's a Type (model reference for tokens) ··· 517 `Use @inline to inline them at usage sites, use @token models for known values, or use string literals.`, 518 target: union, 519 }); 520 - } else if (unionDef.type === "integer" && (unionDef as any).enum) { 521 // Integer enums can also be defs 522 const defName = name.charAt(0).toLowerCase() + name.slice(1); 523 const description = getDoc(this.program, union); ··· 525 // Apply @default decorator if present 526 const rawDefault = getDefault(this.program, union); 527 const defaultValue = this.processDefaultValue(rawDefault); 528 - let defWithDefault = { ...unionDef }; 529 530 if (defaultValue !== undefined) { 531 if (typeof defaultValue === "number") { ··· 645 // Check for default value: property default takes precedence, then union's @default 646 let defaultValue: string | number | boolean | undefined; 647 if (prop?.defaultValue !== undefined) { 648 - defaultValue = serializeValueAsJson(this.program, prop.defaultValue, prop) as any; 649 } else { 650 // If no property default, check union's @default decorator 651 const rawUnionDefault = getDefault(this.program, unionType); ··· 681 // Check for default value: property default takes precedence, then union's @default 682 let defaultValue: string | number | boolean | undefined; 683 if (prop?.defaultValue !== undefined) { 684 - defaultValue = serializeValueAsJson(this.program, prop.defaultValue, prop) as any; 685 } else { 686 // If no property default, check union's @default decorator 687 const rawUnionDefault = getDefault(this.program, unionType); ··· 1452 const propDefault = serializeValueAsJson(this.program, prop.defaultValue, prop); 1453 1454 // For union defaults that are model references, we need to resolve them for comparison 1455 - let resolvedUnionDefault: string | number | boolean | undefined = unionDefault as any; 1456 if (unionDefault && typeof unionDefault === 'object' && 'kind' in unionDefault && unionDefault.kind === 'Model') { 1457 const ref = this.getModelReference(unionDefault as Model, true); 1458 resolvedUnionDefault = ref || undefined; 1459 } 1460 1461 // If the union has a different default, or if the property has a default but the union doesn't, error
··· 48 LexCidLink, 49 LexRefVariant, 50 LexToken, 51 + LexBoolean, 52 + LexInteger, 53 + LexString, 54 } from "./types.js"; 55 56 import { ··· 418 // Apply @default decorator if present 419 const rawDefault = getDefault(this.program, scalar); 420 const defaultValue = this.processDefaultValue(rawDefault); 421 + let defWithDefault: LexObjectProperty = { ...scalarDef }; 422 423 if (defaultValue !== undefined) { 424 // Check if it's a Type (model reference for tokens) ··· 434 } else { 435 // Validate that the default value matches the type 436 this.assertValidValueForType(scalarDef.type, defaultValue, scalar); 437 + // Type-safe narrowing based on both the type discriminator and value type 438 + if (scalarDef.type === "boolean" && typeof defaultValue === "boolean") { 439 + (defWithDefault as LexBoolean).default = defaultValue; 440 + } else if (scalarDef.type === "integer" && typeof defaultValue === "number") { 441 + (defWithDefault as LexInteger).default = defaultValue; 442 + } else if (scalarDef.type === "string" && typeof defaultValue === "string") { 443 + (defWithDefault as LexString).default = defaultValue; 444 + } 445 } 446 } 447 ··· 449 if (scalarDef.type === "integer") { 450 const minValue = getMinValue(this.program, scalar); 451 if (minValue !== undefined) { 452 + (defWithDefault as LexInteger).minimum = minValue; 453 } 454 const maxValue = getMaxValue(this.program, scalar); 455 if (maxValue !== undefined) { 456 + (defWithDefault as LexInteger).maximum = maxValue; 457 } 458 } 459 ··· 484 // Apply @default decorator if present 485 const rawDefault = getDefault(this.program, union); 486 const defaultValue = this.processDefaultValue(rawDefault); 487 + let defWithDefault: LexString = { ...unionDef as LexString }; 488 489 if (defaultValue !== undefined) { 490 // Check if it's a Type (model reference for tokens) ··· 527 `Use @inline to inline them at usage sites, use @token models for known values, or use string literals.`, 528 target: union, 529 }); 530 + } else if (unionDef.type === "integer" && (unionDef as LexInteger).enum) { 531 // Integer enums can also be defs 532 const defName = name.charAt(0).toLowerCase() + name.slice(1); 533 const description = getDoc(this.program, union); ··· 535 // Apply @default decorator if present 536 const rawDefault = getDefault(this.program, union); 537 const defaultValue = this.processDefaultValue(rawDefault); 538 + let defWithDefault: LexInteger = { ...unionDef as LexInteger }; 539 540 if (defaultValue !== undefined) { 541 if (typeof defaultValue === "number") { ··· 655 // Check for default value: property default takes precedence, then union's @default 656 let defaultValue: string | number | boolean | undefined; 657 if (prop?.defaultValue !== undefined) { 658 + defaultValue = serializeValueAsJson(this.program, prop.defaultValue, prop) as string | number | boolean; 659 } else { 660 // If no property default, check union's @default decorator 661 const rawUnionDefault = getDefault(this.program, unionType); ··· 691 // Check for default value: property default takes precedence, then union's @default 692 let defaultValue: string | number | boolean | undefined; 693 if (prop?.defaultValue !== undefined) { 694 + defaultValue = serializeValueAsJson(this.program, prop.defaultValue, prop) as string | number | boolean; 695 } else { 696 // If no property default, check union's @default decorator 697 const rawUnionDefault = getDefault(this.program, unionType); ··· 1462 const propDefault = serializeValueAsJson(this.program, prop.defaultValue, prop); 1463 1464 // For union defaults that are model references, we need to resolve them for comparison 1465 + let resolvedUnionDefault: string | number | boolean | undefined; 1466 if (unionDefault && typeof unionDefault === 'object' && 'kind' in unionDefault && unionDefault.kind === 'Model') { 1467 const ref = this.getModelReference(unionDefault as Model, true); 1468 resolvedUnionDefault = ref || undefined; 1469 + } else { 1470 + resolvedUnionDefault = unionDefault as string | number | boolean; 1471 } 1472 1473 // If the union has a different default, or if the property has a default but the union doesn't, error