diff --git a/README.md b/README.md index 3ea49e38..9d6531b2 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,15 @@ # json-document -json-document는 Zod schema가 있는 JSON 문서를 편집하기 위한 headless document -engine입니다. +json-document는 문서, 표, 슬라이드, 캔버스, 노트 편집기가 함께 쓸 수 있는 +provider-neutral JSON 편집 protocol과 headless document projection입니다. -폼, CMS block, kanban board, outliner, settings editor처럼 UI가 다른 편집 툴도 -결국 schema가 있는 JSON document를 읽고, 바꾸고, 선택하고, 복사하고, -붙여넣고, 되돌립니다. json-document는 이 공통 document engine을 UI 밖에 둡니다. +v2 root는 JSON, JSON Pointer, JSONPath, JSON Patch만 전제로 하며 Zod, React, +selection, clipboard, history를 필수 계약에 넣지 않습니다. ```txt -schema -> document -> pointer/query -> can* -> change -> result +Pure Protocol + |-> Document Projection -> host adapter + `-> Candidate Editing Session -> React / rich host adapter ``` 공식 사이트: https://developer-1px.github.io/json-document/ @@ -24,17 +25,15 @@ schema -> document -> pointer/query -> can* -> change -> result | 제품별 feature 지도 | [docs/public/recipes.md](docs/public/recipes.md) | | 문서 구조 | [docs/README.md](docs/README.md) | | 변경 기록 | [docs/changelog.md](docs/changelog.md) | -| core 의미론 명세 | [docs/standard/json-document-spec.md](docs/standard/json-document-spec.md) | -| 1.0 conformance profile | [docs/standard/conformance-profile.md](docs/standard/conformance-profile.md) | -| result/error 계약 | [docs/standard/result-contract.md](docs/standard/result-contract.md) | -| selection 계약 | [docs/standard/selection-contract.md](docs/standard/selection-contract.md) | -| schema introspection 계약 | [docs/standard/schema-introspection-contract.md](docs/standard/schema-introspection-contract.md) | +| v2 Projection 표준 | [docs/standard/v2-projection-profile.md](docs/standard/v2-projection-profile.md) | +| v2 공개 표면 manifest | [docs/standard/v2-public-surface.json](docs/standard/v2-public-surface.json) | +| Candidate Session의 1.x 기준선 | [docs/standard/conformance-profile.md](docs/standard/conformance-profile.md) | ## 코드 지도 | 위치 | 역할 | | --- | --- | -| [packages/json-document](packages/json-document) | core package. `createJSONDocument`, JSON Patch/Pointer/Path, selection, clipboard, history | +| [packages/json-document](packages/json-document) | v2 Kernel과 optional Candidate Session | | [packages/collection](packages/collection) | ordered JSON array item 이동/복제/삭제 | | [packages/clipboard-web](packages/clipboard-web) | browser clipboard bridge | | [packages/contenteditable-web](packages/contenteditable-web) | `@interactive-os/json-document-contenteditable-web` DOM contenteditable text-surface adapter | @@ -61,13 +60,16 @@ schema -> document -> pointer/query -> can* -> change -> result ## 경계 -json-document가 제공하는 document engine: +v2 Kernel이 제공하는 최소 계약: -- Zod schema로 검증되는 JSON document state -- JSON Pointer 주소, JSON Patch mutation, JSONPath search -- `can*` capability result -- headless selection, clipboard payload, undo/redo history -- 반복 편집 개념을 조립하는 작은 extension 함수 +- immutable JSON snapshot +- JSON Pointer read와 JSONPath query +- state를 바꾸지 않는 `canPatch` +- ordered atomic JSON Patch commit +- canonical applied change publication + +`@interactive-os/json-document/session`은 Zod 기반 schema 검증, selection, +clipboard, history와 고수준 편집 동사를 제공하는 optional Candidate 표면입니다. 편집 툴이 계속 소유하는 것: diff --git a/apps/grouping-lab/src/App.tsx b/apps/grouping-lab/src/App.tsx index 6b17c630..b866da3c 100644 --- a/apps/grouping-lab/src/App.tsx +++ b/apps/grouping-lab/src/App.tsx @@ -1,6 +1,6 @@ import { useMemo, useState } from "react"; import { createGrouping, type GroupingAdapter, type GroupingChangeResult } from "@interactive-os/json-document-grouping"; -import type { Pointer } from "@interactive-os/json-document"; +import type { Pointer } from "@interactive-os/json-document/session"; import { useJSONDocument } from "@interactive-os/json-document/react"; import { z } from "zod"; import "./grouping-lab.css"; diff --git a/apps/outliner-blind-b/src/outlinerModel.test.ts b/apps/outliner-blind-b/src/outlinerModel.test.ts index f2e7ef64..3d0ab23b 100644 --- a/apps/outliner-blind-b/src/outlinerModel.test.ts +++ b/apps/outliner-blind-b/src/outlinerModel.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { createJSONDocument } from "@interactive-os/json-document"; +import { createJSONDocument } from "@interactive-os/json-document/session"; import { addChild, addSibling, diff --git a/apps/outliner-blind-b/src/outlinerModel.ts b/apps/outliner-blind-b/src/outlinerModel.ts index 1621b874..02006b66 100644 --- a/apps/outliner-blind-b/src/outlinerModel.ts +++ b/apps/outliner-blind-b/src/outlinerModel.ts @@ -1,5 +1,5 @@ import * as z from "zod"; -import type { JSONDocument, JSONPatchOperation, Pointer } from "@interactive-os/json-document"; +import type { JSONDocument, JSONPatchOperation, Pointer } from "@interactive-os/json-document/session"; export type OutlineNode = { id: string; diff --git a/apps/outliner/src/OutlineRow.tsx b/apps/outliner/src/OutlineRow.tsx index f35e6e36..a5d4b117 100644 --- a/apps/outliner/src/OutlineRow.tsx +++ b/apps/outliner/src/OutlineRow.tsx @@ -2,7 +2,7 @@ // keydown 은 props 로 받는다 — chord dispatcher 는 부모 책임. import { useEffect, useRef } from "react"; -import type { JSONDocument, Pointer } from "@interactive-os/json-document"; +import type { JSONDocument, Pointer } from "@interactive-os/json-document/session"; import type { OutlineNode } from "./schema.js"; import type { Mode } from "./keymap.js"; diff --git a/apps/outliner/src/clipboard.ts b/apps/outliner/src/clipboard.ts index df30af9e..81d893af 100644 --- a/apps/outliner/src/clipboard.ts +++ b/apps/outliner/src/clipboard.ts @@ -10,7 +10,7 @@ import { type WebClipboardCutResult, type WebClipboardPasteResult, } from "@interactive-os/json-document-clipboard-web"; -import type { JSONDocument, Pointer } from "@interactive-os/json-document"; +import type { JSONDocument, Pointer } from "@interactive-os/json-document/session"; import type { OutlineNode } from "./schema.js"; export type ClipboardMode = "empty" | "copy" | "cut"; diff --git a/apps/outliner/src/commands/context.ts b/apps/outliner/src/commands/context.ts index 0f70a8d8..86e35a15 100644 --- a/apps/outliner/src/commands/context.ts +++ b/apps/outliner/src/commands/context.ts @@ -1,6 +1,6 @@ // Command 들이 공유하는 ctx 형식 + 공용 헬퍼. -import type { JSONDocument, Pointer, SelectionPoint, SelectionState } from "@interactive-os/json-document"; +import type { JSONDocument, Pointer, SelectionPoint, SelectionState } from "@interactive-os/json-document/session"; import type { OutlineNode } from "../schema.js"; import type { ClipboardApi } from "../clipboard.js"; import { comparePointer } from "../pointer-utils.js"; diff --git a/apps/outliner/src/commands/focus.ts b/apps/outliner/src/commands/focus.ts index 6f191997..73ffc25f 100644 --- a/apps/outliner/src/commands/focus.ts +++ b/apps/outliner/src/commands/focus.ts @@ -1,6 +1,6 @@ // Focus navigation — DFS visible order 위에서 좌표 이동만 (state 미변경). -import type { Pointer } from "@interactive-os/json-document"; +import type { Pointer } from "@interactive-os/json-document/session"; import type { OutlineNode } from "../schema.js"; import { parentOf, nextVisible, prevVisible, firstVisible, lastVisible, firstChildOf, diff --git a/apps/outliner/src/commands/structure.ts b/apps/outliner/src/commands/structure.ts index bacd81a3..76568660 100644 --- a/apps/outliner/src/commands/structure.ts +++ b/apps/outliner/src/commands/structure.ts @@ -1,6 +1,6 @@ import { createCollection } from "@interactive-os/json-document-collection"; import { createOutline } from "@interactive-os/json-document-outline"; -import { type JSONResult, type Pointer } from "@interactive-os/json-document"; +import { type JSONResult, type Pointer } from "@interactive-os/json-document/session"; import { lastIndex, parentOf } from "../pointer-utils.js"; import { focusOf, type CommandContext, targetsOf, sortDfs } from "./context.js"; diff --git a/apps/outliner/src/hooks/useClickPolicy.ts b/apps/outliner/src/hooks/useClickPolicy.ts index dd73fa05..f75dd122 100644 --- a/apps/outliner/src/hooks/useClickPolicy.ts +++ b/apps/outliner/src/hooks/useClickPolicy.ts @@ -4,7 +4,7 @@ // click = collapse import { useCallback } from "react"; -import type { Pointer, SelectionState } from "@interactive-os/json-document"; +import type { Pointer, SelectionState } from "@interactive-os/json-document/session"; import type { Mode } from "../keymap.js"; export function useClickPolicy( diff --git a/apps/outliner/src/hooks/useDraftState.ts b/apps/outliner/src/hooks/useDraftState.ts index eff2bf6a..f079f3a1 100644 --- a/apps/outliner/src/hooks/useDraftState.ts +++ b/apps/outliner/src/hooks/useDraftState.ts @@ -5,7 +5,7 @@ import { type DocumentPersistenceRestoreResult, type DocumentPersistenceSaveResult, } from "@interactive-os/json-document-persist-web"; -import type { JSONDocument } from "@interactive-os/json-document"; +import type { JSONDocument } from "@interactive-os/json-document/session"; import type { OutlineNode } from "../schema.js"; const DRAFT_KEY = "json-document.outliner.draft"; diff --git a/apps/outliner/src/hooks/useToasts.ts b/apps/outliner/src/hooks/useToasts.ts index d772f527..4142705a 100644 --- a/apps/outliner/src/hooks/useToasts.ts +++ b/apps/outliner/src/hooks/useToasts.ts @@ -1,7 +1,7 @@ // Toast 상태. error 는 클릭 시까지 유지 (zod 메시지가 길어서), info 는 2.5s. import { useCallback, useEffect, useRef, useState } from "react"; -import type { JSONDocumentError } from "@interactive-os/json-document"; +import type { JSONDocumentError } from "@interactive-os/json-document/session"; export interface ToastMessage { id: number; diff --git a/apps/outliner/src/pointer-utils.ts b/apps/outliner/src/pointer-utils.ts index cd7314fd..064327b8 100644 --- a/apps/outliner/src/pointer-utils.ts +++ b/apps/outliner/src/pointer-utils.ts @@ -1,6 +1,6 @@ // Outliner-local Pointer helpers. RFC 6901 위에서 outline 트리를 다루는 식별 함수들. -import { parentPointer, lastSegmentIndex, withLastSegment, type Pointer } from "@interactive-os/json-document"; +import { parentPointer, lastSegmentIndex, withLastSegment, type Pointer } from "@interactive-os/json-document/session"; import type { OutlineNode } from "./schema.js"; // Outliner-local 별칭 — json-document 의 path arithmetic 헬퍼를 짧은 이름으로. diff --git a/apps/outliner/tests/stress.test.tsx b/apps/outliner/tests/stress.test.tsx index f08fa429..8b670c2c 100644 --- a/apps/outliner/tests/stress.test.tsx +++ b/apps/outliner/tests/stress.test.tsx @@ -12,7 +12,7 @@ import { renderHook } from "@testing-library/react"; import { afterEach, describe, expect, test } from "vitest"; import { z } from "zod"; import { Outliner, OutlineSchema, SAMPLE } from "../src/index.js"; -import type { JSONDocumentError } from "@interactive-os/json-document"; +import type { JSONDocumentError } from "@interactive-os/json-document/session"; import { useJSONDocument } from "@interactive-os/json-document/react"; afterEach(cleanup); diff --git a/apps/review-comments-lab/src/App.tsx b/apps/review-comments-lab/src/App.tsx index 07124048..fab9678c 100644 --- a/apps/review-comments-lab/src/App.tsx +++ b/apps/review-comments-lab/src/App.tsx @@ -6,7 +6,7 @@ import { type Comments, } from "@interactive-os/json-document-comments"; import { useJSONDocument } from "@interactive-os/json-document/react"; -import { type Pointer } from "@interactive-os/json-document"; +import { type Pointer } from "@interactive-os/json-document/session"; import { z } from "zod"; import "./review-comments-lab.css"; diff --git a/apps/site/index.html b/apps/site/index.html index 66af1565..9b72cf92 100644 --- a/apps/site/index.html +++ b/apps/site/index.html @@ -5,7 +5,7 @@ @@ -13,14 +13,14 @@ diff --git a/apps/site/public/site.webmanifest b/apps/site/public/site.webmanifest index e4145643..38c1f5a2 100644 --- a/apps/site/public/site.webmanifest +++ b/apps/site/public/site.webmanifest @@ -1,7 +1,7 @@ { "name": "@interactive-os/json-document", "short_name": "@interactive-os/json-document", - "description": "Zod-guarded headless JSON editing.", + "description": "Provider-neutral JSON editing protocol and headless document projection.", "start_url": ".", "display": "standalone", "background_color": "#fafaf9", diff --git a/apps/site/src/generated/repo-catalog.ts b/apps/site/src/generated/repo-catalog.ts index e06763a1..4e2c623f 100644 --- a/apps/site/src/generated/repo-catalog.ts +++ b/apps/site/src/generated/repo-catalog.ts @@ -4,7 +4,7 @@ export const repoCatalog = { "repo": { "name": "@interactive-os/json-document-monorepo", "private": true, - "summary": "json-document는 Zod schema가 있는 JSON 문서를 편집하기 위한 headless document\nengine입니다." + "summary": "json-document는 문서, 표, 슬라이드, 캔버스, 노트 편집기가 함께 쓸 수 있는\nprovider-neutral JSON 편집 protocol과 headless document projection입니다." }, "packages": [ { @@ -386,163 +386,43 @@ export const repoCatalog = { "status": "core", "private": false, "publishable": true, - "version": "1.1.0-rc.0", - "description": "Headless JSON editing primitives guarded by Zod schemas.", + "version": "2.0.0-rc.0", + "description": "Provider-neutral JSON editing protocol and headless document projection.", "license": "MIT", - "summary": "Zod schema로 보호되는 JSON state를 읽고, 바꾸고, 선택하고, 복사하고,\n붙여넣고, 되돌리기 위한 headless document layer입니다.", + "summary": "문서, 표, 슬라이드, 캔버스, 노트 편집기가 함께 쓸 수 있는 provider-neutral\nJSON 편집 protocol과 headless document projection입니다.", "guidance": null, "publicExports": [ - "ClipboardCopyError", - "ClipboardCopyOk", - "ClipboardCopyOptions", - "ClipboardCopyResult", - "ClipboardCutError", - "ClipboardCutOk", - "ClipboardCutOptions", - "ClipboardCutResult", - "ClipboardEmpty", - "ClipboardMutationOk", - "ClipboardPasteDiscriminatorMismatch", - "ClipboardPasteError", - "ClipboardPasteResult", - "ClipboardReadOk", - "ClipboardReadOptions", - "ClipboardReadResult", - "ClipboardSource", - "ClipboardState", - "ClipboardWriteOptions", - "DeleteSelectionTextResult", - "EntriesResult", - "EntryKind", - "HistoryTransactionOptions", + "JSONAppliedChange", "JSONCapabilityResult", "JSONChangeMetadata", "JSONDocument", "JSONDocumentCommitOptions", - "JSONDocumentDuplicateError", - "JSONDocumentDuplicateOptions", - "JSONDocumentDuplicateResult", - "JSONDocumentEditError", - "JSONDocumentEditOk", - "JSONDocumentEditResult", - "JSONDocumentError", - "JSONDocumentHistory", - "JSONDocumentInsertOptions", - "JSONDocumentInsertTarget", - "JSONDocumentMoveTarget", - "JSONDocumentOptions", - "JSONDocumentPasteOptions", - "JSONDocumentPasteTarget", - "JSONDocumentSchemaInput", - "JSONDocumentSchemaLike", - "JSONDocumentSchemaOutput", - "JSONDocumentSelectionTarget", - "JSONPatchInput", + "JSONDocumentCommitResult", "JSONPatchOperation", - "JSONResult", + "JSONPatchResult", + "JSONValue", "Pointer", - "PointerSyntaxError", "QueryResult", - "ReadEntry", "ReadResult", - "ReplaceSelectionTextResult", - "ResolveSiblingRangeOptions", - "SchemaDescription", - "SchemaDescriptionResult", - "SchemaErrorCode", - "SchemaErrorResult", - "SchemaKind", - "SchemaKindResult", - "SchemaPathMode", - "SchemaQueryResult", - "SchemaState", - "SelectionAffinity", - "SelectionContext", - "SelectionCursorDirection", - "SelectionCursorErrorCode", - "SelectionCursorOptions", - "SelectionCursorResult", - "SelectionCursorTarget", - "SelectionDirection", - "SelectionEdge", - "SelectionMode", - "SelectionOptions", - "SelectionOrderErrorCode", - "SelectionOrderOptions", - "SelectionOrderedRange", - "SelectionOrderedRangeEntry", - "SelectionPoint", - "SelectionPointObject", - "SelectionPointOrderResult", - "SelectionPointerSpan", - "SelectionPointerSpansResult", - "SelectionRange", - "SelectionRangeInput", - "SelectionRangeOrderResult", - "SelectionRangesOrderResult", - "SelectionScopeErrorCode", - "SelectionScopeOptions", - "SelectionScopeResult", - "SelectionScopeTarget", - "SelectionSnap", - "SelectionSource", - "SelectionSpanOptions", - "SelectionState", - "SelectionTextDeleteDirection", - "SelectionTextDeleteOptions", - "SelectionTextEdit", - "SelectionTextEditErrorCode", - "SelectionTextEditOptions", - "SelectionTextEditsResult", - "SelectionType", - "SiblingLocation", - "SiblingRangeErrorCode", - "SiblingRangeResult", - "TextSurface", - "TextSurfaceAtom", - "TextSurfaceError", - "TextSurfaceErrorCode", - "TextSurfaceFragment", - "TextSurfaceFragmentResult", - "TextSurfaceMutationRange", - "TextSurfaceMutationResult", - "TextSurfaceRange", - "TextSurfaceReplaceOptions", - "TextSurfaceReplaceResult", - "TextSurfaceReplacement", - "TextSurfaceSelectionRange", "appendSegment", - "applyOperation", "applyPatch", - "applyPatchToTrustedState", "buildPointer", "createJSONDocument", - "escapeSegment", - "lastSegment", - "lastSegmentIndex", "parentPointer", "parsePointer", - "replaceTextSurfaceSelection", - "resolveSiblingRange", - "syncTextSurfaceMutation", - "textSurfaceFragment", "trackPointer", - "tryParsePointer", - "unescapeSegment", - "withLastSegment" + "tryParsePointer" ], - "publicExportCount": 138, + "publicExportCount": 20, "keywords": [ - "clipboard", - "crud", + "document", + "editor", "headless", "json", - "redo", - "schema", - "tree", - "treegrid", - "undo", - "zod" + "json-patch", + "json-pointer", + "jsonpath", + "protocol" ] }, { diff --git a/apps/site/src/playgrounds/InterfaceWorkbench.playground.tsx b/apps/site/src/playgrounds/InterfaceWorkbench.playground.tsx index da880b9c..1ba675a2 100644 --- a/apps/site/src/playgrounds/InterfaceWorkbench.playground.tsx +++ b/apps/site/src/playgrounds/InterfaceWorkbench.playground.tsx @@ -22,7 +22,7 @@ import { type JSONCapabilityResult, type Pointer, type SelectionSnap, -} from "@interactive-os/json-document"; +} from "@interactive-os/json-document/session"; import { useJSONDocument } from "@interactive-os/json-document/react"; const Card = z.object({ diff --git a/apps/site/src/routes/Home.tsx b/apps/site/src/routes/Home.tsx index b49d37fb..68f24c25 100644 --- a/apps/site/src/routes/Home.tsx +++ b/apps/site/src/routes/Home.tsx @@ -1,9 +1,9 @@ const modelRows = [ - ["document", "value, patch, duplicate, read/query"], - ["selection", "anchor, focus, ranges, text plans"], - ["clipboard", "copy, cut, paste, payload insertion"], - ["history", "undo, redo, transaction metadata"], - ["can*", "reasoned checks for UI and tests"], + ["protocol", "provider-neutral JSON Patch application"], + ["projection", "value, at, query, canPatch, commit, subscribe"], + ["acceptance", "optional provider-neutral candidate validation"], + ["session", "optional selection, clipboard, history, rich edit verbs"], + ["host", "rendering, focus, keyboard, persistence, collaboration"], ] as const; const BASE_PATH = import.meta.env.BASE_URL.replace(/\/$/, ""); @@ -19,14 +19,14 @@ export function Home() {

- Zod-guarded JSON editing + Provider-neutral JSON editing

json-document

- A headless document facade for JSON Patch, JSON Pointer, JSONPath, - selection, clipboard, history, and reasoned capability checks. + A headless JSON protocol and six-member document projection for + documents, tables, slides, canvases, and notes.

@@ -49,7 +49,7 @@ export function Home() {
Install
-
npm install @interactive-os/json-document zod
+
npm install @interactive-os/json-document@2.0.0-rc.0
Start
{`import { createJSONDocument } from "@interactive-os/json-document";`}
@@ -82,8 +82,8 @@ export function Home() {