Skip to content

Commit 825263b

Browse files
Scaffold oxlint plugin with initial rule (#2603)
Co-authored-by: codex <codex@users.noreply.github.com>
1 parent 25b02f4 commit 825263b

86 files changed

Lines changed: 1137 additions & 455 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.oxlintrc.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"**/routeTree.gen.ts"
1010
],
1111
"plugins": ["eslint", "oxc", "react", "unicorn", "typescript"],
12+
"jsPlugins": ["./oxlint-plugin-t3code/index.ts"],
1213
"categories": {
1314
"correctness": "warn",
1415
"suspicious": "warn",
@@ -17,6 +18,8 @@
1718
"rules": {
1819
"react-in-jsx-scope": "off",
1920
"eslint/no-shadow": "off",
20-
"eslint/no-await-in-loop": "off"
21+
"eslint/no-await-in-loop": "off",
22+
"eslint/no-underscore-dangle": "off",
23+
"t3code/no-inline-schema-compile": "warn"
2124
}
2225
}

apps/desktop/src/app/DesktopAppIdentity.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const COMMIT_HASH_DISPLAY_LENGTH = 12;
1616
const AppPackageMetadata = Schema.Struct({
1717
t3codeCommitHash: Schema.optional(Schema.String),
1818
});
19+
const decodeAppPackageMetadata = Schema.decodeEffect(Schema.fromJsonString(AppPackageMetadata));
1920

