Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Removes singleton registries #1634

Merged
merged 23 commits into from
Mar 24, 2025
Merged
23 changes: 14 additions & 9 deletions packages/abstractions/src/apiClientBuilder.ts
Original file line number Diff line number Diff line change
@@ -9,60 +9,65 @@

/**
* Registers the default serializer to the registry.
* @param serializationWriterFactoryRegistry The registry to which the default serializer will be registered.
* @param type the class of the factory to be registered.
*/
export function registerDefaultSerializer(type: new () => SerializationWriterFactory): void {
export function registerDefaultSerializer(serializationWriterFactoryRegistry: SerializationWriterFactoryRegistry, type: new () => SerializationWriterFactory): void {

Check warning on line 15 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (18.x)

Use const or class constructors instead of named functions

Check warning on line 15 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (20.x)

Use const or class constructors instead of named functions

Check warning on line 15 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (22.x)

Use const or class constructors instead of named functions
if (!type) throw new Error("Type is required");
const serializer = new type();
SerializationWriterFactoryRegistry.defaultInstance.contentTypeAssociatedFactories.set(serializer.getValidContentType(), serializer);
serializationWriterFactoryRegistry.contentTypeAssociatedFactories.set(serializer.getValidContentType(), serializer);
}
/**
* Registers the default deserializer to the registry.
* @param parseNodeFactoryRegistry The registry to which the default deserializer will be registered.
* @param type the class of the factory to be registered.
*/
export function registerDefaultDeserializer(type: new () => ParseNodeFactory): void {
export function registerDefaultDeserializer(parseNodeFactoryRegistry: ParseNodeFactoryRegistry, type: new () => ParseNodeFactory): void {

Check warning on line 25 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (18.x)

Use const or class constructors instead of named functions

Check warning on line 25 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (20.x)

Use const or class constructors instead of named functions

Check warning on line 25 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (22.x)

Use const or class constructors instead of named functions
if (!type) throw new Error("Type is required");
const deserializer = new type();
ParseNodeFactoryRegistry.defaultInstance.contentTypeAssociatedFactories.set(deserializer.getValidContentType(), deserializer);
parseNodeFactoryRegistry.contentTypeAssociatedFactories.set(deserializer.getValidContentType(), deserializer);
}
/**
* Enables the backing store on default serialization writers and the given serialization writer.
* @param serializationWriterFactoryRegistry The serialization writer factory registry to enable the backing store on.
* @param parseNodeFactoryRegistry The parse node factory registry to enable the backing store on.
* @param original The serialization writer to enable the backing store on.
* @returns A new serialization writer with the backing store enabled.
*/
export function enableBackingStoreForSerializationWriterFactory(original: SerializationWriterFactory): SerializationWriterFactory {
export function enableBackingStoreForSerializationWriterFactory(serializationWriterFactoryRegistry: SerializationWriterFactoryRegistry, parseNodeFactoryRegistry: ParseNodeFactoryRegistry, original: SerializationWriterFactory): SerializationWriterFactory {

Check warning on line 37 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (18.x)

Use const or class constructors instead of named functions

Check warning on line 37 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (20.x)

Use const or class constructors instead of named functions

Check warning on line 37 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (22.x)

Use const or class constructors instead of named functions
if (!original) throw new Error("Original must be specified");
let result = original;
if (original instanceof SerializationWriterFactoryRegistry) {
enableBackingStoreForSerializationRegistry(original);
} else {
result = new BackingStoreSerializationWriterProxyFactory(original);
}
enableBackingStoreForSerializationRegistry(SerializationWriterFactoryRegistry.defaultInstance);
enableBackingStoreForParseNodeRegistry(ParseNodeFactoryRegistry.defaultInstance);
enableBackingStoreForSerializationRegistry(serializationWriterFactoryRegistry);
enableBackingStoreForParseNodeRegistry(parseNodeFactoryRegistry);
return result;
}
/**
* Enables the backing store on default parse node factories and the given parse node factory.
* @param parseNodeFactoryRegistry The parse node factory registry to enable the backing store on.
* @param original The parse node factory to enable the backing store on.
* @returns A new parse node factory with the backing store enabled.
*/
export function enableBackingStoreForParseNodeFactory(original: ParseNodeFactory): ParseNodeFactory {
export function enableBackingStoreForParseNodeFactory(parseNodeFactoryRegistry: ParseNodeFactoryRegistry, original: ParseNodeFactory): ParseNodeFactory {

Check warning on line 55 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (18.x)

Use const or class constructors instead of named functions

Check warning on line 55 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (20.x)

Use const or class constructors instead of named functions

Check warning on line 55 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (22.x)

Use const or class constructors instead of named functions
if (!original) throw new Error("Original must be specified");
let result = original;
if (original instanceof ParseNodeFactoryRegistry) {
enableBackingStoreForParseNodeRegistry(original);
} else {
result = new BackingStoreParseNodeFactory(original);
}
enableBackingStoreForParseNodeRegistry(ParseNodeFactoryRegistry.defaultInstance);
enableBackingStoreForParseNodeRegistry(parseNodeFactoryRegistry);
return result;
}
/**
* Enables the backing store on the given parse node factory registry.
* @param registry The parse node factory registry to enable the backing store on.
*/
function enableBackingStoreForParseNodeRegistry(registry: ParseNodeFactoryRegistry): void {

Check warning on line 70 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (18.x)

Use const or class constructors instead of named functions

Check warning on line 70 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (20.x)

Use const or class constructors instead of named functions

Check warning on line 70 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (22.x)

Use const or class constructors instead of named functions
for (const [k, v] of registry.contentTypeAssociatedFactories) {
if (!(v instanceof BackingStoreParseNodeFactory || v instanceof ParseNodeFactoryRegistry)) {
registry.contentTypeAssociatedFactories.set(k, new BackingStoreParseNodeFactory(v));
@@ -73,7 +78,7 @@
* Enables the backing store on the given serialization factory registry.
* @param registry The serialization factory registry to enable the backing store on.
*/
function enableBackingStoreForSerializationRegistry(registry: SerializationWriterFactoryRegistry): void {

Check warning on line 81 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (18.x)

Use const or class constructors instead of named functions

Check warning on line 81 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (20.x)

Use const or class constructors instead of named functions

Check warning on line 81 in packages/abstractions/src/apiClientBuilder.ts

GitHub Actions / build (22.x)

Use const or class constructors instead of named functions
for (const [k, v] of registry.contentTypeAssociatedFactories) {
if (!(v instanceof BackingStoreSerializationWriterProxyFactory || v instanceof SerializationWriterFactoryRegistry)) {
registry.contentTypeAssociatedFactories.set(k, new BackingStoreSerializationWriterProxyFactory(v));
8 changes: 7 additions & 1 deletion packages/abstractions/src/requestAdapter.ts
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@
import type { DateOnly } from "./dateOnly";
import type { Duration } from "./duration";
import { type RequestInformation } from "./requestInformation";
import type { Parsable, ParsableFactory, SerializationWriterFactory } from "./serialization";
import type { Parsable, ParsableFactory, ParseNodeFactory, SerializationWriterFactory } from "./serialization";
import { type BackingStoreFactory } from "./store";
import type { TimeOnly } from "./timeOnly";

@@ -18,6 +18,12 @@ export interface RequestAdapter {
* @returns the serialization writer factory currently in use for the HTTP core service.
*/
getSerializationWriterFactory(): SerializationWriterFactory;

/**
* Gets the parse node factory currently in use for the HTTP core service.
* @returns the parse node factory currently in use for the HTTP core service.
*/
getParseNodeFactory(): ParseNodeFactory;
/**
* Executes the HTTP request specified by the given RequestInformation and returns the deserialized response model.
* @param requestInfo the request info to execute.
34 changes: 21 additions & 13 deletions packages/abstractions/src/serialization/kiotaJsonSerializer.ts
Original file line number Diff line number Diff line change
@@ -8,64 +8,72 @@ import { deserialize, deserializeCollection, serialize, serializeCollection, ser
import type { Parsable } from "./parsable";
import type { ParsableFactory } from "./parsableFactory";
import type { ModelSerializerFunction } from "./serializationFunctionTypes";
import { SerializationWriterFactoryRegistry } from "./serializationWriterFactoryRegistry";
import type { ParseNodeFactory } from "./parseNodeFactory";

const jsonContentType = "application/json";
/**
* Serializes a parsable object into a buffer
* @param serializationWriterFactoryRegistry the serialization writer factory registry
* @param value the value to serialize
* @param serializationFunction the serialization function for the model type
* @returns a buffer containing the serialized value
*/
export function serializeToJson<T extends Parsable>(value: T, serializationFunction: ModelSerializerFunction<T>): ArrayBuffer {
return serialize(jsonContentType, value, serializationFunction);
export function serializeToJson<T extends Parsable>(serializationWriterFactoryRegistry: SerializationWriterFactoryRegistry, value: T, serializationFunction: ModelSerializerFunction<T>): ArrayBuffer {
return serialize(serializationWriterFactoryRegistry, jsonContentType, value, serializationFunction);
}

/**
* Serializes a parsable object into a string representation
* @param serializationWriterFactoryRegistry the serialization writer factory registry
* @param value the value to serialize
* @param serializationFunction the serialization function for the model type
* @returns a string representing the serialized value
*/
export function serializeToJsonAsString<T extends Parsable>(value: T, serializationFunction: ModelSerializerFunction<T>): string {
return serializeAsString(jsonContentType, value, serializationFunction);
export function serializeToJsonAsString<T extends Parsable>(serializationWriterFactoryRegistry: SerializationWriterFactoryRegistry, value: T, serializationFunction: ModelSerializerFunction<T>): string {
return serializeAsString(serializationWriterFactoryRegistry, jsonContentType, value, serializationFunction);
}

/**
* Serializes a collection of parsable objects into a buffer
* @param serializationWriterFactoryRegistry the serialization writer factory registry
* @param values the value to serialize
* @param serializationFunction the serialization function for the model type
* @returns a string representing the serialized value
*/
export function serializeCollectionToJson<T extends Parsable>(values: T[], serializationFunction: ModelSerializerFunction<T>): ArrayBuffer {
return serializeCollection(jsonContentType, values, serializationFunction);
export function serializeCollectionToJson<T extends Parsable>(serializationWriterFactoryRegistry: SerializationWriterFactoryRegistry, values: T[], serializationFunction: ModelSerializerFunction<T>): ArrayBuffer {
return serializeCollection(serializationWriterFactoryRegistry, jsonContentType, values, serializationFunction);
}

/**
* Serializes a collection of parsable objects into a string representation
* @param serializationWriterFactoryRegistry the serialization writer factory registry
* @param values the value to serialize
* @param serializationFunction the serialization function for the model type
* @returns a string representing the serialized value
*/
export function serializeCollectionToJsonAsString<T extends Parsable>(values: T[], serializationFunction: ModelSerializerFunction<T>): string {
return serializeCollectionAsString(jsonContentType, values, serializationFunction);
export function serializeCollectionToJsonAsString<T extends Parsable>(serializationWriterFactoryRegistry: SerializationWriterFactoryRegistry, values: T[], serializationFunction: ModelSerializerFunction<T>): string {
return serializeCollectionAsString(serializationWriterFactoryRegistry, jsonContentType, values, serializationFunction);
}

/**
* Deserializes a buffer into a parsable object
* @param parseNodeFactory the parse node factory for the content type
* @param bufferOrString the value to serialize
* @param factory the factory for the model type
* @returns the deserialized parsable object
*/
export function deserializeFromJson<T extends Parsable>(bufferOrString: ArrayBuffer | string, factory: ParsableFactory<T>): Parsable {
return deserialize(jsonContentType, bufferOrString, factory);
export function deserializeFromJson<T extends Parsable>(parseNodeFactory: ParseNodeFactory, bufferOrString: ArrayBuffer | string, factory: ParsableFactory<T>): Parsable {
return deserialize(parseNodeFactory, jsonContentType, bufferOrString, factory);
}

/**
* Deserializes a buffer into a a collection of parsable object
* Deserializes a buffer into a collection of parsable object
* @param parseNodeFactory the parse node factory for the content type
* @param bufferOrString the value to serialize
* @param factory the factory for the model type
* @returns the deserialized collection of parsable objects
*/
export function deserializeCollectionFromJson<T extends Parsable>(bufferOrString: ArrayBuffer | string, factory: ParsableFactory<T>): T[] | undefined {
return deserializeCollection(jsonContentType, bufferOrString, factory);
export function deserializeCollectionFromJson<T extends Parsable>(parseNodeFactory: ParseNodeFactory, bufferOrString: ArrayBuffer | string, factory: ParsableFactory<T>): T[] | undefined {
return deserializeCollection(parseNodeFactory, jsonContentType, bufferOrString, factory);
}
46 changes: 27 additions & 19 deletions packages/abstractions/src/serialization/kiotaSerializer.ts
Original file line number Diff line number Diff line change
@@ -7,67 +7,72 @@
import type { Parsable } from "./parsable";
import type { ParsableFactory } from "./parsableFactory";
import type { ParseNode } from "./parseNode";
import { ParseNodeFactoryRegistry } from "./parseNodeFactoryRegistry";
import type { ModelSerializerFunction } from "./serializationFunctionTypes";
import type { SerializationWriter } from "./serializationWriter";
import { SerializationWriterFactoryRegistry } from "./serializationWriterFactoryRegistry";
import { SerializationWriterFactory } from "./serializationWriterFactory";
import { ParseNodeFactory } from "./parseNodeFactory";

/**
* Serializes a parsable object into a buffer
* @param serializationWriterFactory the serialization writer factory for the content type
* @param contentType the content type to serialize to
* @param value the value to serialize
* @param serializationFunction the serialization function for the model type
* @returns a buffer containing the serialized value
*/
export function serialize<T extends Parsable>(contentType: string, value: T, serializationFunction: ModelSerializerFunction<T>): ArrayBuffer {
const writer = getSerializationWriter(contentType, value, serializationFunction);
export function serialize<T extends Parsable>(serializationWriterFactory: SerializationWriterFactory, contentType: string, value: T, serializationFunction: ModelSerializerFunction<T>): ArrayBuffer {
const writer = getSerializationWriter(serializationWriterFactory, contentType, value, serializationFunction);
writer.writeObjectValue(undefined, value, serializationFunction);
return writer.getSerializedContent();
}
/**
* Serializes a parsable object into a string representation
* @param serializationWriterFactory the serialization writer factory for the content type
* @param contentType the content type to serialize to
* @param value the value to serialize
* @param serializationFunction the serialization function for the model type
* @returns a string representing the serialized value
*/
export function serializeToString<T extends Parsable>(contentType: string, value: T, serializationFunction: ModelSerializerFunction<T>): string {
const buffer = serialize(contentType, value, serializationFunction);
export function serializeToString<T extends Parsable>(serializationWriterFactory: SerializationWriterFactory, contentType: string, value: T, serializationFunction: ModelSerializerFunction<T>): string {
const buffer = serialize(serializationWriterFactory, contentType, value, serializationFunction);
return getStringValueFromBuffer(buffer);
}
/**
* Serializes a collection of parsable objects into a buffer
* @param serializationWriterFactory the serialization writer factory for the content type
* @param contentType the content type to serialize to
* @param values the value to serialize
* @param serializationFunction the serialization function for the model type
* @returns a string representing the serialized value
*/
export function serializeCollection<T extends Parsable>(contentType: string, values: T[], serializationFunction: ModelSerializerFunction<T>): ArrayBuffer {
const writer = getSerializationWriter(contentType, values, serializationFunction);
export function serializeCollection<T extends Parsable>(serializationWriterFactory: SerializationWriterFactory, contentType: string, values: T[], serializationFunction: ModelSerializerFunction<T>): ArrayBuffer {
const writer = getSerializationWriter(serializationWriterFactory, contentType, values, serializationFunction);
writer.writeCollectionOfObjectValues(undefined, values, serializationFunction);
return writer.getSerializedContent();
}

/**
* Serializes a collection of parsable objects into a string representation
* @param serializationWriterFactory the serialization writer factory for the content type
* @param contentType the content type to serialize to
* @param values the value to serialize
* @param serializationFunction the serialization function for the model type
* @returns a string representing the serialized value
*/
export function serializeCollectionToString<T extends Parsable>(contentType: string, values: T[], serializationFunction: ModelSerializerFunction<T>): string {
const buffer = serializeCollection(contentType, values, serializationFunction);
export function serializeCollectionToString<T extends Parsable>(serializationWriterFactory: SerializationWriterFactory, contentType: string, values: T[], serializationFunction: ModelSerializerFunction<T>): string {
const buffer = serializeCollection(serializationWriterFactory, contentType, values, serializationFunction);
return getStringValueFromBuffer(buffer);
}

/**
* Gets a serialization writer for a given content type
* @param serializationWriterFactory the serialization writer factory for the content type
* @param contentType the content type to serialize to
* @param value the value to serialize
* @param serializationFunction the serialization function for the model type
* @returns the serialization writer for the given content type
*/
function getSerializationWriter(contentType: string, value: unknown, serializationFunction: unknown): SerializationWriter {
function getSerializationWriter(serializationWriterFactory: SerializationWriterFactory, contentType: string, value: unknown, serializationFunction: unknown): SerializationWriter {
if (!contentType) {
throw new Error("content type cannot be undefined or empty");
}
@@ -77,7 +82,7 @@ function getSerializationWriter(contentType: string, value: unknown, serializati
if (!serializationFunction) {
throw new Error("serializationFunction cannot be undefined");
}
return SerializationWriterFactoryRegistry.defaultInstance.getSerializationWriter(contentType);
return serializationWriterFactory.getSerializationWriter(contentType);
}

/**
@@ -92,26 +97,28 @@ function getStringValueFromBuffer(buffer: ArrayBuffer): string {

/**
* Deserializes a buffer into a parsable object
* @param parseNodeFactory the parse node factory for the content type
* @param contentType the content type to serialize to
* @param bufferOrString the value to serialize
* @param factory the factory for the model type
* @returns the deserialized parsable object
*/
export function deserialize<T extends Parsable>(contentType: string, bufferOrString: ArrayBuffer | string, factory: ParsableFactory<T>): Parsable {
export function deserialize<T extends Parsable>(parseNodeFactory: ParseNodeFactory, contentType: string, bufferOrString: ArrayBuffer | string, factory: ParsableFactory<T>): Parsable {
if (typeof bufferOrString === "string") {
bufferOrString = getBufferFromString(bufferOrString);
}
const reader = getParseNode(contentType, bufferOrString, factory);
const reader = getParseNode(parseNodeFactory, contentType, bufferOrString, factory);
return reader.getObjectValue(factory);
}
/**
* Deserializes a buffer into a parsable object
* @param parseNodeFactory the parse node factory for the content type
* @param contentType the content type to serialize to
* @param buffer the value to deserialize
* @param factory the factory for the model type
* @returns the deserialized parsable object
*/
function getParseNode(contentType: string, buffer: ArrayBuffer, factory: unknown): ParseNode {
function getParseNode(parseNodeFactory: ParseNodeFactory, contentType: string, buffer: ArrayBuffer, factory: unknown): ParseNode {
if (!contentType) {
throw new Error("content type cannot be undefined or empty");
}
@@ -121,20 +128,21 @@ function getParseNode(contentType: string, buffer: ArrayBuffer, factory: unknown
if (!factory) {
throw new Error("factory cannot be undefined");
}
return ParseNodeFactoryRegistry.defaultInstance.getRootParseNode(contentType, buffer);
return parseNodeFactory.getRootParseNode(contentType, buffer);
}
/**
* Deserializes a buffer into a a collection of parsable object
* Deserializes a buffer into a collection of parsable object
* @param parseNodeFactory the parse node factory for the content type
* @param contentType the content type to serialize to
* @param bufferOrString the value to serialize
* @param factory the factory for the model type
* @returns the deserialized collection of parsable objects
*/
export function deserializeCollection<T extends Parsable>(contentType: string, bufferOrString: ArrayBuffer | string, factory: ParsableFactory<T>): T[] | undefined {
export function deserializeCollection<T extends Parsable>(parseNodeFactory: ParseNodeFactory, contentType: string, bufferOrString: ArrayBuffer | string, factory: ParsableFactory<T>): T[] | undefined {
if (typeof bufferOrString === "string") {
bufferOrString = getBufferFromString(bufferOrString);
}
const reader = getParseNode(contentType, bufferOrString, factory);
const reader = getParseNode(parseNodeFactory, contentType, bufferOrString, factory);
return reader.getCollectionOfObjectValues(factory);
}

Loading

Unchanged files with check annotations Beta

* Validates the protocol of the url.
* @param url - The url to validate.
*/
export function validateProtocol(url: string): void {

Check warning on line 14 in packages/abstractions/src/authentication/validateProtocol.ts

GitHub Actions / build (18.x)

Use const or class constructors instead of named functions

Check warning on line 14 in packages/abstractions/src/authentication/validateProtocol.ts

GitHub Actions / build (20.x)

Use const or class constructors instead of named functions

Check warning on line 14 in packages/abstractions/src/authentication/validateProtocol.ts

GitHub Actions / build (22.x)

Use const or class constructors instead of named functions
if (!isLocalhostUrl(url) && !url.toLocaleLowerCase().startsWith("https://") && !windowUrlStartsWithHttps()) {
throw new Error("Authentication scheme can only be used with https requests");
}
* Checks if the window url starts with https.
* @returns True if the window url starts with https, false otherwise.
*/
function windowUrlStartsWithHttps(): boolean {

Check warning on line 24 in packages/abstractions/src/authentication/validateProtocol.ts

GitHub Actions / build (18.x)

Use const or class constructors instead of named functions

Check warning on line 24 in packages/abstractions/src/authentication/validateProtocol.ts

GitHub Actions / build (20.x)

Use const or class constructors instead of named functions

Check warning on line 24 in packages/abstractions/src/authentication/validateProtocol.ts

GitHub Actions / build (22.x)

Use const or class constructors instead of named functions
if (!inNodeEnv()) {
return window.location.protocol.toLocaleLowerCase() === "https:";
}
* @param urlString - The url to check.
* @returns True if the url is a localhost url, false otherwise.
*/
export function isLocalhostUrl(urlString: string): boolean {

Check warning on line 36 in packages/abstractions/src/authentication/validateProtocol.ts

GitHub Actions / build (18.x)

Use const or class constructors instead of named functions

Check warning on line 36 in packages/abstractions/src/authentication/validateProtocol.ts

GitHub Actions / build (20.x)

Use const or class constructors instead of named functions

Check warning on line 36 in packages/abstractions/src/authentication/validateProtocol.ts

GitHub Actions / build (22.x)

Use const or class constructors instead of named functions
try {
const url = new URL(urlString);
return localhostStrings.has(url.hostname);
* @param digits The number of digits to pad
* @returns The formatted segment
*/
export function formatSegment(segment: number, digits = 2): string {

Check warning on line 104 in packages/abstractions/src/dateOnly.ts

GitHub Actions / build (18.x)

Use const or class constructors instead of named functions

Check warning on line 104 in packages/abstractions/src/dateOnly.ts

GitHub Actions / build (20.x)

Use const or class constructors instead of named functions

Check warning on line 104 in packages/abstractions/src/dateOnly.ts

GitHub Actions / build (22.x)

Use const or class constructors instead of named functions
return segment.toString().padStart(digits, "0");
}