Remove all circular references in TypeSpec Compiler (#3308)

They cause vitest to not be happy randomly. This is only a problem with
non type import so adding `type` helps finding which ones are a real
problem

Use madge with this command to find them
```
npx madge --circular --extensions ts ./src/
```

with this config
```
{
  "detectiveOptions": {
    "ts": {
      "skipTypeImports": true,
      "skipAsyncImports": true
    }
  }
}
```
This commit is contained in:
Timothee Guerin 2024-05-09 15:56:46 -07:00 коммит произвёл GitHub
Родитель bdb3f24bff
Коммит 8c44c3a89d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
46 изменённых файлов: 302 добавлений и 284 удалений

Просмотреть файл

@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: internal
packages:
- "@typespec/compiler"
- "@typespec/http"
- "@typespec/playground"
---

Просмотреть файл

@ -1,5 +1,5 @@
import { Diagnostic, RuleRef } from "../core/index.js";
import { YamlScript } from "../yaml/types.js";
import type { Diagnostic, RuleRef } from "../core/index.js";
import type { YamlScript } from "../yaml/types.js";
/**
* Represent the normalized user configuration.

Просмотреть файл

@ -1,8 +1,8 @@
import { mutate } from "../utils/misc.js";
import { compilerAssert } from "./diagnostics.js";
import { getLocationContext } from "./helpers/index.js";
import { getLocationContext } from "./helpers/location-context.js";
import { visitChildren } from "./parser.js";
import { Program } from "./program.js";
import type { Program } from "./program.js";
import {
AliasStatementNode,
ConstStatementNode,

Просмотреть файл

@ -12,14 +12,14 @@ import {
reportDeprecated,
} from "./diagnostics.js";
import { validateInheritanceDiscriminatedUnions } from "./helpers/discriminator-utils.js";
import { getLocationContext } from "./helpers/location-context.js";
import { explainStringTemplateNotSerializable } from "./helpers/string-template-utils.js";
import {
TypeNameOptions,
getEntityName,
getLocationContext,
getNamespaceFullName,
getTypeName,
} from "./helpers/index.js";
import { explainStringTemplateNotSerializable } from "./helpers/string-template-utils.js";
type TypeNameOptions,
} from "./helpers/type-name-utils.js";
import {
getMaxItems,
getMaxLength,

Просмотреть файл

@ -1,8 +1,7 @@
import { getPropertyType } from "../lib/decorators.js";
import { compilerAssert, ignoreDiagnostics } from "./diagnostics.js";
import { getTypeName } from "./helpers/type-name-utils.js";
import { createDiagnostic, reportDiagnostic } from "./messages.js";
import { Program } from "./program.js";
import type { Program } from "./program.js";
import {
DecoratorContext,
DecoratorFunction,
@ -516,3 +515,14 @@ export function validateDecoratorNotOnType(
}
}
}
/**
* Return the type of the property or the model itself.
*/
export function getPropertyType(target: Scalar | ModelProperty): Type {
if (target.kind === "ModelProperty") {
return target.type;
} else {
return target;
}
}

Просмотреть файл

@ -1,4 +1,4 @@
import { Program } from "./program.js";
import type { Program } from "./program.js";
import { BaseNode, Node, SyntaxKind, Type } from "./types.js";
function createStateSymbol(name: string) {

Просмотреть файл

@ -1,4 +1,4 @@
import { formatLog } from "./logger/index.js";
import { formatLog } from "./logger/console-sink.js";
import type { Program } from "./program.js";
import { createSourceFile } from "./source-file.js";
import {

Просмотреть файл

@ -1,5 +1,5 @@
import { getDirectoryPath } from "./path-utils.js";
import { Program } from "./program.js";
import type { Program } from "./program.js";
export type NewLine = "lf" | "crlf";
export interface EmitFileOptions {

Просмотреть файл

@ -1,8 +1,8 @@
import { Discriminator, getDiscriminatedTypes } from "../../lib/decorators.js";
import { DuplicateTracker } from "../../utils/duplicate-tracker.js";
import { isDefined } from "../../utils/misc.js";
import { Discriminator, getDiscriminatedTypes } from "../intrinsic-type-state.js";
import { createDiagnostic } from "../messages.js";
import { Program } from "../program.js";
import type { Program } from "../program.js";
import { isTemplateDeclarationOrInstance } from "../type-utils.js";
import { Diagnostic, Model, Type, Union } from "../types.js";

Просмотреть файл

@ -1,6 +1,6 @@
import { getSourceLocation } from "../diagnostics.js";
import { Program } from "../program.js";
import { DiagnosticTarget, LocationContext } from "../types.js";
import type { Program } from "../program.js";
import type { DiagnosticTarget, LocationContext } from "../types.js";
export function getLocationContext(program: Program, type: DiagnosticTarget): LocationContext {
const sourceLocation = getSourceLocation(type);

Просмотреть файл

@ -1,5 +1,6 @@
import { Program, ProjectedProgram, projectProgram } from "../program.js";
import { Projector, Type } from "../types.js";
import type { Program, ProjectedProgram } from "../program.js";
import { projectProgram } from "../program.js";
import type { Projector, Type } from "../types.js";
export interface ProjectedNameView {
program: ProjectedProgram;

Просмотреть файл

@ -7,6 +7,8 @@ export * from "./emitter-utils.js";
export * from "./formatter.js";
export * from "./helpers/index.js";
export {
getDiscriminatedTypes,
getDiscriminator,
getDocData,
getMaxItems,
getMaxItemsAsNumeric,
@ -45,6 +47,7 @@ export { getPositionBeforeTrivia } from "./parser-utils.js";
export * from "./parser.js";
export * from "./path-utils.js";
export * from "./program.js";
export { isProjectedProgram } from "./projected-program.js";
export * from "./scanner.js";
export * from "./semantic-walker.js";
export { createSourceFile, getSourceFileKindFromExt } from "./source-file.js";

Просмотреть файл

@ -1,7 +1,7 @@
// Contains all intrinsic data setter or getter
// Anything that the TypeSpec check might should be here.
import type { Type } from "./index.js";
import type { Model, Type, Union } from "./index.js";
import type { Numeric } from "./numeric.js";
import type { Program } from "./program.js";
@ -22,6 +22,8 @@ const stateKeys = {
docs: createStateSymbol("docs"),
returnDocs: createStateSymbol("returnsDocs"),
errorsDocs: createStateSymbol("errorDocs"),
discriminator: createStateSymbol("discriminator"),
};
// #region @minValue
@ -208,3 +210,23 @@ export function getDocData(program: Program, target: Type): DocData | undefined
return getDocDataInternal(program, target, "self");
}
// #endregion doc
// #region discriminator
export interface Discriminator {
readonly propertyName: string;
}
export function setDiscriminator(program: Program, entity: Type, discriminator: Discriminator) {
program.stateMap(stateKeys.discriminator).set(entity, discriminator);
}
export function getDiscriminator(program: Program, entity: Type): Discriminator | undefined {
return program.stateMap(stateKeys.discriminator).get(entity);
}
export function getDiscriminatedTypes(program: Program): [Model | Union, Discriminator][] {
return [...program.stateMap(stateKeys.discriminator).entries()] as any;
}
// #endregion

Просмотреть файл

@ -1,4 +1,4 @@
import { Checker } from "./checker.js";
import type { Checker } from "./checker.js";
import { compilerAssert } from "./diagnostics.js";
import { numericRanges } from "./numeric-ranges.js";
import { Numeric } from "./numeric.js";

Просмотреть файл

@ -1,6 +1,6 @@
import { createDiagnosticCreator } from "./diagnostic-creator.js";
import { compilerAssert } from "./diagnostics.js";
import { Program } from "./program.js";
import type { Program } from "./program.js";
import { createJSONSchemaValidator } from "./schema-validator.js";
import {
DiagnosticMessages,

Просмотреть файл

@ -1,7 +1,7 @@
import { DiagnosticCollector, compilerAssert, createDiagnosticCollector } from "./diagnostics.js";
import { getLocationContext } from "./helpers/index.js";
import { getLocationContext } from "./helpers/location-context.js";
import { createDiagnostic } from "./messages.js";
import { Program } from "./program.js";
import type { Program } from "./program.js";
import { EventEmitter, mapEventEmitterToNodeListener, navigateProgram } from "./semantic-walker.js";
import {
Diagnostic,

Просмотреть файл

@ -37,6 +37,7 @@ import { isImportStatement, parse, parseStandaloneTypeReference } from "./parser
import { getDirectoryPath, joinPaths, resolvePath } from "./path-utils.js";
import { createProjector } from "./projector.js";
import { createSourceFile } from "./source-file.js";
import { StateMap, StateSet, createStateAccessors } from "./state-accessors.js";
import {
CompilerHost,
Diagnostic,
@ -73,10 +74,12 @@ export interface ProjectedProgram extends Program {
projector: Projector;
}
export function isProjectedProgram(
program: Program | ProjectedProgram
): program is ProjectedProgram {
return "projector" in program;
export function projectProgram(
program: Program,
projections: ProjectionApplication[],
startNode?: Type
): ProjectedProgram {
return createProjector(program, projections, startNode);
}
export interface Program {
@ -132,146 +135,11 @@ interface Validator {
callback: (program: Program) => void | Promise<void>;
}
class StateMap extends Map<undefined | Projector, Map<Type, unknown>> {}
class StateSet extends Map<undefined | Projector, Set<Type>> {}
class StateMapView<V> implements Map<Type, V> {
public constructor(
private state: StateMap,
private projector?: Projector
) {}
has(t: Type) {
return this.dispatch(t)?.has(t) ?? false;
}
set(t: Type, v: any) {
this.dispatch(t).set(t, v);
return this;
}
get(t: Type) {
return this.dispatch(t).get(t);
}
delete(t: Type) {
return this.dispatch(t).delete(t);
}
forEach(cb: (value: V, key: Type, map: Map<Type, V>) => void, thisArg?: any) {
this.dispatch().forEach(cb, thisArg);
return this;
}
get size() {
return this.dispatch().size;
}
clear() {
return this.dispatch().clear();
}
entries() {
return this.dispatch().entries();
}
values() {
return this.dispatch().values();
}
keys() {
return this.dispatch().keys();
}
[Symbol.iterator]() {
return this.entries();
}
[Symbol.toStringTag] = "StateMap";
dispatch(keyType?: Type): Map<Type, V> {
const key = keyType ? keyType.projector : this.projector;
if (!this.state.has(key)) {
this.state.set(key, new Map());
}
return this.state.get(key)! as any;
}
}
class StateSetView implements Set<Type> {
public constructor(
private state: StateSet,
private projector?: Projector
) {}
has(t: Type) {
return this.dispatch(t)?.has(t) ?? false;
}
add(t: Type) {
this.dispatch(t).add(t);
return this;
}
delete(t: Type) {
return this.dispatch(t).delete(t);
}
forEach(cb: (value: Type, value2: Type, set: Set<Type>) => void, thisArg?: any) {
this.dispatch().forEach(cb, thisArg);
return this;
}
get size() {
return this.dispatch().size;
}
clear() {
return this.dispatch().clear();
}
values() {
return this.dispatch().values();
}
keys() {
return this.dispatch().keys();
}
entries() {
return this.dispatch().entries();
}
[Symbol.iterator]() {
return this.values();
}
[Symbol.toStringTag] = "StateSet";
dispatch(keyType?: Type): Set<Type> {
const key = keyType ? keyType.projector : this.projector;
if (!this.state.has(key)) {
this.state.set(key, new Set());
}
return this.state.get(key)!;
}
}
interface TypeSpecLibraryReference {
path: string;
manifest: NodePackage;
}
export function projectProgram(
program: Program,
projections: ProjectionApplication[],
startNode?: Type
): ProjectedProgram {
return createProjector(program, projections, startNode);
}
export async function compile(
host: CompilerHost,
mainFile: string,
@ -1228,36 +1096,6 @@ export async function compile(
}
}
export function createStateAccessors(
stateMaps: Map<symbol, StateMap>,
stateSets: Map<symbol, StateSet>,
projector?: Projector
) {
function stateMap<T>(key: symbol): StateMapView<T> {
let m = stateMaps.get(key);
if (!m) {
m = new StateMap();
stateMaps.set(key, m);
}
return new StateMapView(m, projector);
}
function stateSet(key: symbol): StateSetView {
let s = stateSets.get(key);
if (!s) {
s = new StateSet();
stateSets.set(key, s);
}
return new StateSetView(s, projector);
}
return { stateMap, stateSet };
}
/**
* Resolve compiler options from input options.
*/

Просмотреть файл

@ -0,0 +1,7 @@
import type { Program, ProjectedProgram } from "./index.js";
export function isProjectedProgram(
program: Program | ProjectedProgram
): program is ProjectedProgram {
return "projector" in program;
}

Просмотреть файл

@ -1,7 +1,7 @@
import { camelCase, kebabCase, pascalCase, snakeCase } from "change-case";
import { Checker } from "./checker.js";
import type { Checker } from "./checker.js";
import { ProjectionError, assertType } from "./diagnostics.js";
import { ObjectType, Type, UnionVariant } from "./types.js";
import type { ObjectType, Type, UnionVariant } from "./types.js";
export function createProjectionMembers(checker: Checker): {
[TKind in Type["kind"]]?: Record<string, (base: Type & { kind: TKind }) => Type>;

Просмотреть файл

@ -1,9 +1,11 @@
import { createRekeyableMap, mutate } from "../utils/misc.js";
import { finishTypeForProgram } from "./checker.js";
import { compilerAssert } from "./diagnostics.js";
import { Program, ProjectedProgram, createStateAccessors, isProjectedProgram } from "./program.js";
import type { Program, ProjectedProgram } from "./program.js";
import { isProjectedProgram } from "./projected-program.js";
import { createStateAccessors } from "./state-accessors.js";
import { getParentTemplateNode, isNeverType, isTemplateInstance, isValue } from "./type-utils.js";
import {
import type {
DecoratorApplication,
DecoratorArgument,
Enum,

Просмотреть файл

@ -1,4 +1,4 @@
import { Program } from "./program.js";
import type { Program } from "./program.js";
import { isTemplateDeclaration } from "./type-utils.js";
import {
Decorator,

Просмотреть файл

@ -0,0 +1,158 @@
import type { Projector, Type } from "./types.js";
export class StateMap extends Map<undefined | Projector, Map<Type, unknown>> {}
export class StateSet extends Map<undefined | Projector, Set<Type>> {}
class StateMapView<V> implements Map<Type, V> {
public constructor(
private state: StateMap,
private projector?: Projector
) {}
has(t: Type) {
return this.dispatch(t)?.has(t) ?? false;
}
set(t: Type, v: any) {
this.dispatch(t).set(t, v);
return this;
}
get(t: Type) {
return this.dispatch(t).get(t);
}
delete(t: Type) {
return this.dispatch(t).delete(t);
}
forEach(cb: (value: V, key: Type, map: Map<Type, V>) => void, thisArg?: any) {
this.dispatch().forEach(cb, thisArg);
return this;
}
get size() {
return this.dispatch().size;
}
clear() {
return this.dispatch().clear();
}
entries() {
return this.dispatch().entries();
}
values() {
return this.dispatch().values();
}
keys() {
return this.dispatch().keys();
}
[Symbol.iterator]() {
return this.entries();
}
[Symbol.toStringTag] = "StateMap";
dispatch(keyType?: Type): Map<Type, V> {
const key = keyType ? keyType.projector : this.projector;
if (!this.state.has(key)) {
this.state.set(key, new Map());
}
return this.state.get(key)! as any;
}
}
class StateSetView implements Set<Type> {
public constructor(
private state: StateSet,
private projector?: Projector
) {}
has(t: Type) {
return this.dispatch(t)?.has(t) ?? false;
}
add(t: Type) {
this.dispatch(t).add(t);
return this;
}
delete(t: Type) {
return this.dispatch(t).delete(t);
}
forEach(cb: (value: Type, value2: Type, set: Set<Type>) => void, thisArg?: any) {
this.dispatch().forEach(cb, thisArg);
return this;
}
get size() {
return this.dispatch().size;
}
clear() {
return this.dispatch().clear();
}
values() {
return this.dispatch().values();
}
keys() {
return this.dispatch().keys();
}
entries() {
return this.dispatch().entries();
}
[Symbol.iterator]() {
return this.values();
}
[Symbol.toStringTag] = "StateSet";
dispatch(keyType?: Type): Set<Type> {
const key = keyType ? keyType.projector : this.projector;
if (!this.state.has(key)) {
this.state.set(key, new Set());
}
return this.state.get(key)!;
}
}
export function createStateAccessors(
stateMaps: Map<symbol, StateMap>,
stateSets: Map<symbol, StateSet>,
projector?: Projector
) {
function stateMap<T>(key: symbol): StateMapView<T> {
let m = stateMaps.get(key);
if (!m) {
m = new StateMap();
stateMaps.set(key, m);
}
return new StateMapView(m, projector);
}
function stateSet(key: symbol): StateSetView {
let s = stateSets.get(key);
if (!s) {
s = new StateSet();
stateSets.set(key, s);
}
return new StateSetView(s, projector);
}
return { stateMap, stateSet };
}

Просмотреть файл

@ -1,14 +1,8 @@
import {
compilerAssert,
EmitContext,
getTypeName,
isTemplateDeclaration,
joinPaths,
Model,
Namespace,
Program,
Type,
} from "../core/index.js";
import { compilerAssert } from "../core/diagnostics.js";
import { getTypeName } from "../core/helpers/type-name-utils.js";
import type { EmitContext, Model, Namespace, Program, Type } from "../core/index.js";
import { joinPaths } from "../core/path-utils.js";
import { isTemplateDeclaration } from "../core/type-utils.js";
import { CustomKeyMap } from "./custom-key-map.js";
import { Placeholder } from "./placeholder.js";
import { resolveDeclarationReferenceScope } from "./ref-scope.js";
@ -20,9 +14,9 @@ import {
ContextState,
Declaration,
EmitEntity,
EmitTypeReferenceOptions,
EmitterResult,
EmitterState,
EmitTypeReferenceOptions,
LexicalTypeStackEntry,
NamespaceScope,
NoEmit,

Просмотреть файл

@ -1,4 +1,4 @@
import { Declaration, Scope } from "./types.js";
import type { Declaration, Scope } from "./types.js";
export function scopeChain<T>(scope: Scope<T> | null) {
const chain = [];

Просмотреть файл

@ -1,5 +1,6 @@
import { Type, getTypeName } from "../core/index.js";
import { EmitEntity } from "./types.js";
import { getTypeName } from "../core/helpers/type-name-utils.js";
import type { Type } from "../core/index.js";
import type { EmitEntity } from "./types.js";
export interface ReferenceCycleEntry {
type: Type;

Просмотреть файл

@ -1,18 +1,18 @@
import {
import { compilerAssert } from "../core/diagnostics.js";
import { emitFile } from "../core/emitter-utils.js";
import type { Program } from "../core/program.js";
import { isTemplateDeclaration } from "../core/type-utils.js";
import type {
BooleanLiteral,
compilerAssert,
emitFile,
Enum,
EnumMember,
Interface,
IntrinsicType,
isTemplateDeclaration,
Model,
ModelProperty,
Namespace,
NumericLiteral,
Operation,
Program,
Scalar,
StringLiteral,
StringTemplate,
@ -20,8 +20,8 @@ import {
Type,
Union,
UnionVariant,
} from "../core/index.js";
import { code, StringBuilder } from "./builders/string-builder.js";
} from "../core/types.js";
import { StringBuilder, code } from "./builders/string-builder.js";
import { Placeholder } from "./placeholder.js";
import { resolveDeclarationReferenceScope } from "./ref-scope.js";
import { ReferenceCycle } from "./reference-cycle.js";

Просмотреть файл

@ -1,4 +1,4 @@
import {
import type {
Enum,
Interface,
IntrinsicType,
@ -12,7 +12,7 @@ import {
Union,
} from "../core/index.js";
import { Placeholder } from "./placeholder.js";
import { TypeEmitter } from "./type-emitter.js";
import type { TypeEmitter } from "./type-emitter.js";
type AssetEmitterOptions<TOptions extends object> = {
noEmit: boolean;

Просмотреть файл

@ -1,7 +1,7 @@
import { camelCase, kebabCase, pascalCase } from "change-case";
import Mustache from "mustache";
import { InitTemplate } from "./init-template.js";
import { ScaffoldingConfig } from "./scaffold.js";
import type { InitTemplate } from "./init-template.js";
import type { ScaffoldingConfig } from "./scaffold.js";
export type FileTemplatingContext = Omit<InitTemplate, "libraries"> &
ScaffoldingConfig & {

Просмотреть файл

@ -37,6 +37,7 @@ import type {
WithoutOmittedPropertiesDecorator,
} from "../../generated-defs/TypeSpec.js";
import {
getPropertyType,
isIntrinsicType,
validateDecoratorNotOnType,
validateDecoratorTarget,
@ -53,6 +54,7 @@ import {
validateDecoratorUniqueOnNode,
} from "../core/index.js";
import {
Discriminator,
DocData,
getDocDataInternal,
getMaxItemsAsNumeric,
@ -63,6 +65,7 @@ import {
getMinLengthAsNumeric,
getMinValueAsNumeric,
getMinValueExclusiveAsNumeric,
setDiscriminator,
setDocData,
setMaxItems,
setMaxLength,
@ -310,17 +313,6 @@ function validateTargetingAString(
return valid;
}
/**
* Return the type of the property or the model itself.
*/
export function getPropertyType(target: Scalar | ModelProperty): Type {
if (target.kind === "ModelProperty") {
return target.type;
} else {
return target;
}
}
// -- @error decorator ----------------------
const errorKey = createStateSymbol("error");
@ -1343,12 +1335,6 @@ function validateRange(
return true;
}
export interface Discriminator {
propertyName: string;
}
const discriminatorKey = createStateSymbol("discriminator");
export const $discriminator: DiscriminatorDecorator = (
context: DecoratorContext,
entity: Model | Union,
@ -1364,17 +1350,9 @@ export const $discriminator: DiscriminatorDecorator = (
return;
}
}
context.program.stateMap(discriminatorKey).set(entity, discriminator);
setDiscriminator(context.program, entity, discriminator);
};
export function getDiscriminator(program: Program, entity: Type): Discriminator | undefined {
return program.stateMap(discriminatorKey).get(entity);
}
export function getDiscriminatedTypes(program: Program): [Model | Union, Discriminator][] {
return [...program.stateMap(discriminatorKey).entries()] as any;
}
const parameterVisibilityKey = createStateSymbol("parameterVisibility");
export const $parameterVisibility: ParameterVisibilityDecorator = (

Просмотреть файл

@ -1,7 +1,7 @@
import { reportDiagnostic } from "../core/messages.js";
import { parseMimeType } from "../core/mime-type.js";
import { Program } from "../core/program.js";
import { DecoratorContext, Enum, Model, Type, Union } from "../core/types.js";
import type { Program } from "../core/program.js";
import type { DecoratorContext, Enum, Model, Type, Union } from "../core/types.js";
import { DuplicateTracker } from "../utils/index.js";
function createStateSymbol(name: string) {

Просмотреть файл

@ -2,7 +2,7 @@ import { ServiceDecorator } from "../../generated-defs/TypeSpec.js";
import { validateDecoratorUniqueOnNode } from "../core/decorator-utils.js";
import { Type, getTypeName, reportDeprecated } from "../core/index.js";
import { reportDiagnostic } from "../core/messages.js";
import { Program } from "../core/program.js";
import type { Program } from "../core/program.js";
import { DecoratorContext, Namespace } from "../core/types.js";
export interface ServiceDetails {

Просмотреть файл

@ -54,7 +54,7 @@ import { ResolveModuleHost, resolveModule } from "../core/index.js";
import { getPositionBeforeTrivia } from "../core/parser-utils.js";
import { getNodeAtPosition, visitChildren } from "../core/parser.js";
import { ensureTrailingDirectorySeparator, getDirectoryPath } from "../core/path-utils.js";
import { Program } from "../core/program.js";
import type { Program } from "../core/program.js";
import { skipTrivia, skipWhiteSpace } from "../core/scanner.js";
import { createSourceFile, getSourceFileKindFromExt } from "../core/source-file.js";
import {

Просмотреть файл

@ -1,6 +1,6 @@
import { compilerAssert } from "../core/diagnostics.js";
import { getEntityName, getTypeName, isStdNamespace } from "../core/helpers/type-name-utils.js";
import { Program } from "../core/program.js";
import type { Program } from "../core/program.js";
import { getFullyQualifiedSymbolName } from "../core/type-utils.js";
import {
AliasStatementNode,

Просмотреть файл

@ -37,7 +37,7 @@ import {
WorkspaceFoldersChangeEvent,
} from "vscode-languageserver";
import { TextDocument, TextEdit } from "vscode-languageserver-textdocument";
import { CompilerHost, Program, SourceFile, TypeSpecScriptNode } from "../index.js";
import type { CompilerHost, Program, SourceFile, TypeSpecScriptNode } from "../core/index.js";
export interface ServerHost {
readonly compilerHost: CompilerHost;

Просмотреть файл

@ -1,7 +1,7 @@
import { fail, match, strictEqual } from "assert";
import { Diagnostic, NoTarget, Type, formatDiagnostic, getSourceLocation } from "../core/index.js";
import { isArray } from "../utils/misc.js";
import { resolveVirtualPath } from "./test-host.js";
import { resolveVirtualPath } from "./test-utils.js";
/**
* Assert there is no diagnostics.

Просмотреть файл

@ -10,8 +10,7 @@ import {
} from "../core/index.js";
import { createLinterRuleContext } from "../core/linter.js";
import { DiagnosticMatch, expectDiagnosticEmpty, expectDiagnostics } from "./expect.js";
import { resolveVirtualPath } from "./test-host.js";
import { trimBlankLines } from "./test-utils.js";
import { resolveVirtualPath, trimBlankLines } from "./test-utils.js";
import { BasicTestRunner } from "./types.js";
export interface LinterRuleTester {

Просмотреть файл

@ -1,5 +1,5 @@
import assert from "assert";
import { RmOptions } from "fs";
import type { RmOptions } from "fs";
import { readFile } from "fs/promises";
import { globby } from "globby";
import { fileURLToPath, pathToFileURL } from "url";
@ -9,11 +9,11 @@ import { NodeHost } from "../core/node-host.js";
import { CompilerOptions } from "../core/options.js";
import { getAnyExtensionFromPath, resolvePath } from "../core/path-utils.js";
import { Program, compile as compileProgram } from "../core/program.js";
import { CompilerHost, Diagnostic, StringLiteral, Type } from "../core/types.js";
import type { CompilerHost, Diagnostic, StringLiteral, Type } from "../core/types.js";
import { createSourceFile, getSourceFileKindFromExt } from "../index.js";
import { createStringMap } from "../utils/misc.js";
import { expectDiagnosticEmpty } from "./expect.js";
import { createTestWrapper, findTestPackageRoot } from "./test-utils.js";
import { createTestWrapper, findTestPackageRoot, resolveVirtualPath } from "./test-utils.js";
import {
BasicTestRunner,
TestFileSystem,
@ -29,14 +29,6 @@ export interface TestHostOptions {
compilerHostOverrides?: Partial<CompilerHost>;
}
export function resolveVirtualPath(path: string, ...paths: string[]) {
// NB: We should always resolve an absolute path, and there is no absolute
// path that works across OSes. This ensures that we can still rely on API
// like pathToFileURL in tests.
const rootDir = process.platform === "win32" ? "Z:/test" : "/test";
return resolvePath(rootDir, path, ...paths);
}
function createTestCompilerHost(
virtualFs: Map<string, string>,
jsImports: Map<string, Record<string, any>>,

Просмотреть файл

@ -6,12 +6,8 @@ import { parse, visitChildren } from "../core/parser.js";
import { IdentifierNode, SyntaxKind } from "../core/types.js";
import { Server, ServerHost, createServer } from "../server/index.js";
import { createStringMap } from "../utils/misc.js";
import {
StandardTestLibrary,
TestHostOptions,
createTestFileSystem,
resolveVirtualPath,
} from "./test-host.js";
import { StandardTestLibrary, TestHostOptions, createTestFileSystem } from "./test-host.js";
import { resolveVirtualPath } from "./test-utils.js";
import { TestFileSystem } from "./types.js";
export interface TestServerHost extends ServerHost, TestFileSystem {

Просмотреть файл

@ -9,6 +9,14 @@ import {
TypeSpecTestLibraryInit,
} from "./types.js";
export function resolveVirtualPath(path: string, ...paths: string[]) {
// NB: We should always resolve an absolute path, and there is no absolute
// path that works across OSes. This ensures that we can still rely on API
// like pathToFileURL in tests.
const rootDir = process.platform === "win32" ? "Z:/test" : "/test";
return resolvePath(rootDir, path, ...paths);
}
/** Find the package root from the provided file */
export function findTestPackageRoot(fileUrl: string): Promise<string> {
return findProjectRoot(NodeHost.stat, fileURLToPath(fileUrl)) as Promise<string>;

Просмотреть файл

@ -4,7 +4,7 @@ import { Binder, createBinder } from "../src/core/binder.js";
import { createLogger } from "../src/core/logger/logger.js";
import { createTracer } from "../src/core/logger/tracer.js";
import { parse } from "../src/core/parser.js";
import { Program } from "../src/core/program.js";
import type { Program } from "../src/core/program.js";
import { createSourceFile } from "../src/core/source-file.js";
import {
AliasStatementNode,

Просмотреть файл

@ -1,6 +1,6 @@
import { deepStrictEqual, ok, strictEqual } from "assert";
import { beforeEach, describe, it } from "vitest";
import { Program } from "../../src/core/program.js";
import type { Program } from "../../src/core/program.js";
import { DecoratorContext, Type } from "../../src/core/types.js";
import { TestHost, createTestHost } from "../../src/testing/index.js";
import { createRekeyableMap } from "../../src/utils/misc.js";

Просмотреть файл

@ -1,7 +1,7 @@
import { ok, strictEqual } from "assert";
import { beforeEach, describe, it } from "vitest";
import { getTypeName } from "../../src/core/index.js";
import { Program } from "../../src/core/program.js";
import type { Program } from "../../src/core/program.js";
import { Model, Namespace, Type } from "../../src/core/types.js";
import {
TestHost,

Просмотреть файл

@ -1,8 +1,8 @@
import { deepStrictEqual, fail, ok, strictEqual } from "assert";
import { beforeEach, describe, it } from "vitest";
import { Program, projectProgram } from "../../src/core/program.js";
import type { Program } from "../../src/core/program.js";
import { createProjector } from "../../src/core/projector.js";
import {
import type {
DecoratorArgumentValue,
DecoratorContext,
Enum,
@ -17,6 +17,7 @@ import {
Type,
Union,
} from "../../src/core/types.js";
import { projectProgram } from "../../src/index.js";
import { getDoc } from "../../src/lib/decorators.js";
import { TestHost, createTestHost } from "../../src/testing/index.js";

Просмотреть файл

@ -1,4 +1,4 @@
import { Program } from "@typespec/compiler";
import type { Program } from "@typespec/compiler";
import { reportDiagnostic } from "./lib.js";
import { getAllHttpServices } from "./operations.js";
import { isSharedRoute } from "./route.js";

Просмотреть файл

@ -1,5 +1,5 @@
import { tokens } from "@fluentui/react-components";
import { Program } from "@typespec/compiler";
import type { Program } from "@typespec/compiler";
import { ColorPalette, ColorProvider, TypeSpecProgramViewer } from "@typespec/html-program-viewer";
import { FunctionComponent, useCallback, useEffect, useMemo, useState } from "react";
import { FileOutput } from "../file-output/file-output.js";

Просмотреть файл

@ -1,4 +1,4 @@
import { Program } from "@typespec/compiler";
import type { Program } from "@typespec/compiler";
import { ReactElement } from "react";
export type CompilationCrashed = {