@miy2/xml-api 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -2
- package/dist/collab/bridge.js +1 -2
- package/dist/cst/cst-utils.d.ts +11 -0
- package/dist/cst/cst-utils.js +32 -0
- package/dist/cst/grammar.js +11 -25
- package/dist/cst/parser.js +7 -11
- package/dist/cst/xml-cst.js +1 -5
- package/dist/cst/xml-grammar.js +83 -86
- package/dist/dom.d.ts +20 -1
- package/dist/dom.js +93 -60
- package/dist/engine/editor-state.js +1 -5
- package/dist/engine/sync-engine.d.ts +43 -9
- package/dist/engine/sync-engine.js +166 -122
- package/dist/engine/transaction-builder.d.ts +14 -0
- package/dist/engine/transaction-builder.js +143 -0
- package/dist/engine/transaction.d.ts +3 -0
- package/dist/engine/transaction.js +12 -8
- package/dist/history-manager.d.ts +4 -0
- package/dist/history-manager.js +75 -5
- package/dist/model/formatter.d.ts +2 -0
- package/dist/model/formatter.js +15 -18
- package/dist/model/xml-api-model.d.ts +17 -6
- package/dist/model/xml-api-model.js +40 -34
- package/dist/model/xml-binder.d.ts +8 -1
- package/dist/model/xml-binder.js +48 -34
- package/dist/model/xml-schema.js +1 -5
- package/dist/view/schema-view.d.ts +80 -0
- package/dist/view/schema-view.js +222 -0
- package/dist/view/view-binder.d.ts +47 -0
- package/dist/view/view-binder.js +163 -0
- package/dist/xml-api-events.d.ts +8 -4
- package/dist/xml-api-events.js +1 -5
- package/dist/xml-api.d.ts +36 -22
- package/dist/xml-api.js +77 -59
- package/package.json +4 -2
- package/LICENSE.md +0 -21
package/dist/xml-api.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const sync_engine_1 = require("./engine/sync-engine");
|
|
6
|
-
const xml_api_model_1 = require("./model/xml-api-model");
|
|
1
|
+
import { createWrapper, Document, Element, } from "./dom";
|
|
2
|
+
import { SyncEngine } from "./engine/sync-engine";
|
|
3
|
+
import { ModelElement } from "./model/xml-api-model";
|
|
4
|
+
import { SchemaView } from "./view/schema-view";
|
|
7
5
|
/**
|
|
8
6
|
* The primary entry point for the XML API.
|
|
9
|
-
* Orchestrates the synchronization between source code (CST)
|
|
7
|
+
* Orchestrates the synchronization between source code (CST), the logical Model, and Schema Views.
|
|
8
|
+
*
|
|
9
|
+
* This class serves as the central hub for the "Three-Level Reconciliation" architecture:
|
|
10
|
+
* 1. Source <-> CST: Incremental parsing.
|
|
11
|
+
* 2. CST <-> Model: Logical binding and identity preservation.
|
|
12
|
+
* 3. Model <-> View: Schema projection and filtering (via `createView`).
|
|
10
13
|
*/
|
|
11
|
-
class XMLAPI {
|
|
14
|
+
export class XMLAPI {
|
|
12
15
|
/**
|
|
13
16
|
* Initializes the API with the source XML string.
|
|
14
17
|
* @param source The initial XML source code.
|
|
@@ -16,49 +19,58 @@ class XMLAPI {
|
|
|
16
19
|
*/
|
|
17
20
|
constructor(source, grammar) {
|
|
18
21
|
this.document = null;
|
|
19
|
-
this.
|
|
22
|
+
this._engine = new SyncEngine(source, grammar);
|
|
20
23
|
}
|
|
21
24
|
// --- Read-only State Access ---
|
|
25
|
+
/** The underlying synchronization engine. */
|
|
26
|
+
get engine() {
|
|
27
|
+
return this._engine;
|
|
28
|
+
}
|
|
22
29
|
/** The current source code string. */
|
|
23
30
|
get source() {
|
|
24
|
-
return this.
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Alias for `source` to maintain compatibility with existing tests/demos temporarily.
|
|
28
|
-
* @deprecated Use `source` instead.
|
|
29
|
-
*/
|
|
30
|
-
get input() {
|
|
31
|
-
return this.engine.source;
|
|
31
|
+
return this._engine.source;
|
|
32
32
|
}
|
|
33
33
|
/** The authoritative logical model. */
|
|
34
34
|
get model() {
|
|
35
|
-
return this.
|
|
35
|
+
return this._engine.model;
|
|
36
36
|
}
|
|
37
37
|
/** The Concrete Syntax Tree (Physical layer). */
|
|
38
38
|
get cst() {
|
|
39
|
-
return this.
|
|
39
|
+
return this._engine.cst;
|
|
40
40
|
}
|
|
41
41
|
/** The grammar used for parsing. */
|
|
42
42
|
get grammar() {
|
|
43
|
-
return this.
|
|
43
|
+
return this._engine.grammar;
|
|
44
44
|
}
|
|
45
45
|
// --- Operations ---
|
|
46
|
+
/**
|
|
47
|
+
* Creates a projected view of the document.
|
|
48
|
+
*
|
|
49
|
+
* A SchemaView allows you to work with a filtered subset of the document (e.g., only XHTML tags)
|
|
50
|
+
* while the underlying system maintains full fidelity of the original source (including comments,
|
|
51
|
+
* custom tags, and formatting) in the background.
|
|
52
|
+
*
|
|
53
|
+
* @param config Configuration for the view, including filter logic.
|
|
54
|
+
* @returns A `SchemaView` instance providing a DOM-like interface for the projected content.
|
|
55
|
+
*/
|
|
56
|
+
createView(config = {}) {
|
|
57
|
+
if (!this._engine.model) {
|
|
58
|
+
throw new Error("Cannot create view: Model not initialized");
|
|
59
|
+
}
|
|
60
|
+
return new SchemaView(this._engine.model, this._engine, config);
|
|
61
|
+
}
|
|
46
62
|
/**
|
|
47
63
|
* Updates the source code directly (e.g. from a text editor).
|
|
48
64
|
* Attempts an optimized incremental update, falling back to full re-parse if needed.
|
|
49
65
|
* @param from Start index of the range to replace.
|
|
50
66
|
* @param to End index of the range.
|
|
51
67
|
* @param text The new text to insert.
|
|
68
|
+
* @param meta (Optional) Metadata for the transaction.
|
|
52
69
|
*/
|
|
53
|
-
updateSource(from, to, text
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* Alias for `updateSource` to maintain compatibility.
|
|
58
|
-
* @deprecated Use `updateSource` instead.
|
|
59
|
-
*/
|
|
60
|
-
updateInput(from, to, text) {
|
|
61
|
-
this.updateSource(from, to, text);
|
|
70
|
+
updateSource(from, to, text,
|
|
71
|
+
// biome-ignore lint/suspicious/noExplicitAny: Metadata can store any type
|
|
72
|
+
meta) {
|
|
73
|
+
this._engine.updateSource(from, to, text, meta);
|
|
62
74
|
}
|
|
63
75
|
/**
|
|
64
76
|
* Returns a DOM-compatible Document object linked to this API.
|
|
@@ -67,11 +79,11 @@ class XMLAPI {
|
|
|
67
79
|
getDocument() {
|
|
68
80
|
if (this.document)
|
|
69
81
|
return this.document;
|
|
70
|
-
const doc = new
|
|
82
|
+
const doc = new Document();
|
|
71
83
|
this.document = doc;
|
|
72
84
|
if (this.model) {
|
|
73
|
-
const rootWrapper =
|
|
74
|
-
if (rootWrapper instanceof
|
|
85
|
+
const rootWrapper = createWrapper(this.model, doc);
|
|
86
|
+
if (rootWrapper instanceof Element) {
|
|
75
87
|
doc.documentElement = rootWrapper;
|
|
76
88
|
}
|
|
77
89
|
}
|
|
@@ -79,17 +91,17 @@ class XMLAPI {
|
|
|
79
91
|
doc.setObserver({
|
|
80
92
|
onAttributeChange: (element, name, value) => {
|
|
81
93
|
const model = element.getModel();
|
|
82
|
-
if (model instanceof
|
|
94
|
+
if (model instanceof ModelElement && model.cst) {
|
|
83
95
|
if (value === null) {
|
|
84
96
|
// Attribute removal support needed in Engine/Binder
|
|
85
97
|
console.warn("Attribute removal not fully supported yet");
|
|
86
98
|
}
|
|
87
99
|
else {
|
|
88
|
-
this.
|
|
100
|
+
this._engine.setAttribute(model, name, value);
|
|
89
101
|
}
|
|
90
102
|
}
|
|
91
103
|
},
|
|
92
|
-
onTextChange: (
|
|
104
|
+
onTextChange: (_node, _text) => {
|
|
93
105
|
// Direct text update on CharacterData
|
|
94
106
|
// Need to find parent element to update properly or support direct node replacement
|
|
95
107
|
// For now, simple text node update via parent if available
|
|
@@ -100,22 +112,33 @@ class XMLAPI {
|
|
|
100
112
|
},
|
|
101
113
|
onElementTextChange: (element, text) => {
|
|
102
114
|
const model = element.getModel();
|
|
103
|
-
if (model instanceof
|
|
104
|
-
this.
|
|
115
|
+
if (model instanceof ModelElement && model.cst) {
|
|
116
|
+
this._engine.updateText(model, text);
|
|
105
117
|
}
|
|
106
118
|
},
|
|
107
119
|
onChildAdded: (parent, child, index) => {
|
|
108
120
|
const parentModel = parent.getModel();
|
|
109
121
|
const childModel = child.getModel();
|
|
110
|
-
if (parentModel instanceof
|
|
111
|
-
this.
|
|
122
|
+
if (parentModel instanceof ModelElement && parentModel.cst) {
|
|
123
|
+
this._engine.insertNode(parentModel, childModel, index);
|
|
112
124
|
}
|
|
113
125
|
},
|
|
114
|
-
onChildRemoved: (parent, child,
|
|
126
|
+
onChildRemoved: (parent, child, _index) => {
|
|
115
127
|
const parentModel = parent.getModel();
|
|
116
128
|
const childModel = child.getModel();
|
|
117
|
-
if (parentModel instanceof
|
|
118
|
-
|
|
129
|
+
if (parentModel instanceof ModelElement && parentModel.cst) {
|
|
130
|
+
if (childModel.cst) {
|
|
131
|
+
this._engine.removeNode(parentModel, childModel);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
onChildReplaced: (_parent, newChild, oldChild) => {
|
|
136
|
+
const newModel = newChild.getModel();
|
|
137
|
+
const oldModel = oldChild.getModel();
|
|
138
|
+
// Use replaceNode on the engine.
|
|
139
|
+
// Even if oldModel is detached from parent, it retains CST info needed for replacement.
|
|
140
|
+
if (oldModel.cst) {
|
|
141
|
+
this._engine.replaceNode(oldModel, newModel);
|
|
119
142
|
}
|
|
120
143
|
},
|
|
121
144
|
});
|
|
@@ -126,27 +149,22 @@ class XMLAPI {
|
|
|
126
149
|
* Registers an event handler to listen for model changes.
|
|
127
150
|
*/
|
|
128
151
|
on(handler) {
|
|
129
|
-
return this.
|
|
152
|
+
return this._engine.on(handler);
|
|
130
153
|
}
|
|
131
154
|
// --- History ---
|
|
132
155
|
undo() {
|
|
133
|
-
this.
|
|
156
|
+
this._engine.undo();
|
|
134
157
|
}
|
|
135
158
|
redo() {
|
|
136
|
-
this.
|
|
137
|
-
}
|
|
138
|
-
// --- Advanced/Legacy Operation Shortcuts (Proxy to Engine) ---
|
|
139
|
-
/** @deprecated Use DOM interface or Engine directly if needed. */
|
|
140
|
-
setAttribute(modelNode, key, value) {
|
|
141
|
-
this.engine.setAttribute(modelNode, key, value);
|
|
142
|
-
}
|
|
143
|
-
/** @deprecated Use DOM interface or Engine directly if needed. */
|
|
144
|
-
updateText(modelNode, text) {
|
|
145
|
-
this.engine.updateText(modelNode, text);
|
|
146
|
-
}
|
|
147
|
-
/** @deprecated Use DOM interface or Engine directly if needed. */
|
|
148
|
-
replaceNode(target, content) {
|
|
149
|
-
this.engine.replaceNode(target, content);
|
|
159
|
+
this._engine.redo();
|
|
150
160
|
}
|
|
151
161
|
}
|
|
152
|
-
|
|
162
|
+
export { CST } from "./cst/xml-cst";
|
|
163
|
+
export { CDATASection, Comment, Document, Element, Node, NodeList, Text, } from "./dom";
|
|
164
|
+
export { EditorState } from "./engine/editor-state";
|
|
165
|
+
export { Transaction } from "./engine/transaction";
|
|
166
|
+
export { ModelCDATA, ModelComment, ModelElement, ModelNode, ModelNodeType, ModelText, } from "./model/xml-api-model";
|
|
167
|
+
export { XMLBinder } from "./model/xml-binder";
|
|
168
|
+
export { SchemaView } from "./view/schema-view";
|
|
169
|
+
export { ViewBinder } from "./view/view-binder";
|
|
170
|
+
export { EventEmitter, } from "./xml-api-events";
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miy2/xml-api",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "An XML library that faithfully synchronizes documents and AST.",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/xml-api.js",
|
|
6
7
|
"exports": {
|
|
7
8
|
".": {
|
|
@@ -29,8 +30,9 @@
|
|
|
29
30
|
"test:all": "jest",
|
|
30
31
|
"docs:dev": "vitepress dev docs",
|
|
31
32
|
"docs:build": "vitepress build docs",
|
|
32
|
-
"docs:gen-api": "typedoc && ts-node scripts/generate-sidebar.
|
|
33
|
+
"docs:gen-api": "typedoc && pnpm exec esbuild scripts/generate-sidebar.ts --bundle --platform=node --format=esm --outfile=scripts/generate-sidebar.mjs && pnpm exec node scripts/generate-sidebar.mjs && rm scripts/generate-sidebar.mjs",
|
|
33
34
|
"docs:preview": "vitepress preview docs",
|
|
35
|
+
"lint": "biome check --write .",
|
|
34
36
|
"format": "biome format --write ."
|
|
35
37
|
},
|
|
36
38
|
"keywords": [
|
package/LICENSE.md
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright 2026 Kazuya Miyashita
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|