Skip to content

JSONDocument Method Reference

유용태 edited this page Jun 18, 2026 · 4 revisions

JSONDocument Method Reference

JSONDocument<T>는 제품 코드가 가장 자주 붙잡는 core runtime object다. 현재 값, 편집 command, 읽기, 검색, selection, clipboard, history, schema 확인이 같은 instance에 모여 있다.

이 페이지는 method 단위로 언제 쓰는지, 무엇을 반환하는지, 실패를 어떻게 다루는지 설명한다. 전체 type 이름 목록은 json-document Core API Reference를 기준으로 한다.

이 페이지도 위에서 아래로 제품 개발자가 바로 만지는 상태와 command에서 시작해, 점점 더 낮은 수준의 patch/lifecycle API로 내려간다.

기본 상태

interface JSONDocument<T> {
  readonly value: T;
  readonly lastPatch: ReadonlyArray<JSONPatchOperation>;
  readonly selection: SelectionState | undefined;
  readonly history: JSONDocumentHistory;
  readonly clipboard: ClipboardState<T>;
  readonly schema: SchemaState;
}

value

현재 document state다. 항상 schema를 통과한 T로 취급한다. 직접 mutate하지 말고 replace, insert, delete, commit 같은 command로 바꾼다.

lastPatch

마지막으로 성공한 변경에서 실제 적용된 JSON Patch operation 목록이다.

selection, annotation, comment anchor, external id mapping처럼 document 바깥의 pointer 상태를 따라가야 하는 adapter가 trackPointer(pointer, doc.lastPatch)와 함께 쓴다.

selection

선택 기능을 켠 document에서만 존재한다. selection: true 또는 selection: SelectionOptions로 만든 경우 SelectionState를 반환한다.

history

Undo/redo stack과 transaction 제어를 제공한다. 일반 제품 command는 top-level doc.undo()doc.redo()를 우선 사용하고, 세밀한 제어가 필요할 때 doc.history를 쓴다.

clipboard

Document instance 내부의 headless clipboard다. browser clipboard가 아니다.

schema

현재 document schema를 path 기준으로 확인하는 runtime affordance API다. Form, paste guard, import review, command availability를 만들 때 쓴다.

읽기와 검색

at(path)

at(path: Pointer): ReadResult;

JSON Pointer로 값을 읽는다.

const title = doc.at("/title");
if (title.ok) title.value;

실패:

  • invalid_pointer: pointer syntax가 잘못됨
  • path_not_found: pointer는 유효하지만 값이 없음

exists(path)

exists(path: Pointer): boolean;

해당 path에 값이 있는지 boolean으로 확인한다. 실패 이유가 필요하면 at(path)를 쓴다.

entries(path)

entries(path: Pointer): EntriesResult;

해당 path의 child entry 목록을 반환한다. Object, array, record를 같은 방식으로 순회할 수 있다. Primitive는 성공하더라도 entries: []다.

find(jsonpath) / query(jsonpath)

find(jsonpath: string): QueryResult;
query(jsonpath: string): QueryResult;

JSONPath로 document를 검색하고 결과를 JSON Pointer 배열로 반환한다.

findquery는 같은 검색 surface로 볼 수 있다. 검색은 JSONPath로 하고, 변경은 반환된 JSON Pointer로 한다.

const result = doc.find("$..cards[?(@.done==false)]");
if (result.ok) {
  for (const pointer of result.pointers) {
    doc.replace(`${pointer}/done`, true);
  }
}

실패:

  • invalid_query: JSONPath syntax가 잘못됨

편집 command

insert(target, value) / insert(value)

insert(
  target: JSONDocumentInsertTarget,
  value: unknown,
  options?: JSONDocumentInsertOptions,
): JSONDocumentEditResult;
insert(value: unknown): JSONDocumentEditResult;

값을 삽입한다. target을 생략하면 selection이 켜져 있을 때 현재 selection을 기준으로 삽입 계획을 만든다.

doc.insert("/items/-", { id: "new", title: "New" });
doc.insert({ after: "/items/0" }, { id: "new", title: "New" });
doc.insert({ id: "new", title: "New" });

replace(path, value) / replace(value)

replace(path: Pointer, value: unknown): JSONDocumentEditResult;
replace(value: unknown): JSONDocumentEditResult;

값을 교체한다. replace(value)는 selection을 기본 target으로 쓰는 편집 UI에서 가장 자주 쓰인다.

doc.replace("/title", "Ready");
doc.replace("Ready");

delete(source?)

delete(source?: SelectionSource): JSONDocumentEditResult;

Pointer 하나, pointer 배열, 또는 현재 selection을 삭제한다.

