Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
- name: Install dependencies
if: steps.scope.outputs.package_any == 'true'
run: npm ci --no-audit --no-fund
- name: Verify active v2 packages
- name: Verify active v3 packages
if: steps.scope.outputs.package_full == 'true'
run: npm run verify -w @interactive-os/json-document && npm run verify:companions && npm run standard:check && npm run docs:evaluate
- name: Verify package documentation
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lab-extensions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ jobs:
- uses: actions/setup-node@v6
with:
node-version: "22"
- name: Verify archived code is outside the v2 release graph
- name: Verify archived code is outside the v3 release graph
run: npm run archive:check
6 changes: 3 additions & 3 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Publish v2 package
name: Publish v3 package

on:
push:
Expand All @@ -12,7 +12,7 @@ permissions:
id-token: write

concurrency:
group: npm-v2-package-${{ github.ref }}
group: npm-v3-package-${{ github.ref }}
cancel-in-progress: false

jobs:
Expand Down Expand Up @@ -82,7 +82,7 @@ jobs:
'
- name: Install dependencies
run: npm ci --no-audit --no-fund
- name: Verify v2 release graph
- name: Verify v3 release graph
run: npm run release:check
- name: Publish package
env:
Expand Down
39 changes: 20 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# json-document

json-document는 문서, 표, 슬라이드, 캔버스, 노트 편집기가 함께 쓸 수 있는
provider-neutral JSON 편집 protocol과 headless document projection입니다.
implementation-neutral JSON 편집 API와 headless JSON Document입니다.

v2 root는 JSON, JSON Pointer, JSONPath, JSON Patch만 전제로 하며 Zod, React,
v3 root는 JSON, JSON Pointer, JSONPath, JSON Patch만 전제로 하며 Zod, React,
selection, clipboard, history를 필수 계약에 넣지 않습니다.

```txt
Pure Protocol
|-> local provider -----------\
| > same six-member Document Projection
`-> collaboration provider --/ |-> optional history/text authoring
`-> optional DOM/IME lease
stateless JSON Patch
|-> local implementation -----\
| > same six-member JSON Document
`-> collaboration engine -----/ |-> optional history/text authoring
`-> optional native-input DOM lease
```

로컬 전용 사용자는 Core만 설치합니다. 협업으로 전환해도 편집기가 받는
`JSONDocument` 포트는 바뀌지 않고, causal merge와 DOM publication lease만
`JSONDocument` 포트는 바뀌지 않고, causal merge와 native-input DOM lease만
독립 package로 추가합니다.

공식 사이트: https://developer-1px.github.io/json-document/
Expand All @@ -29,21 +29,22 @@ Pure Protocol
| 공개 API | [docs/public/api.md](docs/public/api.md) |
| 문서 구조 | [docs/README.md](docs/README.md) |
| 변경 기록 | [docs/changelog.md](docs/changelog.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) |
| 개념·이름 정본 | [docs/standard/concept-and-naming-standard.md](docs/standard/concept-and-naming-standard.md) |
| v3 JSON Document profile | [docs/standard/v3-json-document-profile.md](docs/standard/v3-json-document-profile.md) |
| v3 공개 표면 manifest | [docs/standard/v3-public-surface.json](docs/standard/v3-public-surface.json) |
| 1.x 기록 | [archive/v1/docs](archive/v1/docs) |

## 코드 지도

| 위치 | 역할 |
| --- | --- |
| [packages/json-document](packages/json-document) | 배포되는 v2 Kernel |
| [packages/json-document-collaboration](packages/json-document-collaboration) | transport-free causal multi-writer provider |
| [packages/contenteditable-collaboration](packages/contenteditable-collaboration) | collaborative string을 위한 optional DOM/IME publication lease |
| [apps/site](apps/site) | v2 Core 공개 문서 사이트 |
| [packages/json-document](packages/json-document) | 배포되는 v3 Kernel |
| [packages/json-document-collaboration](packages/json-document-collaboration) | transport-free causal collaboration engine |
| [packages/contenteditable-collaboration](packages/contenteditable-collaboration) | collaborative string을 위한 optional native-input DOM lease |
| [apps/site](apps/site) | v3 Core 공개 문서 사이트 |
| [archive/v1](archive/v1) | 배포·workspace·검증에서 분리된 1.x 기록 |