2021
export interface DesktopAppIdentityShape {
2122
readonly resolveUserDataPath: Effect.Effect<string>;
@@ -47,7 +48,7 @@ const make = Effect.gen(function* () {
4748
return yield* Option.match(raw, {
4849
onNone: () => Effect.succeed(Option.none<string>()),
4950
onSome: (value) =>
50-
Schema.decodeEffect(Schema.fromJsonString(AppPackageMetadata))(value).pipe(
51+
decodeAppPackageMetadata(value).pipe(
5152
Effect.map((parsed) =>
5253
Option.fromNullishOr(parsed.t3codeCommitHash).pipe(Option.flatMap(normalizeCommitHash)),
5354
),

apps/desktop/src/backend/DesktopBackendManager.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ import * as DesktopObservability from "../app/DesktopObservability.ts";
2525
import * as DesktopState from "../app/DesktopState.ts";
2626
import * as DesktopWindow from "../window/DesktopWindow.ts";
2727

28+
const decodeDesktopBackendBootstrap = Schema.decodeEffect(
29+
Schema.fromJsonString(DesktopBackendBootstrap),
30+
);
31+
2832
const baseConfig: DesktopBackendManager.DesktopBackendStartConfig = {
2933
executablePath: "/electron",
3034
entryPath: "/server/bin.mjs",
@@ -94,7 +98,7 @@ const healthyHttpClientLayer = httpClientLayer((request) =>
9498
);
9599

96100
function decodeBootstrap(raw: string) {
97-
return Schema.decodeEffect(Schema.fromJsonString(DesktopBackendBootstrap))(raw);
101+
return decodeDesktopBackendBootstrap(raw);
98102
}
99103

100104
function makeManagerLayer(input: {

apps/desktop/src/settings/DesktopClientSettings.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,14 @@ const ClientSettingsDocumentSchema = Schema.Struct({
2020

2121
const ClientSettingsJson = fromLenientJson(ClientSettingsSchema);
2222
const LegacyClientSettingsDocumentJson = fromLenientJson(ClientSettingsDocumentSchema);
23+
const decodeLegacyClientSettingsDocumentJson = Schema.decodeEffect(
24+
LegacyClientSettingsDocumentJson,
25+
);
26+
const decodeClientSettingsJsonValue = Schema.decodeEffect(ClientSettingsJson);
2327
const decodeClientSettingsJson = (raw: string): Effect.Effect<ClientSettings, Schema.SchemaError> =>
24-
Schema.decodeEffect(LegacyClientSettingsDocumentJson)(raw).pipe(
28+
decodeLegacyClientSettingsDocumentJson(raw).pipe(
2529
Effect.map((document) => document.settings),
26-
Effect.catch(() => Schema.decodeEffect(ClientSettingsJson)(raw)),
30+
Effect.catch(() => decodeClientSettingsJsonValue(raw)),
2731
);
2832
const encodeClientSettingsJson = Schema.encodeEffect(ClientSettingsJson);
2933

apps/desktop/src/updates/DesktopUpdates.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ const UpdateInfo = Schema.Struct({
5454
const DownloadProgressInfo = Schema.Struct({
5555
percent: Schema.Number,
5656
});
57+
const decodeAppUpdateYmlConfig = Schema.decodeUnknownEffect(AppUpdateYmlConfig);
58+
const decodeUpdateInfo = Schema.decodeUnknownEffect(UpdateInfo);
59+
const decodeDownloadProgressInfo = Schema.decodeUnknownEffect(DownloadProgressInfo);
5760

5861
const currentIsoTimestamp = DateTime.now.pipe(Effect.map(DateTime.formatIso));
5962

@@ -115,7 +118,7 @@ function parseAppUpdateYml(raw: string): Effect.Effect<Option.Option<AppUpdateYm
115118
}
116119
}
117120

118-
return Schema.decodeUnknownEffect(AppUpdateYmlConfig)(entries).pipe(
121+
return decodeAppUpdateYmlConfig(entries).pipe(
119122
Effect.map((config) => (config.provider ? Option.some(config) : Option.none())),
120123
Effect.catch(() => Effect.succeed(Option.none<AppUpdateYmlConfig>())),
121124
);
@@ -408,7 +411,7 @@ const make = Effect.gen(function* () {
408411
const handleUpdateAvailable = Effect.fn("desktop.updates.handleUpdateAvailable")(function* (
409412
raw: unknown,
410413
) {
411-
yield* Schema.decodeUnknownEffect(UpdateInfo)(raw).pipe(
414+
yield* decodeUpdateInfo(raw).pipe(
412415
Effect.flatMap(
413416
Effect.fn("desktop.updates.applyUpdateAvailable")(function* (info) {
414417
const state = yield* Ref.get(updateStateRef);
@@ -479,7 +482,7 @@ const make = Effect.gen(function* () {
479482
const handleDownloadProgress = Effect.fn("desktop.updates.handleDownloadProgress")(function* (
480483
raw: unknown,
481484
) {
482-
yield* Schema.decodeUnknownEffect(DownloadProgressInfo)(raw).pipe(
485+
yield* decodeDownloadProgressInfo(raw).pipe(
483486
Effect.flatMap(
484487
Effect.fn("desktop.updates.applyDownloadProgress")(function* (progress) {
485488
const state = yield* Ref.get(updateStateRef);
@@ -506,7 +509,7 @@ const make = Effect.gen(function* () {
506509
const handleUpdateDownloaded = Effect.fn("desktop.updates.handleUpdateDownloaded")(function* (
507510
raw: unknown,
508511
) {
509-
yield* Schema.decodeUnknownEffect(UpdateInfo)(raw).pipe(
512+
yield* decodeUpdateInfo(raw).pipe(
510513
Effect.flatMap(
511514
Effect.fn("desktop.updates.applyUpdateDownloaded")(function* (info) {
512515
const state = yield* Ref.get(updateStateRef);

apps/server/integration/OrchestrationEngineHarness.integration.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ import { VcsStatusBroadcaster } from "../src/vcs/VcsStatusBroadcaster.ts";
7979
import { GitWorkflowService } from "../src/git/GitWorkflowService.ts";
8080
import * as VcsProcess from "../src/vcs/VcsProcess.ts";
8181

82+
const decodeCodexSettings = Schema.decodeEffect(CodexSettings);
83+
8284
function runGit(cwd: string, args: ReadonlyArray<string>) {
8385
return execFileSync("git", args, {
8486
cwd,
@@ -266,7 +268,7 @@ export const makeOrchestrationIntegrationHarness = (
266268
const realCodexRegistry = Layer.effect(
267269
ProviderAdapterRegistry,
268270
Effect.gen(function* () {
269-
const codexSettings = Schema.decodeSync(CodexSettings)({});
271+
const codexSettings = yield* decodeCodexSettings({});
270272
const codexAdapter = yield* makeCodexAdapter(codexSettings);
271273
return makeAdapterRegistryMock({
272274
[ProviderDriverKind.make("codex")]: codexAdapter,

apps/server/src/bootstrap.test.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ vi.mock("node:fs", async (importOriginal) => {
3838
});
3939

4040
const TestEnvelopeSchema = Schema.Struct({ mode: Schema.String });
41+
const encodeTestEnvelopeSchema = Schema.encodeEffect(Schema.fromJsonString(TestEnvelopeSchema));
4142

4243
it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => {
4344
it.effect("uses platform-specific fd paths", () =>
@@ -55,9 +56,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => {
5556

5657
yield* fs.writeFileString(
5758
filePath,
58-
`${yield* Schema.encodeEffect(Schema.fromJsonString(TestEnvelopeSchema))({
59-
mode: "desktop",
60-
})}\n`,
59+
`${yield* encodeTestEnvelopeSchema({ mode: "desktop" })}\n`,
6160
);
6261

6362
const fd = yield* Effect.acquireRelease(
@@ -79,9 +78,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => {
7978

8079
yield* fs.writeFileString(
8180
filePath,
82-
`${yield* Schema.encodeEffect(Schema.fromJsonString(TestEnvelopeSchema))({
83-
mode: "desktop",
84-
})}\n`,
81+
`${yield* encodeTestEnvelopeSchema({ mode: "desktop" })}\n`,
8582
);
8683

8784
// Open without acquireRelease: the direct-stream fallback uses autoClose: true,

apps/server/src/diagnostics/ProcessDiagnostics.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class ProcessDiagnosticsError extends Schema.TaggedErrorClass<ProcessDiagnostics
5050
cause: Schema.optional(Schema.Defect),
5151
},
5252
) {}
53+
const isProcessDiagnosticsError = Schema.is(ProcessDiagnosticsError);
5354

5455
function toProcessDiagnosticsError(message: string, cause?: unknown): ProcessDiagnosticsError {
5556
return new ProcessDiagnosticsError({
@@ -316,7 +317,7 @@ const runProcess = Effect.fn("runProcess")(
316317
}),
317318
),
318319
Effect.mapError((cause) =>
319-
Schema.is(ProcessDiagnosticsError)(cause)
320+
isProcessDiagnosticsError(cause)
320321
? cause
321322
: toProcessDiagnosticsError(input.errorMessage, cause),
322323
),

apps/server/src/keybindings.test.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ import {
2323
import { KeybindingsConfigError } from "@t3tools/contracts";
2424

2525
const KeybindingsConfigJson = Schema.fromJsonString(KeybindingsConfig);
26+
const encodeKeybindingsConfigJson = Schema.encodeEffect(KeybindingsConfigJson);
27+
const decodeKeybindingsConfigJson = Schema.decodeUnknownEffect(KeybindingsConfigJson);
28+
const encodeResolvedKeybindingFromConfig = Schema.encodeEffect(ResolvedKeybindingFromConfig);
29+
const decodeResolvedKeybindingFromConfigExit = Schema.decodeUnknownExit(
30+
ResolvedKeybindingFromConfig,
31+
);
2632
const makeKeybindingsLayer = () => {
2733
return KeybindingsLive.pipe(
2834
Layer.provideMerge(
@@ -45,7 +51,7 @@ const writeKeybindingsConfig = (configPath: string, rules: readonly KeybindingRu
4551
Effect.gen(function* () {
4652
const fileSystem = yield* FileSystem.FileSystem;
4753
const path = yield* Path.Path;
48-
const encoded = yield* Schema.encodeEffect(KeybindingsConfigJson)(rules);
54+
const encoded = yield* encodeKeybindingsConfigJson(rules);
4955
yield* fileSystem.makeDirectory(path.dirname(configPath), { recursive: true });
5056
yield* fileSystem.writeFileString(configPath, encoded);
5157
});
@@ -54,7 +60,7 @@ const readKeybindingsConfig = (configPath: string) =>
5460
Effect.gen(function* () {
5561
const fileSystem = yield* FileSystem.FileSystem;
5662
const rawConfig = yield* fileSystem.readFileString(configPath);
57-
return yield* Schema.decodeUnknownEffect(KeybindingsConfigJson)(rawConfig);
63+
return yield* decodeKeybindingsConfigJson(rawConfig);
5864
});
5965

6066
it.layer(NodeServices.layer)("keybindings", (it) => {
@@ -111,7 +117,7 @@ it.layer(NodeServices.layer)("keybindings", (it) => {
111117

112118
it.effect("encodes resolved plus-key shortcuts", () =>
113119
Effect.gen(function* () {
114-
const encoded = yield* Schema.encodeEffect(ResolvedKeybindingFromConfig)({
120+
const encoded = yield* encodeResolvedKeybindingFromConfig({
115121
command: "terminal.toggle",
116122
shortcut: {
117123
key: "+",
@@ -157,7 +163,7 @@ it.layer(NodeServices.layer)("keybindings", (it) => {
157163

158164
it.effect("formats invalid resolved keybinding rules with the custom message", () =>
159165
Effect.sync(() => {
160-
const result = Schema.decodeUnknownExit(ResolvedKeybindingFromConfig)({
166+
const result = decodeResolvedKeybindingFromConfigExit({
161167
key: "mod+shift+d+o",
162168
command: "terminal.new",
163169
});

apps/server/src/keybindings.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ function encodeWhenAst(node: KeybindingWhenNode): string {
170170

171171
const RawKeybindingsEntries = fromLenientJson(Schema.Array(Schema.Unknown));
172172
const KeybindingsConfigPrettyJson = fromJsonStringPretty(KeybindingsConfig);
173+
const decodeKeybindingRuleExit = Schema.decodeUnknownExit(KeybindingRule);
174+
const decodeResolvedKeybindingFromConfigExit = Schema.decodeExit(ResolvedKeybindingFromConfig);
175+
const decodeRawKeybindingsEntriesExit = Schema.decodeUnknownExit(RawKeybindingsEntries);
176+
const encodeKeybindingsConfigPrettyJson = Schema.encodeEffect(KeybindingsConfigPrettyJson);
173177

174178
export interface KeybindingsConfigState {
175179
readonly keybindings: ResolvedKeybindingsConfig;
@@ -344,7 +348,7 @@ const makeKeybindings = Effect.gen(function* () {
344348

345349
return yield* Effect.forEach(rawConfig, (entry) =>
346350
Effect.gen(function* () {
347-
const decodedRule = Schema.decodeUnknownExit(KeybindingRule)(entry);
351+
const decodedRule = decodeKeybindingRuleExit(entry);
348352
if (decodedRule._tag === "Failure") {
349353
yield* Effect.logWarning("ignoring invalid keybinding entry", {
350354
path: keybindingsConfigPath,
@@ -353,7 +357,7 @@ const makeKeybindings = Effect.gen(function* () {
353357
});
354358
return null;
355359
}
356-
const resolved = Schema.decodeExit(ResolvedKeybindingFromConfig)(decodedRule.value);
360+
const resolved = decodeResolvedKeybindingFromConfigExit(decodedRule.value);
357361
if (resolved._tag === "Failure") {
358362
yield* Effect.logWarning("ignoring invalid keybinding entry", {
359363
path: keybindingsConfigPath,
@@ -379,7 +383,7 @@ const makeKeybindings = Effect.gen(function* () {
379383
}
380384

381385
const rawConfig = yield* readRawConfig;
382-
const decodedEntries = Schema.decodeUnknownExit(RawKeybindingsEntries)(rawConfig);
386+
const decodedEntries = decodeRawKeybindingsEntriesExit(rawConfig);
383387
if (decodedEntries._tag === "Failure") {
384388
const detail = `expected JSON array (${Cause.pretty(decodedEntries.cause)})`;
385389
return {
@@ -391,7 +395,7 @@ const makeKeybindings = Effect.gen(function* () {
391395
const keybindings: KeybindingRule[] = [];
392396
const issues: ServerConfigIssue[] = [];
393397
for (const [index, entry] of decodedEntries.value.entries()) {
394-
const decodedRule = Schema.decodeUnknownExit(KeybindingRule)(entry);
398+
const decodedRule = decodeKeybindingRuleExit(entry);
395399
if (decodedRule._tag === "Failure") {
396400
const detail = Cause.pretty(decodedRule.cause);
397401
issues.push(invalidEntryIssue(index, detail));
@@ -404,7 +408,7 @@ const makeKeybindings = Effect.gen(function* () {
404408
continue;
405409
}
406410

407-
const resolvedRule = Schema.decodeExit(ResolvedKeybindingFromConfig)(decodedRule.value);
411+
const resolvedRule = decodeResolvedKeybindingFromConfigExit(decodedRule.value);
408412
if (resolvedRule._tag === "Failure") {
409413
const detail = Cause.pretty(resolvedRule.cause);
410414
issues.push(invalidEntryIssue(index, detail));
@@ -423,7 +427,7 @@ const makeKeybindings = Effect.gen(function* () {
423427
});
424428

425429
const writeConfigAtomically = (rules: readonly KeybindingRule[]) => {
426-
return Schema.encodeEffect(KeybindingsConfigPrettyJson)(rules).pipe(
430+
return encodeKeybindingsConfigPrettyJson(rules).pipe(
427431
Effect.map((encoded) => `${encoded}\n`),
428432
Effect.flatMap((encoded) =>
429433
writeFileStringAtomically({

0 commit comments

Comments
 (0)