@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 CHANGED
@@ -56,7 +56,7 @@ if (item) {
56
56
  item.textContent = 'Updated Value';
57
57
  }
58
58
 
59
- console.log(api.input);
59
+ console.log(api.source);
60
60
  /*
61
61
  Output:
62
62
  <root>
@@ -69,7 +69,27 @@ Output:
69
69
 
70
70
  ```typescript
71
71
  // Update the source code directly at specific offsets
72
- api.updateInput(14, 28, "New Content");
72
+ api.updateSource(14, 28, "New Content");
73
+ ```
74
+
75
+ ### Schema Projection (New in v0.9.1)
76
+
77
+ Create a filtered view of the document that adheres to a specific schema (e.g. XHTML).
78
+ The view preserves the underlying model's full fidelity (including comments and custom tags) while presenting a simplified DOM for editing.
79
+
80
+ ```typescript
81
+ const api = new XMLAPI(source);
82
+ const view = api.createView({
83
+ // Only show 'p' and 'div' elements
84
+ filter: (node) =>
85
+ node.getType() === 'Element' &&
86
+ ['p', 'div'].includes((node as ModelElement).tagName)
87
+ });
88
+
89
+ const root = view.getRoot(); // Returns a filtered DOM-like element
90
+ const p = view.getDocument().createElement('p');
91
+ p.textContent = "New Paragraph";
92
+ root.appendChild(p); // Updates source automatically with smart formatting
73
93
  ```
74
94
 
75
95
  ## Documentation
@@ -1,2 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { CST } from "./xml-cst";
2
+ /**
3
+ * Detects the indentation string preceding a CST node.
4
+ * Scans backwards from the node's start position until a newline or non-whitespace character is found.
5
+ *
6
+ * @param node The CST node to analyze.
7
+ * @param source The full source string.
8
+ * @returns The indentation string (e.g., " ", "\t") if the node starts on a new line (or start of file).
9
+ * Returns null if the node follows non-whitespace content on the same line (inline).
10
+ */
11
+ export declare function detectIndent(node: CST, source: string): string | null;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Detects the indentation string preceding a CST node.
3
+ * Scans backwards from the node's start position until a newline or non-whitespace character is found.
4
+ *
5
+ * @param node The CST node to analyze.
6
+ * @param source The full source string.
7
+ * @returns The indentation string (e.g., " ", "\t") if the node starts on a new line (or start of file).
8
+ * Returns null if the node follows non-whitespace content on the same line (inline).
9
+ */
10
+ export function detectIndent(node, source) {
11
+ let i = node.start - 1;
12
+ while (i >= 0) {
13
+ const char = source[i];
14
+ if (char === "\n") {
15
+ return source.slice(i + 1, node.start);
16
+ }
17
+ if (char !== " " && char !== "\t" && char !== "\r") {
18
+ // Found non-whitespace on the same line, so no clean indent.
19
+ return null;
20
+ }
21
+ i--;
22
+ }
23
+ // Start of file
24
+ if (node.start >= 0) {
25
+ // Check if the line from 0 to node.start is all whitespace
26
+ const prefix = source.slice(0, node.start);
27
+ if (/^\s*$/.test(prefix)) {
28
+ return prefix;
29
+ }
30
+ }
31
+ return null;
32
+ }
@@ -1,71 +1,58 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GrammarBuilder = exports.Grammar = exports.ref = exports.exc = exports.opt = exports.plus = exports.rep = exports.alt = exports.seq = exports.reg = exports.lit = void 0;
4
1
  // Combinators
5
2
  /** Defines a literal string match. */
6
- const lit = (value) => ({ type: "Literal", value });
7
- exports.lit = lit;
3
+ export const lit = (value) => ({ type: "Literal", value });
8
4
  /** Defines a regular expression match. */
