Skip to content

Commit fa540a9

Browse files
Split intrinsic from std lib (microsoft#3170)
fix microsoft#3171 Currently the `--nostdlib` option is just useless, here splitting the intrinsic types from the rest of the std lib. Intrinsic types will always be loaded regardless of what `nostdlib` says. Being able to disable that can be useful in the compiler test to not be polluted by some extra elements.
1 parent daad326 commit fa540a9

19 files changed

+214
-106
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
3+
changeKind: fix
4+
packages:
5+
- "@typespec/compiler"
6+
---
7+
8+
`--nostdlib` flag will now work by only applying to optional standard library types
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
3+
changeKind: fix
4+
packages:
5+
- "@typespec/playground"
6+
---
7+
8+
Add support for new intrinsic vs std lib split in the compiler.

packages/compiler/lib/lib.tsp packages/compiler/lib/intrinsics.tsp

+3-75
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import "../dist/src/lib/intrinsic-decorators.js";
2+
3+
// This file contains all the intrinsic types of typespec. Everything here will always be loaded
14
namespace TypeSpec;
25

36
/**
@@ -122,20 +125,6 @@ scalar duration;
122125
*/
123126
scalar boolean;
124127

125-
/**
126-
* Represent a 32-bit unix timestamp datetime with 1s of granularity.
127-
* It measures time by the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970.
128-
*/
129-
@encode("unixTimestamp", int32)
130-
scalar unixTimestamp32 extends utcDateTime;
131-
132-
/**
133-
* Represent a model
134-
*/
135-
// Deprecated June 2023 sprint
136-
#deprecated "object is deprecated. Please use {} for an empty model, `Record<unknown>` for a record with unknown property types, `unknown[]` for an array."
137-
model object {}
138-
139128
/**
140129
* @dev Array model type, equivalent to `Element[]`
141130
* @template Element The type of the array elements
@@ -149,64 +138,3 @@ model Array<Element> {}
149138
*/
150139
@indexer(string, Element)
151140
model Record<Element> {}
152-
153-
/**
154-
* Represent a URL string as described by https://url.spec.whatwg.org/
155-
*/
156-
scalar url extends string;
157-
158-
/**
159-
* Represents a collection of optional properties.
160-
*
161-
* @template Source An object whose spread properties are all optional.
162-
*/
163-
@doc("The template for adding optional properties.")
164-
@withOptionalProperties
165-
model OptionalProperties<Source> {
166-
...Source;
167-
}
168-
169-
/**
170-
* Represents a collection of updateable properties.
171-
*
172-
* @template Source An object whose spread properties are all updateable.
173-
*/
174-
@doc("The template for adding updateable properties.")
175-
@withUpdateableProperties
176-
model UpdateableProperties<Source> {
177-
...Source;
178-
}
179-
180-
/**
181-
* Represents a collection of omitted properties.
182-
*
183-
* @template Source An object whose properties are spread.
184-
* @template Keys The property keys to omit.
185-
*/
186-
@doc("The template for omitting properties.")
187-
@withoutOmittedProperties(Keys)
188-
model OmitProperties<Source, Keys extends string> {
189-
...Source;
190-
}
191-
192-
/**
193-
* Represents a collection of properties with default values omitted.
194-
*
195-
* @template Source An object whose spread property defaults are all omitted.
196-
*/
197-
@withoutDefaultValues
198-
model OmitDefaults<Source> {
199-
...Source;
200-
}
201-
202-
/**
203-
* Applies a visibility setting to a collection of properties.
204-
*
205-
* @template Source An object whose properties are spread.
206-
* @template Visibility The visibility to apply to all properties.
207-
*/
208-
@doc("The template for setting the default visibility of key properties.")
209-
@withDefaultKeyVisibility(Visibility)
210-
model DefaultKeyVisibility<Source, Visibility extends valueof string> {
211-
...Source;
212-
}

packages/compiler/lib/main.tsp

-4
This file was deleted.

packages/compiler/lib/decorators.tsp packages/compiler/lib/std/decorators.tsp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import "../dist/src/lib/decorators.js";
1+
import "../../dist/src/lib/decorators.js";
22

33
using TypeSpec.Reflection;
44

packages/compiler/lib/std/main.tsp

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// TypeSpec standard library. Everything in here can be omitted by using `--nostdlib` cli flag or `nostdlib` in the config.
2+
import "./types.tsp";
3+
import "./decorators.tsp";
4+
import "./reflection.tsp";
5+
import "./projected-names.tsp";
File renamed without changes.

packages/compiler/lib/std/types.tsp

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
namespace TypeSpec;
2+
3+
/**
4+
* Represent a 32-bit unix timestamp datetime with 1s of granularity.
5+
* It measures time by the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970.
6+
*/
7+
@encode("unixTimestamp", int32)
8+
scalar unixTimestamp32 extends utcDateTime;
9+
10+
/**
11+
* Represent a model
12+
*/
13+
// Deprecated June 2023 sprint
14+
#deprecated "object is deprecated. Please use {} for an empty model, `Record<unknown>` for a record with unknown property types, `unknown[]` for an array."
15+
model object {}
16+
17+
/**
18+
* Represent a URL string as described by https://url.spec.whatwg.org/
19+
*/
20+
scalar url extends string;
21+
22+
/**
23+
* Represents a collection of optional properties.
24+
*
25+
* @template Source An object whose spread properties are all optional.
26+
*/
27+
@doc("The template for adding optional properties.")
28+
@withOptionalProperties
29+
model OptionalProperties<Source> {
30+
...Source;
31+
}
32+
33+
/**
34+
* Represents a collection of updateable properties.
35+
*
36+
* @template Source An object whose spread properties are all updateable.
37+
*/
38+
@doc("The template for adding updateable properties.")
39+
@withUpdateableProperties
40+
model UpdateableProperties<Source> {
41+
...Source;
42+
}
43+
44+
/**
45+
* Represents a collection of omitted properties.
46+
*
47+
* @template Source An object whose properties are spread.
48+
* @template Keys The property keys to omit.
49+
*/
50+
@doc("The template for omitting properties.")
51+
@withoutOmittedProperties(Keys)
52+
model OmitProperties<Source, Keys extends string> {
53+
...Source;
54+
}
55+
56+
/**
57+
* Represents a collection of properties with default values omitted.
58+
*
59+
* @template Source An object whose spread property defaults are all omitted.
60+
*/
61+
@withoutDefaultValues
62+
model OmitDefaults<Source> {
63+
...Source;
64+
}
65+
66+
/**
67+
* Applies a visibility setting to a collection of properties.
68+
*
69+
* @template Source An object whose properties are spread.
70+
* @template Visibility The visibility to apply to all properties.
71+
*/
72+
@doc("The template for setting the default visibility of key properties.")
73+
@withDefaultKeyVisibility(Visibility)
74+
model DefaultKeyVisibility<Source, Visibility extends valueof string> {
75+
...Source;
76+
}

packages/compiler/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
],
2020
"type": "module",
2121
"main": "dist/src/index.js",
22-
"tspMain": "lib/main.tsp",
22+
"tspMain": "lib/std/main.tsp",
2323
"exports": {
2424
".": {
2525
"types": "./dist/src/index.d.ts",
@@ -54,7 +54,7 @@
5454
"tsp-server": "cmd/tsp-server.js"
5555
},
5656
"files": [
57-
"lib/*.tsp",
57+
"lib/**/*.tsp",
5858
"dist/**",
5959
"templates/**",
6060
"entrypoints",

packages/compiler/src/core/checker.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { $docFromComment, getIndexer, isArrayModelType } from "../lib/decorators.js";
1+
import { $docFromComment, isArrayModelType } from "../lib/decorators.js";
2+
import { getIndexer } from "../lib/intrinsic-decorators.js";
23
import { MultiKeyMap, Mutable, createRekeyableMap, isArray, mutate } from "../utils/misc.js";
34
import { createSymbol, createSymbolTable } from "./binder.js";
45
import { createChangeIdentifierCodeFix } from "./compiler-code-fixes/change-identifier.codefix.js";
@@ -356,9 +357,6 @@ export function createChecker(program: Program): Checker {
356357

357358
const typespecNamespaceBinding = globalNamespaceNode.symbol.exports!.get("TypeSpec");
358359
if (typespecNamespaceBinding) {
359-
// the TypeSpec namespace binding will be absent if we've passed
360-
// the no-std-lib option.
361-
// the first declaration here is the JS file for the TypeSpec script.
362360
initializeTypeSpecIntrinsics();
363361
for (const file of program.sourceFiles.values()) {
364362
addUsingSymbols(typespecNamespaceBinding.exports!, file.locals);

packages/compiler/src/core/node-host.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const NodeHost: CompilerHost = {
2828
getJsImport: (path: string) => import(pathToFileURL(path).href),
2929
getLibDirs() {
3030
const rootDir = this.getExecutionRoot();
31-
return [joinPaths(rootDir, "lib")];
31+
return [joinPaths(rootDir, "lib/std")];
3232
},
3333
stat(path: string) {
3434
return stat(path);

packages/compiler/src/core/program.ts

+13-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
} from "./module-resolver.js";
3535
import { CompilerOptions } from "./options.js";
3636
import { isImportStatement, parse, parseStandaloneTypeReference } from "./parser.js";
37-
import { getDirectoryPath, joinPaths } from "./path-utils.js";
37+
import { getDirectoryPath, joinPaths, resolvePath } from "./path-utils.js";
3838
import { createProjector } from "./projector.js";
3939
import { createSourceFile } from "./source-file.js";
4040
import {
@@ -332,8 +332,9 @@ export async function compile(
332332
}
333333
const binder = createBinder(program);
334334

335+
await loadIntrinsicTypes();
335336
if (!options?.nostdlib) {
336-
await loadStandardLibrary(program);
337+
await loadStandardLibrary();
337338
}
338339

339340
// Load additional imports prior to compilation
@@ -458,7 +459,16 @@ export async function compile(
458459
}
459460
}
460461

461-
async function loadStandardLibrary(program: Program) {
462+
async function loadIntrinsicTypes() {
463+
const locationContext: LocationContext = { type: "compiler" };
464+
await loadTypeSpecFile(
465+
resolvePath(host.getExecutionRoot(), "lib/intrinsics.tsp"),
466+
locationContext,
467+
NoTarget
468+
);
469+
}
470+
471+
async function loadStandardLibrary() {
462472
const locationContext: LocationContext = { type: "compiler" };
463473
for (const dir of host.getLibDirs()) {
464474
await loadDirectory(dir, locationContext, NoTarget);

packages/compiler/src/lib/decorators.ts

-11
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ import {
5959
EnumMember,
6060
Interface,
6161
Model,
62-
ModelIndexer,
6362
ModelProperty,
6463
Namespace,
6564
Operation,
@@ -287,16 +286,6 @@ export const $inspectTypeName: InspectTypeNameDecorator = (context, target: Type
287286
console.log(getTypeName(target));
288287
};
289288

290-
const indexTypeKey = createStateSymbol("index");
291-
export const $indexer = (context: DecoratorContext, target: Type, key: Scalar, value: Type) => {
292-
const indexer: ModelIndexer = { key, value };
293-
context.program.stateMap(indexTypeKey).set(target, indexer);
294-
};
295-
296-
export function getIndexer(program: Program, target: Type): ModelIndexer | undefined {
297-
return program.stateMap(indexTypeKey).get(target);
298-
}
299-
300289
export function isStringType(program: Program | ProjectedProgram, target: Type): target is Scalar {
301290
const coreType = program.checker.getStdType("string");
302291
const stringType = target.projector ? target.projector.projectType(coreType) : coreType;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Program } from "../core/program.js";
2+
import { DecoratorContext, ModelIndexer, Scalar, Type } from "../core/types.js";
3+
4+
export const namespace = "TypeSpec";
5+
6+
const indexTypeKey = Symbol.for(`TypeSpec.index`);
7+
export const $indexer = (context: DecoratorContext, target: Type, key: Scalar, value: Type) => {
8+
const indexer: ModelIndexer = { key, value };
9+
context.program.stateMap(indexTypeKey).set(target, indexer);
10+
};
11+
12+
export function getIndexer(program: Program, target: Type): ModelIndexer | undefined {
13+
return program.stateMap(indexTypeKey).get(target);
14+
}

packages/compiler/src/testing/test-host.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ function createTestCompilerHost(
4242
jsImports: Map<string, Record<string, any>>,
4343
options?: TestHostOptions
4444
): CompilerHost {
45-
const libDirs = [resolveVirtualPath(".tsp/lib")];
45+
const libDirs = [resolveVirtualPath(".tsp/lib/std")];
4646
if (!options?.excludeTestLib) {
4747
libDirs.push(resolveVirtualPath(".tsp/test-lib"));
4848
}
@@ -224,7 +224,7 @@ export const StandardTestLibrary: TypeSpecTestLibrary = {
224224
packageRoot: await findTestPackageRoot(import.meta.url),
225225
files: [
226226
{ virtualPath: "./.tsp/dist/src/lib", realDir: "./dist/src/lib", pattern: "*" },
227-
{ virtualPath: "./.tsp/lib", realDir: "./lib", pattern: "*" },
227+
{ virtualPath: "./.tsp/lib", realDir: "./lib", pattern: "**" },
228228
],
229229
};
230230

packages/compiler/test/semantic-walker.test.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,15 @@ describe("compiler: semantic walker", () => {
127127

128128
deepStrictEqual(
129129
result.namespaces.map((x) => getNamespaceFullName(x)),
130-
["", "Global", "Global.My", "Global.My.Simple", "Global.My.Parent", "Global.My.Parent.Child"]
130+
[
131+
"",
132+
"TypeSpec",
133+
"Global",
134+
"Global.My",
135+
"Global.My.Simple",
136+
"Global.My.Parent",
137+
"Global.My.Parent.Child",
138+
]
131139
);
132140
});
133141

0 commit comments

Comments
 (0)