effect-start 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -2
- package/src/Entity.ts +6 -6
- package/src/FileRouterCodegen.ts +4 -4
- package/src/FileSystem.ts +4 -8
- package/src/RouteHook.ts +1 -1
- package/src/RouteSse.ts +3 -3
- package/src/SqlIntrospect.ts +2 -2
- package/src/Start.ts +102 -2
- package/src/Values.ts +11 -0
- package/src/bun/BunRoute.ts +1 -1
- package/src/bun/BunRuntime.ts +5 -5
- package/src/hyper/HyperHtml.ts +11 -7
- package/src/hyper/jsx.d.ts +1 -1
- package/src/lint/plugin.js +174 -4
- package/src/sql/SqlClient.ts +355 -0
- package/src/sql/bun/index.ts +117 -50
- package/src/sql/index.ts +1 -1
- package/src/sql/libsql/index.ts +91 -77
- package/src/sql/libsql/libsql.d.ts +4 -1
- package/src/sql/mssql/index.ts +141 -108
- package/src/sql/mssql/mssql.d.ts +1 -0
- package/src/testing/TestLogger.ts +4 -4
- package/src/x/tailwind/compile.ts +6 -14
- package/src/console/Console.ts +0 -42
- package/src/console/ConsoleErrors.ts +0 -213
- package/src/console/ConsoleLogger.ts +0 -56
- package/src/console/ConsoleMetrics.ts +0 -72
- package/src/console/ConsoleProcess.ts +0 -59
- package/src/console/ConsoleStore.ts +0 -187
- package/src/console/ConsoleTracer.ts +0 -107
- package/src/console/Simulation.ts +0 -814
- package/src/console/console.html +0 -340
- package/src/console/index.ts +0 -3
- package/src/console/routes/errors/route.tsx +0 -97
- package/src/console/routes/fiberDetail.tsx +0 -54
- package/src/console/routes/fibers/route.tsx +0 -45
- package/src/console/routes/git/route.tsx +0 -64
- package/src/console/routes/layout.tsx +0 -4
- package/src/console/routes/logs/route.tsx +0 -77
- package/src/console/routes/metrics/route.tsx +0 -36
- package/src/console/routes/route.tsx +0 -8
- package/src/console/routes/routes/route.tsx +0 -30
- package/src/console/routes/services/route.tsx +0 -21
- package/src/console/routes/system/route.tsx +0 -43
- package/src/console/routes/traceDetail.tsx +0 -22
- package/src/console/routes/traces/route.tsx +0 -81
- package/src/console/routes/tree.ts +0 -30
- package/src/console/ui/Errors.tsx +0 -76
- package/src/console/ui/Fibers.tsx +0 -321
- package/src/console/ui/Git.tsx +0 -182
- package/src/console/ui/Logs.tsx +0 -46
- package/src/console/ui/Metrics.tsx +0 -78
- package/src/console/ui/Routes.tsx +0 -125
- package/src/console/ui/Services.tsx +0 -273
- package/src/console/ui/Shell.tsx +0 -62
- package/src/console/ui/System.tsx +0 -131
- package/src/console/ui/Traces.tsx +0 -426
- package/src/sql/Sql.ts +0 -51
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-start",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"src/",
|
|
7
7
|
"!src/**/*.test.ts",
|
|
8
8
|
"!src/**/*.test.tsx",
|
|
9
|
+
"!src/tower",
|
|
9
10
|
"dist/",
|
|
10
11
|
"README.md",
|
|
11
12
|
"package.json"
|
|
@@ -16,7 +17,8 @@
|
|
|
16
17
|
"./bun": "./src/bun/index.ts",
|
|
17
18
|
"./client": "./src/client/index.ts",
|
|
18
19
|
"./testing": "./src/testing/index.ts",
|
|
19
|
-
"./
|
|
20
|
+
"./tower": "./src/tower/index.ts",
|
|
21
|
+
"./sql": "./src/sql/index.ts",
|
|
20
22
|
"./sql/*": "./src/sql/*/index.ts",
|
|
21
23
|
"./x/*": "./src/x/*/index.ts",
|
|
22
24
|
"./x/tailwind/plugin": "./src/x/tailwind/plugin.ts",
|
package/src/Entity.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import * as Effectable from "effect/Effectable"
|
|
1
2
|
import * as Effect from "effect/Effect"
|
|
2
3
|
import * as ParseResult from "effect/ParseResult"
|
|
3
|
-
import * as Pipeable from "effect/Pipeable"
|
|
4
4
|
import * as Predicate from "effect/Predicate"
|
|
5
5
|
import * as Schema from "effect/Schema"
|
|
6
6
|
import * as Stream from "effect/Stream"
|
|
@@ -24,7 +24,7 @@ export type Headers = {
|
|
|
24
24
|
[header: string]: string | null | undefined
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export interface Entity<T = unknown, E = never> extends
|
|
27
|
+
export interface Entity<T = unknown, E = never> extends Effect.Effect<Entity<T, E>, E> {
|
|
28
28
|
readonly [TypeId]: TypeId
|
|
29
29
|
readonly body: T
|
|
30
30
|
readonly headers: Headers
|
|
@@ -57,7 +57,7 @@ export interface Entity<T = unknown, E = never> extends Pipeable.Pipeable {
|
|
|
57
57
|
: Stream.Stream<Uint8Array, ParseResult.ParseError | E>
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
export interface Proto extends
|
|
60
|
+
export interface Proto extends Effect.Effect<Entity, never> {
|
|
61
61
|
readonly [TypeId]: TypeId
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -218,11 +218,11 @@ function getStream(self: Entity<unknown, unknown>): Stream.Stream<unknown, unkno
|
|
|
218
218
|
return Stream.fromEffect(getBytes(self))
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
const Proto: Proto = Object.defineProperties(Object.create(
|
|
221
|
+
const Proto: Proto = Object.defineProperties(Object.create(Effectable.CommitPrototype), {
|
|
222
222
|
[TypeId]: { value: TypeId },
|
|
223
|
-
|
|
223
|
+
commit: {
|
|
224
224
|
value: function (this: Entity) {
|
|
225
|
-
return
|
|
225
|
+
return resolve(this)
|
|
226
226
|
},
|
|
227
227
|
},
|
|
228
228
|
text: {
|
package/src/FileRouterCodegen.ts
CHANGED
|
@@ -166,14 +166,14 @@ export function generateCode(fileRoutes: FileRouter.OrderedFileRoutes): string |
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
const routeEntries = entries
|
|
169
|
-
.map((
|
|
170
|
-
const loadersCode = loaders.join(",\n ")
|
|
171
|
-
return ` "${path}": [\n ${loadersCode},\n ]`
|
|
169
|
+
.map((v) => {
|
|
170
|
+
const loadersCode = v.loaders.join(",\n ")
|
|
171
|
+
return ` "${v.path}": [\n ${loadersCode},\n ]`
|
|
172
172
|
})
|
|
173
173
|
.join(",\n")
|
|
174
174
|
|
|
175
175
|
return `/**
|
|
176
|
-
* Auto-generated by effect-start.
|
|
176
|
+
* Auto-generated by effect-start on startup and changes. Do not edit manually.
|
|
177
177
|
*/
|
|
178
178
|
|
|
179
179
|
export default {
|
package/src/FileSystem.ts
CHANGED
|
@@ -344,14 +344,10 @@ export const make = (
|
|
|
344
344
|
|
|
345
345
|
const fileStream = (
|
|
346
346
|
file: File,
|
|
347
|
-
{
|
|
348
|
-
bufferSize = 16,
|
|
349
|
-
bytesToRead: bytesToRead_,
|
|
350
|
-
chunkSize: chunkSize_ = Size(64 * 1024),
|
|
351
|
-
}: StreamOptions = {},
|
|
347
|
+
options: StreamOptions = {},
|
|
352
348
|
) => {
|
|
353
|
-
const bytesToRead =
|
|
354
|
-
const chunkSize = Size(
|
|
349
|
+
const bytesToRead = options.bytesToRead !== undefined ? Size(options.bytesToRead) : undefined
|
|
350
|
+
const chunkSize = Size(options.chunkSize ?? 64 * 1024)
|
|
355
351
|
|
|
356
352
|
function loop(
|
|
357
353
|
totalBytesRead: bigint,
|
|
@@ -385,6 +381,6 @@ const fileStream = (
|
|
|
385
381
|
}
|
|
386
382
|
|
|
387
383
|
return Stream.bufferChunks(Stream.fromChannel(loop(BigInt(0))), {
|
|
388
|
-
capacity: bufferSize,
|
|
384
|
+
capacity: options.bufferSize ?? 16,
|
|
389
385
|
})
|
|
390
386
|
}
|
package/src/RouteHook.ts
CHANGED
package/src/RouteSse.ts
CHANGED
|
@@ -13,7 +13,7 @@ const HEARTBEAT = ": <3\n\n"
|
|
|
13
13
|
|
|
14
14
|
export interface SseEvent {
|
|
15
15
|
data?: string | undefined
|
|
16
|
-
|
|
16
|
+
type?: string
|
|
17
17
|
retry?: number
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -35,8 +35,8 @@ function formatSseEvent(event: SseEventInput): string {
|
|
|
35
35
|
|
|
36
36
|
const e = event as SseEvent
|
|
37
37
|
let result = ""
|
|
38
|
-
if (e.
|
|
39
|
-
result += `event: ${e.
|
|
38
|
+
if (e.type) {
|
|
39
|
+
result += `event: ${e.type}\n`
|
|
40
40
|
}
|
|
41
41
|
if (typeof e.data === "string") {
|
|
42
42
|
for (const line of e.data.split("\n")) {
|
package/src/SqlIntrospect.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect"
|
|
2
2
|
import * as Schema from "effect/Schema"
|
|
3
|
-
import * as Sql from "./sql/
|
|
3
|
+
import * as Sql from "./sql/SqlClient.ts"
|
|
4
4
|
|
|
5
5
|
export interface Column {
|
|
6
6
|
readonly tableSchema: string
|
|
@@ -496,7 +496,7 @@ export interface DatabaseReader {
|
|
|
496
496
|
const escapeIdentifier = (id: string): string => `"${id.replace(/"/g, '""')}"`
|
|
497
497
|
|
|
498
498
|
const concatSql = (
|
|
499
|
-
sql: Sql.
|
|
499
|
+
sql: Sql.Connection,
|
|
500
500
|
fragments: Array<{ strings: ReadonlyArray<string>; values: Array<unknown> }>,
|
|
501
501
|
): Effect.Effect<ReadonlyArray<unknown>, Sql.SqlError> => {
|
|
502
502
|
const strings: Array<string> = []
|
package/src/Start.ts
CHANGED
|
@@ -2,8 +2,12 @@ import type * as FileSystem from "./FileSystem.ts"
|
|
|
2
2
|
import * as Context from "effect/Context"
|
|
3
3
|
import * as Deferred from "effect/Deferred"
|
|
4
4
|
import * as Effect from "effect/Effect"
|
|
5
|
+
import * as ExecutionStrategy from "effect/ExecutionStrategy"
|
|
6
|
+
import * as Exit from "effect/Exit"
|
|
5
7
|
import * as Function from "effect/Function"
|
|
6
8
|
import * as Layer from "effect/Layer"
|
|
9
|
+
import * as Scope from "effect/Scope"
|
|
10
|
+
import * as SynchronizedRef from "effect/SynchronizedRef"
|
|
7
11
|
import type * as ChildProcess from "./ChildProcess.ts"
|
|
8
12
|
import * as BunRuntime from "./bun/BunRuntime.ts"
|
|
9
13
|
import * as BunServer from "./bun/BunServer.ts"
|
|
@@ -44,8 +48,10 @@ export function layer<
|
|
|
44
48
|
* @since 1.0.0
|
|
45
49
|
* @category constructors
|
|
46
50
|
*/
|
|
47
|
-
export function pack<
|
|
48
|
-
|
|
51
|
+
export function pack<
|
|
52
|
+
const Layers extends readonly [Layer.Layer.Any, ...Array<Layer.Layer.Any>],
|
|
53
|
+
>(
|
|
54
|
+
...layers: Layers & OrderedPack<NoInfer<Layers>, NoInfer<Layers>>
|
|
49
55
|
): Layer.Layer<
|
|
50
56
|
{ [K in keyof Layers]: Layer.Layer.Success<Layers[K]> }[number],
|
|
51
57
|
{ [K in keyof Layers]: Layer.Layer.Error<Layers[K]> }[number],
|
|
@@ -64,6 +70,100 @@ export function pack<const Layers extends readonly [Layer.Layer.Any, ...Array<La
|
|
|
64
70
|
return result as AnyLayer
|
|
65
71
|
}
|
|
66
72
|
|
|
73
|
+
type Unsatisfied<Unmet, Success> =
|
|
74
|
+
Unmet extends Success ? Unmet : never
|
|
75
|
+
|
|
76
|
+
type OrderedPack<
|
|
77
|
+
Layers extends readonly Layer.Layer.Any[],
|
|
78
|
+
All extends readonly Layer.Layer.Any[],
|
|
79
|
+
> = Layers extends readonly [
|
|
80
|
+
infer Head extends Layer.Layer.Any,
|
|
81
|
+
...infer Tail extends Layer.Layer.Any[],
|
|
82
|
+
]
|
|
83
|
+
? [
|
|
84
|
+
[
|
|
85
|
+
Unsatisfied<
|
|
86
|
+
Exclude<Layer.Layer.Context<Head>, { [K in keyof Tail]: Layer.Layer.Success<Tail[K]> }[number]>,
|
|
87
|
+
{ [K in keyof All]: Layer.Layer.Success<All[K]> }[number]
|
|
88
|
+
>,
|
|
89
|
+
] extends [never]
|
|
90
|
+
? Head
|
|
91
|
+
: never,
|
|
92
|
+
...OrderedPack<Tail, All>,
|
|
93
|
+
]
|
|
94
|
+
: []
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Like `pack`, but accepts layers in any order.
|
|
98
|
+
*
|
|
99
|
+
* ```ts
|
|
100
|
+
* // These all produce the same result:
|
|
101
|
+
* Start.build(LoggerLive, DatabaseLive, UserRepoLive)
|
|
102
|
+
* Start.build(UserRepoLive, DatabaseLive, LoggerLive)
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @since 1.0.0
|
|
106
|
+
* @category constructors
|
|
107
|
+
*/
|
|
108
|
+
export function build<
|
|
109
|
+
const Layers extends readonly [Layer.Layer.Any, ...Array<Layer.Layer.Any>],
|
|
110
|
+
>(
|
|
111
|
+
...layers: Layers
|
|
112
|
+
): Layer.Layer<
|
|
113
|
+
{ [K in keyof Layers]: Layer.Layer.Success<Layers[K]> }[number],
|
|
114
|
+
{ [K in keyof Layers]: Layer.Layer.Error<Layers[K]> }[number],
|
|
115
|
+
Exclude<
|
|
116
|
+
{ [K in keyof Layers]: Layer.Layer.Context<Layers[K]> }[number],
|
|
117
|
+
{ [K in keyof Layers]: Layer.Layer.Success<Layers[K]> }[number]
|
|
118
|
+
>
|
|
119
|
+
> {
|
|
120
|
+
type AnyLayer = Layer.Layer<any, any, any>
|
|
121
|
+
const layerArray = layers as unknown as ReadonlyArray<AnyLayer>
|
|
122
|
+
|
|
123
|
+
return Layer.scopedContext(
|
|
124
|
+
Effect.gen(function* () {
|
|
125
|
+
const scope = yield* Effect.scope
|
|
126
|
+
const memoMap = yield* Layer.makeMemoMap
|
|
127
|
+
const memoMapRef = (memoMap as any).ref as SynchronizedRef.SynchronizedRef<Map<AnyLayer, any>>
|
|
128
|
+
let ctx = yield* Effect.context<any>()
|
|
129
|
+
const pending = new Set<AnyLayer>(layerArray)
|
|
130
|
+
|
|
131
|
+
for (let pass = 0; pass < layerArray.length && pending.size > 0; pass++) {
|
|
132
|
+
for (const layer of [...pending]) {
|
|
133
|
+
const childScope = yield* Scope.fork(scope, ExecutionStrategy.sequential)
|
|
134
|
+
const exit = yield* layer.pipe(
|
|
135
|
+
Layer.buildWithMemoMap(memoMap, childScope),
|
|
136
|
+
Effect.provide(ctx),
|
|
137
|
+
Effect.exit,
|
|
138
|
+
)
|
|
139
|
+
if (Exit.isSuccess(exit)) {
|
|
140
|
+
ctx = Context.merge(ctx, exit.value)
|
|
141
|
+
pending.delete(layer)
|
|
142
|
+
} else {
|
|
143
|
+
yield* Scope.close(childScope, exit)
|
|
144
|
+
yield* SynchronizedRef.update(memoMapRef, (map) => {
|
|
145
|
+
map.delete(layer)
|
|
146
|
+
return map
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
for (const layer of pending) {
|
|
153
|
+
const childScope = yield* Scope.fork(scope, ExecutionStrategy.sequential)
|
|
154
|
+
const built = yield* layer.pipe(
|
|
155
|
+
Layer.buildWithMemoMap(memoMap, childScope),
|
|
156
|
+
Effect.provide(ctx),
|
|
157
|
+
)
|
|
158
|
+
ctx = Context.merge(ctx, built)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return ctx
|
|
162
|
+
}),
|
|
163
|
+
// TODO: not sure how to properly type it yet
|
|
164
|
+
) as any
|
|
165
|
+
}
|
|
166
|
+
|
|
67
167
|
export type PlatformServices =
|
|
68
168
|
| BunServer.BunServer
|
|
69
169
|
| FileSystem.FileSystem
|
package/src/Values.ts
CHANGED
|
@@ -73,9 +73,20 @@ export const firstValue = <T>(record: Record<string, T>): T | undefined => {
|
|
|
73
73
|
return undefined
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
export const isTemplateStringsArray = (value: unknown): value is TemplateStringsArray =>
|
|
77
|
+
Array.isArray(value) && "raw" in value
|
|
78
|
+
|
|
76
79
|
export const concatBytes = (a: Uint8Array, b: Uint8Array): Uint8Array => {
|
|
77
80
|
const result = new Uint8Array(a.byteLength + b.byteLength)
|
|
78
81
|
result.set(a)
|
|
79
82
|
result.set(b, a.byteLength)
|
|
80
83
|
return result
|
|
81
84
|
}
|
|
85
|
+
|
|
86
|
+
export const compact = (record: Record<string, unknown | undefined>): Record<string, unknown> => {
|
|
87
|
+
const out: Record<string, unknown> = {}
|
|
88
|
+
for (const [key, value] of Object.entries(record)) {
|
|
89
|
+
if (value !== undefined) out[key] = value
|
|
90
|
+
}
|
|
91
|
+
return out
|
|
92
|
+
}
|
package/src/bun/BunRoute.ts
CHANGED
|
@@ -113,7 +113,7 @@ export function htmlBundle(load: () => HTMLBundleModule | Promise<HTMLBundleModu
|
|
|
113
113
|
}),
|
|
114
114
|
})
|
|
115
115
|
|
|
116
|
-
const childEntity = yield*
|
|
116
|
+
const childEntity = yield* next(context)
|
|
117
117
|
const children = childEntity?.body ?? childEntity
|
|
118
118
|
|
|
119
119
|
let childrenHtml = ""
|
package/src/bun/BunRuntime.ts
CHANGED
|
@@ -7,19 +7,19 @@ const mainFiber = GlobalValue.globalValue(Symbol.for("effect-start/BunRuntime/ex
|
|
|
7
7
|
MutableRef.make<Fiber.RuntimeFiber<unknown, unknown> | undefined>(undefined),
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
-
export const runMain = PlatformRuntime.makeRunMain((
|
|
10
|
+
export const runMain = PlatformRuntime.makeRunMain((options) => {
|
|
11
11
|
const prevFiber = MutableRef.get(mainFiber)
|
|
12
12
|
|
|
13
|
-
MutableRef.set(mainFiber, fiber)
|
|
13
|
+
MutableRef.set(mainFiber, options.fiber)
|
|
14
14
|
|
|
15
15
|
let receivedSignal = false
|
|
16
16
|
|
|
17
|
-
fiber.addObserver((exit) => {
|
|
17
|
+
options.fiber.addObserver((exit) => {
|
|
18
18
|
if (!receivedSignal) {
|
|
19
19
|
process.removeListener("SIGINT", onSigint)
|
|
20
20
|
process.removeListener("SIGTERM", onSigint)
|
|
21
21
|
}
|
|
22
|
-
teardown(exit, (code) => {
|
|
22
|
+
options.teardown(exit, (code) => {
|
|
23
23
|
if (receivedSignal || code !== 0) {
|
|
24
24
|
process.exit(code)
|
|
25
25
|
}
|
|
@@ -30,7 +30,7 @@ export const runMain = PlatformRuntime.makeRunMain(({ fiber, teardown }) => {
|
|
|
30
30
|
receivedSignal = true
|
|
31
31
|
process.removeListener("SIGINT", onSigint)
|
|
32
32
|
process.removeListener("SIGTERM", onSigint)
|
|
33
|
-
fiber.unsafeInterruptAsFork(fiber.id())
|
|
33
|
+
options.fiber.unsafeInterruptAsFork(options.fiber.id())
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
process.on("SIGINT", onSigint)
|
package/src/hyper/HyperHtml.ts
CHANGED
|
@@ -53,6 +53,9 @@ let map = {
|
|
|
53
53
|
|
|
54
54
|
const RAW_TEXT_TAGS = ["script", "style"]
|
|
55
55
|
|
|
56
|
+
// Prevents closing html tags in embedded css/js source
|
|
57
|
+
const escapeRawText = (text: string) => text.replaceAll("</", "<\\/")
|
|
58
|
+
|
|
56
59
|
export function renderToString(
|
|
57
60
|
node: JSX.Children,
|
|
58
61
|
hooks?: { onNode?: (node: HyperNode.HyperNode) => void },
|
|
@@ -113,8 +116,7 @@ export function renderToString(
|
|
|
113
116
|
for (const key in props) {
|
|
114
117
|
if (
|
|
115
118
|
key !== "children" &&
|
|
116
|
-
key !== "
|
|
117
|
-
key !== "dangerouslySetInnerHTML" && // React-specific
|
|
119
|
+
key !== "dangerouslySetInnerHTML" &&
|
|
118
120
|
props[key] !== false &&
|
|
119
121
|
props[key] != null
|
|
120
122
|
) {
|
|
@@ -140,17 +142,19 @@ export function renderToString(
|
|
|
140
142
|
if (!EMPTY_TAGS.includes(type)) {
|
|
141
143
|
stack.push(`</${type}>`)
|
|
142
144
|
|
|
143
|
-
const
|
|
145
|
+
const isRawText = RAW_TEXT_TAGS.includes(type)
|
|
146
|
+
const html = props.dangerouslySetInnerHTML?.__html
|
|
144
147
|
|
|
145
148
|
if (html) {
|
|
146
|
-
result += html
|
|
149
|
+
result += isRawText ? escapeRawText(html) : html
|
|
147
150
|
} else {
|
|
148
151
|
const children = props.children
|
|
149
152
|
|
|
150
153
|
if (type === "script" && typeof children === "function") {
|
|
151
|
-
result += `(${children.toString()})(window)`
|
|
152
|
-
} else if (
|
|
153
|
-
|
|
154
|
+
result += escapeRawText(`(${children.toString()})(window)`)
|
|
155
|
+
} else if (isRawText && children != null) {
|
|
156
|
+
const raw = Array.isArray(children) ? children.join("") : String(children)
|
|
157
|
+
result += escapeRawText(raw)
|
|
154
158
|
} else if (Array.isArray(children)) {
|
|
155
159
|
for (let i = children.length - 1; i >= 0; i--) {
|
|
156
160
|
stack.push(children[i])
|
package/src/hyper/jsx.d.ts
CHANGED
package/src/lint/plugin.js
CHANGED
|
@@ -55,15 +55,41 @@ export default {
|
|
|
55
55
|
|
|
56
56
|
const typePrefix = node.importKind === "type" ? "type " : ""
|
|
57
57
|
|
|
58
|
+
const sourceCode = context.sourceCode || context.getSourceCode()
|
|
59
|
+
|
|
58
60
|
context.report({
|
|
59
61
|
node,
|
|
60
62
|
messageId: "preferNamespace",
|
|
61
63
|
data: { source, baseName, typePrefix },
|
|
62
64
|
fix(fixer) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
const fixes = [
|
|
66
|
+
fixer.replaceText(
|
|
67
|
+
node,
|
|
68
|
+
`import ${typePrefix}* as ${baseName} from "${source}"`,
|
|
69
|
+
),
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
for (const specifier of node.specifiers) {
|
|
73
|
+
if (specifier.type !== "ImportSpecifier") continue
|
|
74
|
+
const localName = specifier.local.name
|
|
75
|
+
const importedName = specifier.imported.name
|
|
76
|
+
|
|
77
|
+
for (const variable of sourceCode.getDeclaredVariables(specifier)) {
|
|
78
|
+
for (const ref of variable.references) {
|
|
79
|
+
if (ref.identifier.range[0] === specifier.local.range[0]) continue
|
|
80
|
+
fixes.push(
|
|
81
|
+
fixer.replaceTextRange(
|
|
82
|
+
ref.identifier.range,
|
|
83
|
+
localName !== importedName
|
|
84
|
+
? `${baseName}.${importedName}`
|
|
85
|
+
: `${baseName}.${localName}`,
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return fixes
|
|
67
93
|
},
|
|
68
94
|
})
|
|
69
95
|
},
|
|
@@ -182,6 +208,150 @@ export default {
|
|
|
182
208
|
},
|
|
183
209
|
},
|
|
184
210
|
|
|
211
|
+
"no-destructured-params": {
|
|
212
|
+
meta: {
|
|
213
|
+
type: "suggestion",
|
|
214
|
+
docs: {
|
|
215
|
+
description: "Disallow destructuring objects in function parameters",
|
|
216
|
+
},
|
|
217
|
+
fixable: "code",
|
|
218
|
+
schema: [],
|
|
219
|
+
messages: {
|
|
220
|
+
noDestructuredParam:
|
|
221
|
+
"Avoid destructuring objects in function parameters. Use a single parameter and access properties on it instead.",
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
create(context) {
|
|
225
|
+
const sourceCode = context.sourceCode || context.getSourceCode()
|
|
226
|
+
|
|
227
|
+
function findUnusedName(scope, base) {
|
|
228
|
+
const names = new Set()
|
|
229
|
+
let current = scope
|
|
230
|
+
while (current) {
|
|
231
|
+
for (const v of current.variables) names.add(v.name)
|
|
232
|
+
current = current.upper
|
|
233
|
+
}
|
|
234
|
+
if (!names.has(base)) return base
|
|
235
|
+
for (let i = 2; ; i++) {
|
|
236
|
+
const candidate = base + i
|
|
237
|
+
if (!names.has(candidate)) return candidate
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function isDefinition(node) {
|
|
242
|
+
if (node.type === "FunctionDeclaration") return true
|
|
243
|
+
const ancestors = sourceCode.getAncestors(node)
|
|
244
|
+
const parent = ancestors[ancestors.length - 1]
|
|
245
|
+
if (!parent) return false
|
|
246
|
+
if (parent.type === "MethodDefinition" || parent.type === "Property" && parent.method) return true
|
|
247
|
+
if (
|
|
248
|
+
parent.type === "VariableDeclarator" &&
|
|
249
|
+
parent.init === node
|
|
250
|
+
) return true
|
|
251
|
+
return false
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function checkParams(node) {
|
|
255
|
+
for (const param of node.params) {
|
|
256
|
+
const pattern =
|
|
257
|
+
param.type === "AssignmentPattern" ? param.left : param
|
|
258
|
+
if (pattern.type !== "ObjectPattern") continue
|
|
259
|
+
|
|
260
|
+
const baseName = isDefinition(node) ? "options" : "v"
|
|
261
|
+
const outerScope = sourceCode.getScope(node).upper || sourceCode.getScope(node)
|
|
262
|
+
const name = findUnusedName(outerScope, baseName)
|
|
263
|
+
|
|
264
|
+
const hasPropertyDefaults = pattern.properties.some(
|
|
265
|
+
(prop) =>
|
|
266
|
+
prop.type !== "RestElement" &&
|
|
267
|
+
prop.value.type === "AssignmentPattern",
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
context.report({
|
|
271
|
+
node: pattern,
|
|
272
|
+
messageId: "noDestructuredParam",
|
|
273
|
+
fix: hasPropertyDefaults ? undefined : (fixer) => {
|
|
274
|
+
const fixes = []
|
|
275
|
+
|
|
276
|
+
const typeAnnotation = pattern.typeAnnotation
|
|
277
|
+
? sourceCode.getText(pattern.typeAnnotation)
|
|
278
|
+
: ""
|
|
279
|
+
const hasDefault = param.type === "AssignmentPattern"
|
|
280
|
+
const defaultValue = hasDefault
|
|
281
|
+
? " = " + sourceCode.getText(param.right)
|
|
282
|
+
: ""
|
|
283
|
+
|
|
284
|
+
fixes.push(
|
|
285
|
+
fixer.replaceTextRange(
|
|
286
|
+
param.range,
|
|
287
|
+
name + typeAnnotation + defaultValue,
|
|
288
|
+
),
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
const fnScope = sourceCode.getScope(node)
|
|
292
|
+
const localToKey = new Map()
|
|
293
|
+
for (const prop of pattern.properties) {
|
|
294
|
+
if (prop.type === "RestElement") continue
|
|
295
|
+
const keyName =
|
|
296
|
+
prop.key.type === "Identifier"
|
|
297
|
+
? prop.key.name
|
|
298
|
+
: sourceCode.getText(prop.key)
|
|
299
|
+
const localNode =
|
|
300
|
+
prop.value.type === "AssignmentPattern"
|
|
301
|
+
? prop.value.left
|
|
302
|
+
: prop.value
|
|
303
|
+
if (localNode.type === "Identifier") {
|
|
304
|
+
localToKey.set(localNode.name, keyName)
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
for (const variable of fnScope.variables) {
|
|
309
|
+
const keyName = localToKey.get(variable.name)
|
|
310
|
+
if (keyName === undefined) continue
|
|
311
|
+
|
|
312
|
+
for (const ref of variable.references) {
|
|
313
|
+
if (ref.identifier.range[0] >= pattern.range[0] &&
|
|
314
|
+
ref.identifier.range[1] <= pattern.range[1]) continue
|
|
315
|
+
|
|
316
|
+
const ancestors = sourceCode.getAncestors(ref.identifier)
|
|
317
|
+
const parent = ancestors[ancestors.length - 1]
|
|
318
|
+
if (
|
|
319
|
+
parent &&
|
|
320
|
+
parent.type === "Property" &&
|
|
321
|
+
parent.shorthand &&
|
|
322
|
+
parent.value === ref.identifier
|
|
323
|
+
) {
|
|
324
|
+
fixes.push(
|
|
325
|
+
fixer.replaceTextRange(
|
|
326
|
+
parent.range,
|
|
327
|
+
keyName + ": " + name + "." + keyName,
|
|
328
|
+
),
|
|
329
|
+
)
|
|
330
|
+
} else {
|
|
331
|
+
fixes.push(
|
|
332
|
+
fixer.replaceTextRange(
|
|
333
|
+
ref.identifier.range,
|
|
334
|
+
name + "." + keyName,
|
|
335
|
+
),
|
|
336
|
+
)
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return fixes
|
|
342
|
+
},
|
|
343
|
+
})
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
FunctionDeclaration: checkParams,
|
|
349
|
+
FunctionExpression: checkParams,
|
|
350
|
+
ArrowFunctionExpression: checkParams,
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
|
|
185
355
|
"test-assertion-newline": {
|
|
186
356
|
meta: {
|
|
187
357
|
type: "layout",
|