From 5e71f460de130b318229c0ae3475e2efe210b6a5 Mon Sep 17 00:00:00 2001 From: Kostya Farber Date: Mon, 20 Apr 2026 20:45:42 +0000 Subject: [PATCH 1/3] refactor: sweep leaky naming suffixes --- Claude.md | 2 +- apps/desktop/src/main/docs/DOCS.md | 4 +- .../desktop/src/main/managers/AppLifecycle.ts | 2 +- apps/desktop/src/main/managers/MenuManager.ts | 12 +++--- apps/desktop/src/preload/preload.ts | 2 +- .../src/renderer/src/bridge/NativeBridge.ts | 10 ++--- .../src/renderer/src/bridge/docs/DOCS.md | 2 +- .../src/renderer/src/context/DebugContext.tsx | 2 +- .../src/renderer/src/lib/clipboard/types.ts | 2 +- .../src/renderer/src/lib/editor/Editor.ts | 12 +++--- .../core/StateDiagram.compliance.test.ts | 4 +- .../pen/behaviors/DragHandlesBehaviour.ts | 10 ++--- .../src/renderer/src/lib/tools/pen/index.ts | 2 +- .../src/renderer/src/lib/tools/pen/types.ts | 10 ++--- .../lib/tools/select/behaviors/BendCurve.ts | 4 +- .../select/behaviors/ContourDoubleClick.ts | 4 +- .../src/lib/tools/select/behaviors/Escape.ts | 4 +- .../src/lib/tools/select/behaviors/Marquee.ts | 4 +- .../src/lib/tools/select/behaviors/Nudge.ts | 4 +- .../src/lib/tools/select/behaviors/Resize.ts | 4 +- .../src/lib/tools/select/behaviors/Rotate.ts | 4 +- .../lib/tools/select/behaviors/Selection.ts | 4 +- .../lib/tools/select/behaviors/TextRunEdit.ts | 4 +- .../tools/select/behaviors/TextRunHover.ts | 4 +- .../tools/select/behaviors/ToggleSmooth.ts | 4 +- .../lib/tools/select/behaviors/Translate.ts | 4 +- .../tools/select/behaviors/UpgradeSegment.ts | 4 +- .../renderer/src/lib/tools/select/index.ts | 2 +- .../renderer/src/lib/tools/select/types.ts | 21 +++++----- .../src/renderer/src/persistence/kernel.ts | 6 +-- .../src/renderer/src/persistence/types.ts | 8 ++-- .../src/renderer/src/types/electron.d.ts | 2 +- apps/desktop/src/renderer/src/types/engine.ts | 2 +- apps/desktop/src/renderer/src/types/focus.ts | 2 +- .../src/renderer/src/types/indicator.ts | 2 +- apps/desktop/src/renderer/src/types/tools.ts | 4 +- .../src/shared/bridge/FontEngineAPI.ts | 6 +-- apps/desktop/src/shared/bridge/docs/DOCS.md | 2 +- apps/desktop/src/shared/ipc/channels.ts | 4 +- apps/desktop/src/shared/ipc/electronAPI.ts | 2 +- apps/desktop/src/shared/ipc/types.ts | 2 +- crates/shift-node/src/font_engine.rs | 10 ++--- packages/glyph-info/scripts/generate.ts | 6 +-- .../scripts/generators/glyphData.ts | 6 +-- .../glyph-info/scripts/generators/search.ts | 4 +- packages/glyph-info/scripts/repl.ts | 2 +- packages/glyph-info/src/GlyphInfo.test.ts | 42 +++++++++---------- packages/glyph-info/src/GlyphInfo.ts | 12 +++--- packages/glyph-info/src/index.ts | 4 +- packages/glyph-info/src/types.ts | 10 ++--- packages/validation/docs/DOCS.md | 6 +-- packages/validation/src/index.ts | 8 ++-- packages/validation/src/persistence.test.ts | 4 +- packages/validation/src/persistence.ts | 10 ++--- 54 files changed, 158 insertions(+), 159 deletions(-) diff --git a/Claude.md b/Claude.md index 39937f4d..907e3eb4 100644 --- a/Claude.md +++ b/Claude.md @@ -7,7 +7,7 @@ ## Naming -- **Domain types are plain nouns.** `Glyph`, `Contour`, `Point`, `Anchor` — not `GlyphData`, `GlyphInfo`, `GlyphState`, `GlyphRenderData`. If you need a modifier, it should describe the _kind_ of thing (`EditableGlyph`, `RenderContour`), not append generic suffixes. +- **Domain types are plain nouns.** `Glyph`, `Contour`, `Point`, `Anchor` — not `Glyph`, `GlyphInfo`, `GlyphState`, `GlyphRenderData`. If you need a modifier, it should describe the _kind_ of thing (`EditableGlyph`, `RenderContour`), not append generic suffixes. - **Avoid `-Data`, `-Info`, `-State` suffixes** on types unless it genuinely represents transient mutable state (e.g. `TextRunRenderState` for a signal value consumed by a render pass). If the type represents a domain concept, name it after the concept. ## Roadmap diff --git a/apps/desktop/src/main/docs/DOCS.md b/apps/desktop/src/main/docs/DOCS.md index 16aa77c3..c2d7bd52 100644 --- a/apps/desktop/src/main/docs/DOCS.md +++ b/apps/desktop/src/main/docs/DOCS.md @@ -29,7 +29,7 @@ src/main/ ## Key Types - `ThemeName` -- `"light" | "dark" | "system"`, stored in `MenuManager.currentTheme` -- `DebugState` -- aggregates `reactScanEnabled`, `debugPanelOpen`, and `DebugOverlays`; only used in dev builds +- `Debug` -- aggregates `reactScanEnabled`, `debugPanelOpen`, and `DebugOverlays`; only used in dev builds - `DebugOverlays` -- per-overlay booleans (`tightBounds`, `hitRadii`, `segmentBounds`, `glyphBbox`) - `IpcCommands` -- renderer-to-main request/response channels (invoke/handle) - `IpcEvents` -- main-to-renderer broadcast channels (send/on) @@ -110,5 +110,5 @@ IPC handlers are split across managers. `WindowManager` registers window-control - `IpcCommands`, `IpcEvents` -- type-safe IPC channel definitions in `shared/ipc/channels.ts` - `ipc.send`, `ipc.handle` -- typed wrappers in `shared/ipc/main.ts` -- `ThemeName`, `DebugState`, `DebugOverlays` -- shared types in `shared/ipc/types.ts` +- `ThemeName`, `Debug`, `DebugOverlays` -- shared types in `shared/ipc/types.ts` - Preload bridge -- exposes IPC to renderer (see preload DOCS.md) diff --git a/apps/desktop/src/main/managers/AppLifecycle.ts b/apps/desktop/src/main/managers/AppLifecycle.ts index 76fdd021..e7452ad7 100644 --- a/apps/desktop/src/main/managers/AppLifecycle.ts +++ b/apps/desktop/src/main/managers/AppLifecycle.ts @@ -203,7 +203,7 @@ export class AppLifecycle { this.menuManager.setTheme(theme); }); - ipc.handle(ipcMain, "debug:getState", () => this.menuManager.getDebugState()); + ipc.handle(ipcMain, "debug:getState", () => this.menuManager.getDebug()); ipc.handle(ipcMain, "dialog:openFont", async () => { const result = await dialog.showOpenDialog({ diff --git a/apps/desktop/src/main/managers/MenuManager.ts b/apps/desktop/src/main/managers/MenuManager.ts index 100493be..b3d41b00 100644 --- a/apps/desktop/src/main/managers/MenuManager.ts +++ b/apps/desktop/src/main/managers/MenuManager.ts @@ -1,7 +1,7 @@ import { Menu, dialog, nativeTheme, app } from "electron"; import type { DocumentState } from "./DocumentState"; import type { WindowManager } from "./WindowManager"; -import type { ThemeName, DebugOverlays, DebugState } from "../../shared/ipc/types"; +import type { ThemeName, DebugOverlays, Debug } from "../../shared/ipc/types"; import type { IpcEvents } from "../../shared/ipc/channels"; import * as ipc from "../../shared/ipc/main"; @@ -9,7 +9,7 @@ export class MenuManager { private documentState: DocumentState; private windowManager: WindowManager; private currentTheme: ThemeName = "light"; - private debugState: DebugState = { + private debugState: Debug = { reactScanEnabled: false, debugPanelOpen: false, overlays: { @@ -29,7 +29,7 @@ export class MenuManager { return this.currentTheme; } - getDebugState(): DebugState { + getDebug(): Debug { return { ...this.debugState }; } @@ -42,7 +42,7 @@ export class MenuManager { ipc.send(webContents, channel, ...args); } - private setDebugState(key: K, value: DebugState[K]) { + private setDebug(key: K, value: Debug[K]) { this.debugState[key] = value; switch (key) { case "reactScanEnabled": @@ -263,14 +263,14 @@ export class MenuManager { type: "checkbox" as const, checked: this.debugState.reactScanEnabled, click: () => - this.setDebugState("reactScanEnabled", !this.debugState.reactScanEnabled), + this.setDebug("reactScanEnabled", !this.debugState.reactScanEnabled), }, { label: "Debug Panel", type: "checkbox" as const, checked: this.debugState.debugPanelOpen, click: () => - this.setDebugState("debugPanelOpen", !this.debugState.debugPanelOpen), + this.setDebug("debugPanelOpen", !this.debugState.debugPanelOpen), }, { type: "separator" as const }, { diff --git a/apps/desktop/src/preload/preload.ts b/apps/desktop/src/preload/preload.ts index 05b3fe01..7f991668 100644 --- a/apps/desktop/src/preload/preload.ts +++ b/apps/desktop/src/preload/preload.ts @@ -41,7 +41,7 @@ const electronAPI: ElectronAPI = { setDocumentDirty: invoke("document:setDirty"), setDocumentFilePath: invoke("document:setFilePath"), saveCompleted: invoke("document:saveCompleted"), - getDebugState: invoke("debug:getState"), + getDebug: invoke("debug:getState"), pathsExist: invoke("fs:pathsExist"), // Events diff --git a/apps/desktop/src/renderer/src/bridge/NativeBridge.ts b/apps/desktop/src/renderer/src/bridge/NativeBridge.ts index b389b56f..18efed88 100644 --- a/apps/desktop/src/renderer/src/bridge/NativeBridge.ts +++ b/apps/desktop/src/renderer/src/bridge/NativeBridge.ts @@ -23,8 +23,8 @@ import { constrainDrag } from "@shift/rules"; import { ValidateSnapshot } from "@shift/validation"; import { Glyphs } from "@shift/font"; import type { FontEngineAPI } from "@shared/bridge/FontEngineAPI"; -import type { CompositeComponentsPayload } from "@shared/bridge/FontEngineAPI"; -import type { CommandResponse, PasteResult, PointEdit } from "@/types/engine"; +import type { CompositeComponents } from "@shared/bridge/FontEngineAPI"; +import type { CommandResult, PasteResult, PointEdit } from "@/types/engine"; import { ContourContent } from "@/lib/clipboard"; import type { NodePositionUpdateList } from "@/types/positionUpdate"; import { Glyph, type GlyphChange } from "@/lib/model/Glyph"; @@ -141,10 +141,10 @@ export class NativeBridge { return svg ? new Path2D(svg) : null; } - getGlyphCompositeComponents(glyphName: string): CompositeComponentsPayload | null { + getGlyphCompositeComponents(glyphName: string): CompositeComponents | null { const payload = this.#raw.getGlyphCompositeComponents(glyphName); if (!payload) return null; - return JSON.parse(payload) as CompositeComponentsPayload; + return JSON.parse(payload) as CompositeComponents; } /** @knipclassignore — used by VariationPanel component */ @@ -184,7 +184,7 @@ export class NativeBridge { return JSON.parse(this.#raw.getSnapshotData()) as GlyphSnapshot; } - #execute(json: string): CommandResponse { + #execute(json: string): CommandResult { const raw = JSON.parse(json); if (!raw.success) { throw new NativeOperationError(raw.error ?? "Unknown native error"); diff --git a/apps/desktop/src/renderer/src/bridge/docs/DOCS.md b/apps/desktop/src/renderer/src/bridge/docs/DOCS.md index b5d68860..1a5826c6 100644 --- a/apps/desktop/src/renderer/src/bridge/docs/DOCS.md +++ b/apps/desktop/src/renderer/src/bridge/docs/DOCS.md @@ -49,7 +49,7 @@ The bridge separates JS-side reactivity from Rust-side persistence. Not every mu `#dispatch` / `#dispatchVoid` are the standard Rust command path for structural mutations (addPoint, removePoints, closeContour, etc.): 1. Call NAPI method, receive JSON string -2. `#execute` parses JSON, checks `success`, extracts `CommandResponse` (snapshot + affectedPointIds) +2. `#execute` parses JSON, checks `success`, extracts `CommandResult` (snapshot + affectedPointIds) 3. `#syncFromResponse` applies the returned snapshot to the reactive `Glyph` via `Glyph.apply` ### NAPI position sync diff --git a/apps/desktop/src/renderer/src/context/DebugContext.tsx b/apps/desktop/src/renderer/src/context/DebugContext.tsx index 58a08fce..d074ab86 100644 --- a/apps/desktop/src/renderer/src/context/DebugContext.tsx +++ b/apps/desktop/src/renderer/src/context/DebugContext.tsx @@ -56,7 +56,7 @@ export function DebugProvider({ children }: DebugProviderProps) { useEffect(() => { if (!isDev) return undefined; - window.electronAPI?.getDebugState().then((state) => { + window.electronAPI?.getDebug().then((state) => { setReactScanEnabled(state.reactScanEnabled); setDebugPanelOpen(state.debugPanelOpen); if (state.overlays) { diff --git a/apps/desktop/src/renderer/src/lib/clipboard/types.ts b/apps/desktop/src/renderer/src/lib/clipboard/types.ts index a6fd6cdd..607ec1cc 100644 --- a/apps/desktop/src/renderer/src/lib/clipboard/types.ts +++ b/apps/desktop/src/renderer/src/lib/clipboard/types.ts @@ -54,7 +54,7 @@ export interface SystemClipboard { } /** Current in-memory clipboard state held by the clipboard service. */ -export interface ClipboardState { +export interface Clipboard { content: ClipboardContent | null; bounds: Rect2D | null; timestamp: number; diff --git a/apps/desktop/src/renderer/src/lib/editor/Editor.ts b/apps/desktop/src/renderer/src/lib/editor/Editor.ts index 77fd0bd1..c37a0474 100644 --- a/apps/desktop/src/renderer/src/lib/editor/Editor.ts +++ b/apps/desktop/src/renderer/src/lib/editor/Editor.ts @@ -84,8 +84,8 @@ import type { } from "./snapping/types"; import { SnapManager } from "./managers/SnapManager"; import { TextRunController } from "@/lib/tools/text/TextRunController"; -import { SnapPreferencesSchema, TextRunModulePayloadSchema } from "@shift/validation"; -import type { TextRunModulePayload } from "@/persistence/types"; +import { SnapPreferencesSchema, TextRunModuleSchema } from "@shift/validation"; +import type { TextRunModule } from "@/persistence/types"; interface AppSettings { snap: SnapPreferences; @@ -102,7 +102,7 @@ const defaultAppSettings: AppSettings = { }, }; import type { CompositeGlyph } from "@shift/types"; -import type { ToolDescriptor, ToolShortcutEntry } from "@/types/tools"; +import type { ToolManifest, ToolShortcutEntry } from "@/types/tools"; import type { ToolStateScope } from "@/types/editor"; import { EventEmitter } from "./lifecycle"; import { StateRegistry, type ShiftState, type ShiftStateOptions } from "@/lib/state/ShiftState"; @@ -294,13 +294,13 @@ export class Editor { this.#textRunController = new TextRunController(); this.#textRunController.setFont(this.font); - const textRunPersistence = this.registerState({ + const textRunPersistence = this.registerState({ id: "text-run", scope: "document", initial: () => ({ runsByGlyph: {} }), serialize: () => ({ runsByGlyph: this.#textRunController.exportRuns() }), deserialize: (json) => { - const payload = TextRunModulePayloadSchema.parse(json); + const payload = TextRunModuleSchema.parse(json); this.#textRunController.hydrateRuns(payload.runsByGlyph); return payload; }, @@ -386,7 +386,7 @@ export class Editor { }); } - public registerTool(descriptor: ToolDescriptor): void { + public registerTool(descriptor: ToolManifest): void { const { id, icon, tooltip, shortcut } = descriptor; this.#toolMetadata.set(id, shortcut ? { icon, tooltip, shortcut } : { icon, tooltip }); this.toolManager.register(descriptor); diff --git a/apps/desktop/src/renderer/src/lib/tools/core/StateDiagram.compliance.test.ts b/apps/desktop/src/renderer/src/lib/tools/core/StateDiagram.compliance.test.ts index ef7eca6f..be9e0f30 100644 --- a/apps/desktop/src/renderer/src/lib/tools/core/StateDiagram.compliance.test.ts +++ b/apps/desktop/src/renderer/src/lib/tools/core/StateDiagram.compliance.test.ts @@ -8,7 +8,7 @@ import { Shape } from "../shape/Shape"; import { Pen } from "../pen/Pen"; import { Select } from "../select/Select"; import { asPointId } from "@shift/types"; -import type { HandleData } from "../pen/types"; +import type { Handles } from "../pen/types"; const p = { x: 0, y: 0 }; const coordsP = makeTestCoordinates(p); @@ -188,7 +188,7 @@ describe("State diagram compliance", () => { const draggingState = { type: "dragging" as const, anchor: anchor.anchor, - handles: {} as HandleData, + handles: {} as Handles, mousePos: p, }; diff --git a/apps/desktop/src/renderer/src/lib/tools/pen/behaviors/DragHandlesBehaviour.ts b/apps/desktop/src/renderer/src/lib/tools/pen/behaviors/DragHandlesBehaviour.ts index 61e3718b..5a8d538c 100644 --- a/apps/desktop/src/renderer/src/lib/tools/pen/behaviors/DragHandlesBehaviour.ts +++ b/apps/desktop/src/renderer/src/lib/tools/pen/behaviors/DragHandlesBehaviour.ts @@ -5,7 +5,7 @@ import { Validate } from "@shift/validation"; import type { ToolContext } from "../../core/Behavior"; import type { Editor } from "@/lib/editor/Editor"; import type { ToolEventOf } from "../../core/GestureDetector"; -import type { PenState, PenBehavior, AnchorData, HandleData } from "../types"; +import type { PenState, PenBehavior, Anchor, Handles } from "../types"; import type { DragSnapSession } from "@/lib/editor/snapping/types"; const DRAG_THRESHOLD = 3; @@ -123,7 +123,7 @@ export class HandleBehavior implements PenBehavior { }; } - #createHandles(anchor: AnchorData, snappedPos: Point2D, editor: Editor): HandleData { + #createHandles(anchor: Anchor, snappedPos: Point2D, editor: Editor): Handles { const glyph = editor.glyph.peek(); if (!glyph) return {}; @@ -194,8 +194,8 @@ export class HandleBehavior implements PenBehavior { } #updateHandles( - anchor: AnchorData, - handles: HandleData, + anchor: Anchor, + handles: Handles, snappedPos: Point2D, editor: Editor, ): void { @@ -212,7 +212,7 @@ export class HandleBehavior implements PenBehavior { } } - #startSnap(editor: Editor, anchor: AnchorData): void { + #startSnap(editor: Editor, anchor: Anchor): void { if (!anchor.pointId) return; this.#clearSnap(); diff --git a/apps/desktop/src/renderer/src/lib/tools/pen/index.ts b/apps/desktop/src/renderer/src/lib/tools/pen/index.ts index 5efc01e2..39c4c906 100644 --- a/apps/desktop/src/renderer/src/lib/tools/pen/index.ts +++ b/apps/desktop/src/renderer/src/lib/tools/pen/index.ts @@ -1,3 +1,3 @@ export { Pen, type PenState } from "./Pen"; -export type { AnchorData, HandleData, PenBehavior } from "./types"; +export type { Anchor, Handles, PenBehavior } from "./types"; export { PenDownBehaviour, HandleBehavior, EscapeBehavior } from "./behaviors"; diff --git a/apps/desktop/src/renderer/src/lib/tools/pen/types.ts b/apps/desktop/src/renderer/src/lib/tools/pen/types.ts index 25425636..d69082bd 100644 --- a/apps/desktop/src/renderer/src/lib/tools/pen/types.ts +++ b/apps/desktop/src/renderer/src/lib/tools/pen/types.ts @@ -1,12 +1,12 @@ import type { Point2D, PointId } from "@shift/types"; import type { Behavior } from "../core/Behavior"; -export interface AnchorData { +export interface Anchor { position: Point2D; pointId?: PointId; } -export interface HandleData { +export interface Handles { cpIn?: PointId; cpOut?: PointId; } @@ -14,11 +14,11 @@ export interface HandleData { export type PenState = | { type: "idle" } | { type: "ready"; mousePos: Point2D } - | { type: "anchored"; anchor: AnchorData } + | { type: "anchored"; anchor: Anchor } | { type: "dragging"; - anchor: AnchorData; - handles: HandleData; + anchor: Anchor; + handles: Handles; mousePos: Point2D; snappedPos?: Point2D; }; diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/BendCurve.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/BendCurve.ts index 0adff76d..995bf1d0 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/BendCurve.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/BendCurve.ts @@ -1,10 +1,10 @@ import { Vec2 } from "@shift/geo"; import type { ToolContext } from "../../core/Behavior"; import type { ToolEventOf } from "../../core/GestureDetector"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; import type { GlyphDraft } from "@/types/draft"; -export class BendCurve implements SelectHandlerBehavior { +export class BendCurve implements SelectBehavior { #draft: GlyphDraft | null = null; #hasChanges = false; diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/ContourDoubleClick.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/ContourDoubleClick.ts index 56e77110..f8a12fc9 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/ContourDoubleClick.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/ContourDoubleClick.ts @@ -1,12 +1,12 @@ import type { ToolContext } from "../../core/Behavior"; import type { ToolEventOf } from "../../core/GestureDetector"; import type { Editor } from "@/lib/editor/Editor"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; import type { PointId } from "@shift/types"; import type { SegmentId } from "@/types/indicator"; import { isSegmentHit } from "@/types/hitResult"; -export class ContourDoubleClick implements SelectHandlerBehavior { +export class ContourDoubleClick implements SelectBehavior { onDoubleClick( state: SelectState, ctx: ToolContext, diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Escape.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Escape.ts index 1eff8eb0..2d00761b 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Escape.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Escape.ts @@ -1,8 +1,8 @@ import type { ToolContext } from "../../core/Behavior"; import type { ToolEventOf } from "../../core/GestureDetector"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; -export class Escape implements SelectHandlerBehavior { +export class Escape implements SelectBehavior { onKeyDown( state: SelectState, ctx: ToolContext, diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Marquee.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Marquee.ts index 06954d44..166b3bc5 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Marquee.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Marquee.ts @@ -1,10 +1,10 @@ import type { PointId, Rect2D } from "@shift/types"; import type { ToolContext } from "../../core/Behavior"; import type { ToolEventOf } from "../../core/GestureDetector"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; import { normalizeRect, pointInRect } from "../utils"; -export class Marquee implements SelectHandlerBehavior { +export class Marquee implements SelectBehavior { onDragStart( state: SelectState, ctx: ToolContext, diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Nudge.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Nudge.ts index 643ea534..c3374410 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Nudge.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Nudge.ts @@ -1,9 +1,9 @@ import type { ToolContext } from "../../core/Behavior"; import type { ToolEventOf } from "../../core/GestureDetector"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; import { NUDGES_VALUES, type NudgeMagnitude } from "@/types/nudge"; -export class Nudge implements SelectHandlerBehavior { +export class Nudge implements SelectBehavior { onKeyDown( state: SelectState, ctx: ToolContext, diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Resize.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Resize.ts index 47af200e..b1b9b258 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Resize.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Resize.ts @@ -5,12 +5,12 @@ import type { ToolContext } from "../../core/Behavior"; import type { Editor } from "@/lib/editor/Editor"; import type { DragTarget } from "../types"; import type { ToolEventOf } from "../../core/GestureDetector"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; import type { BoundingRectEdge } from "../cursor"; import type { GlyphDraft } from "@/types/draft"; import type { NodePositionUpdateList } from "@/types/positionUpdate"; -export class Resize implements SelectHandlerBehavior { +export class Resize implements SelectBehavior { #draft: GlyphDraft | null = null; #target: DragTarget | null = null; #origin: Point2D | null = null; diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Rotate.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Rotate.ts index 7bd7c849..9b00ffb7 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Rotate.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Rotate.ts @@ -4,7 +4,7 @@ import type { GlyphSnapshot, Point2D } from "@shift/types"; import type { ToolContext } from "../../core/Behavior"; import type { Editor } from "@/lib/editor/Editor"; import type { ToolEventOf } from "../../core/GestureDetector"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; import type { CornerHandle } from "@/types/boundingBox"; import type { RotateSnapSession } from "@/lib/editor/snapping/types"; import type { GlyphDraft } from "@/types/draft"; @@ -12,7 +12,7 @@ import type { GlyphDraft } from "@/types/draft"; import type { NodePositionUpdateList } from "@/types/positionUpdate"; import type { DragTarget } from "../types"; -export class Rotate implements SelectHandlerBehavior { +export class Rotate implements SelectBehavior { #snap: RotateSnapSession | null = null; #draft: GlyphDraft | null = null; #target: DragTarget | null = null; diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Selection.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Selection.ts index b4ee52b4..cff53974 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Selection.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Selection.ts @@ -1,7 +1,7 @@ import type { ToolContext } from "../../core/Behavior"; import type { ToolEventOf } from "../../core/GestureDetector"; import type { Editor } from "@/lib/editor/Editor"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; import type { PointId, AnchorId } from "@shift/types"; import type { SegmentId } from "@/types/indicator"; import { getPointIdFromHit, isAnchorHit, isSegmentHit } from "@/types/hitResult"; @@ -15,7 +15,7 @@ function nextSelectionStateAfterToggle( return nextInTypeCount + selectedInOtherTypesCount > 0 ? "selected" : "ready"; } -export class Selection implements SelectHandlerBehavior { +export class Selection implements SelectBehavior { onClick(state: SelectState, ctx: ToolContext, event: ToolEventOf<"click">): boolean { if (state.type !== "ready" && state.type !== "selected") return false; const editor = ctx.editor; diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/TextRunEdit.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/TextRunEdit.ts index 7dd312aa..22707b9c 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/TextRunEdit.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/TextRunEdit.ts @@ -1,6 +1,6 @@ import type { ToolEventOf } from "../../core/GestureDetector"; import type { ToolContext } from "../../core/Behavior"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; import { hitTestTextSlot, type GlyphRef } from "../../text/layout"; import { resolveComponentAtPoint } from "@/lib/editor/hit/composite"; @@ -10,7 +10,7 @@ import { resolveComponentAtPoint } from "@/lib/editor/hit/composite"; * Takes priority over the normal double-click-select-contour behavior * when a text run is active. */ -export class TextRunEdit implements SelectHandlerBehavior { +export class TextRunEdit implements SelectBehavior { onDoubleClick( state: SelectState, ctx: ToolContext, diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/TextRunHover.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/TextRunHover.ts index 0bceec0e..5cd8b477 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/TextRunHover.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/TextRunHover.ts @@ -1,6 +1,6 @@ import type { ToolEventOf } from "../../core/GestureDetector"; import type { ToolContext } from "../../core/Behavior"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; import { hitTestTextSlot } from "../../text/layout"; import { resolveComponentAtPoint } from "@/lib/editor/hit/composite"; @@ -10,7 +10,7 @@ import { resolveComponentAtPoint } from "@/lib/editor/hit/composite"; * This is a visual-only behavior — it returns false so that * subsequent behaviors can also process the pointer move event. */ -export class TextRunHover implements SelectHandlerBehavior { +export class TextRunHover implements SelectBehavior { onPointerMove( state: SelectState, ctx: ToolContext, diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/ToggleSmooth.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/ToggleSmooth.ts index f983dbbb..bd4198d4 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/ToggleSmooth.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/ToggleSmooth.ts @@ -1,10 +1,10 @@ import type { ToolContext } from "../../core/Behavior"; import type { ToolEventOf } from "../../core/GestureDetector"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; import { getPointIdFromHit } from "@/types/hitResult"; import { Validate } from "@shift/validation"; -export class ToggleSmooth implements SelectHandlerBehavior { +export class ToggleSmooth implements SelectBehavior { onDoubleClick( state: SelectState, ctx: ToolContext, diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Translate.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Translate.ts index b42dd367..918bcac2 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Translate.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/Translate.ts @@ -5,7 +5,7 @@ import type { ToolContext } from "../../core/Behavior"; import type { Editor } from "@/lib/editor/Editor"; import type { DragTarget } from "../types"; import type { ToolEventOf } from "../../core/GestureDetector"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; import type { SegmentId } from "@/types/indicator"; import { getPointIdFromHit, isAnchorHit, isSegmentHit } from "@/types/hitResult"; import type { DragSnapSession } from "@/lib/editor/snapping/types"; @@ -20,7 +20,7 @@ import type { NodePositionUpdateList } from "@/types/positionUpdate"; type TranslatingState = Extract; -export class Translate implements SelectHandlerBehavior { +export class Translate implements SelectBehavior { #snap: DragSnapSession | null = null; #draft: GlyphDraft | null = null; #target: DragTarget | null = null; diff --git a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/UpgradeSegment.ts b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/UpgradeSegment.ts index d7b88162..cb144874 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/behaviors/UpgradeSegment.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/behaviors/UpgradeSegment.ts @@ -1,9 +1,9 @@ import type { ToolEventOf } from "../../core/GestureDetector"; import type { ToolContext } from "../../core/Behavior"; -import type { SelectHandlerBehavior, SelectState } from "../types"; +import type { SelectBehavior, SelectState } from "../types"; import { isSegmentHit } from "@/types/hitResult"; -export class UpgradeSegment implements SelectHandlerBehavior { +export class UpgradeSegment implements SelectBehavior { onClick(state: SelectState, ctx: ToolContext, event: ToolEventOf<"click">): boolean { if ((state.type !== "ready" && state.type !== "selected") || !event.altKey) return false; diff --git a/apps/desktop/src/renderer/src/lib/tools/select/index.ts b/apps/desktop/src/renderer/src/lib/tools/select/index.ts index 37b55770..0e344a4e 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/index.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/index.ts @@ -1,5 +1,5 @@ export { Select, type BoundingRectEdge, type SelectState } from "./Select"; -export type { SelectionData, TranslateData, ResizeData, SelectBehavior } from "./types"; +export type { SelectionDrag, TranslateDrag, ResizeDrag, SelectBehavior } from "./types"; export { edgeToCursor } from "./cursor"; export { normalizeRect, pointInRect } from "./utils"; export { diff --git a/apps/desktop/src/renderer/src/lib/tools/select/types.ts b/apps/desktop/src/renderer/src/lib/tools/select/types.ts index 6cf06199..135f292d 100644 --- a/apps/desktop/src/renderer/src/lib/tools/select/types.ts +++ b/apps/desktop/src/renderer/src/lib/tools/select/types.ts @@ -10,20 +10,20 @@ export interface DragTarget { } /** Tracks the start and current positions of a marquee drag. */ -export interface SelectionData { +export interface SelectionDrag { startPos: Point2D; currentPos: Point2D; } /** Live state of a point-translate drag, including accumulated delta for undo grouping. */ -export interface TranslateData { +export interface TranslateDrag { startPos: Point2D; lastPos: Point2D; totalDelta: Point2D; } /** Live state of a bounding-box resize operation, capturing the original geometry for proportional scaling. */ -export interface ResizeData { +export interface ResizeDrag { edge: Exclude; startPos: Point2D; lastPos: Point2D; @@ -33,7 +33,7 @@ export interface ResizeData { } /** Live state of a rotation drag, tracking angles and initial point positions for the transform. */ -export interface RotateData { +export interface RotateDrag { corner: CornerHandle; startPos: Point2D; lastPos: Point2D; @@ -43,7 +43,7 @@ export interface RotateData { snappedAngle?: number; } -export interface BendData { +export interface BendDrag { t: number; startPos: Point2D; initialControlOne: Point2D; @@ -65,12 +65,11 @@ export interface BendData { export type SelectState = | { type: "idle" } | { type: "ready" } - | { type: "selecting"; selection: SelectionData } + | { type: "selecting"; selection: SelectionDrag } | { type: "selected" } - | { type: "translating"; translate: TranslateData } - | { type: "resizing"; resize: ResizeData } - | { type: "rotating"; rotate: RotateData } - | { type: "bending"; bend: BendData }; + | { type: "translating"; translate: TranslateDrag } + | { type: "resizing"; resize: ResizeDrag } + | { type: "rotating"; rotate: RotateDrag } + | { type: "bending"; bend: BendDrag }; export type SelectBehavior = Behavior; -export type SelectHandlerBehavior = SelectBehavior; diff --git a/apps/desktop/src/renderer/src/persistence/kernel.ts b/apps/desktop/src/renderer/src/persistence/kernel.ts index e4e4e57c..987db13e 100644 --- a/apps/desktop/src/renderer/src/persistence/kernel.ts +++ b/apps/desktop/src/renderer/src/persistence/kernel.ts @@ -6,7 +6,7 @@ import { toolStateAppModule, toolStateDocumentModule } from "./modules/toolState import { PERSISTENCE_DOCUMENT_LIMIT, PERSISTENCE_SCHEMA_VERSION, - type PersistedDocumentState, + type PersistedDocument, type PersistedModuleEnvelope, type PersistedRoot, } from "./types"; @@ -345,11 +345,11 @@ export class DocumentStatePersistence { }, SAVE_DEBOUNCE_MS); } - private ensureDocumentState(docId: string): PersistedDocumentState { + private ensureDocumentState(docId: string): PersistedDocument { const existing = this.#state.documents[docId]; if (existing) return existing; - const next: PersistedDocumentState = { + const next: PersistedDocument = { docId, updatedAt: Date.now(), modules: {}, diff --git a/apps/desktop/src/renderer/src/persistence/types.ts b/apps/desktop/src/renderer/src/persistence/types.ts index 0869fc27..85675c6d 100644 --- a/apps/desktop/src/renderer/src/persistence/types.ts +++ b/apps/desktop/src/renderer/src/persistence/types.ts @@ -1,11 +1,11 @@ import type { - PersistedDocumentState, + PersistedDocument, PersistedModuleEnvelope, PersistedRoot, PersistenceRegistry, PersistedTextRun, UserPreferences, - TextRunModulePayload, + TextRunModule, } from "@shift/validation"; export const PERSISTENCE_SCHEMA_VERSION = 1; @@ -14,10 +14,10 @@ export const PERSISTENCE_DOCUMENT_LIMIT = 100; export type PersistenceScope = "app" | "document"; export type { PersistedModuleEnvelope, - PersistedDocumentState, + PersistedDocument, PersistenceRegistry, PersistedRoot, UserPreferences, - TextRunModulePayload, + TextRunModule, PersistedTextRun, }; diff --git a/apps/desktop/src/renderer/src/types/electron.d.ts b/apps/desktop/src/renderer/src/types/electron.d.ts index f3c4faf6..4d60ed64 100644 --- a/apps/desktop/src/renderer/src/types/electron.d.ts +++ b/apps/desktop/src/renderer/src/types/electron.d.ts @@ -1,6 +1,6 @@ import type { ElectronAPI } from "@shared/ipc/electronAPI"; -export type { ThemeName, DebugOverlays, DebugState } from "@shared/ipc/types"; +export type { ThemeName, DebugOverlays, Debug } from "@shared/ipc/types"; export type { ElectronAPI } from "@shared/ipc/electronAPI"; declare global { diff --git a/apps/desktop/src/renderer/src/types/engine.ts b/apps/desktop/src/renderer/src/types/engine.ts index 4ff95389..f4f0b2cc 100644 --- a/apps/desktop/src/renderer/src/types/engine.ts +++ b/apps/desktop/src/renderer/src/types/engine.ts @@ -1,6 +1,6 @@ import type { ContourId, GlyphSnapshot, PointId, PointType } from "@shift/types"; -export interface CommandResponse { +export interface CommandResult { snapshot: GlyphSnapshot; affectedPointIds: PointId[]; } diff --git a/apps/desktop/src/renderer/src/types/focus.ts b/apps/desktop/src/renderer/src/types/focus.ts index eeaf776f..1f63958f 100644 --- a/apps/desktop/src/renderer/src/types/focus.ts +++ b/apps/desktop/src/renderer/src/types/focus.ts @@ -1,6 +1,6 @@ export type FocusZone = "canvas" | "sidebar" | "toolbar" | "modal"; -export interface FocusZoneState { +export interface FocusZoneFocus { activeZone: FocusZone; focusLock: boolean; } diff --git a/apps/desktop/src/renderer/src/types/indicator.ts b/apps/desktop/src/renderer/src/types/indicator.ts index 38a23d0b..f697f1ba 100644 --- a/apps/desktop/src/renderer/src/types/indicator.ts +++ b/apps/desktop/src/renderer/src/types/indicator.ts @@ -31,7 +31,7 @@ export interface SegmentIndicator { * Drives visual feedback (highlight rings, segment indicators) and determines * what a click would target. */ -export interface IndicatorState { +export interface Indicator { hoveredPoint: PointId | null; hoveredSegment: SegmentIndicator | null; } diff --git a/apps/desktop/src/renderer/src/types/tools.ts b/apps/desktop/src/renderer/src/types/tools.ts index 49cd8064..7e386773 100644 --- a/apps/desktop/src/renderer/src/types/tools.ts +++ b/apps/desktop/src/renderer/src/types/tools.ts @@ -1,6 +1,6 @@ -import type { ToolManifest, ToolName } from "@/lib/tools/core"; +import type { ToolName } from "@/lib/tools/core"; -export type ToolDescriptor = ToolManifest; +export type { ToolManifest } from "@/lib/tools/core"; export type ToolShortcutEntry = { toolId: ToolName; diff --git a/apps/desktop/src/shared/bridge/FontEngineAPI.ts b/apps/desktop/src/shared/bridge/FontEngineAPI.ts index 25d5c5a3..44d1e7a8 100644 --- a/apps/desktop/src/shared/bridge/FontEngineAPI.ts +++ b/apps/desktop/src/shared/bridge/FontEngineAPI.ts @@ -10,15 +10,15 @@ export type FontEngineAPI = Omit; export type NodeRef = JsNodeRef; export type NodePositionUpdate = JsNodePositionUpdate; -export interface CompositeComponentPayload { +export interface CompositeComponent { componentGlyphName: string; sourceUnicodes: number[]; contours: RenderContourSnapshot[]; } -export interface CompositeComponentsPayload { +export interface CompositeComponents { glyphName: string; - components: CompositeComponentPayload[]; + components: CompositeComponent[]; } declare global { diff --git a/apps/desktop/src/shared/bridge/docs/DOCS.md b/apps/desktop/src/shared/bridge/docs/DOCS.md index c2a79b9c..baf9c8df 100644 --- a/apps/desktop/src/shared/bridge/docs/DOCS.md +++ b/apps/desktop/src/shared/bridge/docs/DOCS.md @@ -29,7 +29,7 @@ renderer/src/bridge/ - **`FontEngineAPI`** -- `Omit`. The complete method surface exposed to the renderer. Derived, not hand-written. - **`NodeRef`** -- alias for `JsNodeRef`. Tagged union `{ kind: "point" | "anchor" | "guideline", id: string }`. - **`NodePositionUpdate`** -- alias for `JsNodePositionUpdate`. `{ node: NodeRef, x: number, y: number }`. -- **`CompositeComponentPayload`** / **`CompositeComponentsPayload`** -- shapes for composite glyph component data (component glyph name, source unicodes, contours). +- **`CompositeComponent`** / **`CompositeComponents`** -- shapes for composite glyph component data (component glyph name, source unicodes, contours). - **`Window.shiftFont`** -- global declaration (`FontEngineAPI | undefined`) that both preload and renderer rely on. ## How it works diff --git a/apps/desktop/src/shared/ipc/channels.ts b/apps/desktop/src/shared/ipc/channels.ts index 8257759a..05f130ed 100644 --- a/apps/desktop/src/shared/ipc/channels.ts +++ b/apps/desktop/src/shared/ipc/channels.ts @@ -1,4 +1,4 @@ -import type { ThemeName, DebugState, DebugOverlays } from "./types"; +import type { ThemeName, Debug, DebugOverlays } from "./types"; /** Main -> Renderer broadcasts (webContents.send / ipcRenderer.on) */ export type IpcEvents = { @@ -24,7 +24,7 @@ export type IpcCommands = { "dialog:openFont": () => string | null; "theme:get": () => ThemeName; "theme:set": (theme: ThemeName) => void; - "debug:getState": () => DebugState; + "debug:getState": () => Debug; "window:close": () => void; "window:minimize": () => void; "window:maximize": () => void; diff --git a/apps/desktop/src/shared/ipc/electronAPI.ts b/apps/desktop/src/shared/ipc/electronAPI.ts index fa2a585a..73ca469b 100644 --- a/apps/desktop/src/shared/ipc/electronAPI.ts +++ b/apps/desktop/src/shared/ipc/electronAPI.ts @@ -26,7 +26,7 @@ export interface ElectronAPI { setDocumentDirty: CommandInvoker<"document:setDirty">; setDocumentFilePath: CommandInvoker<"document:setFilePath">; saveCompleted: CommandInvoker<"document:saveCompleted">; - getDebugState: CommandInvoker<"debug:getState">; + getDebug: CommandInvoker<"debug:getState">; pathsExist: CommandInvoker<"fs:pathsExist">; // Events diff --git a/apps/desktop/src/shared/ipc/types.ts b/apps/desktop/src/shared/ipc/types.ts index 7b683eba..64b23400 100644 --- a/apps/desktop/src/shared/ipc/types.ts +++ b/apps/desktop/src/shared/ipc/types.ts @@ -7,7 +7,7 @@ export interface DebugOverlays { glyphBbox: boolean; } -export interface DebugState { +export interface Debug { reactScanEnabled: boolean; debugPanelOpen: boolean; overlays: DebugOverlays; diff --git a/crates/shift-node/src/font_engine.rs b/crates/shift-node/src/font_engine.rs index 142af615..4dc9cfdd 100644 --- a/crates/shift-node/src/font_engine.rs +++ b/crates/shift-node/src/font_engine.rs @@ -450,7 +450,7 @@ impl FontEngine { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] - struct CompositeComponentPayload { + struct CompositeComponent { component_glyph_name: String, source_unicodes: Vec, contours: Vec, @@ -458,14 +458,14 @@ impl FontEngine { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] - struct CompositeComponentsPayload { + struct CompositeComponents { glyph_name: String, - components: Vec, + components: Vec, } let components = instances .into_iter() - .map(|instance| CompositeComponentPayload { + .map(|instance| CompositeComponent { source_unicodes: self .font .glyph(&instance.component_glyph_name) @@ -476,7 +476,7 @@ impl FontEngine { }) .collect(); - Some(to_json(&CompositeComponentsPayload { + Some(to_json(&CompositeComponents { glyph_name: resolved_name.to_string(), components, })) diff --git a/packages/glyph-info/scripts/generate.ts b/packages/glyph-info/scripts/generate.ts index d48cca46..8b4449bc 100644 --- a/packages/glyph-info/scripts/generate.ts +++ b/packages/glyph-info/scripts/generate.ts @@ -1,7 +1,7 @@ import { existsSync, mkdirSync, statSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; -import { generateGlyphData } from "./generators/glyphData.js"; +import { generateGlyph } from "./generators/glyphData.js"; import { generateDecomposition } from "./generators/decomposition.js"; import { generateCharsets } from "./generators/charsets.js"; import { generateSearchIndex } from "./generators/search.js"; @@ -31,8 +31,8 @@ function generate() { // Step 1: glyph-data.json const glyphDataPath = join(RESOURCES_DIR, "glyph-data.json"); - const xmlPath = join(VENDOR_DIR, "GlyphData.xml"); - const glyphCount = generateGlyphData(xmlPath, glyphDataPath); + const xmlPath = join(VENDOR_DIR, "Glyph.xml"); + const glyphCount = generateGlyph(xmlPath, glyphDataPath); console.log(` glyph-data.json: ${glyphCount} entries (${formatSize(glyphDataPath)})`); // Step 2: decomposition.json diff --git a/packages/glyph-info/scripts/generators/glyphData.ts b/packages/glyph-info/scripts/generators/glyphData.ts index 0e5f7b72..bfa9ce61 100644 --- a/packages/glyph-info/scripts/generators/glyphData.ts +++ b/packages/glyph-info/scripts/generators/glyphData.ts @@ -1,6 +1,6 @@ import { readFileSync, writeFileSync } from "node:fs"; import { XMLParser } from "fast-xml-parser"; -import type { GlyphCategory, GlyphData } from "../../src/types.js"; +import type { GlyphCategory, Glyph } from "../../src/types.js"; interface XmlGlyph { unicode?: string; @@ -12,7 +12,7 @@ interface XmlGlyph { altNames?: string; } -export function generateGlyphData(xmlPath: string, outputPath: string): number { +export function generateGlyph(xmlPath: string, outputPath: string): number { const xml = readFileSync(xmlPath, "utf-8"); const parser = new XMLParser({ @@ -24,7 +24,7 @@ export function generateGlyphData(xmlPath: string, outputPath: string): number { const parsed = parser.parse(xml); const glyphs: XmlGlyph[] = parsed.glyphData.glyph; - const results: GlyphData[] = []; + const results: Glyph[] = []; for (const g of glyphs) { if (!g.unicode) continue; diff --git a/packages/glyph-info/scripts/generators/search.ts b/packages/glyph-info/scripts/generators/search.ts index 06236b5a..f5545b3a 100644 --- a/packages/glyph-info/scripts/generators/search.ts +++ b/packages/glyph-info/scripts/generators/search.ts @@ -1,9 +1,9 @@ import { readFileSync, writeFileSync } from "node:fs"; import { unicodeName } from "unicode-name"; -import type { GlyphData } from "../../src/types.js"; +import type { Glyph } from "../../src/types.js"; export function generateSearchIndex(glyphDataPath: string, outputPath: string): number { - const glyphDataRaw: GlyphData[] = JSON.parse(readFileSync(glyphDataPath, "utf-8")); + const glyphDataRaw: Glyph[] = JSON.parse(readFileSync(glyphDataPath, "utf-8")); const glyphMap = new Map(glyphDataRaw.map((g) => [g.codepoint, g])); const records: Array<{ diff --git a/packages/glyph-info/scripts/repl.ts b/packages/glyph-info/scripts/repl.ts index 8bdbf133..d09884d8 100644 --- a/packages/glyph-info/scripts/repl.ts +++ b/packages/glyph-info/scripts/repl.ts @@ -19,7 +19,7 @@ const db = new GlyphInfo(resources); console.log("GlyphInfo REPL — `db` is ready to use"); console.log("Try: db.getGlyphName(0x24)"); -console.log(" db.getGlyphData(0x41)"); +console.log(" db.getGlyph(0x41)"); console.log(" db.getDecomposition(0xE9)"); console.log(' db.search("dollar")'); console.log(" db.listCharsets()"); diff --git a/packages/glyph-info/src/GlyphInfo.test.ts b/packages/glyph-info/src/GlyphInfo.test.ts index 7c12c197..d63c2a5c 100644 --- a/packages/glyph-info/src/GlyphInfo.test.ts +++ b/packages/glyph-info/src/GlyphInfo.test.ts @@ -13,9 +13,9 @@ afterAll(() => { db.close(); }); -describe("getGlyphData", () => { +describe("getGlyph", () => { it("returns full data for dollar sign", () => { - const result = db.getGlyphData(0x24); + const result = db.getGlyph(0x24); expect(result).toEqual({ codepoint: 0x24, name: "dollar", @@ -28,19 +28,19 @@ describe("getGlyphData", () => { }); it("returns data for LATIN CAPITAL LETTER A", () => { - const result = db.getGlyphData(0x41); + const result = db.getGlyph(0x41); expect(result).not.toBeNull(); expect(result!.name).toBe("A"); expect(result!.category).toBe("Letter"); expect(result!.script).toBe("latin"); }); - it("returns null for codepoint not in GlyphData.xml", () => { - expect(db.getGlyphData(0xfffe)).toBeNull(); + it("returns null for codepoint not in Glyph.xml", () => { + expect(db.getGlyph(0xfffe)).toBeNull(); }); it("returns data for space (U+0020)", () => { - const result = db.getGlyphData(0x20); + const result = db.getGlyph(0x20); expect(result).not.toBeNull(); expect(result!.name).toBe("space"); expect(result!.category).toBe("Separator"); @@ -49,7 +49,7 @@ describe("getGlyphData", () => { it("returns data with altNames field", () => { // bar (U+007C) has altNames="verticalbar" - const result = db.getGlyphData(0x7c); + const result = db.getGlyph(0x7c); expect(result).not.toBeNull(); expect(result!.name).toBe("bar"); expect(result!.altNames).toBe("verticalbar"); @@ -57,25 +57,25 @@ describe("getGlyphData", () => { it("returns data with production field", () => { // nbspace (U+00A0) has production="uni00A0" - const result = db.getGlyphData(0xa0); + const result = db.getGlyph(0xa0); expect(result).not.toBeNull(); expect(result!.production).toBe("uni00A0"); }); it("returns null for negative codepoint", () => { - expect(db.getGlyphData(-1)).toBeNull(); + expect(db.getGlyph(-1)).toBeNull(); }); it("returns null for codepoint beyond BMP", () => { - expect(db.getGlyphData(0x10000)).toBeNull(); + expect(db.getGlyph(0x10000)).toBeNull(); }); it("returns null for surrogate codepoint", () => { - expect(db.getGlyphData(0xd800)).toBeNull(); + expect(db.getGlyph(0xd800)).toBeNull(); }); it("returns data for digit zero", () => { - const result = db.getGlyphData(0x30); + const result = db.getGlyph(0x30); expect(result).not.toBeNull(); expect(result!.name).toBe("zero"); expect(result!.category).toBe("Number"); @@ -103,14 +103,14 @@ describe("getGlyphName", () => { }); }); -describe("getAllGlyphData", () => { +describe("getAllGlyph", () => { it("returns many entries", () => { - const all = db.getAllGlyphData(); + const all = db.getAllGlyph(); expect(all.length).toBeGreaterThan(100); }); it("every entry has required fields", () => { - const all = db.getAllGlyphData(); + const all = db.getAllGlyph(); for (const g of all) { expect(g.codepoint).toBeTypeOf("number"); expect(g.name).toBeTypeOf("string"); @@ -121,14 +121,14 @@ describe("getAllGlyphData", () => { }); it("contains no duplicate codepoints", () => { - const all = db.getAllGlyphData(); + const all = db.getAllGlyph(); const codepoints = all.map((g) => g.codepoint); const uniqueCodepoints = new Set(codepoints); expect(uniqueCodepoints.size).toBe(codepoints.length); }); it("codepoints are all non-negative integers", () => { - const all = db.getAllGlyphData(); + const all = db.getAllGlyph(); for (const g of all) { expect(g.codepoint).toBeGreaterThanOrEqual(0); expect(Number.isInteger(g.codepoint)).toBe(true); @@ -177,8 +177,8 @@ describe("getGlyphsByCategory", () => { } }); - it("category results are consistent with getAllGlyphData", () => { - const all = db.getAllGlyphData(); + it("category results are consistent with getAllGlyph", () => { + const all = db.getAllGlyph(); const categories = db.getGlyphCategories(); let totalFromCategories = 0; for (const cat of categories) { @@ -569,7 +569,7 @@ describe("cross-domain consistency", () => { expect(name.length).toBeGreaterThan(0); } } - // Most Adobe Latin 1 codepoints should be in GlyphData.xml + // Most Adobe Latin 1 codepoints should be in Glyph.xml expect(matchCount).toBeGreaterThan(200); }); @@ -596,7 +596,7 @@ describe("cross-domain consistency", () => { const dollarResult = searchResults.find((r) => r.codepoint === 0x24); expect(dollarResult).toBeDefined(); - const glyphData = db.getGlyphData(0x24); + const glyphData = db.getGlyph(0x24); expect(glyphData).not.toBeNull(); expect(dollarResult!.glyphName).toBe(glyphData!.name); }); diff --git a/packages/glyph-info/src/GlyphInfo.ts b/packages/glyph-info/src/GlyphInfo.ts index 860f9a50..a24df048 100644 --- a/packages/glyph-info/src/GlyphInfo.ts +++ b/packages/glyph-info/src/GlyphInfo.ts @@ -8,7 +8,7 @@ import type { GlyphCodepointFilter, GlyphCategoryOptions, GlyphCodepointCategory, - GlyphData, + Glyph, GlyphInfoResources, SearchResult, } from "./types.js"; @@ -125,7 +125,7 @@ function toSortedCategorySummaries( * when done (currently a no-op, but present for future resource cleanup). */ export class GlyphInfo { - #glyphData: Map; + #glyphData: Map; #decomposed: Map; #usedBy: Map; #charsets: CharsetDefinition[]; @@ -155,7 +155,7 @@ export class GlyphInfo { // --- Glyph Data (Map lookups) --- /** Look up the full metadata record for a codepoint, or `null` if unknown. */ - getGlyphData(cp: number): GlyphData | null { + getGlyph(cp: number): Glyph | null { return this.#glyphData.get(cp) ?? null; } @@ -167,7 +167,7 @@ export class GlyphInfo { return data.name; } - getAllGlyphData(): GlyphData[] { + getAllGlyph(): Glyph[] { return Array.from(this.#glyphData.values()); } @@ -179,8 +179,8 @@ export class GlyphInfo { return Array.from(categories).sort(); } - getGlyphsByCategory(category: GlyphCategory): GlyphData[] { - const results: GlyphData[] = []; + getGlyphsByCategory(category: GlyphCategory): Glyph[] { + const results: Glyph[] = []; for (const g of this.#glyphData.values()) { if (g.category === category) { results.push(g); diff --git a/packages/glyph-info/src/index.ts b/packages/glyph-info/src/index.ts index f7384dd4..d2932a6f 100644 --- a/packages/glyph-info/src/index.ts +++ b/packages/glyph-info/src/index.ts @@ -28,7 +28,7 @@ export type { /** Lightweight summary returned by `GlyphInfo.listCharsets()`. */ CharsetSummary, /** Bidirectional codepoint decomposition maps. */ - DecompositionData, + Decomposition, /** Known Unicode general category for glyph classification. */ GlyphCategory, /** Category fallback and inclusion options for codepoint categorization APIs. */ @@ -44,7 +44,7 @@ export type { /** Subcategory summary entry used inside `GlyphCategorySummary`. */ GlyphSubCategorySummary, /** Per-codepoint glyph metadata (name, category, script, etc.). */ - GlyphData, + Glyph, /** Bundle of all resources needed to construct a {@link GlyphInfo} instance. */ GlyphInfoResources, /** A single hit from `GlyphInfo.search()`, ranked by relevance. */ diff --git a/packages/glyph-info/src/types.ts b/packages/glyph-info/src/types.ts index 2ce9dfa6..8cd19692 100644 --- a/packages/glyph-info/src/types.ts +++ b/packages/glyph-info/src/types.ts @@ -1,4 +1,4 @@ -// TODO: Derive GlyphSubCategory and GlyphScript unions from GlyphData.xml during the generate step. +// TODO: Derive GlyphSubCategory and GlyphScript unions from Glyph.xml during the generate step. /** Known Unicode general categories used for glyph classification. */ export const GLYPH_CATEGORIES = [ @@ -13,7 +13,7 @@ export const GLYPH_CATEGORIES = [ export type GlyphCategory = (typeof GLYPH_CATEGORIES)[number]; -export interface GlyphData { +export interface Glyph { codepoint: number; name: string; category: GlyphCategory; @@ -84,14 +84,14 @@ export interface GlyphCategoryCatalog { filter(filter?: GlyphCodepointFilter): number[]; } -export interface DecompositionData { +export interface Decomposition { decomposed: Record; usedBy: Record; } export interface GlyphInfoResources { - glyphData: GlyphData[]; - decomposition: DecompositionData; + glyphData: Glyph[]; + decomposition: Decomposition; charsets: CharsetDefinition[]; searchData: Record[]; } diff --git a/packages/validation/docs/DOCS.md b/packages/validation/docs/DOCS.md index 1613a0cb..48c21be2 100644 --- a/packages/validation/docs/DOCS.md +++ b/packages/validation/docs/DOCS.md @@ -32,9 +32,9 @@ validation/src/ - `ValidateSnapshot` -- namespace object with type guards for `PointSnapshot`, `ContourSnapshot`, `AnchorSnapshot`, `RenderPointSnapshot`, `RenderContourSnapshot`, `GlyphSnapshot`. Also provides `glyphSnapshot` which returns `ValidationResult` with detailed field-level errors. - `ValidateClipboard` -- namespace object with `isClipboardContent` (validates contour array shape) and `isClipboardPayload` (validates full `shift/glyph-data` envelope with format, version, metadata, content). - `PersistedRootSchema` -- top-level Zod schema for the entire persisted state file (registry, app modules, documents). -- `PersistedDocumentStateSchema` -- Zod schema for a single document's persisted state (docId, updatedAt, modules map). +- `PersistedDocumentSchema` -- Zod schema for a single document's persisted state (docId, updatedAt, modules map). - `SnapPreferencesSchema` / `UserPreferencesSchema` -- Zod schemas for user snap/preference settings. -- `TextRunModulePayloadSchema` -- Zod schema for the text-run persistence module payload. +- `TextRunModuleSchema` -- Zod schema for the text-run persistence module payload. ## How it works @@ -103,6 +103,6 @@ cd packages/validation && npx tsc --noEmit - `NativeBridge` -- calls `ValidateSnapshot.isGlyphSnapshot` before Rust snapshot restore - `Segments` / `Segment` -- uses `Validate.isOnCurve` / `Validate.isOffCurve` for segment decomposition - `SnapManager` -- uses `Validate.isOnCurve` / `Validate.isOffCurve` for snap target classification -- `Editor` -- parses `SnapPreferencesSchema` and `TextRunModulePayloadSchema` from persisted state +- `Editor` -- parses `SnapPreferencesSchema` and `TextRunModuleSchema` from persisted state - `persistence/kernel` -- parses `PersistedRootSchema` on app startup - `PointType` from `@shift/types` -- the underlying union (`"onCurve" | "offCurve"`) that `PointLike` wraps diff --git a/packages/validation/src/index.ts b/packages/validation/src/index.ts index c8f1bfeb..8a671af6 100644 --- a/packages/validation/src/index.ts +++ b/packages/validation/src/index.ts @@ -26,23 +26,23 @@ export { ValidateSnapshot } from "./ValidateSnapshot"; export { ValidateClipboard } from "./ValidateClipboard"; export { PersistedTextRunSchema, - TextRunModulePayloadSchema, + TextRunModuleSchema, SnapPreferencesSchema, UserPreferencesSchema, PersistedModuleEnvelopeSchema, PersistenceRegistrySchema, - PersistedDocumentStateSchema, + PersistedDocumentSchema, PersistedRootSchema, } from "./persistence"; export type { ValidationResult, ValidationError, ValidationErrorCode, PointLike } from "./types"; export type { PersistedTextRun, - TextRunModulePayload, + TextRunModule, SnapPreferencesShape, UserPreferences, PersistedModuleEnvelope, PersistenceRegistry, - PersistedDocumentState, + PersistedDocument, PersistedRoot, } from "./persistence"; diff --git a/packages/validation/src/persistence.test.ts b/packages/validation/src/persistence.test.ts index aa772048..b9d332b4 100644 --- a/packages/validation/src/persistence.test.ts +++ b/packages/validation/src/persistence.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; import { PersistedRootSchema, - TextRunModulePayloadSchema, + TextRunModuleSchema, UserPreferencesSchema, } from "./persistence"; @@ -62,7 +62,7 @@ describe("persistence schemas", () => { }); it("rejects invalid text-run payload", () => { - const result = TextRunModulePayloadSchema.safeParse({ + const result = TextRunModuleSchema.safeParse({ runsByGlyph: { "65": { glyphs: [{ glyphName: "A", unicode: 65 }], diff --git a/packages/validation/src/persistence.ts b/packages/validation/src/persistence.ts index 10b23ad2..c5383d4e 100644 --- a/packages/validation/src/persistence.ts +++ b/packages/validation/src/persistence.ts @@ -13,7 +13,7 @@ export const PersistedTextRunSchema = z.object({ editingGlyph: GlyphRefSchema.nullable(), }); -export const TextRunModulePayloadSchema = z.object({ +export const TextRunModuleSchema = z.object({ runsByGlyph: z.record(z.string(), PersistedTextRunSchema), }); @@ -42,7 +42,7 @@ export const PersistenceRegistrySchema = z.object({ lruDocIds: z.array(z.string()), }); -export const PersistedDocumentStateSchema = z.object({ +export const PersistedDocumentSchema = z.object({ docId: z.string(), updatedAt: z.number().finite(), modules: z.record(z.string(), PersistedModuleEnvelopeSchema), @@ -52,14 +52,14 @@ export const PersistedRootSchema = z.object({ version: z.number().int().positive(), registry: PersistenceRegistrySchema, appModules: z.record(z.string(), PersistedModuleEnvelopeSchema), - documents: z.record(z.string(), PersistedDocumentStateSchema), + documents: z.record(z.string(), PersistedDocumentSchema), }); export type PersistedTextRun = z.infer; -export type TextRunModulePayload = z.infer; +export type TextRunModule = z.infer; export type SnapPreferencesShape = z.infer; export type UserPreferences = z.infer; export type PersistedModuleEnvelope = z.infer; export type PersistenceRegistry = z.infer; -export type PersistedDocumentState = z.infer; +export type PersistedDocument = z.infer; export type PersistedRoot = z.infer; From 30f8135af25c4da8faa4d685310ef1c0eb79a8d3 Mon Sep 17 00:00:00 2001 From: Kostya Farber Date: Sun, 26 Apr 2026 20:53:44 +0100 Subject: [PATCH 2/3] refactor: more leaky -Result names; restore vendor path; fix hook glob MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to the first naming sweep: - PointStepResult/RotateStepResult -> PointStep/RotateStep - PointSnapResult/RotateSnapResult -> PointSnap/RotateSnap - ClosestPointResult -> ClosestPoint - GlyphCategoryCatalogData -> GlyphCategoryCatalogIndex Restore GlyphData.xml as the vendor file path. The first commit renamed it to Glyph.xml, but GlyphData.xml is the upstream schriftgestalt/GlyphsInfo file name and not under our control — this was the cause of CI failure on this PR. Also extend the no-console-log hook glob from scripts/* to also match */scripts/* so nested package script files (which legitimately use console.log) are not flagged. --- .pre-commit-config.yaml | 2 +- .../src/lib/editor/managers/SnapManager.ts | 8 ++++---- .../lib/editor/snapping/SnapPipelineRunner.ts | 12 +++++------ .../renderer/src/lib/editor/snapping/types.ts | 20 +++++++++---------- packages/geo/docs/DOCS.md | 2 +- packages/geo/src/Curve.ts | 10 +++++----- packages/geo/src/index.ts | 2 +- packages/glyph-info/scripts/generate.ts | 2 +- packages/glyph-info/src/GlyphInfo.ts | 6 +++--- packages/glyph-info/src/types.ts | 2 +- 10 files changed, 33 insertions(+), 33 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c693b690..15015e77 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: - id: no-console-log name: no console.log in production code - entry: "bash -c 'for f in \"$@\"; do case \"$f\" in *.test.*|*/testing/*|*/e2e/*|scripts/*) continue;; esac; if grep -n \"^\\s*console\\.log\\b\" \"$f\" >/dev/null 2>&1; then echo \"$f has console.log:\"; grep -n \"^\\s*console\\.log\\b\" \"$f\"; exit 1; fi; done'" + entry: "bash -c 'for f in \"$@\"; do case \"$f\" in *.test.*|*/testing/*|*/e2e/*|scripts/*|*/scripts/*) continue;; esac; if grep -n \"^\\s*console\\.log\\b\" \"$f\" >/dev/null 2>&1; then echo \"$f has console.log:\"; grep -n \"^\\s*console\\.log\\b\" \"$f\"; exit 1; fi; done'" language: system types_or: [javascript, jsx, ts, tsx] diff --git a/apps/desktop/src/renderer/src/lib/editor/managers/SnapManager.ts b/apps/desktop/src/renderer/src/lib/editor/managers/SnapManager.ts index 6fe9ab27..0212bc62 100644 --- a/apps/desktop/src/renderer/src/lib/editor/managers/SnapManager.ts +++ b/apps/desktop/src/renderer/src/lib/editor/managers/SnapManager.ts @@ -8,10 +8,10 @@ import type { SnapPreferences } from "@/types/editor"; import type { DragSnapSession, DragSnapSessionConfig, - PointSnapResult, + PointSnap, PointSnapStep, RotateSnapSession, - RotateSnapResult, + RotateSnap, RotateSnapStep, SnapContext, SnappableObject, @@ -75,7 +75,7 @@ export class SnapManager { return { getAnchorPosition: () => anchorPosition, - snap: (cursorPoint, modifiers): PointSnapResult => { + snap: (cursorPoint, modifiers): PointSnap => { const pointPosition = Vec2.add(anchorPosition, Vec2.sub(cursorPoint, config.dragStart)); const prefs = this.#getPreferences(); @@ -101,7 +101,7 @@ export class SnapManager { const steps: RotateSnapStep[] = [createRotateAngleStep()]; return { - snap: (delta, modifiers): RotateSnapResult => { + snap: (delta, modifiers): RotateSnap => { const prefs = this.#getPreferences(); return this.#runner.runRotatePipeline(steps, { diff --git a/apps/desktop/src/renderer/src/lib/editor/snapping/SnapPipelineRunner.ts b/apps/desktop/src/renderer/src/lib/editor/snapping/SnapPipelineRunner.ts index c6aef4a4..2f54cd87 100644 --- a/apps/desktop/src/renderer/src/lib/editor/snapping/SnapPipelineRunner.ts +++ b/apps/desktop/src/renderer/src/lib/editor/snapping/SnapPipelineRunner.ts @@ -2,11 +2,11 @@ import { Vec2 } from "@shift/geo"; import type { PointSnapStep, PointSnapStepArgs, - PointSnapResult, - PointStepResult, + PointSnap, + PointStep, RotateSnapStep, RotateSnapStepArgs, - RotateSnapResult, + RotateSnap, } from "./types"; /** @@ -27,8 +27,8 @@ export class SnapPipelineRunner { * to the original point is chosen. * 3. **No match** — returns the input point unchanged with `source: null`. */ - runPointPipeline(steps: readonly PointSnapStep[], args: PointSnapStepArgs): PointSnapResult { - const candidates: PointStepResult[] = []; + runPointPipeline(steps: readonly PointSnapStep[], args: PointSnapStepArgs): PointSnap { + const candidates: PointStep[] = []; for (const step of steps) { const result = step.apply(args); @@ -60,7 +60,7 @@ export class SnapPipelineRunner { * Uses **first-match** semantics: the first step that returns a non-null result * wins. If no step matches, the raw delta passes through with `source: null`. */ - runRotatePipeline(steps: readonly RotateSnapStep[], args: RotateSnapStepArgs): RotateSnapResult { + runRotatePipeline(steps: readonly RotateSnapStep[], args: RotateSnapStepArgs): RotateSnap { for (const step of steps) { const result = step.apply(args); if (result) { diff --git a/apps/desktop/src/renderer/src/lib/editor/snapping/types.ts b/apps/desktop/src/renderer/src/lib/editor/snapping/types.ts index 79b70cbd..1c25169c 100644 --- a/apps/desktop/src/renderer/src/lib/editor/snapping/types.ts +++ b/apps/desktop/src/renderer/src/lib/editor/snapping/types.ts @@ -72,7 +72,7 @@ export interface PointSnapStepArgs { } /** Output of a single point snap step: the corrected position, which source matched, and optional visual indicator. */ -export interface PointStepResult { +export interface PointStep { snappedPoint: Point2D; source: "pointToPoint" | "metrics" | "angle"; indicator: SnapIndicator | null; @@ -80,11 +80,11 @@ export interface PointStepResult { /** * A single stage in the point snap pipeline. Each step inspects the input and - * either returns a {@link PointStepResult} (snap hit) or `null` (no match). + * either returns a {@link PointStep} (snap hit) or `null` (no match). */ export interface PointSnapStep { id: string; - apply(args: PointSnapStepArgs): PointStepResult | null; + apply(args: PointSnapStepArgs): PointStep | null; } /** Input bundle passed to each {@link RotateSnapStep}. Contains the raw rotation delta (radians) and modifier state. */ @@ -97,30 +97,30 @@ export interface RotateSnapStepArgs { } /** Output of a single rotate snap step: the quantized delta and its source. */ -export interface RotateStepResult { +export interface RotateStep { snappedDelta: number; source: "angle"; indicator: SnapIndicator | null; } /** - * A single stage in the rotate snap pipeline. Returns a {@link RotateStepResult} + * A single stage in the rotate snap pipeline. Returns a {@link RotateStep} * when the rotation delta should be quantized, or `null` to pass through. */ export interface RotateSnapStep { id: string; - apply(args: RotateSnapStepArgs): RotateStepResult | null; + apply(args: RotateSnapStepArgs): RotateStep | null; } /** Final resolved result of a point snap pipeline run. If no step matched, `source` is `null` and `point` is unchanged. */ -export interface PointSnapResult { +export interface PointSnap { point: Point2D; indicator: SnapIndicator | null; source: "pointToPoint" | "metrics" | "angle" | null; } /** Final resolved result of a rotate snap pipeline run. If no step matched, `source` is `null` and `delta` is unchanged. */ -export interface RotateSnapResult { +export interface RotateSnap { delta: number; source: "angle" | null; } @@ -142,7 +142,7 @@ export interface DragSnapSessionConfig { */ export interface DragSnapSession { getAnchorPosition(): Point2D; - snap(point: Point2D, modifiers: { shiftKey: boolean }): PointSnapResult; + snap(point: Point2D, modifiers: { shiftKey: boolean }): PointSnap; clear(): void; } @@ -151,6 +151,6 @@ export interface DragSnapSession { * call `snap()` on each rotation event and `clear()` when rotation ends. */ export interface RotateSnapSession { - snap(delta: number, modifiers: { shiftKey: boolean }): RotateSnapResult; + snap(delta: number, modifiers: { shiftKey: boolean }): RotateSnap; clear(): void; } diff --git a/packages/geo/docs/DOCS.md b/packages/geo/docs/DOCS.md index b552e0e4..6d3c30d0 100644 --- a/packages/geo/docs/DOCS.md +++ b/packages/geo/docs/DOCS.md @@ -36,7 +36,7 @@ src/ - `QuadraticCurve` -- `{ type: "quadratic"; p0; c; p1 }`. One control point. - `CubicCurve` -- `{ type: "cubic"; p0; c0; c1; p1 }`. Two control points. - `CurveType` -- discriminated union of `LineCurve | QuadraticCurve | CubicCurve`. Switch on `.type`. -- `ClosestPointResult` -- `{ t, point, distance }`. Returned by `Curve.closestPoint` for hit-testing. +- `ClosestPoint` -- `{ t, point, distance }`. Returned by `Curve.closestPoint` for hit-testing. - `MatModel` -- readonly interface for the six affine matrix coefficients `(a, b, c, d, e, f)`. - `Mat` -- mutable class implementing `MatModel`. Maps directly to Canvas2D `transform(a, b, c, d, e, f)`. diff --git a/packages/geo/src/Curve.ts b/packages/geo/src/Curve.ts index 5ddc3f81..dd307c83 100644 --- a/packages/geo/src/Curve.ts +++ b/packages/geo/src/Curve.ts @@ -70,7 +70,7 @@ export type CurveType = LineCurve | QuadraticCurve | CubicCurve; /** * Result of a closest-point query. */ -export interface ClosestPointResult { +export interface ClosestPoint { /** Parameter t where the closest point lies (0 to 1) */ t: number; /** The closest point on the curve */ @@ -159,7 +159,7 @@ export const Curve = { * Find closest point on curve to a test point. * Uses Newton-Raphson refinement for accuracy. */ - closestPoint(curve: CurveType, point: Point2D): ClosestPointResult { + closestPoint(curve: CurveType, point: Point2D): ClosestPoint { switch (curve.type) { case "line": return lineClosestPoint(curve, point); @@ -279,7 +279,7 @@ function quadraticTangentAt(curve: QuadraticCurve, t: number): Point2D { }; } -function quadraticClosestPoint(curve: QuadraticCurve, point: Point2D): ClosestPointResult { +function quadraticClosestPoint(curve: QuadraticCurve, point: Point2D): ClosestPoint { let bestT = 0; let bestDist = Infinity; @@ -402,7 +402,7 @@ function cubicSecondDerivativeAt(curve: CubicCurve, t: number): Point2D { }; } -function cubicClosestPoint(curve: CubicCurve, point: Point2D): ClosestPointResult { +function cubicClosestPoint(curve: CubicCurve, point: Point2D): ClosestPoint { let bestT = 0; let bestDist = Infinity; @@ -508,7 +508,7 @@ function cubicSplitAt(curve: CubicCurve, t: number): [CubicCurve, CubicCurve] { return [Curve.cubic(curve.p0, p01, p012, p0123), Curve.cubic(p0123, p123, p23, curve.p1)]; } -function lineClosestPoint(curve: LineCurve, point: Point2D): ClosestPointResult { +function lineClosestPoint(curve: LineCurve, point: Point2D): ClosestPoint { const v = Vec2.sub(curve.p1, curve.p0); const w = Vec2.sub(point, curve.p0); diff --git a/packages/geo/src/index.ts b/packages/geo/src/index.ts index 07d43577..26e85f3b 100644 --- a/packages/geo/src/index.ts +++ b/packages/geo/src/index.ts @@ -42,7 +42,7 @@ export { Curve } from "./Curve"; // Polygon operations export { Polygon } from "./Polygon"; -export type { LineCurve, QuadraticCurve, CubicCurve, CurveType, ClosestPointResult } from "./Curve"; +export type { LineCurve, QuadraticCurve, CubicCurve, CurveType, ClosestPoint } from "./Curve"; // Matrix transformations export { Mat, type MatModel } from "./Mat"; diff --git a/packages/glyph-info/scripts/generate.ts b/packages/glyph-info/scripts/generate.ts index 8b4449bc..7d96ec82 100644 --- a/packages/glyph-info/scripts/generate.ts +++ b/packages/glyph-info/scripts/generate.ts @@ -31,7 +31,7 @@ function generate() { // Step 1: glyph-data.json const glyphDataPath = join(RESOURCES_DIR, "glyph-data.json"); - const xmlPath = join(VENDOR_DIR, "Glyph.xml"); + const xmlPath = join(VENDOR_DIR, "GlyphData.xml"); const glyphCount = generateGlyph(xmlPath, glyphDataPath); console.log(` glyph-data.json: ${glyphCount} entries (${formatSize(glyphDataPath)})`); diff --git a/packages/glyph-info/src/GlyphInfo.ts b/packages/glyph-info/src/GlyphInfo.ts index a24df048..25f10d7b 100644 --- a/packages/glyph-info/src/GlyphInfo.ts +++ b/packages/glyph-info/src/GlyphInfo.ts @@ -59,7 +59,7 @@ type GlyphCategoryCountBucket = { subCategoryCounts: Map; }; -type GlyphCategoryCatalogData = { +type GlyphCategoryCatalogIndex = { categories: GlyphCategorySummary[]; entries: GlyphCategoryEntry[]; }; @@ -332,7 +332,7 @@ export class GlyphInfo { #buildCategoryCatalogData( codepoints: number[], options: Required, - ): GlyphCategoryCatalogData { + ): GlyphCategoryCatalogIndex { const categoryCounts = new Map(); const entries: GlyphCategoryEntry[] = []; @@ -353,7 +353,7 @@ export class GlyphInfo { }; } - #filterCategoryCatalog(data: GlyphCategoryCatalogData, filter: GlyphCodepointFilter): number[] { + #filterCategoryCatalog(data: GlyphCategoryCatalogIndex, filter: GlyphCodepointFilter): number[] { const selectedCategory = filter.category ?? null; const selectedSubCategoryKey = filter.subCategoryKey ?? null; const query = filter.query ?? ""; diff --git a/packages/glyph-info/src/types.ts b/packages/glyph-info/src/types.ts index 8cd19692..6f39126f 100644 --- a/packages/glyph-info/src/types.ts +++ b/packages/glyph-info/src/types.ts @@ -1,4 +1,4 @@ -// TODO: Derive GlyphSubCategory and GlyphScript unions from Glyph.xml during the generate step. +// TODO: Derive GlyphSubCategory and GlyphScript unions from GlyphData.xml during the generate step. /** Known Unicode general categories used for glyph classification. */ export const GLYPH_CATEGORIES = [ From d7e35725f5e0f082dfeffa4615500125eecca0a9 Mon Sep 17 00:00:00 2001 From: Kostya Farber Date: Sun, 26 Apr 2026 20:55:22 +0100 Subject: [PATCH 3/3] format: prettier fixes for MenuManager, DragHandlesBehaviour, persistence.test --- apps/desktop/src/main/managers/MenuManager.ts | 6 ++---- .../src/lib/tools/pen/behaviors/DragHandlesBehaviour.ts | 7 +------ packages/validation/src/persistence.test.ts | 6 +----- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/apps/desktop/src/main/managers/MenuManager.ts b/apps/desktop/src/main/managers/MenuManager.ts index b3d41b00..78a737b0 100644 --- a/apps/desktop/src/main/managers/MenuManager.ts +++ b/apps/desktop/src/main/managers/MenuManager.ts @@ -262,15 +262,13 @@ export class MenuManager { label: "React Scan", type: "checkbox" as const, checked: this.debugState.reactScanEnabled, - click: () => - this.setDebug("reactScanEnabled", !this.debugState.reactScanEnabled), + click: () => this.setDebug("reactScanEnabled", !this.debugState.reactScanEnabled), }, { label: "Debug Panel", type: "checkbox" as const, checked: this.debugState.debugPanelOpen, - click: () => - this.setDebug("debugPanelOpen", !this.debugState.debugPanelOpen), + click: () => this.setDebug("debugPanelOpen", !this.debugState.debugPanelOpen), }, { type: "separator" as const }, { diff --git a/apps/desktop/src/renderer/src/lib/tools/pen/behaviors/DragHandlesBehaviour.ts b/apps/desktop/src/renderer/src/lib/tools/pen/behaviors/DragHandlesBehaviour.ts index 5a8d538c..f98c6fb4 100644 --- a/apps/desktop/src/renderer/src/lib/tools/pen/behaviors/DragHandlesBehaviour.ts +++ b/apps/desktop/src/renderer/src/lib/tools/pen/behaviors/DragHandlesBehaviour.ts @@ -193,12 +193,7 @@ export class HandleBehavior implements PenBehavior { return { cpIn: cpInId }; } - #updateHandles( - anchor: Anchor, - handles: Handles, - snappedPos: Point2D, - editor: Editor, - ): void { + #updateHandles(anchor: Anchor, handles: Handles, snappedPos: Point2D, editor: Editor): void { const glyph = editor.glyph.peek(); if (!glyph) return; diff --git a/packages/validation/src/persistence.test.ts b/packages/validation/src/persistence.test.ts index b9d332b4..b80cd6f5 100644 --- a/packages/validation/src/persistence.test.ts +++ b/packages/validation/src/persistence.test.ts @@ -1,9 +1,5 @@ import { describe, expect, it } from "vitest"; -import { - PersistedRootSchema, - TextRunModuleSchema, - UserPreferencesSchema, -} from "./persistence"; +import { PersistedRootSchema, TextRunModuleSchema, UserPreferencesSchema } from "./persistence"; describe("persistence schemas", () => { it("accepts a valid persisted root payload", () => {