doc.delete("/items/0");
doc.delete(["/items/0", "/items/1"]);
doc.delete();

move(source, target) / move(target)

move(source: Pointer, target: JSONDocumentMoveTarget): JSONDocumentEditResult;
move(target: JSONDocumentMoveTarget): JSONDocumentEditResult;

값을 이동한다. move(target)은 현재 selection을 source로 사용하는 편집 UI를 위한 overload다.

doc.move("/items/0", "/items/2");
doc.move("/items/0", { after: "/items/2" });
doc.move({ before: "/items/2" });

주요 실패:

  • empty_selection
  • invalid_pointer
  • path_not_found
  • move_into_self
  • schema_violation

duplicate(source, options?) / duplicate(options?)

duplicate(
  source: Pointer,
  options?: JSONDocumentDuplicateOptions,
): JSONDocumentDuplicateResult<T>;
duplicate(options?: JSONDocumentDuplicateOptions): JSONDocumentDuplicateResult<T>;

값을 복제한다. source를 생략하면 현재 primary selection을 사용한다.

성공 시:

{
  ok: true;
  value: T;
  applied: ReadonlyArray<JSONPatchOperation>;
  duplicatedTo: Pointer;
}

rekey option은 복제한 객체의 id-like field 충돌을 피할 때 쓴다.

doc.duplicate("/items/0", {
  rekey: { fields: ["id"], strategy: "suffix" },
});

주요 실패:

  • empty_selection
  • rekey_failed
  • missing_new_key
  • key_conflict
  • schema_violation

Capability preflight

can* method는 command 실행 전 가능 여부와 실패 이유를 확인한다.

canPatch(operations: JSONPatchInput): JSONCapabilityResult;
canFind(jsonpath: string): JSONCapabilityResult;
canInsert(value: unknown): JSONCapabilityResult;
canInsert(path: Pointer, value: unknown): JSONCapabilityResult;
canReplace(value: unknown): JSONCapabilityResult;
canReplace(path: Pointer, value: unknown): JSONCapabilityResult;
canDelete(source?: SelectionSource): JSONCapabilityResult;
canMove(target: Pointer): JSONCapabilityResult;
canMove(source: Pointer, target: Pointer): JSONCapabilityResult;
canDuplicate(source: Pointer, options?: JSONDocumentDuplicateOptions): JSONCapabilityResult;
canDuplicate(options?: JSONDocumentDuplicateOptions): JSONCapabilityResult;
canCopy(source?: SelectionSource): JSONCapabilityResult;
canCut(source?: SelectionSource): JSONCapabilityResult;
canPaste(target?: JSONDocumentPasteTarget, options?: JSONDocumentPasteOptions): JSONCapabilityResult;
canUndo(): JSONCapabilityResult;
canRedo(): JSONCapabilityResult;

UI button disabled, menu availability, command palette, shortcut preflight에서 사용한다. can* 성공 이후에도 실제 command는 다시 검증한다.

Clipboard method

Top-level doc.copy, doc.cut, doc.pastedoc.clipboard의 같은 command를 호출하는 제품 친화 surface다.

copy(source?, options?)

copy(source?: SelectionSource, options?: ClipboardCopyOptions): ClipboardCopyResult;

값을 document clipboard에 복사한다. source를 생략하면 selection을 사용한다.

cut(source?, options?)

cut(source?: SelectionSource, options?: ClipboardCutOptions): ClipboardCutResult<T>;

값을 clipboard에 저장하고 document에서 제거한다.

paste(target?, options?)

paste(
  target?: JSONDocumentPasteTarget,
  options?: JSONDocumentPasteOptions,
): ClipboardPasteResult<T>;

Clipboard payload 또는 options.payload를 target에 붙여넣는다.

Target 형태:

type JSONDocumentPasteTarget =
  | Pointer
  | { before: Pointer }
  | { after: Pointer }
  | { replace: Pointer };

doc.clipboard.read(options?)

read(options?: ClipboardReadOptions): ClipboardReadResult;

현재 buffer를 읽는다. 비어 있으면 empty_clipboard다.

doc.clipboard.write(payload, options?)

write(payload: unknown, options?: ClipboardWriteOptions): JSONResult;

Payload를 직접 clipboard에 쓴다. 외부 clipboard adapter, drag/drop adapter, extension payload bridge에서 사용한다.

doc.clipboard.clear()

clear(): void;

Clipboard buffer를 비운다.

History method

undo() / redo()

doc.undo(): JSONCapabilityResult;
doc.redo(): JSONCapabilityResult;