9
- const reg = (pattern) => ({
5
+ export const reg = (pattern) => ({
10
6
  type: "RegExpMatch",
11
7
  pattern,
12
8
  });
13
- exports.reg = reg;
14
9
  /** Defines a sequence of matches in order. */
15
- const seq = (...expressions) => ({
10
+ export const seq = (...expressions) => ({
16
11
  type: "Sequence",
17
12
  expressions,
18
13
  });
19
- exports.seq = seq;
20
14
  /** Defines a choice between multiple alternatives. */
21
- const alt = (...expressions) => ({
15
+ export const alt = (...expressions) => ({
22
16
  type: "Choice",
23
17
  expressions,
24
18
  });
25
- exports.alt = alt;
26
19
  /** Zero or more repetitions (equivalent to `*` in EBNF). */
27
- const rep = (expression) => ({
20
+ export const rep = (expression) => ({
28
21
  type: "Repeat",
29
22
  expression,
30
23
  min: 0,
31
24
  max: Infinity,
32
25
  });
33
- exports.rep = rep;
34
26
  /** One or more repetitions (equivalent to `+` in EBNF). */
35
- const plus = (expression) => ({
27
+ export const plus = (expression) => ({
36
28
  type: "Repeat",
37
29
  expression,
38
30
  min: 1,
39
31
  max: Infinity,
40
32
  });
41
- exports.plus = plus;
42
33
  /** Zero or one occurrence (equivalent to `?` in EBNF, optional). */
43
- const opt = (expression) => ({
34
+ export const opt = (expression) => ({
44
35
  type: "Repeat",
45
36
  expression,
46
37
  min: 0,
47
38
  max: 1,
48
39
  });
49
- exports.opt = opt;
50
40
  /** Matches A but excludes B (e.g., matching PITarget as a Name excluding "xml"). */
51
- const exc = (a, b) => ({
41
+ export const exc = (a, b) => ({
52
42
  type: "Exclusion",
53
43
  a,
54
44
  b,
55
45
  });
56
- exports.exc = exc;
57
46
  /** References another rule by its name. */
58
- const ref = (name) => ({ type: "Reference", name });
59
- exports.ref = ref;
60
- class Grammar {
47
+ export const ref = (name) => ({ type: "Reference", name });
48
+ export class Grammar {
61
49
  constructor(rules, validators, rootRule) {
62
50
  this.rules = rules;
63
51
  this.validators = validators;
64
52
  this.rootRule = rootRule;
65
53
  }
66
54
  }
67
- exports.Grammar = Grammar;
68
- class GrammarBuilder {
55
+ export class GrammarBuilder {
69
56
  constructor() {
70
57
  this.rules = {};
71
58
  this.validators = {};
@@ -92,4 +79,3 @@ class GrammarBuilder {
92
79
  return new Grammar({ ...this.rules }, { ...this.validators }, root);
93
80
  }
94
81
  }
95
- exports.GrammarBuilder = GrammarBuilder;
@@ -1,8 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Parser = void 0;
4
- const xml_cst_1 = require("./xml-cst");
5
- class Parser {
1
+ import { CST } from "./xml-cst";
2
+ export class Parser {
6
3
  constructor(grammar) {
7
4
  this.grammar = grammar;
8
5
  }
@@ -56,7 +53,7 @@ class Parser {
56
53
  if (ctx.input.startsWith(expr.value, ctx.pos)) {
57
54
  const start = ctx.pos;
58
55
  ctx.pos += expr.value.length;
59
- return new xml_cst_1.CST("literal", undefined, start, ctx.pos);
56
+ return new CST("literal", undefined, start, ctx.pos);
60
57
  }
61
58
  return null;
62
59
  }
@@ -67,7 +64,7 @@ class Parser {
67
64
  if (match) {
68
65
  const start = ctx.pos;
69
66
  ctx.pos += match[0].length;
70
- return new xml_cst_1.CST("regex", undefined, start, ctx.pos);
67
+ return new CST("regex", undefined, start, ctx.pos);
71
68
  }
72
69
  return null;
73
70
  }
@@ -86,7 +83,7 @@ class Parser {
86
83
  wellFormed = false;
87
84
  }
88
85
  }
89
- return new xml_cst_1.CST("sequence", undefined, startPos, ctx.pos, children, wellFormed);
86
+ return new CST("sequence", undefined, startPos, ctx.pos, children, wellFormed);
90
87
  }
91
88
  execChoice(expr, ctx) {
92
89
  for (const childExpr of expr.expressions) {
@@ -119,7 +116,7 @@ class Parser {
119
116
  ctx.pos = startPos;
120
117
  return null;
121
118
  }
122
- return new xml_cst_1.CST("repeat", undefined, startPos, ctx.pos, children, wellFormed);
119
+ return new CST("repeat", undefined, startPos, ctx.pos, children, wellFormed);
123
120
  }
124
121
  execExclusion(expr, ctx) {
125
122
  const startPos = ctx.pos;
@@ -146,7 +143,7 @@ class Parser {
146
143
  if (result === null)
147
144
  return null;
148
145
  // Always wrap the result to preserve the rule name in the hierarchy.
149
- const node = new xml_cst_1.CST(result.type, expr.name, result.start, result.end, [result], result.wellFormed);
146
+ const node = new CST(result.type, expr.name, result.start, result.end, [result], result.wellFormed);
150
147
  // Apply validation
151
148
  const validator = ctx.grammar.validators[expr.name];
152
149
  if (validator) {
@@ -158,4 +155,3 @@ class Parser {
158
155
  return node;
159
156
  }
160
157
  }
161
- exports.Parser = Parser;
@@ -1,11 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CST = void 0;
4
1
  /**
5
2
  * Represents a node in the Concrete Syntax Tree (Parse Tree).
6
3
  * Each node corresponds to a match of a grammatical structure or rule.
7
4
  */
8
- class CST {
5
+ export class CST {
9
6
  constructor(
10
7
  /**
11
8
  * The type of the grammatical structure matched.
@@ -113,4 +110,3 @@ class CST {
113
110
  return current;
114
111
  }
115
112
  }
116
- exports.CST = CST;