An experimental TypeSpec syntax for Lexicon

enforce empty @externals

+14 -9
-2
packages/emitter/lib/decorators.tsp
··· 1 import "../dist/tsp-index.js"; 2 3 - using TypeSpec.Reflection; 4 - 5 /** 6 * Specifies the maximum number of graphemes (user-perceived characters) allowed. 7 * Used alongside maxLength for proper Unicode text handling.
··· 1 import "../dist/tsp-index.js"; 2 3 /** 4 * Specifies the maximum number of graphemes (user-perceived characters) allowed. 5 * Used alongside maxLength for proper Unicode text handling.
+1
packages/emitter/src/decorators.ts
··· 310 }); 311 return; 312 } 313 context.program.stateSet(externalKey).add(target); 314 } 315
··· 310 }); 311 return; 312 } 313 + 314 context.program.stateSet(externalKey).add(target); 315 } 316
+11
packages/emitter/src/emitter.ts
··· 124 125 // Skip external namespaces - they don't emit JSON files 126 if (isExternal(this.program, ns)) { 127 return; 128 } 129
··· 124 125 // Skip external namespaces - they don't emit JSON files 126 if (isExternal(this.program, ns)) { 127 + // Validate that all models in external namespaces are empty (stub-only) 128 + for (const [_, model] of ns.models) { 129 + if (model.properties && model.properties.size > 0) { 130 + this.program.reportDiagnostic({ 131 + code: "external-model-not-empty", 132 + severity: "error", 133 + message: `Models in @external namespaces must be empty stubs. Model '${model.name}' in namespace '${fullName}' has properties.`, 134 + target: model, 135 + }); 136 + } 137 + } 138 return; 139 } 140
+2 -7
packages/emitter/test/spec/external/input/test/external.tsp
··· 2 3 @external 4 namespace test.external { 5 - model Main { 6 - shouldNotEmit: string; 7 - } 8 9 - model AlsoNotEmitted { 10 - @required 11 - value: boolean; 12 - } 13 }
··· 2 3 @external 4 namespace test.external { 5 + model Main { } 6 7 + model AlsoNotEmitted { } 8 }