back interdiff of round #1 and #0

[Breaking] Add @default decorator, uninline scalars by default #5

merged
opened by danabra.mov targeting main from feat/scalar-defs-and-default
files
packages
emitter
src
test
integration
atproto
input
app
bsky
actor
lexicon-examples
input
community
lexicon
calendar
output
community
lexicon
spec
ERROR
packages/emitter/src/decorators.ts

Failed to calculate interdiff for this file.

ERROR
packages/emitter/src/tsp-index.ts

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/integration/atproto/input/app/bsky/actor/defs.tsp

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/spec/basic/input/com/example/scalarDefaults.tsp

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/spec/basic/input/com/example/scalarDefs.tsp

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/spec/basic/input/com/example/scalarInline.tsp

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/spec/basic/input/com/example/unionDefaults.tsp

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/spec/basic/output/com/example/scalarDefaults.json

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/spec/basic/output/com/example/scalarDefs.json

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/spec/basic/output/com/example/scalarInline.json

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/spec/basic/output/com/example/unionDefaults.json

Failed to calculate interdiff for this file.

ERROR
DOCS.md

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/integration/lexicon-examples/input/community/lexicon/calendar/event.tsp

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/integration/lexicon-examples/input/community/lexicon/calendar/rsvp.tsp

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/integration/lexicon-examples/output/community/lexicon/calendar/event.json

Failed to calculate interdiff for this file.

ERROR
packages/emitter/test/integration/lexicon-examples/output/community/lexicon/calendar/rsvp.json

Failed to calculate interdiff for this file.

NEW
packages/emitter/src/emitter.ts
···
LexCidLink,
LexRefVariant,
LexToken,
+
LexBoolean,
+
LexInteger,
+
LexString,
} from "./types.js";
import {
···
// Apply @default decorator if present
const rawDefault = getDefault(this.program, scalar);
const defaultValue = this.processDefaultValue(rawDefault);
-
let defWithDefault: any = { ...scalarDef };
+
let defWithDefault: LexObjectProperty = { ...scalarDef };
if (defaultValue !== undefined) {
// Check if it's a Type (model reference for tokens)
···
} else {
// Validate that the default value matches the type
this.assertValidValueForType(scalarDef.type, defaultValue, scalar);
-
defWithDefault = { ...defWithDefault, default: defaultValue };
+
// Type-safe narrowing based on both the type discriminator and value type
+
if (scalarDef.type === "boolean" && typeof defaultValue === "boolean") {
+
(defWithDefault as LexBoolean).default = defaultValue;
+
} else if (scalarDef.type === "integer" && typeof defaultValue === "number") {
+
(defWithDefault as LexInteger).default = defaultValue;
+
} else if (scalarDef.type === "string" && typeof defaultValue === "string") {
+
(defWithDefault as LexString).default = defaultValue;
+
}
}
}
···
if (scalarDef.type === "integer") {
const minValue = getMinValue(this.program, scalar);
if (minValue !== undefined) {
-
(defWithDefault as any).minimum = minValue;
+
(defWithDefault as LexInteger).minimum = minValue;
}
const maxValue = getMaxValue(this.program, scalar);
if (maxValue !== undefined) {
-
(defWithDefault as any).maximum = maxValue;
+
(defWithDefault as LexInteger).maximum = maxValue;
}
}
···
// Apply @default decorator if present
const rawDefault = getDefault(this.program, union);
const defaultValue = this.processDefaultValue(rawDefault);
-
let defWithDefault: any = { ...unionDef };
+
let defWithDefault: LexString = { ...unionDef as LexString };
if (defaultValue !== undefined) {
// Check if it's a Type (model reference for tokens)
···
`Use @inline to inline them at usage sites, use @token models for known values, or use string literals.`,
target: union,
});
-
} else if (unionDef.type === "integer" && (unionDef as any).enum) {
+
} else if (unionDef.type === "integer" && (unionDef as LexInteger).enum) {
// Integer enums can also be defs
const defName = name.charAt(0).toLowerCase() + name.slice(1);
const description = getDoc(this.program, union);
···
// Apply @default decorator if present
const rawDefault = getDefault(this.program, union);
const defaultValue = this.processDefaultValue(rawDefault);
-
let defWithDefault = { ...unionDef };
+
let defWithDefault: LexInteger = { ...unionDef as LexInteger };
if (defaultValue !== undefined) {
if (typeof defaultValue === "number") {
···
// Check for default value: property default takes precedence, then union's @default
let defaultValue: string | number | boolean | undefined;
if (prop?.defaultValue !== undefined) {
-
defaultValue = serializeValueAsJson(this.program, prop.defaultValue, prop) as any;
+
defaultValue = serializeValueAsJson(this.program, prop.defaultValue, prop) as string | number | boolean;
} else {
// If no property default, check union's @default decorator
const rawUnionDefault = getDefault(this.program, unionType);
···
// Check for default value: property default takes precedence, then union's @default
let defaultValue: string | number | boolean | undefined;
if (prop?.defaultValue !== undefined) {
-
defaultValue = serializeValueAsJson(this.program, prop.defaultValue, prop) as any;
+
defaultValue = serializeValueAsJson(this.program, prop.defaultValue, prop) as string | number | boolean;
} else {
// If no property default, check union's @default decorator
const rawUnionDefault = getDefault(this.program, unionType);
···
const propDefault = serializeValueAsJson(this.program, prop.defaultValue, prop);
// For union defaults that are model references, we need to resolve them for comparison
-
let resolvedUnionDefault: string | number | boolean | undefined = unionDefault as any;
+
let resolvedUnionDefault: string | number | boolean | undefined;
if (unionDefault && typeof unionDefault === 'object' && 'kind' in unionDefault && unionDefault.kind === 'Model') {
const ref = this.getModelReference(unionDefault as Model, true);
resolvedUnionDefault = ref || undefined;
+
} else {
+
resolvedUnionDefault = unionDefault as string | number | boolean;
// If the union has a different default, or if the property has a default but the union doesn't, error