@adrk/mxls 1.0.0

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.
Files changed (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -0
  3. package/dist/completion/CompletionBuilder.d.ts +26 -0
  4. package/dist/completion/CompletionBuilder.d.ts.map +1 -0
  5. package/dist/completion/CompletionBuilder.js +113 -0
  6. package/dist/completion/CompletionBuilder.js.map +1 -0
  7. package/dist/completion/CompletionCache.d.ts +16 -0
  8. package/dist/completion/CompletionCache.d.ts.map +1 -0
  9. package/dist/completion/CompletionCache.js +25 -0
  10. package/dist/completion/CompletionCache.js.map +1 -0
  11. package/dist/completion/NamespaceResolver.d.ts +21 -0
  12. package/dist/completion/NamespaceResolver.d.ts.map +1 -0
  13. package/dist/completion/NamespaceResolver.js +58 -0
  14. package/dist/completion/NamespaceResolver.js.map +1 -0
  15. package/dist/completion/SchemaCompleter.d.ts +23 -0
  16. package/dist/completion/SchemaCompleter.d.ts.map +1 -0
  17. package/dist/completion/SchemaCompleter.js +164 -0
  18. package/dist/completion/SchemaCompleter.js.map +1 -0
  19. package/dist/completion/TextAnalyzer.d.ts +34 -0
  20. package/dist/completion/TextAnalyzer.d.ts.map +1 -0
  21. package/dist/completion/TextAnalyzer.js +122 -0
  22. package/dist/completion/TextAnalyzer.js.map +1 -0
  23. package/dist/features/EditorPlugin.d.ts +49 -0
  24. package/dist/features/EditorPlugin.d.ts.map +1 -0
  25. package/dist/features/EditorPlugin.js +128 -0
  26. package/dist/features/EditorPlugin.js.map +1 -0
  27. package/dist/formatter/XmlFormatter.d.ts +4 -0
  28. package/dist/formatter/XmlFormatter.d.ts.map +1 -0
  29. package/dist/formatter/XmlFormatter.js +13 -0
  30. package/dist/formatter/XmlFormatter.js.map +1 -0
  31. package/dist/hover/HoverBuilder.d.ts +8 -0
  32. package/dist/hover/HoverBuilder.d.ts.map +1 -0
  33. package/dist/hover/HoverBuilder.js +27 -0
  34. package/dist/hover/HoverBuilder.js.map +1 -0
  35. package/dist/hover/SchemaHover.d.ts +12 -0
  36. package/dist/hover/SchemaHover.d.ts.map +1 -0
  37. package/dist/hover/SchemaHover.js +71 -0
  38. package/dist/hover/SchemaHover.js.map +1 -0
  39. package/dist/index.d.ts +14 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +9 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/interfaces/IMonacoApi.d.ts +39 -0
  44. package/dist/interfaces/IMonacoApi.d.ts.map +1 -0
  45. package/dist/interfaces/IMonacoApi.js +2 -0
  46. package/dist/interfaces/IMonacoApi.js.map +1 -0
  47. package/dist/interfaces/ISchemaParser.d.ts +30 -0
  48. package/dist/interfaces/ISchemaParser.d.ts.map +1 -0
  49. package/dist/interfaces/ISchemaParser.js +2 -0
  50. package/dist/interfaces/ISchemaParser.js.map +1 -0
  51. package/dist/interfaces/ISchemaRegistry.d.ts +46 -0
  52. package/dist/interfaces/ISchemaRegistry.d.ts.map +1 -0
  53. package/dist/interfaces/ISchemaRegistry.js +2 -0
  54. package/dist/interfaces/ISchemaRegistry.js.map +1 -0
  55. package/dist/interfaces/ISchemaWorker.d.ts +25 -0
  56. package/dist/interfaces/ISchemaWorker.d.ts.map +1 -0
  57. package/dist/interfaces/ISchemaWorker.js +2 -0
  58. package/dist/interfaces/ISchemaWorker.js.map +1 -0
  59. package/dist/manager/SchemaRegistry.d.ts +24 -0
  60. package/dist/manager/SchemaRegistry.d.ts.map +1 -0
  61. package/dist/manager/SchemaRegistry.js +84 -0
  62. package/dist/manager/SchemaRegistry.js.map +1 -0
  63. package/dist/manager/SchemaWorker.d.ts +25 -0
  64. package/dist/manager/SchemaWorker.d.ts.map +1 -0
  65. package/dist/manager/SchemaWorker.js +70 -0
  66. package/dist/manager/SchemaWorker.js.map +1 -0
  67. package/dist/parser/SchemaIndex.d.ts +54 -0
  68. package/dist/parser/SchemaIndex.d.ts.map +1 -0
  69. package/dist/parser/SchemaIndex.js +149 -0
  70. package/dist/parser/SchemaIndex.js.map +1 -0
  71. package/dist/parser/SchemaParser.d.ts +23 -0
  72. package/dist/parser/SchemaParser.d.ts.map +1 -0
  73. package/dist/parser/SchemaParser.js +44 -0
  74. package/dist/parser/SchemaParser.js.map +1 -0
  75. package/dist/parser/SchemaQuery.d.ts +38 -0
  76. package/dist/parser/SchemaQuery.d.ts.map +1 -0
  77. package/dist/parser/SchemaQuery.js +364 -0
  78. package/dist/parser/SchemaQuery.js.map +1 -0
  79. package/dist/template/TemplateBuilder.d.ts +18 -0
  80. package/dist/template/TemplateBuilder.d.ts.map +1 -0
  81. package/dist/template/TemplateBuilder.js +52 -0
  82. package/dist/template/TemplateBuilder.js.map +1 -0
  83. package/dist/types.d.ts +81 -0
  84. package/dist/types.d.ts.map +1 -0
  85. package/dist/types.js +27 -0
  86. package/dist/types.js.map +1 -0
  87. package/dist/utils/Logger.d.ts +17 -0
  88. package/dist/utils/Logger.d.ts.map +1 -0
  89. package/dist/utils/Logger.js +41 -0
  90. package/dist/utils/Logger.js.map +1 -0
  91. package/dist/utils/XmlTextUtils.d.ts +20 -0
  92. package/dist/utils/XmlTextUtils.d.ts.map +1 -0
  93. package/dist/utils/XmlTextUtils.js +85 -0
  94. package/dist/utils/XmlTextUtils.js.map +1 -0
  95. package/dist/validation/DecorationMapper.d.ts +15 -0
  96. package/dist/validation/DecorationMapper.d.ts.map +1 -0
  97. package/dist/validation/DecorationMapper.js +59 -0
  98. package/dist/validation/DecorationMapper.js.map +1 -0
  99. package/dist/validation/SchemaDecorator.d.ts +26 -0
  100. package/dist/validation/SchemaDecorator.d.ts.map +1 -0
  101. package/dist/validation/SchemaDecorator.js +50 -0
  102. package/dist/validation/SchemaDecorator.js.map +1 -0
  103. package/dist/validation/SchemaValidator.d.ts +13 -0
  104. package/dist/validation/SchemaValidator.d.ts.map +1 -0
  105. package/dist/validation/SchemaValidator.js +387 -0
  106. package/dist/validation/SchemaValidator.js.map +1 -0
  107. package/dist/validation/validation.worker.d.ts +2 -0
  108. package/dist/validation/validation.worker.d.ts.map +1 -0
  109. package/dist/validation/validation.worker.js +57 -0
  110. package/dist/validation/validation.worker.js.map +1 -0
  111. package/package.json +49 -0
  112. package/style.css +17 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ahmet Durak
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.
package/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # mxls — Monaco XML Language Support
2
+
3
+ Schema-driven autocomplete, real-time validation, template generation, and code formatting for the Monaco editor. Framework-agnostic — works with Angular, React, Vue, or vanilla JS.
4
+
5
+ ---
6
+
7
+ ## Features
8
+
9
+ | Feature | Description |
10
+ |---|---|
11
+ | **Element completion** | Suggests child elements based on the XML schema for the current parent tag |
12
+ | **Attribute completion** | Suggests valid attributes for any open tag |
13
+ | **Attribute value completion** | Suggests enum values when the cursor is inside `attr="..."` |
14
+ | **Closing tag completion** | Suggests `</Tag>` for the nearest unclosed element |
15
+ | **maxOccurs enforcement** | Hides elements from suggestions once they reach their schema-defined occurrence limit |
16
+ | **Context-aware completion** | Resolves the correct element type when the same element name appears with different types in different parent contexts |
17
+ | **Cross-schema type resolution** | Resolves enum values defined in a different schema file than the element |
18
+ | **Real-time validation** | Underlines unknown elements, missing required attributes, wrong attribute values, and occurrence violations |
19
+ | **Hover messages** | Explains each validation error on hover |
20
+ | **Template generation** | Generates an XML skeleton from the schema up to a configurable nesting depth |
21
+ | **Code formatting** | Reformats XML via Prettier |
22
+ | **Dynamic namespace schemas** | Fetches and registers schemas for `xmlns:prefix="uri"` declarations at runtime |
23
+
24
+ ---
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ npm install mxls monaco-editor @xmldom/xmldom ts-debounce prettier
30
+ ```
31
+
32
+ Add squiggle styles (or `@import 'mxls/style.css'`):
33
+
34
+ ```css
35
+ .xml-lint { border-width: 0; border-style: dotted; border-bottom-width: 3px; }
36
+ .xml-lint--fatal-error { border-color: red; }
37
+ .xml-lint--error { border-color: orange; }
38
+ .xml-lint--warning { border-color: blue; }
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Quick Start
44
+
45
+ ```typescript
46
+ import { SchemaRegistry, EditorPlugin } from 'mxls'
47
+ import type { IMonacoApi } from 'mxls'
48
+
49
+ function initEditor(editor: monaco.editor.IStandaloneCodeEditor, monacoApi: IMonacoApi): void {
50
+ const registry = new SchemaRegistry(monacoApi)
51
+
52
+ registry.set({
53
+ path: 'my-schema.xsd',
54
+ value: MY_SCHEMA_STRING,
55
+ alwaysInclude: true,
56
+ })
57
+
58
+ const plugin = new EditorPlugin(monacoApi, editor, registry)
59
+ plugin.activate()
60
+ }
61
+ ```
62
+
63
+ **Angular:**
64
+ ```typescript
65
+ onEditorInit(editor: any): void {
66
+ initEditor(editor, (window as any).monaco)
67
+ }
68
+ ```
69
+
70
+ **React:**
71
+ ```tsx
72
+ <Editor language="xml" onMount={(editor, monaco) => initEditor(editor, monaco)} />
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Keyboard Shortcuts
78
+
79
+ | Action | Shortcut |
80
+ |---|---|
81
+ | Autocomplete | `Ctrl+Space` |
82
+ | Reformat code | `Ctrl+Shift+F` |
83
+ | Generate template | `Ctrl+Shift+G` |
84
+
85
+ All actions also appear in the right-click context menu.
86
+
87
+ ---
88
+
89
+ ## Validation Errors
90
+
91
+ - **Unknown element** — tag not defined in the schema for its parent
92
+ - **Missing required attribute** — `use="required"` attribute absent
93
+ - **Unknown attribute** — attribute not declared in the schema
94
+ - **Invalid boolean** — xs:boolean attribute with value outside {true, false, 1, 0}
95
+ - **Invalid enum value** — value not in xs:enumeration list
96
+ - **maxOccurs exceeded** — child element appears too many times
97
+ - **minOccurs violated** — required child element missing
98
+ - **Empty choice** — xs:choice element has no children
99
+
100
+ ---
101
+
102
+ ## Dependencies
103
+
104
+ | Package | Role |
105
+ |---|---|
106
+ | `monaco-editor` | TypeScript types only |
107
+ | `@xmldom/xmldom` | XML/XSD DOM parsing |
108
+ | `ts-debounce` | Debounces validation on keydown |
109
+ | `prettier` + `prettier/plugins/html` | XML reformatting |
110
+ | `turndown` | HTML → Markdown for documentation hovers |
@@ -0,0 +1,26 @@
1
+ import type { IMonacoApi } from '../interfaces/IMonacoApi';
2
+ import type { DocumentNode, ICompletion } from '../types';
3
+ /** Converts DocumentNode schema data into Monaco ICompletion items. */
4
+ export declare class CompletionBuilder {
5
+ private readonly monacoApi;
6
+ constructor(monacoApi: IMonacoApi);
7
+ /**
8
+ * Build element completions.
9
+ * @param ns Namespace prefix (e.g. "ns1"), or undefined for none.
10
+ * @param withoutTag When true the `<` is already in the editor; omit it.
11
+ * @param incomplete When true the user has already typed a partial tag name;
12
+ * emit only the label (no snippet) so Monaco replaces the word.
13
+ */
14
+ buildElements(nodes: DocumentNode[], ns: string | undefined, withoutTag: boolean, incomplete: boolean): ICompletion[];
15
+ /**
16
+ * Build attribute name completions.
17
+ * @param incomplete When true use plain insert text (no `="$0"` snippet) because
18
+ * the user is mid-word and Monaco will replace the partial word.
19
+ */
20
+ buildAttributes(nodes: DocumentNode[], incomplete: boolean): ICompletion[];
21
+ /** Build enum/string value completions for an attribute. */
22
+ buildAttributeValues(values: string[]): ICompletion[];
23
+ /** Build a single closing-tag completion for `</tagName>`. */
24
+ buildClosingTag(tagName: string): ICompletion;
25
+ }
26
+ //# sourceMappingURL=CompletionBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompletionBuilder.d.ts","sourceRoot":"","sources":["../../src/completion/CompletionBuilder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAUzD,uEAAuE;AACvE,qBAAa,iBAAiB;IACd,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,UAAU;IAElD;;;;;;OAMG;IACH,aAAa,CACT,KAAK,EAAE,YAAY,EAAE,EACrB,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,UAAU,EAAE,OAAO,EACnB,UAAU,EAAE,OAAO,GACpB,WAAW,EAAE;IAkDhB;;;;OAIG;IACH,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,UAAU,EAAE,OAAO,GAAG,WAAW,EAAE;IAqB1E,4DAA4D;IAC5D,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE;IAUrD,8DAA8D;IAC9D,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW;CAQhD"}
@@ -0,0 +1,113 @@
1
+ import TurndownService from 'turndown';
2
+ const td = new TurndownService();
3
+ function docToMarkdown(raw) {
4
+ if (!raw)
5
+ return undefined;
6
+ // Only run TurndownService when the text looks like HTML
7
+ return /<[a-z][\s\S]*>/i.test(raw) ? td.turndown(raw) : raw;
8
+ }
9
+ /** Converts DocumentNode schema data into Monaco ICompletion items. */
10
+ export class CompletionBuilder {
11
+ monacoApi;
12
+ constructor(monacoApi) {
13
+ this.monacoApi = monacoApi;
14
+ }
15
+ /**
16
+ * Build element completions.
17
+ * @param ns Namespace prefix (e.g. "ns1"), or undefined for none.
18
+ * @param withoutTag When true the `<` is already in the editor; omit it.
19
+ * @param incomplete When true the user has already typed a partial tag name;
20
+ * emit only the label (no snippet) so Monaco replaces the word.
21
+ */
22
+ buildElements(nodes, ns, withoutTag, incomplete) {
23
+ const { CompletionItemKind, CompletionItemInsertTextRule } = this.monacoApi.languages;
24
+ return nodes.map((node, i) => {
25
+ const name = node.name ?? '';
26
+ const label = ns ? `${ns}:${name}` : name;
27
+ const reqAttrs = node.requiredAttribute ?? [];
28
+ const docText = docToMarkdown(node.documentation);
29
+ const sortText = String(i).padStart(6, '0');
30
+ if (incomplete) {
31
+ return {
32
+ label,
33
+ kind: CompletionItemKind.Property,
34
+ detail: node.type,
35
+ documentation: docText ? { value: docText } : undefined,
36
+ sortText,
37
+ insertText: label,
38
+ };
39
+ }
40
+ let idx = 1;
41
+ const attrPart = reqAttrs.length
42
+ ? ' ' + reqAttrs.map(a => `${a.name ?? ''}="\${${idx++}}"`).join(' ')
43
+ : '';
44
+ const contentIdx = idx;
45
+ let insertText;
46
+ if (node.selfClose) {
47
+ insertText = withoutTag
48
+ ? `${label}${attrPart}/>`
49
+ : `<${label}${attrPart}/>`;
50
+ }
51
+ else {
52
+ insertText = withoutTag
53
+ ? `${label}${attrPart}>\${${contentIdx}}</${label}>`
54
+ : `<${label}${attrPart}>\${${contentIdx}}</${label}>`;
55
+ }
56
+ return {
57
+ label,
58
+ kind: CompletionItemKind.Property,
59
+ detail: node.type,
60
+ documentation: docText ? { value: docText } : undefined,
61
+ sortText,
62
+ insertText,
63
+ insertTextRules: CompletionItemInsertTextRule.InsertAsSnippet,
64
+ maxOccurs: node.maxOccurs,
65
+ };
66
+ });
67
+ }
68
+ /**
69
+ * Build attribute name completions.
70
+ * @param incomplete When true use plain insert text (no `="$0"` snippet) because
71
+ * the user is mid-word and Monaco will replace the partial word.
72
+ */
73
+ buildAttributes(nodes, incomplete) {
74
+ const { CompletionItemKind, CompletionItemInsertTextRule } = this.monacoApi.languages;
75
+ return nodes.map((node, i) => {
76
+ const name = node.name ?? '';
77
+ const docText = docToMarkdown(node.documentation);
78
+ const isRequired = node.use === 'required';
79
+ return {
80
+ label: name,
81
+ kind: CompletionItemKind.Field,
82
+ detail: node.type,
83
+ documentation: docText ? { value: docText } : undefined,
84
+ sortText: String(i).padStart(6, '0'),
85
+ preselect: isRequired,
86
+ insertText: incomplete ? name : `${name}="$0"`,
87
+ insertTextRules: incomplete
88
+ ? undefined
89
+ : CompletionItemInsertTextRule.InsertAsSnippet,
90
+ };
91
+ });
92
+ }
93
+ /** Build enum/string value completions for an attribute. */
94
+ buildAttributeValues(values) {
95
+ const { CompletionItemKind } = this.monacoApi.languages;
96
+ return values.map((v, i) => ({
97
+ label: v,
98
+ kind: CompletionItemKind.Enum,
99
+ sortText: String(i).padStart(6, '0'),
100
+ insertText: v,
101
+ }));
102
+ }
103
+ /** Build a single closing-tag completion for `</tagName>`. */
104
+ buildClosingTag(tagName) {
105
+ const { CompletionItemKind } = this.monacoApi.languages;
106
+ return {
107
+ label: `/${tagName}>`,
108
+ kind: CompletionItemKind.Property,
109
+ insertText: `/${tagName}>`,
110
+ };
111
+ }
112
+ }
113
+ //# sourceMappingURL=CompletionBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompletionBuilder.js","sourceRoot":"","sources":["../../src/completion/CompletionBuilder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ICompletion } from '../types';
2
+ /**
3
+ * Instance-based memoization of element completion results.
4
+ * Only element/incompleteElement types are cached — attribute completions
5
+ * are intentionally excluded (see SchemaCompleter for rationale).
6
+ * Key: `[...ancestorChain, parentElement].join('>')` when chain is non-empty,
7
+ * else just `parentElement`.
8
+ */
9
+ export declare class CompletionCache {
10
+ private readonly cache;
11
+ makeKey(parentTag: string, ancestorChain: string[]): string;
12
+ get(key: string): ICompletion[] | undefined;
13
+ set(key: string, completions: ICompletion[]): void;
14
+ clear(): void;
15
+ }
16
+ //# sourceMappingURL=CompletionCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompletionCache.d.ts","sourceRoot":"","sources":["../../src/completion/CompletionCache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C;;;;;;GAMG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmC;IAEzD,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM;IAM3D,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,GAAG,SAAS;IAI3C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,IAAI;IAIlD,KAAK,IAAI,IAAI;CAGhB"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Instance-based memoization of element completion results.
3
+ * Only element/incompleteElement types are cached — attribute completions
4
+ * are intentionally excluded (see SchemaCompleter for rationale).
5
+ * Key: `[...ancestorChain, parentElement].join('>')` when chain is non-empty,
6
+ * else just `parentElement`.
7
+ */
8
+ export class CompletionCache {
9
+ cache = new Map();
10
+ makeKey(parentTag, ancestorChain) {
11
+ return ancestorChain.length > 0
12
+ ? [...ancestorChain, parentTag].join('>')
13
+ : parentTag;
14
+ }
15
+ get(key) {
16
+ return this.cache.get(key);
17
+ }
18
+ set(key, completions) {
19
+ this.cache.set(key, completions);
20
+ }
21
+ clear() {
22
+ this.cache.clear();
23
+ }
24
+ }
25
+ //# sourceMappingURL=CompletionCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompletionCache.js","sourceRoot":"","sources":["../../src/completion/CompletionCache.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,OAAO,eAAe;IACP,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAA;IAEzD,OAAO,CAAC,SAAiB,EAAE,aAAuB;QAC9C,OAAO,aAAa,CAAC,MAAM,GAAG,CAAC;YAC3B,CAAC,CAAC,CAAC,GAAG,aAAa,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YACzC,CAAC,CAAC,SAAS,CAAA;IACnB,CAAC;IAED,GAAG,CAAC,GAAW;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC9B,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,WAA0B;QACvC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;IACpC,CAAC;IAED,KAAK;QACD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;IACtB,CAAC;CACJ"}
@@ -0,0 +1,21 @@
1
+ import type { ISchemaRegistry } from '../interfaces/ISchemaRegistry';
2
+ import type { ISchemaWorker } from '../interfaces/ISchemaWorker';
3
+ /**
4
+ * Instance-based (no static state) XML namespace resolver.
5
+ * Extracts xmlns declarations from the document text and maps them to registered
6
+ * XSD workers. Results are cached by the xmlns fingerprint of the text.
7
+ */
8
+ export declare class NamespaceResolver {
9
+ private readonly cache;
10
+ /**
11
+ * Resolves which workers apply to `text` by matching its xmlns declarations
12
+ * to registered schemas in `registry`. Also includes always-included and
13
+ * root-tag-matched workers.
14
+ */
15
+ resolve(text: string, registry: ISchemaRegistry): ISchemaWorker[];
16
+ /** Clear the cache (call when schemas are added, removed, or updated). */
17
+ invalidate(): void;
18
+ private cacheKey;
19
+ private compute;
20
+ }
21
+ //# sourceMappingURL=NamespaceResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NamespaceResolver.d.ts","sourceRoot":"","sources":["../../src/completion/NamespaceResolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAIhE;;;;GAIG;AACH,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAE3D;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,aAAa,EAAE;IAWjE,0EAA0E;IAC1E,UAAU,IAAI,IAAI;IAIlB,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,OAAO;CA0BlB"}
@@ -0,0 +1,58 @@
1
+ import { getRootTag } from '../utils/XmlTextUtils';
2
+ import { logger } from '../utils/Logger';
3
+ /**
4
+ * Instance-based (no static state) XML namespace resolver.
5
+ * Extracts xmlns declarations from the document text and maps them to registered
6
+ * XSD workers. Results are cached by the xmlns fingerprint of the text.
7
+ */
8
+ export class NamespaceResolver {
9
+ cache = new Map();
10
+ /**
11
+ * Resolves which workers apply to `text` by matching its xmlns declarations
12
+ * to registered schemas in `registry`. Also includes always-included and
13
+ * root-tag-matched workers.
14
+ */
15
+ resolve(text, registry) {
16
+ const key = this.cacheKey(text);
17
+ const hit = this.cache.get(key);
18
+ if (hit)
19
+ return hit;
20
+ const workers = this.compute(text, registry);
21
+ this.cache.set(key, workers);
22
+ logger.verbose(`namespace resolver: computed ${workers.length} worker(s) paths=[${workers.map(w => w.xsd.path).join(', ')}]`);
23
+ return workers;
24
+ }
25
+ /** Clear the cache (call when schemas are added, removed, or updated). */
26
+ invalidate() {
27
+ this.cache.clear();
28
+ }
29
+ cacheKey(text) {
30
+ // Cache by the sorted set of xmlns declarations — changes rarely
31
+ const matches = [...text.matchAll(/xmlns(?::[a-zA-Z_][\w.-]*)?="[^"]+"/g)];
32
+ return matches.map(m => m[0]).sort().join('|');
33
+ }
34
+ compute(text, registry) {
35
+ const result = [];
36
+ const seen = new Set();
37
+ const nsRe = /xmlns(?::([a-zA-Z_][\w.-]*))?="([^"]+)"/g;
38
+ let m;
39
+ while ((m = nsRe.exec(text)) !== null) {
40
+ const prefix = m[1] ?? '';
41
+ const uri = m[2];
42
+ const worker = registry.get(uri) ?? registry.getNonStrict(uri);
43
+ if (worker && !seen.has(worker.xsd.path)) {
44
+ seen.add(worker.xsd.path);
45
+ result.push(prefix ? worker.withNamespace(prefix) : worker);
46
+ }
47
+ }
48
+ const rootTag = getRootTag(text);
49
+ for (const worker of registry.getAlwaysIncludedWorkers(rootTag)) {
50
+ if (!seen.has(worker.xsd.path)) {
51
+ seen.add(worker.xsd.path);
52
+ result.push(worker);
53
+ }
54
+ }
55
+ return result;
56
+ }
57
+ }
58
+ //# sourceMappingURL=NamespaceResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NamespaceResolver.js","sourceRoot":"","sources":["../../src/completion/NamespaceResolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { languages } from 'monaco-editor';
2
+ import type { IMonacoApi } from '../interfaces/IMonacoApi';
3
+ import type { ISchemaRegistry } from '../interfaces/ISchemaRegistry';
4
+ /**
5
+ * Thin Monaco CompletionItemProvider shell.
6
+ * All analysis is delegated to TextAnalyzer; all item construction to workers
7
+ * (via doCompletion) and CompletionBuilder.
8
+ */
9
+ export declare class SchemaCompleter {
10
+ private readonly xsdManager;
11
+ private readonly monacoApi;
12
+ private readonly analyzer;
13
+ private readonly builder;
14
+ private readonly cache;
15
+ private readonly resolver;
16
+ constructor(xsdManager: ISchemaRegistry, monacoApi: IMonacoApi);
17
+ /** Returns the Monaco CompletionItemProvider to register. */
18
+ provider(): languages.CompletionItemProvider;
19
+ /** Invalidate the cache (call when a schema is added or updated). */
20
+ invalidateCache(): void;
21
+ private gather;
22
+ }
23
+ //# sourceMappingURL=SchemaCompleter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SchemaCompleter.d.ts","sourceRoot":"","sources":["../../src/completion/SchemaCompleter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AASpE;;;;GAIG;AACH,qBAAa,eAAe;IAOpB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAP9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA0B;gBAG9B,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,UAAU;IAK1C,6DAA6D;IAC7D,QAAQ,IAAI,SAAS,CAAC,sBAAsB;IA4E5C,qEAAqE;IACrE,eAAe,IAAI,IAAI;IAKvB,OAAO,CAAC,MAAM;CAkFjB"}
@@ -0,0 +1,164 @@
1
+ import { CompletionType } from '../types';
2
+ import { TextAnalyzer } from './TextAnalyzer';
3
+ import { CompletionBuilder } from './CompletionBuilder';
4
+ import { CompletionCache } from './CompletionCache';
5
+ import { NamespaceResolver } from './NamespaceResolver';
6
+ import { logger } from '../utils/Logger';
7
+ /**
8
+ * Thin Monaco CompletionItemProvider shell.
9
+ * All analysis is delegated to TextAnalyzer; all item construction to workers
10
+ * (via doCompletion) and CompletionBuilder.
11
+ */
12
+ export class SchemaCompleter {
13
+ xsdManager;
14
+ monacoApi;
15
+ analyzer = new TextAnalyzer();
16
+ builder;
17
+ cache = new CompletionCache();
18
+ resolver = new NamespaceResolver();
19
+ constructor(xsdManager, monacoApi) {
20
+ this.xsdManager = xsdManager;
21
+ this.monacoApi = monacoApi;
22
+ this.builder = new CompletionBuilder(monacoApi);
23
+ }
24
+ /** Returns the Monaco CompletionItemProvider to register. */
25
+ provider() {
26
+ return {
27
+ triggerCharacters: ['<', ' ', '/', '=', '"', "'"],
28
+ provideCompletionItems: (model, position, context) => {
29
+ const fullText = model.getValue();
30
+ const text = model.getValueInRange({
31
+ startLineNumber: 1,
32
+ startColumn: 1,
33
+ endLineNumber: position.lineNumber,
34
+ endColumn: position.column,
35
+ });
36
+ // Monaco requires every CompletionItem to carry a range;
37
+ // items without one are silently dropped. Compute the word range
38
+ // at the cursor once and stamp it onto every suggestion we return.
39
+ const word = model.getWordUntilPosition(position);
40
+ const range = new this.monacoApi.Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
41
+ const withRange = (items) => items.map(item => ({ ...item, range }));
42
+ const type = this.analyzer.getCompletionType(text, context.triggerKind, context.triggerCharacter);
43
+ if (type === CompletionType.none)
44
+ return { suggestions: [] };
45
+ const workers = this.resolver.resolve(fullText, this.xsdManager);
46
+ if (workers.length === 0) {
47
+ logger.debug('completion: no workers resolved, skipping');
48
+ return { suggestions: [] };
49
+ }
50
+ const parentTag = this.analyzer.getParentTag(text) ?? '';
51
+ const ancestorChain = this.analyzer.getAncestorChain(text);
52
+ logger.debug(`completion: type=${CompletionType[type]} parent=<${parentTag}> workers=${workers.length}`);
53
+ // Only cache element completions. Attribute completions are excluded
54
+ // because they use `openTag` (the currently-open tag) as the lookup key,
55
+ // but the cache key is built from `parentTag` (the innermost *closed*
56
+ // element). The two diverge while typing `<Elem `, so caching attributes
57
+ // under parentTag pollutes subsequent element-completion lookups.
58
+ if (type === CompletionType.element ||
59
+ type === CompletionType.incompleteElement) {
60
+ const key = this.cache.makeKey(parentTag, ancestorChain);
61
+ const hit = this.cache.get(key);
62
+ if (hit) {
63
+ logger.verbose(`completion: cache hit key="${key}" items=${hit.length}`);
64
+ return { suggestions: withRange(hit) };
65
+ }
66
+ const items = this.gather(type, parentTag, ancestorChain, workers, text);
67
+ logger.debug(`completion: ${items.length} element suggestion(s) for <${parentTag}>`);
68
+ // Only cache non-empty results — a transient empty (schema not yet
69
+ // ready, cursor in mid-snippet position) must not poison the key.
70
+ if (items.length > 0)
71
+ this.cache.set(key, items);
72
+ return { suggestions: withRange(items) };
73
+ }
74
+ const items = this.gather(type, parentTag, ancestorChain, workers, text);
75
+ logger.debug(`completion: ${items.length} suggestion(s) type=${CompletionType[type]}`);
76
+ return {
77
+ suggestions: withRange(items),
78
+ };
79
+ },
80
+ };
81
+ }
82
+ /** Invalidate the cache (call when a schema is added or updated). */
83
+ invalidateCache() {
84
+ this.cache.clear();
85
+ this.resolver.invalidate();
86
+ }
87
+ gather(type, parentTag, ancestorChain, workers, text) {
88
+ // For attribute completions the cursor is inside an unclosed opening tag,
89
+ // so getParentTag (which tracks *closed* tags) returns the wrong element.
90
+ // getCurrentOpenTagName returns the element whose `<tagName` has not yet
91
+ // received its closing `>` — the correct target for attribute queries.
92
+ const openTag = this.analyzer.getCurrentOpenTagName(text);
93
+ switch (type) {
94
+ case CompletionType.element:
95
+ case CompletionType.incompleteElement: {
96
+ const results = [];
97
+ for (const worker of workers) {
98
+ results.push(...worker.doCompletion(type, parentTag, ancestorChain));
99
+ }
100
+ // Filter out elements that have reached their maxOccurs limit
101
+ return results.filter(item => {
102
+ if (!item.maxOccurs || item.maxOccurs === 'unbounded')
103
+ return true;
104
+ const max = parseInt(item.maxOccurs, 10);
105
+ if (isNaN(max))
106
+ return true;
107
+ const label = typeof item.label === 'string' ? item.label : item.label.label;
108
+ const count = this.analyzer.countChildOccurrences(text, parentTag, label);
109
+ return count < max;
110
+ });
111
+ }
112
+ case CompletionType.attribute:
113
+ case CompletionType.incompleteAttribute: {
114
+ const tagName = openTag ?? parentTag;
115
+ const results = [];
116
+ for (const worker of workers) {
117
+ results.push(...worker.doCompletion(CompletionType.attribute, tagName, ancestorChain));
118
+ }
119
+ return results;
120
+ }
121
+ case CompletionType.attributeValue: {
122
+ const attrName = this.analyzer.getAttrNameBeforeCursor(text);
123
+ if (!attrName)
124
+ return [];
125
+ const tagName = openTag ?? parentTag;
126
+ const results = [];
127
+ for (const worker of workers) {
128
+ const values = worker.getEnumValuesForAttribute(tagName, attrName);
129
+ results.push(...this.builder.buildAttributeValues(values));
130
+ }
131
+ // Cross-schema type resolution: if the attribute's type is defined in
132
+ // another worker (e.g. a shared simpleType XSD), look it up there.
133
+ if (results.length === 0) {
134
+ for (const worker of workers) {
135
+ const attrDef = worker.getAttributesForElement(tagName)
136
+ .find(a => a.name === attrName);
137
+ if (!attrDef?.type)
138
+ continue;
139
+ const typeName = attrDef.type.replace(/^[^:]+:/, '');
140
+ for (const w of workers) {
141
+ const values = w.getEnumValuesForNamedType(typeName);
142
+ if (values.length > 0) {
143
+ results.push(...this.builder.buildAttributeValues(values));
144
+ break;
145
+ }
146
+ }
147
+ if (results.length > 0)
148
+ break;
149
+ }
150
+ }
151
+ const dynamicValues = this.xsdManager.getDynamicEnumValues(tagName, attrName);
152
+ if (dynamicValues.length > 0) {
153
+ results.push(...this.builder.buildAttributeValues(dynamicValues));
154
+ }
155
+ return results;
156
+ }
157
+ case CompletionType.closingElement:
158
+ return parentTag ? [this.builder.buildClosingTag(parentTag)] : [];
159
+ default:
160
+ return [];
161
+ }
162
+ }
163
+ }
164
+ //# sourceMappingURL=SchemaCompleter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SchemaCompleter.js","sourceRoot":"","sources":["../../src/completion/SchemaCompleter.ts"],"names":[],"mappings":"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"}