@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/dist/xml-api.js CHANGED
@@ -1,14 +1,17 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.XMLAPI = void 0;
4
- const dom_1 = require("./dom");
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) and the logical Model.
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.engine = new sync_engine_1.SyncEngine(source, grammar);
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.engine.source;
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.engine.model;
35
+ return this._engine.model;
36
36
  }
37
37
  /** The Concrete Syntax Tree (Physical layer). */
38
38
  get cst() {
39
- return this.engine.cst;
39
+ return this._engine.cst;
40
40
  }
41
41
  /** The grammar used for parsing. */
42
42
  get grammar() {
43
- return this.engine.grammar;
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
- this.engine.updateSource(from, to, text);
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 dom_1.Document();
82
+ const doc = new Document();
71
83
  this.document = doc;
72
84
  if (this.model) {
73
- const rootWrapper = (0, dom_1.createWrapper)(this.model, doc);
74
- if (rootWrapper instanceof dom_1.Element) {
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 xml_api_model_1.ModelElement) {
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.engine.setAttribute(model, name, value);
100
+ this._engine.setAttribute(model, name, value);
89
101
  }
90
102
  }
91
103
  },
92
- onTextChange: (node, text) => {
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 xml_api_model_1.ModelElement) {
104
- this.engine.updateText(model, text);
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 xml_api_model_1.ModelElement) {
111
- this.engine.insertNode(parentModel, childModel, index);
122
+ if (parentModel instanceof ModelElement && parentModel.cst) {
123
+ this._engine.insertNode(parentModel, childModel, index);
112
124
  }
113
125
  },
114
- onChildRemoved: (parent, child, index) => {
126
+ onChildRemoved: (parent, child, _index) => {
115
127
  const parentModel = parent.getModel();
116
128
  const childModel = child.getModel();
117
- if (parentModel instanceof xml_api_model_1.ModelElement) {
118
- this.engine.removeNode(parentModel, childModel);
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.engine.on(handler);
152
+ return this._engine.on(handler);
130
153
  }
131
154
  // --- History ---
132
155
  undo() {
133
- this.engine.undo();
156
+ this._engine.undo();
134
157
  }
135
158
  redo() {
136
- this.engine.redo();
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
- exports.XMLAPI = XMLAPI;
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.0",
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.ts",
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.