v2 Kernel release는 `@interactive-os/json-document` 하나이며 dependency-free
v3 Kernel release는 `@interactive-os/json-document` 하나이며 dependency-free
Core로 남습니다. 두 collaboration package는 독립 version과 release lifecycle을
가진 optional companion입니다. Selection, clipboard, persistence와 제품별 DOM
lifecycle은 host adapter가 여섯-member `JSONDocument` 위에서 조합합니다.
Expand All @@ -52,13 +53,13 @@ lifecycle은 host adapter가 여섯-member `JSONDocument` 위에서 조합합니

## 경계

v2 Kernel이 제공하는 최소 계약:
v3 Kernel이 제공하는 최소 계약:

- immutable JSON snapshot
- immutable document value
- JSON Pointer read와 JSONPath query
- state를 바꾸지 않는 `canPatch`
- state를 바꾸지 않는 `validatePatch`
- ordered atomic JSON Patch commit
- canonical applied change publication
- canonical applied change notification

편집 툴이 계속 소유하는 것:

Expand Down
6 changes: 3 additions & 3 deletions apps/site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="description"
content="Provider-neutral JSON editing protocol and six-member headless document projection for JSON Patch, JSON Pointer, and JSONPath."
content="Implementation-neutral JSON editing and a six-member headless JSON Document for JSON Patch, JSON Pointer, and JSONPath."
/>
<meta name="theme-color" content="#fafaf9" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="@interactive-os/json-document" />
<meta property="og:title" content="json-document - Headless JSON editing" />
<meta
property="og:description"
content="Provider-neutral JSON editing protocol and six-member headless document projection for JSON Patch, JSON Pointer, and JSONPath."
content="Implementation-neutral JSON editing and a six-member headless JSON Document for JSON Patch, JSON Pointer, and JSONPath."
/>
<meta property="og:url" content="https://developer-1px.github.io/json-document/" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="json-document - Headless JSON editing" />
<meta
name="twitter:description"
content="Provider-neutral JSON editing protocol and six-member headless document projection for JSON Patch, JSON Pointer, and JSONPath."
content="Implementation-neutral JSON editing and a six-member headless JSON Document for JSON Patch, JSON Pointer, and JSONPath."
/>
<link rel="canonical" href="https://developer-1px.github.io/json-document/" />
<link rel="icon" href="%BASE_URL%favicon.svg" type="image/svg+xml" />
Expand Down
2 changes: 1 addition & 1 deletion apps/site/public/site.webmanifest
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@interactive-os/json-document",
"short_name": "@interactive-os/json-document",
"description": "Provider-neutral JSON editing protocol and headless document projection.",
"description": "Implementation-neutral JSON editing and a headless JSON Document.",
"start_url": ".",
"display": "standalone",
"background_color": "#fafaf9",
Expand Down
14 changes: 7 additions & 7 deletions apps/site/src/routes/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const modelRows = [
["protocol", "provider-neutral JSON Patch application"],
["projection", "value, at, query, canPatch, commit, subscribe"],
["acceptance", "optional provider-neutral candidate validation"],
["patch", "stateless JSON Patch application"],
["document", "value, at, query, validatePatch, commit, subscribe"],
["validation", "optional implementation-neutral candidate validation"],
["host", "selection, history, rendering, focus, persistence, collaboration"],
] as const;

