Skip to content

Commit

Permalink
make more data types in /platform implement Inspectable (#2357)
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart authored Mar 18, 2024
1 parent 1b3180c commit 71fd528
Show file tree
Hide file tree
Showing 34 changed files with 513 additions and 128 deletions.
10 changes: 10 additions & 0 deletions .changeset/curvy-tips-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@effect/platform-node-shared": patch
"@effect/platform-browser": patch
"@effect/platform-node": patch
"@effect/platform-bun": patch
"@effect/platform": patch
"effect": patch
---

make more data types in /platform implement Inspectable
37 changes: 37 additions & 0 deletions packages/effect/src/Inspectable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,40 @@ export const toJSON = (x: unknown): unknown => {
* @since 2.0.0
*/
export const format = (x: unknown): string => JSON.stringify(x, null, 2)

/**
* @since 2.0.0
*/
export const BaseProto: Inspectable = {
toJSON() {
return toJSON(this)
},
[NodeInspectSymbol]() {
return this.toJSON()
},
toString() {
return format(this.toJSON())
}
}

/**
* @since 2.0.0
*/
export abstract class Class {
/**
* @since 2.0.0
*/
abstract toJSON(): unknown
/**
* @since 2.0.0
*/
[NodeInspectSymbol]() {
return this.toJSON()
}
/**
* @since 2.0.0
*/
toString() {
return format(this.toJSON())
}
}
22 changes: 19 additions & 3 deletions packages/platform-browser/src/internal/http/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as Effect from "effect/Effect"
import * as FiberRef from "effect/FiberRef"
import type { LazyArg } from "effect/Function"
import { globalValue } from "effect/GlobalValue"
import * as Inspectable from "effect/Inspectable"
import * as Layer from "effect/Layer"
import * as Option from "effect/Option"
import * as Stream from "effect/Stream"
Expand Down Expand Up @@ -110,13 +111,14 @@ const sendBody = (
const encoder = new TextEncoder()

/** @internal */
export class IncomingMessageImpl<E> implements IncomingMessage.IncomingMessage<E> {
export abstract class IncomingMessageImpl<E> extends Inspectable.Class implements IncomingMessage.IncomingMessage<E> {
readonly [IncomingMessage.TypeId]: IncomingMessage.TypeId

constructor(
readonly source: XMLHttpRequest,
readonly onError: (error: unknown) => E
) {
super()
this[IncomingMessage.TypeId] = IncomingMessage.TypeId
}

Expand Down Expand Up @@ -249,10 +251,24 @@ class ClientResponseImpl extends IncomingMessageImpl<Error.ResponseError> implem
}

toJSON(): unknown {
let body: unknown
try {
body = Effect.runSync(this.json)
} catch (_) {
//
}
try {
body = body ?? Effect.runSync(this.text)
} catch (_) {
//
}
return {
_tag: "ClientResponse",
_id: "@effect/platform/Http/ClientResponse",
request: this.request.toJSON(),
status: this.status,
headers: this.headers
headers: this.headers,
remoteAddress: this.remoteAddress.toJSON(),
body
}
}
}
Expand Down
11 changes: 10 additions & 1 deletion packages/platform-bun/src/internal/http/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import * as Effect from "effect/Effect"
import * as Exit from "effect/Exit"
import * as FiberSet from "effect/FiberSet"
import { pipe } from "effect/Function"
import * as Inspectable from "effect/Inspectable"
import * as Layer from "effect/Layer"
import * as Option from "effect/Option"
import * as Runtime from "effect/Runtime"
Expand Down Expand Up @@ -216,7 +217,7 @@ function wsDefaultRun(this: WebSocketContext, _: Uint8Array) {
this.buffer.push(_)
}

class ServerRequestImpl implements ServerRequest.ServerRequest {
class ServerRequestImpl extends Inspectable.Class implements ServerRequest.ServerRequest {
readonly [ServerRequest.TypeId]: ServerRequest.TypeId
readonly [IncomingMessage.TypeId]: IncomingMessage.TypeId
constructor(
Expand All @@ -228,9 +229,17 @@ class ServerRequestImpl implements ServerRequest.ServerRequest {
public headersOverride?: Headers.Headers,
private remoteAddressOverride?: string
) {
super()
this[ServerRequest.TypeId] = ServerRequest.TypeId
this[IncomingMessage.TypeId] = IncomingMessage.TypeId
}
toJSON(): unknown {
return IncomingMessage.inspect(this, {
_id: "@effect/platform/Http/ServerRequest",
method: this.method,
url: this.originalUrl
})
}
modify(
options: {
readonly url?: string | undefined
Expand Down
17 changes: 14 additions & 3 deletions packages/platform-node-shared/src/internal/commandExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as FileSystem from "@effect/platform/FileSystem"
import * as Deferred from "effect/Deferred"
import * as Effect from "effect/Effect"
import { constUndefined, pipe } from "effect/Function"
import * as Inspectable from "effect/Inspectable"
import * as Layer from "effect/Layer"
import * as Option from "effect/Option"
import type * as Scope from "effect/Scope"
Expand Down Expand Up @@ -38,6 +39,17 @@ const toPlatformError = (
type ExitCode = readonly [code: number | null, signal: NodeJS.Signals | null]
type ExitCodeDeferred = Deferred.Deferred<ExitCode>

const ProcessProto = {
[CommandExecutor.ProcessTypeId]: CommandExecutor.ProcessTypeId,
...Inspectable.BaseProto,
toJSON(this: CommandExecutor.Process) {
return {
_id: "@effect/platform/CommandExecutor/Process",
pid: this.pid
}
}
}

const runCommand =
(fileSystem: FileSystem.FileSystem) =>
(command: Command.Command): Effect.Effect<CommandExecutor.Process, Error.PlatformError, Scope.Scope> => {
Expand Down Expand Up @@ -146,16 +158,15 @@ const runCommand =
if (typeof command.stdout !== "string") {
stdout = Stream.transduce(stdout, command.stdout)
}
return {
[CommandExecutor.ProcessTypeId]: CommandExecutor.ProcessTypeId,
return Object.assign(Object.create(ProcessProto), {
pid,
exitCode,
isRunning,
kill,
stdin,
stderr,
stdout
}
})
}),
Effect.tap((process) =>
Option.match(command.stdin, {
Expand Down
54 changes: 42 additions & 12 deletions packages/platform-node-shared/src/internal/http/multipart.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as Multipart from "@effect/platform/Http/Multipart"
import * as Effect from "effect/Effect"
import { pipe } from "effect/Function"
import * as Inspectable from "effect/Inspectable"
import * as Stream from "effect/Stream"
import type { MultipartError, PartInfo } from "multipasta"
import { decodeField } from "multipasta"
Expand Down Expand Up @@ -38,14 +39,21 @@ export const persisted = (
Multipart.toPersisted(stream(source, headers), (path, file) =>
Effect.tryPromise({
try: (signal) => NodeStreamP.pipeline((file as FileImpl).file, NFS.createWriteStream(path), { signal }),
catch: (error) => Multipart.MultipartError("InternalError", error)
catch: (error) => new Multipart.MultipartError({ reason: "InternalError", error })
}))

const convertPart = (part: MP.Part): Multipart.Part =>
part._tag === "Field" ? new FieldImpl(part.info, part.value) : new FileImpl(part)

class FieldImpl implements Multipart.Field {
abstract class PartBase extends Inspectable.Class {
readonly [Multipart.TypeId]: Multipart.TypeId
constructor() {
super()
this[Multipart.TypeId] = Multipart.TypeId
}
}

class FieldImpl extends PartBase implements Multipart.Field {
readonly _tag = "Field"
readonly key: string
readonly contentType: string
Expand All @@ -55,27 +63,49 @@ class FieldImpl implements Multipart.Field {
info: PartInfo,
value: Uint8Array
) {
this[Multipart.TypeId] = Multipart.TypeId
super()
this.key = info.name
this.contentType = info.contentType
this.value = decodeField(info, value)
}

toJSON(): unknown {
return {
_id: "@effect/platform/Http/Multipart/Part",
_tag: "Field",
key: this.key,
value: this.value,
contentType: this.contentType
}
}
}

class FileImpl implements Multipart.File {
class FileImpl extends PartBase implements Multipart.File {
readonly _tag = "File"
readonly [Multipart.TypeId]: Multipart.TypeId
readonly key: string
readonly name: string
readonly contentType: string
readonly content: Stream.Stream<Uint8Array, Multipart.MultipartError>

constructor(readonly file: MP.FileStream) {
this[Multipart.TypeId] = Multipart.TypeId
super()
this.key = file.info.name
this.name = file.filename ?? file.info.name
this.contentType = file.info.contentType
this.content = NodeStream.fromReadable(() => file, (error) => Multipart.MultipartError("InternalError", error))
this.content = NodeStream.fromReadable(
() => file,
(error) => new Multipart.MultipartError({ reason: "InternalError", error })
)
}

toJSON(): unknown {
return {
_id: "@effect/platform/Http/Multipart/Part",
_tag: "File",
key: this.key,
name: this.name,
contentType: this.contentType
}
}
}

Expand All @@ -87,21 +117,21 @@ function convertError(error: MultipartError): Multipart.MultipartError {
case "ReachedLimit": {
switch (error.limit) {
case "MaxParts": {
return Multipart.MultipartError("TooManyParts", error)
return new Multipart.MultipartError({ reason: "TooManyParts", error })
}
case "MaxFieldSize": {
return Multipart.MultipartError("FieldTooLarge", error)
return new Multipart.MultipartError({ reason: "FieldTooLarge", error })
}
case "MaxPartSize": {
return Multipart.MultipartError("FileTooLarge", error)
return new Multipart.MultipartError({ reason: "FileTooLarge", error })
}
case "MaxTotalSize": {
return Multipart.MultipartError("BodyTooLarge", error)
return new Multipart.MultipartError({ reason: "BodyTooLarge", error })
}
}
}
default: {
return Multipart.MultipartError("Parse", error)
return new Multipart.MultipartError({ reason: "Parse", error })
}
}
}
5 changes: 4 additions & 1 deletion packages/platform-node-shared/src/internal/path.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BadArgument } from "@effect/platform/Error"
import { Path } from "@effect/platform/Path"
import { Path, TypeId } from "@effect/platform/Path"
import * as Effect from "effect/Effect"
import * as Layer from "effect/Layer"
import * as NodePath from "node:path"
Expand Down Expand Up @@ -31,6 +31,7 @@ const toFileUrl = (path: string): Effect.Effect<URL, BadArgument> =>
export const layerPosix = Layer.succeed(
Path,
Path.of({
[TypeId]: TypeId,
...NodePath.posix,
fromFileUrl,
toFileUrl
Expand All @@ -41,6 +42,7 @@ export const layerPosix = Layer.succeed(
export const layerWin32 = Layer.succeed(
Path,
Path.of({
[TypeId]: TypeId,
...NodePath.win32,
fromFileUrl,
toFileUrl
Expand All @@ -51,6 +53,7 @@ export const layerWin32 = Layer.succeed(
export const layer = Layer.succeed(
Path,
Path.of({
[TypeId]: TypeId,
...NodePath,
fromFileUrl,
toFileUrl
Expand Down
4 changes: 3 additions & 1 deletion packages/platform-node/src/internal/http/incomingMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@ import * as IncomingMessage from "@effect/platform/Http/IncomingMessage"
import * as UrlParams from "@effect/platform/Http/UrlParams"
import * as Effect from "effect/Effect"
import * as FiberRef from "effect/FiberRef"
import * as Inspectable from "effect/Inspectable"
import * as Option from "effect/Option"
import type * as Stream from "effect/Stream"
import type * as Http from "node:http"
import * as NodeStream from "../../NodeStream.js"

/** @internal */
export class IncomingMessageImpl<E> implements IncomingMessage.IncomingMessage<E> {
export abstract class IncomingMessageImpl<E> extends Inspectable.Class implements IncomingMessage.IncomingMessage<E> {
readonly [IncomingMessage.TypeId]: IncomingMessage.TypeId

constructor(
readonly source: Http.IncomingMessage,
readonly onError: (error: unknown) => E,
readonly remoteAddressOverride?: string
) {
super()
this[IncomingMessage.TypeId] = IncomingMessage.TypeId
}

Expand Down
10 changes: 4 additions & 6 deletions packages/platform-node/src/internal/http/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,13 +337,11 @@ class ServerRequestImpl extends IncomingMessageImpl<Error.RequestError> implemen
}

toJSON(): unknown {
return {
_tag: "ServerRequest",
return IncomingMessage.inspect(this, {
_id: "@effect/platform/Http/ServerRequest",
method: this.method,
url: this.url,
originalUrl: this.originalUrl,
headers: this.headers
}
url: this.originalUrl
})
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/platform-node/test/HttpServer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ describe("HttpServer", () => {
Effect.scoped
)
expect(response.status).toEqual(413)
}).pipe(Effect.scoped, runPromise))
}).pipe(Effect.scoped, Effect.tapErrorCause(Effect.log), runPromise))

it("mount", () =>
Effect.gen(function*(_) {
Expand Down
Loading

0 comments on commit 71fd528

Please # to comment.