제품 command로 undo/redo를 실행한다. 실패도 result로 반환하므로 button handler에서 바로 분기할 수 있다.

doc.history.undo() / doc.history.redo()

undo(): boolean;
redo(): boolean;

Lower-level control이다. 성공 여부만 필요할 때 사용한다.

doc.history.transaction(...)

transaction(fn: () => void): void;
transaction(options: HistoryTransactionOptions, fn: () => void): void;

여러 document command를 하나의 history entry로 묶는다.

doc.history.transaction({ label: "bulk edit", origin: "keyboard" }, () => {
  doc.replace("/title", "Ready");
  doc.replace("/done", true);
});

doc.history.mergeLast(options?)

mergeLast(options?: { mergeKey?: string }): boolean;

마지막 두 history entry를 하나로 합친다. 반복 입력, drag update, text replace 연속 입력을 하나의 undo 단위로 줄일 때 쓴다.

Schema method

doc.schema.at(path, mode?)

at(path: Pointer, mode?: SchemaPathMode): SchemaQueryResult;

해당 path의 schema 설명과 kind를 함께 읽는다.

doc.schema.kind(path, mode?)

kind(path: Pointer, mode?: SchemaPathMode): SchemaKindResult;

해당 path의 schema kind만 빠르게 확인한다.

doc.schema.accepts(path, value, mode?)

accepts(path: Pointer, value: unknown, mode?: SchemaPathMode): JSONCapabilityResult;

해당 path 또는 insert slot이 value를 받을 수 있는지 확인한다.

doc.schema.describe(path, mode?)

describe(path: Pointer, mode?: SchemaPathMode): SchemaDescriptionResult;

Form, inspector, import review UI가 사용할 수 있는 schema description을 반환한다.

mode:

type SchemaPathMode = "value" | "insert";

value는 현재 값 위치를 뜻하고, insert는 새 값이 들어갈 slot을 뜻한다.

변경 적용

patch(operations, metadata?)

patch(operations: JSONPatchInput, metadata?: JSONChangeMetadata): JSONResult;

JSON Patch operation 하나 또는 배열을 적용한다.

사용 기준:

  • 이미 JSON Patch operation을 알고 있을 때 사용한다.
  • schema 검증을 통과한 경우에만 state가 바뀐다.
  • 실패하면 state, selection, clipboard, history가 부분적으로 바뀌지 않는다.
  • metadata는 history label, origin, mergeKey, selectionBefore/selectionAfter 같은 사용자 의도 정보를 전달한다.
  • 실패 result는 stable code로 분기한다. reason 문구는 진단용이며 exact string contract가 아니다.
const result = doc.patch({ op: "replace", path: "/title", value: "Ready" });
if (!result.ok) {
  result.code;
  result.pointer;
}

commit(operations, options?)

commit(
  operations: ReadonlyArray<JSONPatchOperation>,
  options?: JSONDocumentCommitOptions,
): JSONResult;

여러 operation을 하나의 사용자 command로 적용한다.

patch와 같은 검증/원자성 규칙을 따른다. 차이는 호출 의도가 더 명확하다는 점이다. 제품에서 "완료 처리", "카드 이동", "일괄 수정"처럼 history에 하나의 command로 남겨야 하는 변경에 적합하다.

구조 편집 후 다음 선택 위치를 알고 있으면 selectionAfter를 넘긴다. 이 값은 patch와 같은 history entry에 기록되고, undo/redo에서 value와 함께 복원된다.

doc.commit([
  { op: "replace", path: "/title", value: "Ready" },
  { op: "replace", path: "/done", value: true },
], {
  label: "complete card",
  origin: "keyboard",
  selectionAfter: "/title",
});

load(value, options?)

load(value: unknown, options?: { preserveHistory?: boolean }): JSONResult;

새 값을 document에 로드한다. 외부 저장소에서 snapshot을 가져오거나 route 전환으로 document 전체를 교체할 때 쓴다.

reset(value?)

reset(value?: unknown): JSONResult;

Document를 초기 상태 또는 전달한 값으로 되돌린다. 전달한 값이 있으면 schema 검증을 통과해야 한다.

Subscribe

subscribe(listener)

subscribe(listener: (
  applied: ReadonlyArray<JSONPatchOperation>,
  metadata?: JSONChangeMetadata,
) => void): () => void;

Document 변경을 구독한다. Listener는 성공적으로 적용된 patch와 metadata를 받는다. 반환값은 unsubscribe 함수다.

const unsubscribe = doc.subscribe((applied, metadata) => {
  console.log(applied, metadata?.origin);
});

unsubscribe();

Clone this wiki locally