Expand All @@ -18,13 +18,13 @@ export function Home() {
<div className="mx-auto grid max-w-6xl gap-8 px-4 py-10 lg:grid-cols-[minmax(0,1fr)_24rem] lg:py-14">
<div>
<p className="m-0 text-xs font-semibold uppercase tracking-wide text-stone-400">
Provider-neutral JSON editing
Implementation-neutral JSON editing
</p>
<h1 className="mb-4 mt-2 text-4xl font-semibold tracking-normal text-stone-950">
json-document
</h1>
<p className="m-0 max-w-2xl text-base leading-7 text-stone-600">
A headless JSON protocol and six-member document projection for
A headless JSON API and six-member JSON Document for
documents, tables, slides, canvases, and notes.
</p>
<div className="mt-6 flex flex-wrap gap-2">
Expand All @@ -44,8 +44,8 @@ export function Home() {
</div>

<div className="rounded border border-stone-200 bg-stone-950 p-3 text-stone-100">
<div className="mb-2 text-xs font-medium text-stone-400">Install</div>
<pre className="m-0 overflow-x-auto text-sm leading-6"><code>npm install @interactive-os/json-document@2.0.0</code></pre>
<div className="mb-2 text-xs font-medium text-stone-400">Release</div>
<pre className="m-0 overflow-x-auto text-sm leading-6"><code>3.0.0 · npm publication pending</code></pre>
<div className="mt-4 border-t border-stone-800 pt-3 text-xs font-medium text-stone-400">Start</div>
<pre className="m-0 mt-2 overflow-x-auto text-sm leading-6"><code>{`import { createJSONDocument } from "@interactive-os/json-document";`}</code></pre>
</div>
Expand Down
8 changes: 4 additions & 4 deletions apps/site/src/site-routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,28 @@
"path": "/",
"label": "Overview",
"title": "json-document - Headless JSON editing",
"description": "Provider-neutral JSON editing protocol and six-member headless document projection for JSON Patch, JSON Pointer, and JSONPath.",
"description": "Implementation-neutral JSON editing and a six-member headless JSON Document for JSON Patch, JSON Pointer, and JSONPath.",
"group": "Start"
},
{
"path": "/docs",
"label": "Docs",
"title": "json-document Docs - json-document",
"description": "User guide to the v2 Kernel, Pure Protocol, Document Projection, and host adapter boundaries.",
"description": "User guide to stateless JSON Patch, the v3 JSON Document, validation, and host adapter boundaries.",
"group": "Start"
},
{
"path": "/docs/tutorial",
"label": "Quickstart",
"title": "Tutorial - json-document",
"description": "Step-by-step guide to reading, probing, committing, and subscribing to provider-neutral JSON document changes.",
"description": "Step-by-step guide to reading, validating, committing, and subscribing to implementation-neutral JSON document changes.",
"group": "Start"
},
{
"path": "/docs/api",
"label": "API reference",
"title": "json-document API - json-document",
"description": "Public v2 Kernel API reference for the exact root surface, six-member Projection, JSON Patch, Pointer, and JSONPath.",
"description": "Public v3 Kernel API reference for the exact six-member JSON Document surface, JSON Patch, Pointer, and JSONPath.",
"group": "Start"
}
]
64 changes: 54 additions & 10 deletions apps/site/tests/docs-consistency.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ const publicDocs = {
};
const docs = {
rootReadme: read("README.md"),
docsReadme: read("docs/README.md"),
readme: read("packages/json-document/README.md"),
profile: read("docs/standard/v2-projection-profile.md"),
naming: read("docs/standard/concept-and-naming-standard.md"),
profile: read("docs/standard/v3-json-document-profile.md"),
llms: read("llms.txt"),
site: Object.values(publicDocs).join("\n\n"),
...publicDocs,
Expand All @@ -52,8 +54,9 @@ describe("public docs consistency", () => {
"quickstart.md",
]);
expect(readdirSync(join(root, "docs/standard")).sort()).toEqual([
"v2-projection-profile.md",
"v2-public-surface.json",
"concept-and-naming-standard.md",
"v3-json-document-profile.md",
"v3-public-surface.json",
]);

expect(exists("apps/site/src/docs/json-document-concepts.md")).toBe(false);
Expand All @@ -64,7 +67,7 @@ describe("public docs consistency", () => {
expect(exists("docs/standard/json-document-spec.md")).toBe(false);
});

test("keeps the active site on the v2 core routes", () => {
test("keeps the active site on the v3 core routes", () => {
expect(siteRoutes.map((route) => route.path)).toEqual([
"/",
"/docs",
Expand Down Expand Up @@ -113,6 +116,7 @@ describe("public docs consistency", () => {
test("keeps core usage and project understanding in public docs", () => {
expect(docs.rootReadme).toMatch(/## 문서 지도/);
expect(docs.rootReadme).toMatch(/docs\/public\/overview\.md/);
expect(docs.rootReadme).toMatch(/docs\/standard\/concept-and-naming-standard\.md/);
expect(docs.rootReadme).toMatch(/## 코드 지도/);
expect(docs.rootReadme).toMatch(/packages\/json-document/);
expect(docs.overview).toMatch(/## 배경/);
Expand All @@ -121,9 +125,41 @@ describe("public docs consistency", () => {
expect(docs.quickstart).toMatch(/튜토리얼: 작은 카드 편집기 만들기/);
expect(docs.api).toMatch(/## 작업별 진입점/);
expect(docs.api).toMatch(/ReadResult/);
expect(docs.readme).toMatch(/npm install @interactive-os\/json-document@2\.0\.0/);
expect(docs.readme).toMatch(/provider-neutral/);
expect(docs.llms).toMatch(/2\.0\.0.*Stable/);
expect(docs.readme).toMatch(/npm install @interactive-os\/json-document@3\.0\.0/);
expect(docs.readme).toMatch(/implementation-neutral/);
expect(docs.llms).toMatch(/v3 표준 상태는 Stable/);
expect(docs.llms).toMatch(/source release version은 `3\.0\.0`/);
expect(docs.llms).toMatch(/npm에는\s+아직 publication되지 않았다/);
});

test("locks one canonical concept and naming standard", () => {
expect(docs.naming).toMatch(/상태: Canonical/);
expect(docs.naming).toMatch(/## 이름 권위/);
expect(docs.naming).toMatch(/## 개념 경계/);
expect(docs.naming).toMatch(/## 접두어와 casing/);
expect(docs.naming).toMatch(/## 접미어/);
expect(docs.naming).toMatch(/## 함수 동사/);
expect(docs.naming).toMatch(/## Boolean/);
expect(docs.naming).toMatch(/## Protocol vocabulary boundary/);
expect(docs.naming).toMatch(/## Current public surface decisions/);
expect(docs.naming).toMatch(/## 새 concept admission/);

for (const term of [
"JSON Document",
"patch validation",
"change notification",
"collaboration engine",
"replica status",
"native-input DOM lease",
]) {
expect(docs.naming).toContain(term);
}

for (const source of [docs.rootReadme, docs.overview, docs.readme]) {
expect(source).not.toMatch(
/Pure Protocol|Document Projection|document projection|local provider|collaboration provider|DOM publication lease/,
);
}
});

test("keeps JSONPath scoped to search and JSON Pointer scoped to mutation", () => {
Expand Down Expand Up @@ -152,7 +188,7 @@ describe("public docs consistency", () => {
}
});

test("locks the documented v2 root contract", () => {
test("locks the documented v3 root contract", () => {
expect(Object.keys(publicContract)).toEqual(["root"]);
expect(publicContract.root.values).toEqual([
"appendSegment",
Expand All @@ -166,20 +202,28 @@ describe("public docs consistency", () => {
]);
expect(publicContract.root.types).toEqual([
"JSONAppliedChange",
"JSONCapabilityResult",
"JSONChangeMetadata",
"JSONDocument",
"JSONDocumentOptions",
"JSONDocumentCommitOptions",
"JSONDocumentCommitResult",
"JSONPatchOperation",
"JSONPatchResult",
"JSONPatchValidationResult",
"JSONValue",
"Pointer",
"QueryResult",
"ReadResult",
]);

for (const member of ["value", "at", "query", "canPatch", "commit", "subscribe"]) {
for (const member of [
"value",
"at",
"query",
"validatePatch",
"commit",
"subscribe",
]) {
expect(docs.api).toContain(member);
}
expect(docs.api).toMatch(/applyPatch[\s\S]*RFC 6902/);
Expand Down
Loading