diff --git a/.github/workflows/run-tests-example-apps.yml b/.github/workflows/run-tests-example-apps.yml
new file mode 100644
index 0000000000..7c324f2cca
--- /dev/null
+++ b/.github/workflows/run-tests-example-apps.yml
@@ -0,0 +1,30 @@
+name: Run tests for example apps
+
+on:
+ workflow_call:
+ # TODO: Enable this when we test this workflow manually
+ # pull_request:
+ # branches:
+ # - develop
+
+jobs:
+ run-tests-example-apps:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup node
+ uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ cache: npm
+
+ - name: Install dependencies
+ run: cd examples/tests && npm ci
+
+ - name: Install Playwright browsers
+ run: cd examples/tests && npx playwright install --with-deps
+
+ - name: Run tests
+ run: cd examples/tests && npm test
\ No newline at end of file
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 08ec9b4ec3..277caee046 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -91,7 +91,7 @@ export default [
}
},
rules: {
- 'no-unused-vars': 'warn', // See warnings but don't block
+ 'no-unused-vars': ['warn', { "varsIgnorePattern": "^_" }], // See warnings but don't block
// Relax these rules - they're more style than bugs
'no-empty': ['warn', { allowEmptyCatch: true }], // Allow empty catch blocks
diff --git a/examples/loading-from-json/demo-config.json b/examples/loading-from-json/demo-config.json
new file mode 100644
index 0000000000..485e31e29c
--- /dev/null
+++ b/examples/loading-from-json/demo-config.json
@@ -0,0 +1,9 @@
+{
+ "dirname": "loading-from-json",
+ "tags": [
+ "editing",
+ "viewing",
+ "vanilla-js"
+ ],
+ "title": "Loading from JSON"
+}
\ No newline at end of file
diff --git a/examples/loading-from-json/demo-thumbnail.png b/examples/loading-from-json/demo-thumbnail.png
new file mode 100644
index 0000000000..6a8b0fe52a
Binary files /dev/null and b/examples/loading-from-json/demo-thumbnail.png differ
diff --git a/examples/loading-from-json/demo-video.mp4 b/examples/loading-from-json/demo-video.mp4
new file mode 100644
index 0000000000..9886a67205
Binary files /dev/null and b/examples/loading-from-json/demo-video.mp4 differ
diff --git a/examples/loading-from-json/index.html b/examples/loading-from-json/index.html
new file mode 100644
index 0000000000..bd0ef18e17
--- /dev/null
+++ b/examples/loading-from-json/index.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+ SuperDoc Vanilla Example
+
+
+
+
+
+
diff --git a/examples/loading-from-json/package.json b/examples/loading-from-json/package.json
new file mode 100644
index 0000000000..e1de37387f
--- /dev/null
+++ b/examples/loading-from-json/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "vanilla-superdoc-example",
+ "private": true,
+ "version": "0.0.1",
+ "type": "module",
+ "scripts": {
+ "dev": "vite"
+ },
+ "dependencies": {
+ "@harbour-enterprises/superdoc": "^0.15.16"
+ },
+ "devDependencies": {
+ "vite": "^4.4.6"
+ }
+}
diff --git a/examples/loading-from-json/src/main.js b/examples/loading-from-json/src/main.js
new file mode 100644
index 0000000000..3112cad3df
--- /dev/null
+++ b/examples/loading-from-json/src/main.js
@@ -0,0 +1,100 @@
+// Imports
+import { SuperDoc } from '@harbour-enterprises/superdoc';
+import '@harbour-enterprises/superdoc/style.css';
+import './style.css';
+
+// Init
+let editor = null;
+
+//Init SuperDoc from DOCX file
+function initSuperDocFromFile(file = null) {
+ if (editor) {
+ editor = null;
+ }
+
+ editor = new SuperDoc({
+ selector: '#superdoc',
+ toolbar: '#superdoc-toolbar',
+ document: file, // DOCX URL, File object, or document config
+ documentMode: 'editing',
+ mode: 'docx',
+ pagination: true,
+ rulers: true,
+ onReady: (event) => {
+ const docJSON = event.superdoc.activeEditor.getJSON();
+ console.log('SuperDoc ready - JSON', docJSON);
+ },
+ onEditorUpdate: (event) => {
+ const docJSON = event.editor.getJSON();
+ console.log('SuperDoc updated - JSON', docJSON);
+ },
+ });
+}
+
+//Init SuperDoc from JSON
+function initSuperDocFromJSON() {
+ if (editor) {
+ editor = null;
+ }
+
+ //Hardcoded demo JSON
+ const demoJSON = {
+ type: 'doc',
+ content: [
+ {
+ type: 'paragraph',
+ content: [
+ {
+ type: 'text',
+ text: 'Hello, SuperDoc~!!',
+ },
+ ],
+ },
+ ],
+ };
+
+ editor = new SuperDoc({
+ selector: '#superdoc',
+ toolbar: '#superdoc-toolbar',
+ documentMode: 'editing',
+
+ /* LOADING JSON */
+ //https://docs.superdoc.dev/core/supereditor/configuration#param-options-content
+ mode: 'docx',
+ jsonOverride: demoJSON,
+
+ pagination: true,
+ rulers: true,
+ onReady: (event) => {
+ const docJSON = event.superdoc.activeEditor.getJSON();
+ console.log('SuperDoc ready - JSON', docJSON);
+ },
+ onEditorUpdate: (event) => {
+ const docJSON = event.editor.getJSON();
+ console.log('SuperDoc updated - JSON', docJSON);
+ },
+ });
+}
+
+// Setup file input handling
+const fileInput = document.getElementById('fileInput');
+const loadButton = document.getElementById('loadButton');
+const loadJSON = document.getElementById('loadJSON');
+
+loadButton.addEventListener('click', () => {
+ fileInput.click();
+});
+
+loadJSON.addEventListener('click', () => {
+ initSuperDocFromJSON();
+});
+
+fileInput.addEventListener('change', (event) => {
+ const file = event.target.files?.[0];
+ if (file) {
+ initSuperDocFromFile(file);
+ }
+});
+
+// Initialize empty editor on page load
+initSuperDocFromFile(null);
diff --git a/examples/loading-from-json/src/style.css b/examples/loading-from-json/src/style.css
new file mode 100644
index 0000000000..09052dcc1d
--- /dev/null
+++ b/examples/loading-from-json/src/style.css
@@ -0,0 +1,45 @@
+.container {
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ }
+
+ header {
+ padding: 1rem;
+ background: #f5f5f5;
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ }
+
+ button {
+ padding: 0.5rem 1rem;
+ background: #1355ff;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ }
+
+ button:hover {
+ background: #0044ff;
+ }
+
+ main {
+ flex: 1;
+ padding: 1rem;
+ display: flex;
+ flex-direction: column;
+ }
+
+ #superdoc-toolbar {
+ border-bottom: 1px solid #eee;
+ }
+
+ #superdoc {
+ display: flex;
+ justify-content: center;
+ flex: 1;
+ overflow: auto;
+ }
+
\ No newline at end of file
diff --git a/examples/loading-from-json/vite.config.js b/examples/loading-from-json/vite.config.js
new file mode 100644
index 0000000000..e1edef2913
--- /dev/null
+++ b/examples/loading-from-json/vite.config.js
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+ optimizeDeps: {
+ include: ['@harbour-enterprises/superdoc']
+ }
+});
\ No newline at end of file
diff --git a/examples/react-example/package-lock.json b/examples/react-example/package-lock.json
index 66d621e35b..e7686cbeb0 100644
--- a/examples/react-example/package-lock.json
+++ b/examples/react-example/package-lock.json
@@ -14,7 +14,7 @@
},
"devDependencies": {
"@vitejs/plugin-react": "^4.0.4",
- "vite": "^7.0.5"
+ "vite": "^6.2.0"
}
},
"node_modules/@ampproject/remapping": {
@@ -3899,24 +3899,24 @@
}
},
"node_modules/vite": {
- "version": "7.0.5",
- "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.5.tgz",
- "integrity": "sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==",
+ "version": "6.3.5",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
+ "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.25.0",
- "fdir": "^6.4.6",
+ "fdir": "^6.4.4",
"picomatch": "^4.0.2",
- "postcss": "^8.5.6",
- "rollup": "^4.40.0",
- "tinyglobby": "^0.2.14"
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
- "node": "^20.19.0 || >=22.12.0"
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
@@ -3925,14 +3925,14 @@
"fsevents": "~2.3.3"
},
"peerDependencies": {
- "@types/node": "^20.19.0 || >=22.12.0",
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
"jiti": ">=1.21.0",
- "less": "^4.0.0",
+ "less": "*",
"lightningcss": "^1.21.0",
- "sass": "^1.70.0",
- "sass-embedded": "^1.70.0",
- "stylus": ">=0.54.8",
- "sugarss": "^5.0.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
"terser": "^5.16.0",
"tsx": "^4.8.1",
"yaml": "^2.4.2"
diff --git a/examples/react-example/package.json b/examples/react-example/package.json
index 18365e9c66..a09eb9343d 100644
--- a/examples/react-example/package.json
+++ b/examples/react-example/package.json
@@ -13,6 +13,6 @@
},
"devDependencies": {
"@vitejs/plugin-react": "^4.0.4",
- "vite": "^7.0.5"
+ "vite": "^6.2.0"
}
}
diff --git a/examples/replace-content-example/README.md b/examples/replace-content-example/README.md
new file mode 100644
index 0000000000..363c66360c
--- /dev/null
+++ b/examples/replace-content-example/README.md
@@ -0,0 +1,26 @@
+# Replace Content Example
+
+A React example demonstrating how to replace document content with HTML or JSON using SuperDoc.
+
+## Features
+
+- Load DOCX documents
+- Replace entire document or selection with custom content
+- Switch between HTML and JSON input formats
+- Side panel with content replacement controls
+
+## Usage
+
+1. Load a document using "Load Document" button
+2. Open the side panel using the tab on the right
+3. Choose replacement scope (Document or Selection)
+4. Select content type (HTML or JSON)
+5. Enter your content in the textarea
+6. Click "Replace content" to apply changes
+
+## Running
+
+```bash
+npm install
+npm run dev
+```
\ No newline at end of file
diff --git a/examples/replace-content-example/demo-config.json b/examples/replace-content-example/demo-config.json
new file mode 100644
index 0000000000..b2193840f3
--- /dev/null
+++ b/examples/replace-content-example/demo-config.json
@@ -0,0 +1,9 @@
+{
+ "dirname": "replace-content-example",
+ "tags": [
+ "editing",
+ "viewing",
+ "react"
+ ],
+ "title": "Replacing content with HTML/JSON"
+}
\ No newline at end of file
diff --git a/examples/replace-content-example/demo-thumbnail.png b/examples/replace-content-example/demo-thumbnail.png
new file mode 100644
index 0000000000..8425d2ff17
Binary files /dev/null and b/examples/replace-content-example/demo-thumbnail.png differ
diff --git a/examples/replace-content-example/demo-video.mp4 b/examples/replace-content-example/demo-video.mp4
new file mode 100644
index 0000000000..4d7b4c9819
Binary files /dev/null and b/examples/replace-content-example/demo-video.mp4 differ
diff --git a/examples/replace-content-example/index.html b/examples/replace-content-example/index.html
new file mode 100644
index 0000000000..5a4e3e6da2
--- /dev/null
+++ b/examples/replace-content-example/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ SuperDoc React Example
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/replace-content-example/package.json b/examples/replace-content-example/package.json
new file mode 100644
index 0000000000..96123482ba
--- /dev/null
+++ b/examples/replace-content-example/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "react-superdoc-example",
+ "private": true,
+ "version": "0.0.1",
+ "type": "module",
+ "scripts": {
+ "dev": "vite"
+ },
+ "dependencies": {
+ "@harbour-enterprises/superdoc": "^0.14.15",
+ "highlight.js": "^11.11.1",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-react": "^4.0.4",
+ "vite": "^7.0.5"
+ }
+}
diff --git a/examples/replace-content-example/public/sample.docx b/examples/replace-content-example/public/sample.docx
new file mode 100644
index 0000000000..c89890fb5d
Binary files /dev/null and b/examples/replace-content-example/public/sample.docx differ
diff --git a/examples/replace-content-example/src/App.jsx b/examples/replace-content-example/src/App.jsx
new file mode 100644
index 0000000000..fcf4e8c6a8
--- /dev/null
+++ b/examples/replace-content-example/src/App.jsx
@@ -0,0 +1,306 @@
+import { useRef, useReducer } from 'react';
+import DocumentEditor from './components/DocumentEditor';
+
+function App() {
+ const [, _forceUpdate] = useReducer(x => x + 1, 0);
+
+ const forceUpdate = async (uploadingFile = false) => {
+ // Save editor content to documentFileRef before forcing update
+ if (editorRef.current && editorRef.current.activeEditor && !uploadingFile) {
+ try {
+ const result = await editorRef.current.activeEditor.exportDocx();
+ const DOCX = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
+ const blob = new Blob([result], { type: DOCX });
+ const file = new File([blob], `document-${Date.now()}.docx`, { type: DOCX });
+ documentFileRef.current = file;
+ console.log('Saved editor content as DOCX file to documentFileRef:', file);
+ } catch (error) {
+ console.warn('Could not save editor content:', error);
+ }
+ }
+ _forceUpdate();
+ };
+
+const exampleJSON = {
+ type: 'text',
+ marks: [
+ {
+ type: 'aiAnimationMark',
+ attrs: {
+ class: 'sd-ai-text-appear',
+ dataMarkId: `ai-animation-${Date.now()}`,
+ },
+ },
+ ],
+ text: 'Hello, SuperDoc~!!',
+};
+
+ const exampleHTML = 'Hello, SuperDoc~!!
';
+
+ const documentFileRef = useRef(null);
+ const drawerOpenRef = useRef(true);
+ const replacementScopeRef = useRef('document');
+ const replacementContentTypeRef = useRef('html');
+ const textareaRef = useRef(null);
+
+ const editorRef = useRef(null);
+ const fileInputRef = useRef(null);
+
+ const handleFileChange = (event) => {
+ const file = event.target.files?.[0];
+ if (file) {
+ documentFileRef.current = file;
+ forceUpdate(true);
+ }
+ };
+
+ const handleEditorReady = (editorInstance) => {
+ console.log('SuperDoc editor is ready', editorInstance);
+ editorRef.current = editorInstance;
+ };
+
+ const handleReplacementScopeChange = (event) => {
+ replacementScopeRef.current = event.target.value;
+ forceUpdate();
+ };
+
+ const handleReplacementContentTypeChange = (event) => {
+ replacementContentTypeRef.current = event.target.value;
+ // Update textarea content without triggering re-render
+ if (textareaRef.current) {
+ textareaRef.current.value = replacementContentTypeRef.current === 'json' ? JSON.stringify(exampleJSON, null, 2) : exampleHTML;
+ }
+ forceUpdate();
+ };
+
+ const toggleDrawer = () => {
+ drawerOpenRef.current = !drawerOpenRef.current;
+ forceUpdate();
+ };
+
+ const handleReplaceContent = () => {
+ // Get textarea value directly from DOM
+ const textareaContent = textareaRef.current ? textareaRef.current.value : '';
+
+ if (!editorRef.current) {
+ console.error('Editor not available');
+ return;
+ }
+
+ if (replacementScopeRef.current === 'document') {
+ // Select all content in the document
+ editorRef.current.activeEditor.commands.selectAll();
+ }
+
+ const replacementContent = replacementContentTypeRef.current === "json" ? JSON.parse(textareaContent) : textareaContent;
+
+ // Insert the raw content with animation mark
+ editorRef.current.activeEditor.commands.insertContent(replacementContent);
+ };
+
+ return (
+
+
+
+
+
+
+
+ {drawerOpenRef.current ? '◀' : '▶'}
+
+
+
+
+
Content Replacement
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default App;
\ No newline at end of file
diff --git a/examples/replace-content-example/src/components/DocumentEditor.jsx b/examples/replace-content-example/src/components/DocumentEditor.jsx
new file mode 100644
index 0000000000..79d3c07aca
--- /dev/null
+++ b/examples/replace-content-example/src/components/DocumentEditor.jsx
@@ -0,0 +1,74 @@
+import { SuperDoc } from '@harbour-enterprises/superdoc';
+import '@harbour-enterprises/superdoc/style.css';
+import { useEffect, useRef } from 'react';
+
+const DocumentEditor = ({
+ initialData = null,
+ readOnly = false,
+ onEditorReady
+}) => {
+ const editorRef = useRef(null);
+
+ useEffect(() => {
+ const config = {
+ selector: '#superdoc',
+ toolbar: '#superdoc-toolbar',
+ documentMode: readOnly ? 'viewing' : 'editing',
+ pagination: true,
+ rulers: true,
+ onReady: () => {
+ if (onEditorReady) {
+ onEditorReady(editor);
+ }
+ },
+ onEditorCreate: (event) => {
+ console.log('Editor is created', event);
+ },
+ onEditorDestroy: () => {
+ console.log('Editor is destroyed');
+ }
+ }
+
+ if (initialData) config.document = initialData;
+ console.log(">>> INITIAL DATA", initialData);
+ // config.document = './sample.docx'; // or use path to file
+
+ const editor = new SuperDoc(config);
+
+ editorRef.current = editor;
+
+ // Cleanup on unmount
+ return () => {
+ if (editorRef.current) {
+ editorRef.current = null;
+ }
+ };
+ }, [initialData, readOnly, onEditorReady]);
+
+ return (
+
+ );
+};
+
+export default DocumentEditor;
\ No newline at end of file
diff --git a/examples/replace-content-example/src/main.jsx b/examples/replace-content-example/src/main.jsx
new file mode 100644
index 0000000000..d91a819a6e
--- /dev/null
+++ b/examples/replace-content-example/src/main.jsx
@@ -0,0 +1,9 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App';
+
+ReactDOM.createRoot(document.getElementById('root')).render(
+
+
+
+);
\ No newline at end of file
diff --git a/examples/replace-content-example/vite.config.js b/examples/replace-content-example/vite.config.js
new file mode 100644
index 0000000000..112d510344
--- /dev/null
+++ b/examples/replace-content-example/vite.config.js
@@ -0,0 +1,9 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+
+export default defineConfig({
+ plugins: [react()],
+ optimizeDeps: {
+ include: ['@harbour-enterprises/superdoc']
+ }
+});
diff --git a/examples/tests/.gitignore b/examples/tests/.gitignore
new file mode 100644
index 0000000000..a0c9a3e8e7
--- /dev/null
+++ b/examples/tests/.gitignore
@@ -0,0 +1 @@
+playwright-report
\ No newline at end of file
diff --git a/examples/tests/package.json b/examples/tests/package.json
new file mode 100644
index 0000000000..ceb4d6e42b
--- /dev/null
+++ b/examples/tests/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "demo-gallery-tests",
+ "version": "1.0.0",
+ "description": "Automated tests suites for all examples on the demo gallery",
+ "main": "index.js",
+ "scripts": {
+ "test": "npx playwright test"
+ },
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "@playwright/test": "^1.55.0",
+ "playwright": "^1.55.0"
+ }
+}
diff --git a/examples/tests/playwright.config.js b/examples/tests/playwright.config.js
new file mode 100644
index 0000000000..ae3cc34766
--- /dev/null
+++ b/examples/tests/playwright.config.js
@@ -0,0 +1,48 @@
+import { defineConfig, devices } from '@playwright/test';
+import testConfig from './test-config.js';
+
+const foldersToTest = testConfig.include;
+
+export default defineConfig({
+ testMatch: '**/*.spec.js',
+
+ // Run all tests in parallel.
+ fullyParallel: true,
+
+ // Fail the build on CI if you accidentally left test.only in the source code.
+ forbidOnly: !!process.env.CI,
+
+ // Retry on CI only.
+ retries: process.env.CI ? 2 : 0,
+
+ // Opt out of parallel tests on CI.
+ workers: process.env.CI ? 1 : undefined,
+
+ // Reporter to use
+ reporter: 'html',
+
+ use: {
+ // Base URL to use in actions like `await page.goto('/')`.
+ baseURL: 'http://localhost:5173',
+
+ // Collect trace when retrying the failed test.
+ trace: 'on-first-retry',
+ },
+ // Configure projects for major browsers.
+ projects: [
+ {
+ name: 'chromium',
+ use: { ...devices['Desktop Chrome'] },
+ },
+ ],
+
+ // Open every example in a separate server
+ webServer: testConfig.include.map(({name, command}, i) => {
+ return {
+ command: `${command} -- --port ${5173 + i}`,
+ url: `http://localhost:${5173 + i}`,
+ reuseExistingServer: !process.env.CI,
+ timeout: 120 * 1000, // 2 minutes timeout for server startup
+ }
+ })
+});
\ No newline at end of file
diff --git a/examples/tests/test-config.js b/examples/tests/test-config.js
new file mode 100644
index 0000000000..9c4cf79ad4
--- /dev/null
+++ b/examples/tests/test-config.js
@@ -0,0 +1,52 @@
+export default {
+ include: [
+ {
+ name: "cdn-example",
+ command: 'cd ../cdn-example && npm run start',
+ },
+ {
+ name: "external-plugin-dynamic-content",
+ command: 'cd ../external-plugin-dynamic-content && npm install && npm run dev',
+ },
+ {
+ name: "next-js-ssr",
+ command: 'cd ../next-js-ssr && npm install && npm run dev',
+ },
+ {
+ name: "programmatic-text-selection",
+ command: 'cd ../programmatic-text-selection && npm install && npm run dev',
+ },
+ {
+ name: "react-example",
+ command: 'cd ../react-example && npm install && npm run dev',
+ },
+ {
+ name: "typescript-example",
+ command: 'cd ../typescript-example && npm install && npm run dev',
+ },
+ {
+ name: "vanilla-example",
+ command: 'cd ../vanilla-example && npm install && npm run dev',
+ },
+ {
+ name: "vue-custom-mark",
+ command: 'cd ../vue-custom-mark && npm install && npm run dev',
+ },
+ {
+ name: "vue-docx-from-html",
+ command: 'cd ../vue-docx-from-html && npm install && npm run dev',
+ },
+ {
+ name: "vue-example",
+ command: 'cd ../vue-example && npm install && npm run dev',
+ },
+ {
+ name: "vue-fields-example",
+ command: 'cd ../vue-fields-example && npm install && npm run dev',
+ },
+ {
+ name: "vue-linked-editor-sections",
+ command: 'cd ../vue-linked-editor-sections && npm install && npm run dev',
+ },
+ ]
+}
\ No newline at end of file
diff --git a/examples/tests/tests.spec.js b/examples/tests/tests.spec.js
new file mode 100644
index 0000000000..6e3d01a3bb
--- /dev/null
+++ b/examples/tests/tests.spec.js
@@ -0,0 +1,22 @@
+import { test, expect } from '@playwright/test';
+import testConfig from './test-config.js';
+const PORT = 5173;
+const foldersToTest = testConfig.include;
+
+foldersToTest.forEach(({name}, i) => {
+ test.describe(name, () => {
+ test('should open the main page', async ({ page }) => {
+ // Should open the main page
+ await page.goto(`http://localhost:${PORT + i}`);
+
+ await page.waitForSelector('div.super-editor', {
+ timeout: 5_000,
+ });
+
+ // Compare the screenshot with the reference screenshot
+ await expect(page).toHaveScreenshot({
+ fullPage: true,
+ });
+ });
+});
+});
\ No newline at end of file
diff --git a/examples/tests/tests.spec.js-snapshots/cdn-example-should-open-the-main-page-1-chromium-darwin.png b/examples/tests/tests.spec.js-snapshots/cdn-example-should-open-the-main-page-1-chromium-darwin.png
new file mode 100644
index 0000000000..91db6873a3
Binary files /dev/null and b/examples/tests/tests.spec.js-snapshots/cdn-example-should-open-the-main-page-1-chromium-darwin.png differ
diff --git a/examples/tests/tests.spec.js-snapshots/external-plugin-dynamic-content-should-open-the-main-page-1-chromium-darwin.png b/examples/tests/tests.spec.js-snapshots/external-plugin-dynamic-content-should-open-the-main-page-1-chromium-darwin.png
new file mode 100644
index 0000000000..8551c124df
Binary files /dev/null and b/examples/tests/tests.spec.js-snapshots/external-plugin-dynamic-content-should-open-the-main-page-1-chromium-darwin.png differ
diff --git a/examples/tests/tests.spec.js-snapshots/next-js-ssr-should-open-the-main-page-1-chromium-darwin.png b/examples/tests/tests.spec.js-snapshots/next-js-ssr-should-open-the-main-page-1-chromium-darwin.png
new file mode 100644
index 0000000000..ed1863a4b1
Binary files /dev/null and b/examples/tests/tests.spec.js-snapshots/next-js-ssr-should-open-the-main-page-1-chromium-darwin.png differ
diff --git a/examples/tests/tests.spec.js-snapshots/programmatic-text-selection-should-open-the-main-page-1-chromium-darwin.png b/examples/tests/tests.spec.js-snapshots/programmatic-text-selection-should-open-the-main-page-1-chromium-darwin.png
new file mode 100644
index 0000000000..97bc888f18
Binary files /dev/null and b/examples/tests/tests.spec.js-snapshots/programmatic-text-selection-should-open-the-main-page-1-chromium-darwin.png differ
diff --git a/examples/tests/tests.spec.js-snapshots/react-example-should-open-the-main-page-1-chromium-darwin.png b/examples/tests/tests.spec.js-snapshots/react-example-should-open-the-main-page-1-chromium-darwin.png
new file mode 100644
index 0000000000..2c2fb9d6f7
Binary files /dev/null and b/examples/tests/tests.spec.js-snapshots/react-example-should-open-the-main-page-1-chromium-darwin.png differ
diff --git a/examples/tests/tests.spec.js-snapshots/typescript-example-should-open-the-main-page-1-chromium-darwin.png b/examples/tests/tests.spec.js-snapshots/typescript-example-should-open-the-main-page-1-chromium-darwin.png
new file mode 100644
index 0000000000..5503d8f7bd
Binary files /dev/null and b/examples/tests/tests.spec.js-snapshots/typescript-example-should-open-the-main-page-1-chromium-darwin.png differ
diff --git a/examples/tests/tests.spec.js-snapshots/vanilla-example-should-open-the-main-page-1-chromium-darwin.png b/examples/tests/tests.spec.js-snapshots/vanilla-example-should-open-the-main-page-1-chromium-darwin.png
new file mode 100644
index 0000000000..5503d8f7bd
Binary files /dev/null and b/examples/tests/tests.spec.js-snapshots/vanilla-example-should-open-the-main-page-1-chromium-darwin.png differ
diff --git a/examples/tests/tests.spec.js-snapshots/vue-custom-mark-should-open-the-main-page-1-chromium-darwin.png b/examples/tests/tests.spec.js-snapshots/vue-custom-mark-should-open-the-main-page-1-chromium-darwin.png
new file mode 100644
index 0000000000..e14141658d
Binary files /dev/null and b/examples/tests/tests.spec.js-snapshots/vue-custom-mark-should-open-the-main-page-1-chromium-darwin.png differ
diff --git a/examples/tests/tests.spec.js-snapshots/vue-docx-from-html-should-open-the-main-page-1-chromium-darwin.png b/examples/tests/tests.spec.js-snapshots/vue-docx-from-html-should-open-the-main-page-1-chromium-darwin.png
new file mode 100644
index 0000000000..51e04289f5
Binary files /dev/null and b/examples/tests/tests.spec.js-snapshots/vue-docx-from-html-should-open-the-main-page-1-chromium-darwin.png differ
diff --git a/examples/tests/tests.spec.js-snapshots/vue-example-should-open-the-main-page-1-chromium-darwin.png b/examples/tests/tests.spec.js-snapshots/vue-example-should-open-the-main-page-1-chromium-darwin.png
new file mode 100644
index 0000000000..7cee24ad9c
Binary files /dev/null and b/examples/tests/tests.spec.js-snapshots/vue-example-should-open-the-main-page-1-chromium-darwin.png differ
diff --git a/examples/tests/tests.spec.js-snapshots/vue-fields-example-should-open-the-main-page-1-chromium-darwin.png b/examples/tests/tests.spec.js-snapshots/vue-fields-example-should-open-the-main-page-1-chromium-darwin.png
new file mode 100644
index 0000000000..8a0dc81f11
Binary files /dev/null and b/examples/tests/tests.spec.js-snapshots/vue-fields-example-should-open-the-main-page-1-chromium-darwin.png differ
diff --git a/examples/tests/tests.spec.js-snapshots/vue-linked-editor-sections-should-open-the-main-page-1-chromium-darwin.png b/examples/tests/tests.spec.js-snapshots/vue-linked-editor-sections-should-open-the-main-page-1-chromium-darwin.png
new file mode 100644
index 0000000000..7d79bb4f74
Binary files /dev/null and b/examples/tests/tests.spec.js-snapshots/vue-linked-editor-sections-should-open-the-main-page-1-chromium-darwin.png differ
diff --git a/examples/vue-custom-node-example/src/custom-node.js b/examples/vue-custom-node-example/src/custom-node.js
index 0ba225e893..0117828444 100644
--- a/examples/vue-custom-node-example/src/custom-node.js
+++ b/examples/vue-custom-node-example/src/custom-node.js
@@ -1,9 +1,9 @@
-import { Extensions } from '@harbour-enterprises/superdoc/super-editor';
+import { Extensions } from '@harbour-enterprises/superdoc';
// Extensions includes the necessary classes for creating custom nodes
-const { Attribute } = Extensions;
+const { Attribute, Node } = Extensions;
-export const myCustomNode = Extensions.Node.create({
+export const myCustomNode = Node.create({
name: 'customNode',
group: 'inline',
diff --git a/package-lock.json b/package-lock.json
index 81359a0fb5..822400e8df 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -32,6 +32,20 @@
"xml-js": "^1.6.11"
}
},
+ "node_modules/@ampproject/remapping": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/@asamuzakjp/css-color": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz",
@@ -106,10 +120,20 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@bcoe/v8-coverage": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz",
+ "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@bufbuild/protobuf": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.6.1.tgz",
- "integrity": "sha512-DaG6XlyKpz08bmHY5SGX2gfIllaqtDJ/KwVoxsmP22COOLYwDBe7yD3DZGwXem/Xq7QOc9cuR7R3MpAv5CFfDw==",
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.7.0.tgz",
+ "integrity": "sha512-qn6tAIZEw5i/wiESBF4nQxZkl86aY4KoO0IkUa2Lh+rya64oTOdJQFlZuMwI1Qz9VBJQrQC4QlSA2DNek5gCOA==",
"dev": true,
"license": "(Apache-2.0 AND BSD-3-Clause)"
},
@@ -389,9 +413,9 @@
}
},
"node_modules/@csstools/color-helpers": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz",
- "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz",
+ "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==",
"funding": [
{
"type": "github",
@@ -431,9 +455,9 @@
}
},
"node_modules/@csstools/css-color-parser": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz",
- "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz",
+ "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==",
"funding": [
{
"type": "github",
@@ -446,7 +470,7 @@
],
"license": "MIT",
"dependencies": {
- "@csstools/color-helpers": "^5.0.2",
+ "@csstools/color-helpers": "^5.1.0",
"@csstools/css-calc": "^2.1.4"
},
"engines": {
@@ -522,9 +546,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz",
- "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz",
+ "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==",
"cpu": [
"ppc64"
],
@@ -539,9 +563,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz",
- "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz",
+ "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==",
"cpu": [
"arm"
],
@@ -556,9 +580,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz",
- "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz",
+ "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==",
"cpu": [
"arm64"
],
@@ -573,9 +597,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz",
- "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz",
+ "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==",
"cpu": [
"x64"
],
@@ -590,9 +614,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz",
- "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz",
+ "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==",
"cpu": [
"arm64"
],
@@ -607,9 +631,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz",
- "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz",
+ "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==",
"cpu": [
"x64"
],
@@ -624,9 +648,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz",
- "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz",
+ "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==",
"cpu": [
"arm64"
],
@@ -641,9 +665,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz",
- "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz",
+ "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==",
"cpu": [
"x64"
],
@@ -658,9 +682,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz",
- "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz",
+ "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==",
"cpu": [
"arm"
],
@@ -675,9 +699,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz",
- "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz",
+ "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==",
"cpu": [
"arm64"
],
@@ -692,9 +716,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz",
- "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz",
+ "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==",
"cpu": [
"ia32"
],
@@ -709,9 +733,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz",
- "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz",
+ "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==",
"cpu": [
"loong64"
],
@@ -726,9 +750,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz",
- "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz",
+ "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==",
"cpu": [
"mips64el"
],
@@ -743,9 +767,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz",
- "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz",
+ "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==",
"cpu": [
"ppc64"
],
@@ -760,9 +784,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz",
- "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz",
+ "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==",
"cpu": [
"riscv64"
],
@@ -777,9 +801,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz",
- "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz",
+ "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==",
"cpu": [
"s390x"
],
@@ -794,9 +818,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz",
- "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz",
+ "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==",
"cpu": [
"x64"
],
@@ -811,9 +835,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz",
- "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz",
+ "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==",
"cpu": [
"arm64"
],
@@ -828,9 +852,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz",
- "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz",
+ "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==",
"cpu": [
"x64"
],
@@ -845,9 +869,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz",
- "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz",
+ "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==",
"cpu": [
"arm64"
],
@@ -862,9 +886,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz",
- "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz",
+ "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==",
"cpu": [
"x64"
],
@@ -879,9 +903,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz",
- "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz",
+ "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==",
"cpu": [
"arm64"
],
@@ -896,9 +920,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz",
- "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz",
+ "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==",
"cpu": [
"x64"
],
@@ -913,9 +937,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz",
- "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz",
+ "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==",
"cpu": [
"arm64"
],
@@ -930,9 +954,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz",
- "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz",
+ "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==",
"cpu": [
"ia32"
],
@@ -947,9 +971,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz",
- "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz",
+ "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==",
"cpu": [
"x64"
],
@@ -1129,9 +1153,9 @@
}
},
"node_modules/@floating-ui/core": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.2.tgz",
- "integrity": "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==",
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
+ "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1139,13 +1163,13 @@
}
},
"node_modules/@floating-ui/dom": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.2.tgz",
- "integrity": "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==",
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
+ "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@floating-ui/core": "^1.7.2",
+ "@floating-ui/core": "^1.7.3",
"@floating-ui/utils": "^0.2.10"
}
},
@@ -1276,12 +1300,12 @@
}
},
"node_modules/@inquirer/checkbox": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.0.tgz",
- "integrity": "sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.2.tgz",
+ "integrity": "sha512-E+KExNurKcUJJdxmjglTl141EwxWyAHplvsYJQgSwXf8qiNWkTxTuCCqmhFEmbIXd4zLaGMfQFJ6WrZ7fSeV3g==",
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.15",
+ "@inquirer/core": "^10.2.0",
"@inquirer/figures": "^1.0.13",
"@inquirer/type": "^3.0.8",
"ansi-escapes": "^4.3.2",
@@ -1327,12 +1351,12 @@
}
},
"node_modules/@inquirer/confirm": {
- "version": "5.1.14",
- "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz",
- "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==",
+ "version": "5.1.16",
+ "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.16.tgz",
+ "integrity": "sha512-j1a5VstaK5KQy8Mu8cHmuQvN1Zc62TbLhjJxwHvKPPKEoowSF6h/0UdOpA9DNdWZ+9Inq73+puRq1df6OJ8Sag==",
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.15",
+ "@inquirer/core": "^10.2.0",
"@inquirer/type": "^3.0.8"
},
"engines": {
@@ -1348,9 +1372,9 @@
}
},
"node_modules/@inquirer/core": {
- "version": "10.1.15",
- "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.15.tgz",
- "integrity": "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA==",
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.0.tgz",
+ "integrity": "sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==",
"license": "MIT",
"dependencies": {
"@inquirer/figures": "^1.0.13",
@@ -1481,14 +1505,14 @@
}
},
"node_modules/@inquirer/editor": {
- "version": "4.2.15",
- "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.15.tgz",
- "integrity": "sha512-wst31XT8DnGOSS4nNJDIklGKnf+8shuauVrWzgKegWUe28zfCftcWZ2vktGdzJgcylWSS2SrDnYUb6alZcwnCQ==",
+ "version": "4.2.18",
+ "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.18.tgz",
+ "integrity": "sha512-yeQN3AXjCm7+Hmq5L6Dm2wEDeBRdAZuyZ4I7tWSSanbxDzqM0KqzoDbKM7p4ebllAYdoQuPJS6N71/3L281i6w==",
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.15",
- "@inquirer/type": "^3.0.8",
- "external-editor": "^3.1.0"
+ "@inquirer/core": "^10.2.0",
+ "@inquirer/external-editor": "^1.0.1",
+ "@inquirer/type": "^3.0.8"
},
"engines": {
"node": ">=18"
@@ -1503,12 +1527,12 @@
}
},
"node_modules/@inquirer/expand": {
- "version": "4.0.17",
- "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.17.tgz",
- "integrity": "sha512-PSqy9VmJx/VbE3CT453yOfNa+PykpKg/0SYP7odez1/NWBGuDXgPhp4AeGYYKjhLn5lUUavVS/JbeYMPdH50Mw==",
+ "version": "4.0.18",
+ "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.18.tgz",
+ "integrity": "sha512-xUjteYtavH7HwDMzq4Cn2X4Qsh5NozoDHCJTdoXg9HfZ4w3R6mxV1B9tL7DGJX2eq/zqtsFjhm0/RJIMGlh3ag==",
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.15",
+ "@inquirer/core": "^10.2.0",
"@inquirer/type": "^3.0.8",
"yoctocolors-cjs": "^2.1.2"
},
@@ -1524,6 +1548,27 @@
}
}
},
+ "node_modules/@inquirer/external-editor": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz",
+ "integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==",
+ "license": "MIT",
+ "dependencies": {
+ "chardet": "^2.1.0",
+ "iconv-lite": "^0.6.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@inquirer/figures": {
"version": "1.0.13",
"resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz",
@@ -1534,12 +1579,12 @@
}
},
"node_modules/@inquirer/input": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.1.tgz",
- "integrity": "sha512-tVC+O1rBl0lJpoUZv4xY+WGWY8V5b0zxU1XDsMsIHYregdh7bN5X5QnIONNBAl0K765FYlAfNHS2Bhn7SSOVow==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.2.tgz",
+ "integrity": "sha512-hqOvBZj/MhQCpHUuD3MVq18SSoDNHy7wEnQ8mtvs71K8OPZVXJinOzcvQna33dNYLYE4LkA9BlhAhK6MJcsVbw==",
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.15",
+ "@inquirer/core": "^10.2.0",
"@inquirer/type": "^3.0.8"
},
"engines": {
@@ -1555,12 +1600,12 @@
}
},
"node_modules/@inquirer/number": {
- "version": "3.0.17",
- "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.17.tgz",
- "integrity": "sha512-GcvGHkyIgfZgVnnimURdOueMk0CztycfC8NZTiIY9arIAkeOgt6zG57G+7vC59Jns3UX27LMkPKnKWAOF5xEYg==",
+ "version": "3.0.18",
+ "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.18.tgz",
+ "integrity": "sha512-7exgBm52WXZRczsydCVftozFTrrwbG5ySE0GqUd2zLNSBXyIucs2Wnm7ZKLe/aUu6NUg9dg7Q80QIHCdZJiY4A==",
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.15",
+ "@inquirer/core": "^10.2.0",
"@inquirer/type": "^3.0.8"
},
"engines": {
@@ -1576,12 +1621,12 @@
}
},
"node_modules/@inquirer/password": {
- "version": "4.0.17",
- "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.17.tgz",
- "integrity": "sha512-DJolTnNeZ00E1+1TW+8614F7rOJJCM4y4BAGQ3Gq6kQIG+OJ4zr3GLjIjVVJCbKsk2jmkmv6v2kQuN/vriHdZA==",
+ "version": "4.0.18",
+ "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.18.tgz",
+ "integrity": "sha512-zXvzAGxPQTNk/SbT3carAD4Iqi6A2JS2qtcqQjsL22uvD+JfQzUrDEtPjLL7PLn8zlSNyPdY02IiQjzoL9TStA==",
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.15",
+ "@inquirer/core": "^10.2.0",
"@inquirer/type": "^3.0.8",
"ansi-escapes": "^4.3.2"
},
@@ -1625,21 +1670,21 @@
}
},
"node_modules/@inquirer/prompts": {
- "version": "7.7.1",
- "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.7.1.tgz",
- "integrity": "sha512-XDxPrEWeWUBy8scAXzXuFY45r/q49R0g72bUzgQXZ1DY/xEFX+ESDMkTQolcb5jRBzaNJX2W8XQl6krMNDTjaA==",
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.4.tgz",
+ "integrity": "sha512-MuxVZ1en1g5oGamXV3DWP89GEkdD54alcfhHd7InUW5BifAdKQEK9SLFa/5hlWbvuhMPlobF0WAx7Okq988Jxg==",
"license": "MIT",
"dependencies": {
- "@inquirer/checkbox": "^4.2.0",
- "@inquirer/confirm": "^5.1.14",
- "@inquirer/editor": "^4.2.15",
- "@inquirer/expand": "^4.0.17",
- "@inquirer/input": "^4.2.1",
- "@inquirer/number": "^3.0.17",
- "@inquirer/password": "^4.0.17",
- "@inquirer/rawlist": "^4.1.5",
- "@inquirer/search": "^3.0.17",
- "@inquirer/select": "^4.3.1"
+ "@inquirer/checkbox": "^4.2.2",
+ "@inquirer/confirm": "^5.1.16",
+ "@inquirer/editor": "^4.2.18",
+ "@inquirer/expand": "^4.0.18",
+ "@inquirer/input": "^4.2.2",
+ "@inquirer/number": "^3.0.18",
+ "@inquirer/password": "^4.0.18",
+ "@inquirer/rawlist": "^4.1.6",
+ "@inquirer/search": "^3.1.1",
+ "@inquirer/select": "^4.3.2"
},
"engines": {
"node": ">=18"
@@ -1654,12 +1699,12 @@
}
},
"node_modules/@inquirer/rawlist": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.5.tgz",
- "integrity": "sha512-R5qMyGJqtDdi4Ht521iAkNqyB6p2UPuZUbMifakg1sWtu24gc2Z8CJuw8rP081OckNDMgtDCuLe42Q2Kr3BolA==",
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.6.tgz",
+ "integrity": "sha512-KOZqa3QNr3f0pMnufzL7K+nweFFCCBs6LCXZzXDrVGTyssjLeudn5ySktZYv1XiSqobyHRYYK0c6QsOxJEhXKA==",
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.15",
+ "@inquirer/core": "^10.2.0",
"@inquirer/type": "^3.0.8",
"yoctocolors-cjs": "^2.1.2"
},
@@ -1676,12 +1721,12 @@
}
},
"node_modules/@inquirer/search": {
- "version": "3.0.17",
- "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.17.tgz",
- "integrity": "sha512-CuBU4BAGFqRYors4TNCYzy9X3DpKtgIW4Boi0WNkm4Ei1hvY9acxKdBdyqzqBCEe4YxSdaQQsasJlFlUJNgojw==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.1.tgz",
+ "integrity": "sha512-TkMUY+A2p2EYVY3GCTItYGvqT6LiLzHBnqsU1rJbrpXUijFfM6zvUx0R4civofVwFCmJZcKqOVwwWAjplKkhxA==",
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.15",
+ "@inquirer/core": "^10.2.0",
"@inquirer/figures": "^1.0.13",
"@inquirer/type": "^3.0.8",
"yoctocolors-cjs": "^2.1.2"
@@ -1699,12 +1744,12 @@
}
},
"node_modules/@inquirer/select": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.1.tgz",
- "integrity": "sha512-Gfl/5sqOF5vS/LIrSndFgOh7jgoe0UXEizDqahFRkq5aJBLegZ6WjuMh/hVEJwlFQjyLq1z9fRtvUMkb7jM1LA==",
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.2.tgz",
+ "integrity": "sha512-nwous24r31M+WyDEHV+qckXkepvihxhnyIaod2MG7eCE6G0Zm/HUF6jgN8GXgf4U7AU6SLseKdanY195cwvU6w==",
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.15",
+ "@inquirer/core": "^10.2.0",
"@inquirer/figures": "^1.0.13",
"@inquirer/type": "^3.0.8",
"ansi-escapes": "^4.3.2",
@@ -1784,10 +1829,20 @@
"node": ">=12"
}
},
+ "node_modules/@istanbuljs/schema": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.12",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz",
- "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==",
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1806,15 +1861,15 @@
}
},
"node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.5.4",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
- "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.29",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz",
- "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==",
+ "version": "0.3.30",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz",
+ "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2314,6 +2369,330 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@parcel/watcher": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
+ "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "detect-libc": "^1.0.3",
+ "is-glob": "^4.0.3",
+ "micromatch": "^4.0.5",
+ "node-addon-api": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher-android-arm64": "2.5.1",
+ "@parcel/watcher-darwin-arm64": "2.5.1",
+ "@parcel/watcher-darwin-x64": "2.5.1",
+ "@parcel/watcher-freebsd-x64": "2.5.1",
+ "@parcel/watcher-linux-arm-glibc": "2.5.1",
+ "@parcel/watcher-linux-arm-musl": "2.5.1",
+ "@parcel/watcher-linux-arm64-glibc": "2.5.1",
+ "@parcel/watcher-linux-arm64-musl": "2.5.1",
+ "@parcel/watcher-linux-x64-glibc": "2.5.1",
+ "@parcel/watcher-linux-x64-musl": "2.5.1",
+ "@parcel/watcher-win32-arm64": "2.5.1",
+ "@parcel/watcher-win32-ia32": "2.5.1",
+ "@parcel/watcher-win32-x64": "2.5.1"
+ }
+ },
+ "node_modules/@parcel/watcher-android-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
+ "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
+ "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
+ "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-freebsd-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
+ "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
+ "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
+ "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
+ "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
+ "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
+ "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
+ "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
+ "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-ia32": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
+ "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
+ "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher/node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/@phun-ky/typeof": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@phun-ky/typeof/-/typeof-1.2.8.tgz",
@@ -2370,9 +2749,9 @@
}
},
"node_modules/@rolldown/pluginutils": {
- "version": "1.0.0-beta.19",
- "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz",
- "integrity": "sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==",
+ "version": "1.0.0-beta.29",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz",
+ "integrity": "sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==",
"dev": true,
"license": "MIT"
},
@@ -2445,9 +2824,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz",
- "integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.48.1.tgz",
+ "integrity": "sha512-rGmb8qoG/zdmKoYELCBwu7vt+9HxZ7Koos3pD0+sH5fR3u3Wb/jGcpnqxcnWsPEKDUyzeLSqksN8LJtgXjqBYw==",
"cpu": [
"arm"
],
@@ -2459,9 +2838,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz",
- "integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.48.1.tgz",
+ "integrity": "sha512-4e9WtTxrk3gu1DFE+imNJr4WsL13nWbD/Y6wQcyku5qadlKHY3OQ3LJ/INrrjngv2BJIHnIzbqMk1GTAC2P8yQ==",
"cpu": [
"arm64"
],
@@ -2473,9 +2852,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz",
- "integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.48.1.tgz",
+ "integrity": "sha512-+XjmyChHfc4TSs6WUQGmVf7Hkg8ferMAE2aNYYWjiLzAS/T62uOsdfnqv+GHRjq7rKRnYh4mwWb4Hz7h/alp8A==",
"cpu": [
"arm64"
],
@@ -2487,9 +2866,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz",
- "integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.48.1.tgz",
+ "integrity": "sha512-upGEY7Ftw8M6BAJyGwnwMw91rSqXTcOKZnnveKrVWsMTF8/k5mleKSuh7D4v4IV1pLxKAk3Tbs0Lo9qYmii5mQ==",
"cpu": [
"x64"
],
@@ -2501,9 +2880,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz",
- "integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.48.1.tgz",
+ "integrity": "sha512-P9ViWakdoynYFUOZhqq97vBrhuvRLAbN/p2tAVJvhLb8SvN7rbBnJQcBu8e/rQts42pXGLVhfsAP0k9KXWa3nQ==",
"cpu": [
"arm64"
],
@@ -2515,9 +2894,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz",
- "integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.48.1.tgz",
+ "integrity": "sha512-VLKIwIpnBya5/saccM8JshpbxfyJt0Dsli0PjXozHwbSVaHTvWXJH1bbCwPXxnMzU4zVEfgD1HpW3VQHomi2AQ==",
"cpu": [
"x64"
],
@@ -2529,9 +2908,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz",
- "integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.48.1.tgz",
+ "integrity": "sha512-3zEuZsXfKaw8n/yF7t8N6NNdhyFw3s8xJTqjbTDXlipwrEHo4GtIKcMJr5Ed29leLpB9AugtAQpAHW0jvtKKaQ==",
"cpu": [
"arm"
],
@@ -2543,9 +2922,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz",
- "integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.48.1.tgz",
+ "integrity": "sha512-leo9tOIlKrcBmmEypzunV/2w946JeLbTdDlwEZ7OnnsUyelZ72NMnT4B2vsikSgwQifjnJUbdXzuW4ToN1wV+Q==",
"cpu": [
"arm"
],
@@ -2557,9 +2936,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz",
- "integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.48.1.tgz",
+ "integrity": "sha512-Vy/WS4z4jEyvnJm+CnPfExIv5sSKqZrUr98h03hpAMbE2aI0aD2wvK6GiSe8Gx2wGp3eD81cYDpLLBqNb2ydwQ==",
"cpu": [
"arm64"
],
@@ -2571,9 +2950,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz",
- "integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.48.1.tgz",
+ "integrity": "sha512-x5Kzn7XTwIssU9UYqWDB9VpLpfHYuXw5c6bJr4Mzv9kIv242vmJHbI5PJJEnmBYitUIfoMCODDhR7KoZLot2VQ==",
"cpu": [
"arm64"
],
@@ -2585,9 +2964,9 @@
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz",
- "integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.48.1.tgz",
+ "integrity": "sha512-yzCaBbwkkWt/EcgJOKDUdUpMHjhiZT/eDktOPWvSRpqrVE04p0Nd6EGV4/g7MARXXeOqstflqsKuXVM3H9wOIQ==",
"cpu": [
"loong64"
],
@@ -2599,9 +2978,9 @@
]
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz",
- "integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.48.1.tgz",
+ "integrity": "sha512-UK0WzWUjMAJccHIeOpPhPcKBqax7QFg47hwZTp6kiMhQHeOYJeaMwzeRZe1q5IiTKsaLnHu9s6toSYVUlZ2QtQ==",
"cpu": [
"ppc64"
],
@@ -2613,9 +2992,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz",
- "integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.48.1.tgz",
+ "integrity": "sha512-3NADEIlt+aCdCbWVZ7D3tBjBX1lHpXxcvrLt/kdXTiBrOds8APTdtk2yRL2GgmnSVeX4YS1JIf0imFujg78vpw==",
"cpu": [
"riscv64"
],
@@ -2627,9 +3006,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz",
- "integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.48.1.tgz",
+ "integrity": "sha512-euuwm/QTXAMOcyiFCcrx0/S2jGvFlKJ2Iro8rsmYL53dlblp3LkUQVFzEidHhvIPPvcIsxDhl2wkBE+I6YVGzA==",
"cpu": [
"riscv64"
],
@@ -2641,9 +3020,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz",
- "integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.48.1.tgz",
+ "integrity": "sha512-w8mULUjmPdWLJgmTYJx/W6Qhln1a+yqvgwmGXcQl2vFBkWsKGUBRbtLRuKJUln8Uaimf07zgJNxOhHOvjSQmBQ==",
"cpu": [
"s390x"
],
@@ -2655,9 +3034,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz",
- "integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.48.1.tgz",
+ "integrity": "sha512-90taWXCWxTbClWuMZD0DKYohY1EovA+W5iytpE89oUPmT5O1HFdf8cuuVIylE6vCbrGdIGv85lVRzTcpTRZ+kA==",
"cpu": [
"x64"
],
@@ -2669,9 +3048,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz",
- "integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.48.1.tgz",
+ "integrity": "sha512-2Gu29SkFh1FfTRuN1GR1afMuND2GKzlORQUP3mNMJbqdndOg7gNsa81JnORctazHRokiDzQ5+MLE5XYmZW5VWg==",
"cpu": [
"x64"
],
@@ -2683,9 +3062,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz",
- "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.48.1.tgz",
+ "integrity": "sha512-6kQFR1WuAO50bxkIlAVeIYsz3RUx+xymwhTo9j94dJ+kmHe9ly7muH23sdfWduD0BA8pD9/yhonUvAjxGh34jQ==",
"cpu": [
"arm64"
],
@@ -2697,9 +3076,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz",
- "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.48.1.tgz",
+ "integrity": "sha512-RUyZZ/mga88lMI3RlXFs4WQ7n3VyU07sPXmMG7/C1NOi8qisUg57Y7LRarqoGoAiopmGmChUhSwfpvQ3H5iGSQ==",
"cpu": [
"ia32"
],
@@ -2711,9 +3090,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz",
- "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.48.1.tgz",
+ "integrity": "sha512-8a/caCUN4vkTChxkaIJcMtwIVcBhi4X2PQRoT+yCK3qRYaZ7cURrmJFL5Ux9H9RaMIXj9RuihckdmkBX3zZsgg==",
"cpu": [
"x64"
],
@@ -2737,6 +3116,10 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/@superdoc-dev/ooxml-inspector": {
+ "resolved": "packages/ooxml-inspector",
+ "link": true
+ },
"node_modules/@tootallnate/quickjs-emscripten": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
@@ -2922,9 +3305,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "22.16.5",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.5.tgz",
- "integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==",
+ "version": "22.18.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.0.tgz",
+ "integrity": "sha512-m5ObIqwsUp6BZzyiy4RdZpzWGub9bqLJMvZDD0QMXhxjqMHMENlj+SqF5QxoUwaQNFe+8kz8XM8ZQhqkQPTgMQ==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
@@ -2981,9 +3364,9 @@
"license": "MIT"
},
"node_modules/@typescript-eslint/types": {
- "version": "8.39.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.1.tgz",
- "integrity": "sha512-7sPDKQQp+S11laqTrhHqeAbsCfMkwJMrV7oTDvtDds4mEofJYir414bYKUEb8YPUm9QL3U+8f6L6YExSoAGdQw==",
+ "version": "8.41.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.41.0.tgz",
+ "integrity": "sha512-9EwxsWdVqh42afLbHP90n2VdHaWU/oWgbH2P0CfcNfdKL7CuKpwMQGjwev56vWu9cSKU7FWSu6r9zck6CVfnag==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3002,20 +3385,54 @@
"license": "ISC"
},
"node_modules/@vitejs/plugin-vue": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.0.tgz",
- "integrity": "sha512-iAliE72WsdhjzTOp2DtvKThq1VBC4REhwRcaA+zPAAph6I+OQhUXv+Xu2KS7ElxYtb7Zc/3R30Hwv1DxEo7NXQ==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.1.tgz",
+ "integrity": "sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@rolldown/pluginutils": "1.0.0-beta.19"
+ "@rolldown/pluginutils": "1.0.0-beta.29"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"peerDependencies": {
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
- "vue": "^3.2.25"
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
+ "vue": "^3.2.25"
+ }
+ },
+ "node_modules/@vitest/coverage-v8": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz",
+ "integrity": "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@ampproject/remapping": "^2.3.0",
+ "@bcoe/v8-coverage": "^1.0.2",
+ "ast-v8-to-istanbul": "^0.3.3",
+ "debug": "^4.4.1",
+ "istanbul-lib-coverage": "^3.2.2",
+ "istanbul-lib-report": "^3.0.1",
+ "istanbul-lib-source-maps": "^5.0.6",
+ "istanbul-reports": "^3.1.7",
+ "magic-string": "^0.30.17",
+ "magicast": "^0.3.5",
+ "std-env": "^3.9.0",
+ "test-exclude": "^7.0.1",
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@vitest/browser": "3.2.4",
+ "vitest": "3.2.4"
+ },
+ "peerDependenciesMeta": {
+ "@vitest/browser": {
+ "optional": true
+ }
}
},
"node_modules/@vitest/expect": {
@@ -3800,15 +4217,15 @@
}
},
"node_modules/@vueuse/core": {
- "version": "13.5.0",
- "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.5.0.tgz",
- "integrity": "sha512-wV7z0eUpifKmvmN78UBZX8T7lMW53Nrk6JP5+6hbzrB9+cJ3jr//hUlhl9TZO/03bUkMK6gGkQpqOPWoabr72g==",
+ "version": "13.7.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.7.0.tgz",
+ "integrity": "sha512-myagn09+c6BmS6yHc1gTwwsdZilAovHslMjyykmZH3JNyzI5HoWhv114IIdytXiPipdHJ2gDUx0PB93jRduJYg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/web-bluetooth": "^0.0.21",
- "@vueuse/metadata": "13.5.0",
- "@vueuse/shared": "13.5.0"
+ "@vueuse/metadata": "13.7.0",
+ "@vueuse/shared": "13.7.0"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
@@ -3818,9 +4235,9 @@
}
},
"node_modules/@vueuse/metadata": {
- "version": "13.5.0",
- "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.5.0.tgz",
- "integrity": "sha512-euhItU3b0SqXxSy8u1XHxUCdQ8M++bsRs+TYhOLDU/OykS7KvJnyIFfep0XM5WjIFry9uAPlVSjmVHiqeshmkw==",
+ "version": "13.7.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.7.0.tgz",
+ "integrity": "sha512-8okFhS/1ite8EwUdZZfvTYowNTfXmVCOrBFlA31O0HD8HKXhY+WtTRyF0LwbpJfoFPc+s9anNJIXMVrvP7UTZg==",
"dev": true,
"license": "MIT",
"funding": {
@@ -3828,9 +4245,9 @@
}
},
"node_modules/@vueuse/shared": {
- "version": "13.5.0",
- "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.5.0.tgz",
- "integrity": "sha512-K7GrQIxJ/ANtucxIXbQlUHdB0TPA8c+q5i+zbrjxuhJCnJ9GtBg75sBSnvmLSxHKPg2Yo8w62PWksl9kwH0Q8g==",
+ "version": "13.7.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.7.0.tgz",
+ "integrity": "sha512-Wi2LpJi4UA9kM0OZ0FCZslACp92HlVNw1KPaDY6RAzvQ+J1s7seOtcOpmkfbD5aBSmMn9NvOakc8ZxMxmDXTIg==",
"dev": true,
"license": "MIT",
"funding": {
@@ -3923,9 +4340,9 @@
}
},
"node_modules/ansi-regex": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
- "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.0.tgz",
+ "integrity": "sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==",
"license": "MIT",
"engines": {
"node": ">=12"
@@ -4098,6 +4515,35 @@
"node": ">=4"
}
},
+ "node_modules/ast-v8-to-istanbul": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.4.tgz",
+ "integrity": "sha512-cxrAnZNLBnQwBPByK4CeDaw5sWZtMilJE/Q3iDA0aamgaIVNDF9T6K2/8DfYDZEejZ2jNnDrG9m8MY72HFd0KA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.29",
+ "estree-walker": "^3.0.3",
+ "js-tokens": "^9.0.1"
+ }
+ },
+ "node_modules/ast-v8-to-istanbul/node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
+ "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
+ "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/async-retry": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz",
@@ -4437,9 +4883,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.25.1",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz",
- "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==",
+ "version": "4.25.3",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.3.tgz",
+ "integrity": "sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==",
"dev": true,
"funding": [
{
@@ -4457,8 +4903,8 @@
],
"license": "MIT",
"dependencies": {
- "caniuse-lite": "^1.0.30001726",
- "electron-to-chromium": "^1.5.173",
+ "caniuse-lite": "^1.0.30001735",
+ "electron-to-chromium": "^1.5.204",
"node-releases": "^2.0.19",
"update-browserslist-db": "^1.1.3"
},
@@ -4660,9 +5106,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001727",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz",
- "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==",
+ "version": "1.0.30001737",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001737.tgz",
+ "integrity": "sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw==",
"dev": true,
"funding": [
{
@@ -4708,9 +5154,9 @@
}
},
"node_modules/chai": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.1.tgz",
- "integrity": "sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==",
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz",
+ "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4725,9 +5171,9 @@
}
},
"node_modules/chalk": {
- "version": "5.4.1",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
- "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz",
+ "integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==",
"license": "MIT",
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
@@ -4759,9 +5205,9 @@
}
},
"node_modules/chardet": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
- "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz",
+ "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==",
"license": "MIT"
},
"node_modules/check-error": {
@@ -5188,19 +5634,18 @@
}
},
"node_modules/concurrently": {
- "version": "9.2.0",
- "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.0.tgz",
- "integrity": "sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ==",
+ "version": "9.2.1",
+ "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz",
+ "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==",
"dev": true,
"license": "MIT",
"dependencies": {
- "chalk": "^4.1.2",
- "lodash": "^4.17.21",
- "rxjs": "^7.8.1",
- "shell-quote": "^1.8.1",
- "supports-color": "^8.1.1",
- "tree-kill": "^1.2.2",
- "yargs": "^17.7.2"
+ "chalk": "4.1.2",
+ "rxjs": "7.8.2",
+ "shell-quote": "1.8.3",
+ "supports-color": "8.1.1",
+ "tree-kill": "1.2.2",
+ "yargs": "17.7.2"
},
"bin": {
"conc": "dist/bin/concurrently.js",
@@ -5259,6 +5704,32 @@
"node": ">=8"
}
},
+ "node_modules/concurrently/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/concurrently/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
"node_modules/confbox": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz",
@@ -6435,9 +6906,9 @@
}
},
"node_modules/electron-to-chromium": {
- "version": "1.5.188",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.188.tgz",
- "integrity": "sha512-pfEx5CBFAocOKNrc+i5fSvhDaI1Vr9R9aT5uX1IzM3hhdL6k649wfuUcdUd9EZnmbE1xdfA51CwqQ61CO3Xl3g==",
+ "version": "1.5.209",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.209.tgz",
+ "integrity": "sha512-Xoz0uMrim9ZETCQt8UgM5FxQF9+imA7PBpokoGcZloA1uw2LeHzTlip5cb5KOAsXZLjh/moN2vReN3ZjJmjI9A==",
"dev": true,
"license": "ISC"
},
@@ -6596,9 +7067,9 @@
}
},
"node_modules/esbuild": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz",
- "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz",
+ "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -6609,32 +7080,32 @@
"node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.25.8",
- "@esbuild/android-arm": "0.25.8",
- "@esbuild/android-arm64": "0.25.8",
- "@esbuild/android-x64": "0.25.8",
- "@esbuild/darwin-arm64": "0.25.8",
- "@esbuild/darwin-x64": "0.25.8",
- "@esbuild/freebsd-arm64": "0.25.8",
- "@esbuild/freebsd-x64": "0.25.8",
- "@esbuild/linux-arm": "0.25.8",
- "@esbuild/linux-arm64": "0.25.8",
- "@esbuild/linux-ia32": "0.25.8",
- "@esbuild/linux-loong64": "0.25.8",
- "@esbuild/linux-mips64el": "0.25.8",
- "@esbuild/linux-ppc64": "0.25.8",
- "@esbuild/linux-riscv64": "0.25.8",
- "@esbuild/linux-s390x": "0.25.8",
- "@esbuild/linux-x64": "0.25.8",
- "@esbuild/netbsd-arm64": "0.25.8",
- "@esbuild/netbsd-x64": "0.25.8",
- "@esbuild/openbsd-arm64": "0.25.8",
- "@esbuild/openbsd-x64": "0.25.8",
- "@esbuild/openharmony-arm64": "0.25.8",
- "@esbuild/sunos-x64": "0.25.8",
- "@esbuild/win32-arm64": "0.25.8",
- "@esbuild/win32-ia32": "0.25.8",
- "@esbuild/win32-x64": "0.25.8"
+ "@esbuild/aix-ppc64": "0.25.9",
+ "@esbuild/android-arm": "0.25.9",
+ "@esbuild/android-arm64": "0.25.9",
+ "@esbuild/android-x64": "0.25.9",
+ "@esbuild/darwin-arm64": "0.25.9",
+ "@esbuild/darwin-x64": "0.25.9",
+ "@esbuild/freebsd-arm64": "0.25.9",
+ "@esbuild/freebsd-x64": "0.25.9",
+ "@esbuild/linux-arm": "0.25.9",
+ "@esbuild/linux-arm64": "0.25.9",
+ "@esbuild/linux-ia32": "0.25.9",
+ "@esbuild/linux-loong64": "0.25.9",
+ "@esbuild/linux-mips64el": "0.25.9",
+ "@esbuild/linux-ppc64": "0.25.9",
+ "@esbuild/linux-riscv64": "0.25.9",
+ "@esbuild/linux-s390x": "0.25.9",
+ "@esbuild/linux-x64": "0.25.9",
+ "@esbuild/netbsd-arm64": "0.25.9",
+ "@esbuild/netbsd-x64": "0.25.9",
+ "@esbuild/openbsd-arm64": "0.25.9",
+ "@esbuild/openbsd-x64": "0.25.9",
+ "@esbuild/openharmony-arm64": "0.25.9",
+ "@esbuild/sunos-x64": "0.25.9",
+ "@esbuild/win32-arm64": "0.25.9",
+ "@esbuild/win32-ia32": "0.25.9",
+ "@esbuild/win32-x64": "0.25.9"
}
},
"node_modules/escalade": {
@@ -6756,9 +7227,9 @@
}
},
"node_modules/eslint-plugin-jsdoc": {
- "version": "54.1.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-54.1.0.tgz",
- "integrity": "sha512-tZJuW6s3gtveVsg08IbJgmfgAA1SpSkEz7KjxPEVmyAO4fPlz7zsMHdxjyn+Zku1l+wejr2JUdTFTNirRgHOrQ==",
+ "version": "54.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-54.1.1.tgz",
+ "integrity": "sha512-qoY2Gl0OkvATXIxRaG2irS2ue78+RTaOyYrADvg1ue+9FHE+2Mp7RcpO0epkuhhQgOkH/REv1oJFe58dYv8SGg==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -6780,17 +7251,6 @@
"eslint": "^7.0.0 || ^8.0.0 || ^9.0.0"
}
},
- "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz",
- "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "spdx-exceptions": "^2.1.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
"node_modules/eslint-scope": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
@@ -6888,6 +7348,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/eslint/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/eslint/node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -7179,32 +7649,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/external-editor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
- "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
- "license": "MIT",
- "dependencies": {
- "chardet": "^0.7.0",
- "iconv-lite": "^0.4.24",
- "tmp": "^0.0.33"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/external-editor/node_modules/iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "license": "MIT",
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/fast-content-type-parse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz",
@@ -7271,9 +7715,9 @@
"license": "MIT"
},
"node_modules/fast-uri": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
- "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
+ "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
"dev": true,
"funding": [
{
@@ -7297,10 +7741,13 @@
}
},
"node_modules/fdir": {
- "version": "6.4.6",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
- "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
"peerDependencies": {
"picomatch": "^3 || ^4"
},
@@ -7470,9 +7917,9 @@
}
},
"node_modules/fs-extra": {
- "version": "11.3.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
- "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==",
+ "version": "11.3.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz",
+ "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -7517,9 +7964,9 @@
"license": "ISC"
},
"node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -7800,6 +8247,24 @@
}
}
},
+ "node_modules/git-semver-tags/node_modules/conventional-commits-parser": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.2.0.tgz",
+ "integrity": "sha512-uLnoLeIW4XaoFtH37qEcg/SXMJmKF4vi7V0H2rnPueg+VEtFGA/asSCNTcq4M/GQ6QmlzchAEtOoDTtKqWeHag==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "meow": "^13.0.0"
+ },
+ "bin": {
+ "conventional-commits-parser": "dist/cli/index.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/git-up": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/git-up/-/git-up-8.1.1.tgz",
@@ -8010,13 +8475,6 @@
"js-yaml": "bin/js-yaml.js"
}
},
- "node_modules/gray-matter/node_modules/sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
- "dev": true,
- "license": "BSD-3-Clause"
- },
"node_modules/handlebars": {
"version": "4.7.8",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
@@ -8040,13 +8498,13 @@
}
},
"node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=8"
+ "node": ">=4"
}
},
"node_modules/has-property-descriptors": {
@@ -8328,6 +8786,13 @@
"node": ">=18"
}
},
+ "node_modules/html-escaper": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/html-void-elements": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz",
@@ -8634,14 +9099,10 @@
}
},
"node_modules/ip-address": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
- "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz",
+ "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==",
"license": "MIT",
- "dependencies": {
- "jsbn": "1.1.0",
- "sprintf-js": "^1.1.3"
- },
"engines": {
"node": ">= 12"
}
@@ -9046,6 +9507,99 @@
"node": "^18.17 || >=20.6.1"
}
},
+ "node_modules/istanbul-lib-coverage": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
+ "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-report": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
+ "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "istanbul-lib-coverage": "^3.0.0",
+ "make-dir": "^4.0.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-lib-report/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-report/node_modules/make-dir": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
+ "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/istanbul-lib-report/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-source-maps": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz",
+ "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.23",
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-reports": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
+ "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "html-escaper": "^2.0.0",
+ "istanbul-lib-report": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/jackspeak": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
@@ -9063,9 +9617,9 @@
}
},
"node_modules/jiti": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
- "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz",
+ "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==",
"license": "MIT",
"bin": {
"jiti": "lib/jiti-cli.mjs"
@@ -9133,12 +9687,6 @@
"js-yaml": "bin/js-yaml.js"
}
},
- "node_modules/jsbn": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
- "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
- "license": "MIT"
- },
"node_modules/jsdoc-type-pratt-parser": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.8.0.tgz",
@@ -9218,9 +9766,9 @@
"license": "MIT"
},
"node_modules/jsonfile": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
- "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
+ "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -9400,13 +9948,13 @@
}
},
"node_modules/lint-staged": {
- "version": "16.1.4",
- "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.4.tgz",
- "integrity": "sha512-xy7rnzQrhTVGKMpv6+bmIA3C0yET31x8OhKBYfvGo0/byeZ6E0BjGARrir3Kg/RhhYHutpsi01+2J5IpfVoueA==",
+ "version": "16.1.5",
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.5.tgz",
+ "integrity": "sha512-uAeQQwByI6dfV7wpt/gVqg+jAPaSp8WwOA8kKC/dv1qw14oGpnpAisY65ibGHUGDUv0rYaZ8CAJZ/1U8hUvC2A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "chalk": "^5.4.1",
+ "chalk": "^5.5.0",
"commander": "^14.0.0",
"debug": "^4.4.1",
"lilconfig": "^3.1.3",
@@ -9415,7 +9963,7 @@
"nano-spawn": "^1.0.2",
"pidtree": "^0.6.0",
"string-argv": "^0.3.2",
- "yaml": "^2.8.0"
+ "yaml": "^2.8.1"
},
"bin": {
"lint-staged": "bin/lint-staged.js"
@@ -9428,9 +9976,9 @@
}
},
"node_modules/listr2": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.1.tgz",
- "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==",
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.2.tgz",
+ "integrity": "sha512-VVd7cS6W+vLJu2wmq4QmfVj14Iep7cz4r/OWNk36Aq5ZOY7G8/BfCrQFexcwB1OIxB3yERiePfE/REBjEFulag==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -9750,9 +10298,9 @@
}
},
"node_modules/loupe": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.4.tgz",
- "integrity": "sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==",
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
+ "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
"dev": true,
"license": "MIT"
},
@@ -9775,12 +10323,24 @@
}
},
"node_modules/magic-string": {
- "version": "0.30.17",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
- "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
+ "version": "0.30.18",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz",
+ "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/magicast": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz",
+ "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==",
+ "devOptional": true,
"license": "MIT",
"dependencies": {
- "@jridgewell/sourcemap-codec": "^1.5.0"
+ "@babel/parser": "^7.25.4",
+ "@babel/types": "^7.25.4",
+ "source-map-js": "^1.2.0"
}
},
"node_modules/make-dir": {
@@ -10234,16 +10794,16 @@
}
},
"node_modules/mlly": {
- "version": "1.7.4",
- "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz",
- "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==",
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz",
+ "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "acorn": "^8.14.0",
- "pathe": "^2.0.1",
- "pkg-types": "^1.3.0",
- "ufo": "^1.5.4"
+ "acorn": "^8.15.0",
+ "pathe": "^2.0.3",
+ "pkg-types": "^1.3.1",
+ "ufo": "^1.6.1"
}
},
"node_modules/mlly/node_modules/confbox": {
@@ -10410,6 +10970,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
@@ -10432,9 +11000,9 @@
}
},
"node_modules/node-fetch-native": {
- "version": "1.6.6",
- "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz",
- "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==",
+ "version": "1.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz",
+ "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==",
"license": "MIT"
},
"node_modules/node-fetch/node_modules/tr46": {
@@ -10575,16 +11143,6 @@
"node": ">= 6"
}
},
- "node_modules/nodemon/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/nodemon/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -10608,20 +11166,7 @@
"picomatch": "^2.2.1"
},
"engines": {
- "node": ">=8.10.0"
- }
- },
- "node_modules/nodemon/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
+ "node": ">=8.10.0"
}
},
"node_modules/nopt": {
@@ -10730,22 +11275,22 @@
}
},
"node_modules/nwsapi": {
- "version": "2.2.20",
- "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz",
- "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==",
+ "version": "2.2.21",
+ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz",
+ "integrity": "sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==",
"license": "MIT"
},
"node_modules/nypm": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.0.tgz",
- "integrity": "sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg==",
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz",
+ "integrity": "sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w==",
"license": "MIT",
"dependencies": {
"citty": "^0.1.6",
- "consola": "^3.4.0",
+ "consola": "^3.4.2",
"pathe": "^2.0.3",
- "pkg-types": "^2.0.0",
- "tinyexec": "^0.3.2"
+ "pkg-types": "^2.2.0",
+ "tinyexec": "^1.0.1"
},
"bin": {
"nypm": "dist/cli.mjs"
@@ -10754,12 +11299,6 @@
"node": "^14.16.0 || >=16.10.0"
}
},
- "node_modules/nypm/node_modules/tinyexec": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
- "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
- "license": "MIT"
- },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -10972,15 +11511,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/os-tmpdir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/p-limit": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
@@ -11540,9 +12070,9 @@
}
},
"node_modules/pkg-types": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.2.0.tgz",
- "integrity": "sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz",
+ "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==",
"license": "MIT",
"dependencies": {
"confbox": "^0.2.2",
@@ -11814,9 +12344,9 @@
}
},
"node_modules/prosemirror-model": {
- "version": "1.25.2",
- "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.2.tgz",
- "integrity": "sha512-BVypCAJ4SL6jOiTsDffP3Wp6wD69lRhI4zg/iT8JXjp3ccZFiq5WyguxvMKmdKFC3prhaig7wSr8dneDToHE1Q==",
+ "version": "1.25.3",
+ "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.3.tgz",
+ "integrity": "sha512-dY2HdaNXlARknJbrManZ1WyUtos+AP97AmvqdOQtWtrrC5g4mohVX5DTi9rXNFSk09eczLq9GuNTtq3EfMeMGA==",
"license": "MIT",
"dependencies": {
"orderedmap": "^2.0.0"
@@ -11877,6 +12407,18 @@
"prosemirror-view": "^1.39.1"
}
},
+ "node_modules/prosemirror-test-builder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/prosemirror-test-builder/-/prosemirror-test-builder-1.1.1.tgz",
+ "integrity": "sha512-DJ1+4TNTE9ZcYN/ozXCaWJVrGA99UttMoVvZuidvAotRg7FaiNtEYxL/vlDwfZDRnzJDXNYhmM3XPv3EweK7yA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prosemirror-model": "^1.0.0",
+ "prosemirror-schema-basic": "^1.0.0",
+ "prosemirror-schema-list": "^1.0.0"
+ }
+ },
"node_modules/prosemirror-transform": {
"version": "1.10.4",
"resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.4.tgz",
@@ -12419,9 +12961,9 @@
}
},
"node_modules/rollup": {
- "version": "4.46.2",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz",
- "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==",
+ "version": "4.48.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.48.1.tgz",
+ "integrity": "sha512-jVG20NvbhTYDkGAty2/Yh7HK6/q3DGSRH4o8ALKGArmMuaauM9kLfoMZ+WliPwA5+JHr2lTn3g557FxBV87ifg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -12435,26 +12977,26 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.46.2",
- "@rollup/rollup-android-arm64": "4.46.2",
- "@rollup/rollup-darwin-arm64": "4.46.2",
- "@rollup/rollup-darwin-x64": "4.46.2",
- "@rollup/rollup-freebsd-arm64": "4.46.2",
- "@rollup/rollup-freebsd-x64": "4.46.2",
- "@rollup/rollup-linux-arm-gnueabihf": "4.46.2",
- "@rollup/rollup-linux-arm-musleabihf": "4.46.2",
- "@rollup/rollup-linux-arm64-gnu": "4.46.2",
- "@rollup/rollup-linux-arm64-musl": "4.46.2",
- "@rollup/rollup-linux-loongarch64-gnu": "4.46.2",
- "@rollup/rollup-linux-ppc64-gnu": "4.46.2",
- "@rollup/rollup-linux-riscv64-gnu": "4.46.2",
- "@rollup/rollup-linux-riscv64-musl": "4.46.2",
- "@rollup/rollup-linux-s390x-gnu": "4.46.2",
- "@rollup/rollup-linux-x64-gnu": "4.46.2",
- "@rollup/rollup-linux-x64-musl": "4.46.2",
- "@rollup/rollup-win32-arm64-msvc": "4.46.2",
- "@rollup/rollup-win32-ia32-msvc": "4.46.2",
- "@rollup/rollup-win32-x64-msvc": "4.46.2",
+ "@rollup/rollup-android-arm-eabi": "4.48.1",
+ "@rollup/rollup-android-arm64": "4.48.1",
+ "@rollup/rollup-darwin-arm64": "4.48.1",
+ "@rollup/rollup-darwin-x64": "4.48.1",
+ "@rollup/rollup-freebsd-arm64": "4.48.1",
+ "@rollup/rollup-freebsd-x64": "4.48.1",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.48.1",
+ "@rollup/rollup-linux-arm-musleabihf": "4.48.1",
+ "@rollup/rollup-linux-arm64-gnu": "4.48.1",
+ "@rollup/rollup-linux-arm64-musl": "4.48.1",
+ "@rollup/rollup-linux-loongarch64-gnu": "4.48.1",
+ "@rollup/rollup-linux-ppc64-gnu": "4.48.1",
+ "@rollup/rollup-linux-riscv64-gnu": "4.48.1",
+ "@rollup/rollup-linux-riscv64-musl": "4.48.1",
+ "@rollup/rollup-linux-s390x-gnu": "4.48.1",
+ "@rollup/rollup-linux-x64-gnu": "4.48.1",
+ "@rollup/rollup-linux-x64-musl": "4.48.1",
+ "@rollup/rollup-win32-arm64-msvc": "4.48.1",
+ "@rollup/rollup-win32-ia32-msvc": "4.48.1",
+ "@rollup/rollup-win32-x64-msvc": "4.48.1",
"fsevents": "~2.3.2"
}
},
@@ -12659,13 +13201,13 @@
}
},
"node_modules/rollup-plugin-visualizer/node_modules/source-map": {
- "version": "0.7.4",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
- "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
+ "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
- "node": ">= 8"
+ "node": ">= 12"
}
},
"node_modules/rope-sequence": {
@@ -12778,10 +13320,32 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
+ "node_modules/sass": {
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.91.0.tgz",
+ "integrity": "sha512-aFOZHGf+ur+bp1bCHZ+u8otKGh77ZtmFyXDo4tlYvT7PWql41Kwd8wdkPqhhT+h2879IVblcHFglIMofsFd1EA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "chokidar": "^4.0.0",
+ "immutable": "^5.0.2",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher": "^2.4.1"
+ }
+ },
"node_modules/sass-embedded": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.89.2.tgz",
- "integrity": "sha512-Ack2K8rc57kCFcYlf3HXpZEJFNUX8xd8DILldksREmYXQkRHI879yy8q4mRDJgrojkySMZqmmmW1NxrFxMsYaA==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.91.0.tgz",
+ "integrity": "sha512-VTckYcH1AglrZ3VpPETilTo3Ef472XKwP13lrNfbOHSR6Eo5p27XTkIi+6lrCbuhBFFGAmy+4BRoLaeFUgn+eg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -12801,28 +13365,47 @@
"node": ">=16.0.0"
},
"optionalDependencies": {
- "sass-embedded-android-arm": "1.89.2",
- "sass-embedded-android-arm64": "1.89.2",
- "sass-embedded-android-riscv64": "1.89.2",
- "sass-embedded-android-x64": "1.89.2",
- "sass-embedded-darwin-arm64": "1.89.2",
- "sass-embedded-darwin-x64": "1.89.2",
- "sass-embedded-linux-arm": "1.89.2",
- "sass-embedded-linux-arm64": "1.89.2",
- "sass-embedded-linux-musl-arm": "1.89.2",
- "sass-embedded-linux-musl-arm64": "1.89.2",
- "sass-embedded-linux-musl-riscv64": "1.89.2",
- "sass-embedded-linux-musl-x64": "1.89.2",
- "sass-embedded-linux-riscv64": "1.89.2",
- "sass-embedded-linux-x64": "1.89.2",
- "sass-embedded-win32-arm64": "1.89.2",
- "sass-embedded-win32-x64": "1.89.2"
+ "sass-embedded-all-unknown": "1.91.0",
+ "sass-embedded-android-arm": "1.91.0",
+ "sass-embedded-android-arm64": "1.91.0",
+ "sass-embedded-android-riscv64": "1.91.0",
+ "sass-embedded-android-x64": "1.91.0",
+ "sass-embedded-darwin-arm64": "1.91.0",
+ "sass-embedded-darwin-x64": "1.91.0",
+ "sass-embedded-linux-arm": "1.91.0",
+ "sass-embedded-linux-arm64": "1.91.0",
+ "sass-embedded-linux-musl-arm": "1.91.0",
+ "sass-embedded-linux-musl-arm64": "1.91.0",
+ "sass-embedded-linux-musl-riscv64": "1.91.0",
+ "sass-embedded-linux-musl-x64": "1.91.0",
+ "sass-embedded-linux-riscv64": "1.91.0",
+ "sass-embedded-linux-x64": "1.91.0",
+ "sass-embedded-unknown-all": "1.91.0",
+ "sass-embedded-win32-arm64": "1.91.0",
+ "sass-embedded-win32-x64": "1.91.0"
+ }
+ },
+ "node_modules/sass-embedded-all-unknown": {
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.91.0.tgz",
+ "integrity": "sha512-AXC1oPqDfLnLtcoxM+XwSnbhcQs0TxAiA5JDEstl6+tt6fhFLKxdyl1Hla39SFtxvMfB2QDUYE3Dmx49O59vYg==",
+ "cpu": [
+ "!arm",
+ "!arm64",
+ "!riscv64",
+ "!x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "sass": "1.91.0"
}
},
"node_modules/sass-embedded-android-arm": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.89.2.tgz",
- "integrity": "sha512-oHAPTboBHRZlDBhyRB6dvDKh4KvFs+DZibDHXbkSI6dBZxMTT+Yb2ivocHnctVGucKTLQeT7+OM5DjWHyynL/A==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.91.0.tgz",
+ "integrity": "sha512-DSh1V8TlLIcpklAbn4NINEFs3yD2OzVTbawEXK93IH990upoGNFVNRTstFQ/gcvlbWph3Y3FjAJvo37zUO485A==",
"cpu": [
"arm"
],
@@ -12837,9 +13420,9 @@
}
},
"node_modules/sass-embedded-android-arm64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.89.2.tgz",
- "integrity": "sha512-+pq7a7AUpItNyPu61sRlP6G2A8pSPpyazASb+8AK2pVlFayCSPAEgpwpCE9A2/Xj86xJZeMizzKUHxM2CBCUxA==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.91.0.tgz",
+ "integrity": "sha512-I8Eeg2CeVcZIhXcQLNEY6ZBRF0m7jc818/fypwMwvIdbxGWBekTzc3aKHTLhdBpFzGnDIyR4s7oB0/OjIpzD1A==",
"cpu": [
"arm64"
],
@@ -12854,9 +13437,9 @@
}
},
"node_modules/sass-embedded-android-riscv64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.89.2.tgz",
- "integrity": "sha512-HfJJWp/S6XSYvlGAqNdakeEMPOdhBkj2s2lN6SHnON54rahKem+z9pUbCriUJfM65Z90lakdGuOfidY61R9TYg==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.91.0.tgz",
+ "integrity": "sha512-qmsl1a7IIJL0fCOwzmRB+6nxeJK5m9/W8LReXUrdgyJNH5RyxChDg+wwQPVATFffOuztmWMnlJ5CV2sCLZrXcQ==",
"cpu": [
"riscv64"
],
@@ -12871,9 +13454,9 @@
}
},
"node_modules/sass-embedded-android-x64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.89.2.tgz",
- "integrity": "sha512-BGPzq53VH5z5HN8de6jfMqJjnRe1E6sfnCWFd4pK+CAiuM7iw5Fx6BQZu3ikfI1l2GY0y6pRXzsVLdp/j4EKEA==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.91.0.tgz",
+ "integrity": "sha512-/wN0HBLATOVSeN3Tzg0yxxNTo1IQvOxxxwFv7Ki/1/UCg2AqZPxTpNoZj/mn8tUPtiVogMGbC8qclYMq1aRZsQ==",
"cpu": [
"x64"
],
@@ -12888,9 +13471,9 @@
}
},
"node_modules/sass-embedded-darwin-arm64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.89.2.tgz",
- "integrity": "sha512-UCm3RL/tzMpG7DsubARsvGUNXC5pgfQvP+RRFJo9XPIi6elopY5B6H4m9dRYDpHA+scjVthdiDwkPYr9+S/KGw==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.91.0.tgz",
+ "integrity": "sha512-gQ6ScInxAN+BDUXy426BSYLRawkmGYlHpQ9i6iOxorr64dtIb3l6eb9YaBV8lPlroUnugylmwN2B3FU9BuPfhA==",
"cpu": [
"arm64"
],
@@ -12905,9 +13488,9 @@
}
},
"node_modules/sass-embedded-darwin-x64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.89.2.tgz",
- "integrity": "sha512-D9WxtDY5VYtMApXRuhQK9VkPHB8R79NIIR6xxVlN2MIdEid/TZWi1MHNweieETXhWGrKhRKglwnHxxyKdJYMnA==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.91.0.tgz",
+ "integrity": "sha512-DSvFMtECL2blYVTFMO5fLeNr5bX437Lrz8R47fdo5438TRyOkSgwKTkECkfh3YbnrL86yJIN2QQlmBMF17Z/iw==",
"cpu": [
"x64"
],
@@ -12922,9 +13505,9 @@
}
},
"node_modules/sass-embedded-linux-arm": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.89.2.tgz",
- "integrity": "sha512-leP0t5U4r95dc90o8TCWfxNXwMAsQhpWxTkdtySDpngoqtTy3miMd7EYNYd1znI0FN1CBaUvbdCMbnbPwygDlA==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.91.0.tgz",
+ "integrity": "sha512-ppAZLp3eZ9oTjYdQDf4nM7EehDpkxq5H1hE8FOrx8LpY7pxn6QF+SRpAbRjdfFChRw0K7vh+IiCnQEMp7uLNAg==",
"cpu": [
"arm"
],
@@ -12939,9 +13522,9 @@
}
},
"node_modules/sass-embedded-linux-arm64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.89.2.tgz",
- "integrity": "sha512-2N4WW5LLsbtrWUJ7iTpjvhajGIbmDR18ZzYRywHdMLpfdPApuHPMDF5CYzHbS+LLx2UAx7CFKBnj5LLjY6eFgQ==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.91.0.tgz",
+ "integrity": "sha512-OnKCabD7f420ZEC/6YI9WhCVGMZF+ybZ5NbAB9SsG1xlxrKbWQ1s7CIl0w/6RDALtJ+Fjn8+mrxsxqakoAkeuA==",
"cpu": [
"arm64"
],
@@ -12956,9 +13539,9 @@
}
},
"node_modules/sass-embedded-linux-musl-arm": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.89.2.tgz",
- "integrity": "sha512-Z6gG2FiVEEdxYHRi2sS5VIYBmp17351bWtOCUZ/thBM66+e70yiN6Eyqjz80DjL8haRUegNQgy9ZJqsLAAmr9g==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.91.0.tgz",
+ "integrity": "sha512-znEsNC2FurPF9+XwQQ6e/fVoic3e5D3/kMB41t/bE8byJVRdaPhkdsszt3pZUE56nNGYoCuieSXUkk7VvyPHsw==",
"cpu": [
"arm"
],
@@ -12973,9 +13556,9 @@
}
},
"node_modules/sass-embedded-linux-musl-arm64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.89.2.tgz",
- "integrity": "sha512-nTyuaBX6U1A/cG7WJh0pKD1gY8hbg1m2SnzsyoFG+exQ0lBX/lwTLHq3nyhF+0atv7YYhYKbmfz+sjPP8CZ9lw==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.91.0.tgz",
+ "integrity": "sha512-VfbPpID1C5TT7rukob6CKgefx/TsLE+XZieMNd00hvfJ8XhqPr5DGvSMCNpXlwaedzTirbJu357m+n2PJI9TFQ==",
"cpu": [
"arm64"
],
@@ -12990,9 +13573,9 @@
}
},
"node_modules/sass-embedded-linux-musl-riscv64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.89.2.tgz",
- "integrity": "sha512-N6oul+qALO0SwGY8JW7H/Vs0oZIMrRMBM4GqX3AjM/6y8JsJRxkAwnfd0fDyK+aICMFarDqQonQNIx99gdTZqw==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.91.0.tgz",
+ "integrity": "sha512-ZfLGldKEEeZjuljKks835LTq7jDRI3gXsKKXXgZGzN6Yymd4UpBOGWiDQlWsWTvw5UwDU2xfFh0wSXbLGHTjVA==",
"cpu": [
"riscv64"
],
@@ -13007,9 +13590,9 @@
}
},
"node_modules/sass-embedded-linux-musl-x64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.89.2.tgz",
- "integrity": "sha512-K+FmWcdj/uyP8GiG9foxOCPfb5OAZG0uSVq80DKgVSC0U44AdGjvAvVZkrgFEcZ6cCqlNC2JfYmslB5iqdL7tg==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.91.0.tgz",
+ "integrity": "sha512-4kSiSGPKFMbLvTRbP/ibyiKheOA3fwsJKWU0SOuekSPmybMdrhNkTm0REp6+nehZRE60kC3lXmEV4a7w8Jrwyg==",
"cpu": [
"x64"
],
@@ -13024,9 +13607,9 @@
}
},
"node_modules/sass-embedded-linux-riscv64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.89.2.tgz",
- "integrity": "sha512-g9nTbnD/3yhOaskeqeBQETbtfDQWRgsjHok6bn7DdAuwBsyrR3JlSFyqKc46pn9Xxd9SQQZU8AzM4IR+sY0A0w==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.91.0.tgz",
+ "integrity": "sha512-Y3Fj94SYYvMX9yo49T78yBgBWXtG3EyYUT5K05XyCYkcdl1mVXJSrEmqmRfe4vQGUCaSe/6s7MmsA9Q+mQez7Q==",
"cpu": [
"riscv64"
],
@@ -13041,9 +13624,9 @@
}
},
"node_modules/sass-embedded-linux-x64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.89.2.tgz",
- "integrity": "sha512-Ax7dKvzncyQzIl4r7012KCMBvJzOz4uwSNoyoM5IV6y5I1f5hEwI25+U4WfuTqdkv42taCMgpjZbh9ERr6JVMQ==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.91.0.tgz",
+ "integrity": "sha512-XwIUaE7pQP/ezS5te80hlyheYiUlo0FolQ0HBtxohpavM+DVX2fjwFm5LOUJHrLAqP+TLBtChfFeLj1Ie4Aenw==",
"cpu": [
"x64"
],
@@ -13057,10 +13640,27 @@
"node": ">=14.0.0"
}
},
+ "node_modules/sass-embedded-unknown-all": {
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.91.0.tgz",
+ "integrity": "sha512-Bj6v7ScQp/HtO91QBy6ood9AArSIN7/RNcT4E7P9QoY3o+e6621Vd28lV81vdepPrt6u6PgJoVKmLNODqB6Q+A==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "!android",
+ "!darwin",
+ "!linux",
+ "!win32"
+ ],
+ "dependencies": {
+ "sass": "1.91.0"
+ }
+ },
"node_modules/sass-embedded-win32-arm64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.89.2.tgz",
- "integrity": "sha512-j96iJni50ZUsfD6tRxDQE2QSYQ2WrfHxeiyAXf41Kw0V4w5KYR/Sf6rCZQLMTUOHnD16qTMVpQi20LQSqf4WGg==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.91.0.tgz",
+ "integrity": "sha512-yDCwTiPRex03i1yo7LwiAl1YQ21UyfOxPobD7UjI8AE8ZcB0mQ28VVX66lsZ+qm91jfLslNFOFCD4v79xCG9hA==",
"cpu": [
"arm64"
],
@@ -13075,9 +13675,9 @@
}
},
"node_modules/sass-embedded-win32-x64": {
- "version": "1.89.2",
- "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.89.2.tgz",
- "integrity": "sha512-cS2j5ljdkQsb4PaORiClaVYynE9OAPZG/XjbOMxpQmjRIf7UroY4PEIH+Waf+y47PfXFX9SyxhYuw2NIKGbEng==",
+ "version": "1.91.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.91.0.tgz",
+ "integrity": "sha512-wiuMz/cx4vsk6rYCnNyoGE5pd73aDJ/zF3qJDose3ZLT1/vV943doJE5pICnS/v5DrUqzV6a1CNq4fN+xeSgFQ==",
"cpu": [
"x64"
],
@@ -13091,6 +13691,32 @@
"node": ">=14.0.0"
}
},
+ "node_modules/sass-embedded/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/sass-embedded/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
@@ -13436,12 +14062,12 @@
}
},
"node_modules/socks": {
- "version": "2.8.6",
- "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.6.tgz",
- "integrity": "sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA==",
+ "version": "2.8.7",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz",
+ "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==",
"license": "MIT",
"dependencies": {
- "ip-address": "^9.0.5",
+ "ip-address": "^10.0.1",
"smart-buffer": "^4.2.0"
},
"engines": {
@@ -13512,6 +14138,17 @@
"spdx-license-ids": "^3.0.0"
}
},
+ "node_modules/spdx-correct/node_modules/spdx-expression-parse": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+ "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
"node_modules/spdx-exceptions": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
@@ -13520,9 +14157,9 @@
"license": "CC-BY-3.0"
},
"node_modules/spdx-expression-parse": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
- "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz",
+ "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -13531,9 +14168,9 @@
}
},
"node_modules/spdx-license-ids": {
- "version": "3.0.21",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz",
- "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==",
+ "version": "3.0.22",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz",
+ "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==",
"dev": true,
"license": "CC0-1.0"
},
@@ -13558,9 +14195,10 @@
}
},
"node_modules/sprintf-js": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
- "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "dev": true,
"license": "BSD-3-Clause"
},
"node_modules/stackback": {
@@ -13863,19 +14501,16 @@
}
},
"node_modules/supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"license": "MIT",
"dependencies": {
- "has-flag": "^4.0.0"
+ "has-flag": "^3.0.0"
},
"engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/supports-color?sponsor=1"
+ "node": ">=4"
}
},
"node_modules/supports-preserve-symlinks-flag": {
@@ -13948,6 +14583,47 @@
"node": ">=8"
}
},
+ "node_modules/test-exclude": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz",
+ "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@istanbuljs/schema": "^0.1.2",
+ "glob": "^10.4.1",
+ "minimatch": "^9.0.4"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/test-exclude/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/test-exclude/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/text-extensions": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz",
@@ -14015,7 +14691,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz",
"integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==",
- "dev": true,
"license": "MIT"
},
"node_modules/tinyglobby": {
@@ -14098,18 +14773,6 @@
"integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==",
"license": "MIT"
},
- "node_modules/tmp": {
- "version": "0.0.33",
- "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
- "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
- "license": "MIT",
- "dependencies": {
- "os-tmpdir": "~1.0.2"
- },
- "engines": {
- "node": ">=0.6.0"
- }
- },
"node_modules/to-buffer": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz",
@@ -14298,6 +14961,7 @@
"version": "0.8.0-beta.0",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
"integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==",
+ "deprecated": "The work that was done in this beta branch won't be included in future versions",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -14399,9 +15063,9 @@
"license": "MIT"
},
"node_modules/typescript": {
- "version": "5.8.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
- "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "version": "5.9.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
+ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"devOptional": true,
"license": "Apache-2.0",
"bin": {
@@ -14448,9 +15112,9 @@
"license": "MIT"
},
"node_modules/undici": {
- "version": "7.12.0",
- "resolved": "https://registry.npmjs.org/undici/-/undici-7.12.0.tgz",
- "integrity": "sha512-GrKEsc3ughskmGA9jevVlIOPMiiAHJ4OFUtaAH+NhfTUSiZ1wMPIQqQvAJUrJspFXJt3EBWgpAeoHEDVT1IBug==",
+ "version": "7.15.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.15.0.tgz",
+ "integrity": "sha512-7oZJCPvvMvTd0OlqWsIxTuItTpJBpU1tcbVl24FMn3xt3+VSunwUasmfPJRE57oNO1KsZ4PgA1xTdAX4hq8NyQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -14721,6 +15385,17 @@
"spdx-expression-parse": "^3.0.0"
}
},
+ "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+ "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
"node_modules/varint": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
@@ -14771,9 +15446,9 @@
}
},
"node_modules/vfile-message": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz",
- "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz",
+ "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -14786,15 +15461,15 @@
}
},
"node_modules/vite": {
- "version": "7.0.5",
- "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.5.tgz",
- "integrity": "sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.6.tgz",
+ "integrity": "sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.6",
- "picomatch": "^4.0.2",
+ "picomatch": "^4.0.3",
"postcss": "^8.5.6",
"rollup": "^4.40.0",
"tinyglobby": "^0.2.14"
@@ -14900,21 +15575,6 @@
"vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
}
},
- "node_modules/vite/node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
"node_modules/vitest": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz",
@@ -15069,14 +15729,14 @@
}
},
"node_modules/vue-draggable-next": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/vue-draggable-next/-/vue-draggable-next-2.2.1.tgz",
- "integrity": "sha512-EAMS1IRHF0kZO0o5PMOinsQsXIqsrKT1hKmbICxG3UEtn7zLFkLxlAtajcCcUTisNvQ6TtCB5COjD9a1raNADw==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/vue-draggable-next/-/vue-draggable-next-2.3.0.tgz",
+ "integrity": "sha512-ymbY0UIwfSdg0iDN/iyNNwUrTqZ/6KbPryzsvTNXBLuDCuOBdNijSK8yynNtmiSj6RapTPQfjLGQdJrZkzBd2w==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"sortablejs": "^1.14.0",
- "vue": "^3.2.2"
+ "vue": "^3.5.17"
}
},
"node_modules/vue-router": {
@@ -15643,9 +16303,9 @@
"optional": true
},
"node_modules/yaml": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
- "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
+ "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
"dev": true,
"license": "ISC",
"bin": {
@@ -15770,9 +16430,9 @@
}
},
"node_modules/yoctocolors-cjs": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz",
- "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz",
+ "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==",
"license": "MIT",
"engines": {
"node": ">=18"
@@ -15817,11 +16477,72 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
+ "packages/ooxml-inspector": {
+ "name": "@superdoc-dev/ooxml-inspector",
+ "version": "1.0.1",
+ "license": "AGPL-3.0",
+ "dependencies": {
+ "fast-xml-parser": "^4.4.0"
+ },
+ "bin": {
+ "ooxml": "dist/bin/cli.js"
+ },
+ "devDependencies": {
+ "@types/node": "^24.3.0",
+ "@vitest/coverage-v8": "^3.2.4",
+ "tsup": "^8.1.0",
+ "typescript": "^5.9.2",
+ "vitest": "^3.2.4"
+ },
+ "engines": {
+ "node": ">=18.17"
+ }
+ },
+ "packages/ooxml-inspector/node_modules/@types/node": {
+ "version": "24.3.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.10.0"
+ }
+ },
+ "packages/ooxml-inspector/node_modules/fast-xml-parser": {
+ "version": "4.5.3",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "strnum": "^1.1.1"
+ },
+ "bin": {
+ "fxparser": "src/cli/cli.js"
+ }
+ },
+ "packages/ooxml-inspector/node_modules/strnum": {
+ "version": "1.1.2",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT"
+ },
+ "packages/ooxml-inspector/node_modules/undici-types": {
+ "version": "7.10.0",
+ "dev": true,
+ "license": "MIT"
+ },
"packages/super-editor": {
"name": "@harbour-enterprises/super-editor",
"version": "0.0.1",
"license": "AGPL-3.0",
"dependencies": {
+ "@superdoc-dev/ooxml-inspector": "^1.0.0",
"color2k": "^2.0.3",
"eventemitter3": "^5.0.1",
"he": "^1.2.0",
@@ -15851,6 +16572,7 @@
"@vue/test-utils": "^2.4.6",
"postcss-nested": "^6.0.1",
"postcss-nested-import": "^1.3.0",
+ "prosemirror-test-builder": "^1.1.1",
"tippy.js": "^6.3.7",
"typescript": "^5.7.3",
"vite": "^6.3.5",
@@ -15882,21 +16604,6 @@
"vue": "^3.2.25"
}
},
- "packages/super-editor/node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
"packages/super-editor/node_modules/vite": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
@@ -15974,7 +16681,7 @@
},
"packages/superdoc": {
"name": "@harbour-enterprises/superdoc",
- "version": "0.15.16-next.11",
+ "version": "0.15.17-next.2",
"license": "AGPL-3.0",
"dependencies": {
"buffer-crc32": "^1.0.0",
@@ -16022,21 +16729,6 @@
"vue": "^3.2.25"
}
},
- "packages/superdoc/node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
"packages/superdoc/node_modules/vite": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
diff --git a/package.json b/package.json
index e1b880e180..eb87cacaf9 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,8 @@
"shared/*"
],
"scripts": {
- "test": "vitest --root ./packages/super-editor",
+ "test": "vitest --root ./packages/super-editor/",
+ "test:cov": "vitest --root ./packages/super-editor --coverage",
"unzip": "bash packages/super-editor/src/tests/helpers/unzip.sh",
"dev": "npm --workspace=@harbour-enterprises/superdoc run dev",
"dev:superdoc": "npm run dev --workspace=packages/superdoc",
@@ -32,7 +33,8 @@
"pack": "npm run build:super-editor && npm --prefix ./packages/superdoc run pack",
"prepare": "husky",
"lint:staged": "lint-staged",
- "watch": "npm run watch:es --workspace=packages/superdoc"
+ "watch": "npm run watch:es --workspace=packages/superdoc",
+ "check:all": "npm run format && npm run lint:fix && npm --workspace=packages/super-editor run types:build"
},
"lint-staged": {
"*.{js,jsx}": [
diff --git a/packages/ooxml-inspector/.gitignore b/packages/ooxml-inspector/.gitignore
new file mode 100644
index 0000000000..8b0dedc084
--- /dev/null
+++ b/packages/ooxml-inspector/.gitignore
@@ -0,0 +1,3 @@
+coverage/
+dist/
+node_modules/
\ No newline at end of file
diff --git a/packages/ooxml-inspector/README.md b/packages/ooxml-inspector/README.md
new file mode 100644
index 0000000000..5dc32063d7
--- /dev/null
+++ b/packages/ooxml-inspector/README.md
@@ -0,0 +1,51 @@
+# OOXML Inspector
+
+**OOXML Inspector** is a developer tool + library for working with [Office Open XML (OOXML)](https://en.wikipedia.org/wiki/Office_Open_XML) schemas.
+It bundles the transitional WordprocessingML schema into JSON and provides both:
+
+- a **CLI** (`ooxml`) for inspecting schema relationships, and
+- a **JavaScript/TypeScript library** for programmatic access.
+
+## Features
+
+- Query OOXML element children, attributes, and namespaces
+- Explore schema relationships and tag hierarchies
+- Use as a CLI or import as a library in Node.js/TypeScript
+
+## Installation
+
+```bash
+npm install @superdoc-dev/ooxml-inspector
+```
+
+## CLI Usage
+
+```bash
+npx ooxml children w:p
+npx ooxml tags --parents
+npx ooxml namespaces
+npx ooxml attrs w:p
+```
+
+- `children `: List allowed children for an element
+- `tags [prefix] [--parents] [--plain]`: List tags, optionally filtering by namespace or parent status
+- `namespaces`: List all namespaces in the schema
+- `attrs `: List attributes for an element
+
+## Library Usage
+
+```js
+import { childrenOf } from '@superdoc-dev/ooxml-inspector';
+
+const children = childrenOf('w:p'); // Get children of
+```
+
+## Development
+
+- Build: `npm run build`
+- Test: `npm run test`
+- Coverage: `npm run test:cov`
+
+## License
+
+AGPLv3
diff --git a/packages/ooxml-inspector/example/index.js b/packages/ooxml-inspector/example/index.js
new file mode 100644
index 0000000000..fd918e7b25
--- /dev/null
+++ b/packages/ooxml-inspector/example/index.js
@@ -0,0 +1,4 @@
+import { childrenOf } from '@superdoc-dev/ooxml-inspector';
+
+const children = childrenOf('w:p');
+console.debug('Children of w:p', children);
diff --git a/packages/ooxml-inspector/generator/index.js b/packages/ooxml-inspector/generator/index.js
new file mode 100644
index 0000000000..89632cd3d3
--- /dev/null
+++ b/packages/ooxml-inspector/generator/index.js
@@ -0,0 +1,3 @@
+import { runGenerator } from './src/index.js';
+
+runGenerator();
diff --git a/packages/ooxml-inspector/generator/src/builder/autoprefix.js b/packages/ooxml-inspector/generator/src/builder/autoprefix.js
new file mode 100644
index 0000000000..cf66e82127
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/autoprefix.js
@@ -0,0 +1,13 @@
+/**
+ * Auto-assign a prefix for a given target namespace.
+ * @param {string} tns - The target namespace
+ * @param {Object} nsMap - The namespace map
+ * @returns {string} - The assigned prefix
+ */
+export const autoPrefix = (tns, nsMap) => {
+ if (!tns) return 'unknown';
+ if (nsMap[tns]) return nsMap[tns];
+ const newPrefix = 'g' + Object.keys(nsMap).length;
+ nsMap[tns] = newPrefix;
+ return newPrefix;
+};
diff --git a/packages/ooxml-inspector/generator/src/builder/autoprefix.test.js b/packages/ooxml-inspector/generator/src/builder/autoprefix.test.js
new file mode 100644
index 0000000000..cb2e212472
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/autoprefix.test.js
@@ -0,0 +1,43 @@
+import { describe, it, expect } from 'vitest';
+import { autoPrefix } from './index.js';
+
+describe('autoPrefix', () => {
+ it('returns "unknown" if tns is falsy', () => {
+ const nsMap = {};
+ expect(autoPrefix('', nsMap)).toBe('unknown');
+ expect(autoPrefix(null, nsMap)).toBe('unknown');
+ expect(autoPrefix(undefined, nsMap)).toBe('unknown');
+ });
+
+ it('returns existing prefix if tns is already in nsMap', () => {
+ const nsMap = { 'http://example.com': 'ex' };
+ const result = autoPrefix('http://example.com', nsMap);
+ expect(result).toBe('ex');
+ expect(nsMap).toEqual({ 'http://example.com': 'ex' }); // unchanged
+ });
+
+ it('assigns a new prefix if tns is not in nsMap', () => {
+ const nsMap = {};
+ const result = autoPrefix('http://new.com', nsMap);
+ expect(result).toBe('g0');
+ expect(nsMap).toEqual({ 'http://new.com': 'g0' });
+ });
+
+ it('assigns incrementing prefixes based on nsMap size', () => {
+ const nsMap = { 'http://one.com': 'g0', 'http://two.com': 'g1' };
+ const result = autoPrefix('http://three.com', nsMap);
+ expect(result).toBe('g2');
+ expect(nsMap).toEqual({
+ 'http://one.com': 'g0',
+ 'http://two.com': 'g1',
+ 'http://three.com': 'g2',
+ });
+ });
+
+ it('does not overwrite existing mapping for different tns', () => {
+ const nsMap = { 'http://foo.com': 'g0' };
+ autoPrefix('http://bar.com', nsMap);
+ expect(nsMap).toHaveProperty('http://foo.com', 'g0');
+ expect(nsMap).toHaveProperty('http://bar.com', 'g1');
+ });
+});
diff --git a/packages/ooxml-inspector/generator/src/builder/collect-elements.js b/packages/ooxml-inspector/generator/src/builder/collect-elements.js
new file mode 100644
index 0000000000..ce6b8db02c
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/collect-elements.js
@@ -0,0 +1,61 @@
+import { arr } from './index.js';
+
+/** @type {number} */
+const MAX_XSD_DEPTH = 10;
+
+/**
+ * Recursively collect elements from a given node. Most nodes seem to max out around 7 levels
+ * so 10 seems like a sufficient max.
+ *
+ * @param {Object} node - The XML node to collect elements from.
+ * @param {string} tns - The target namespace.
+ * @param {string} prefix - The namespace prefix.
+ * @param {Map} elements - The map to collect elements.
+ * @param {Map} elementRefs - The map to collect element references.
+ * @param {number} depth - The current depth in the XML structure.
+ */
+export function collectElements(node, tns, prefix, elements, elementRefs, depth = 0) {
+ if (!node || depth > MAX_XSD_DEPTH) return;
+
+ // Direct elements
+ const els = arr(node['xs:element']).concat(arr(node['xsd:element']));
+ for (const el of els) {
+ if (el.name) {
+ const key = `${tns}::${el.name}`;
+ if (!elements.has(key)) {
+ elements.set(key, { tns, prefix, name: el.name, el });
+ }
+ } else if (el.ref) {
+ // Track element reference for later resolution
+ elementRefs.set(el.ref, { tns, prefix });
+ }
+ }
+
+ // Recurse into sequences, choices, alls
+ const containers = []
+ .concat(arr(node['xs:sequence']), arr(node['xsd:sequence']))
+ .concat(arr(node['xs:choice']), arr(node['xsd:choice']))
+ .concat(arr(node['xs:all']), arr(node['xsd:all']));
+
+ for (const container of containers) {
+ collectElements(container, tns, prefix, elements, elementRefs, depth + 1);
+ }
+
+ // Recurse into complex content
+ const complexContent = node['xs:complexContent'] || node['xsd:complexContent'];
+ if (complexContent) {
+ const ext = complexContent['xs:extension'] || complexContent['xsd:extension'];
+ const res = complexContent['xs:restriction'] || complexContent['xsd:restriction'];
+ if (ext) collectElements(ext, tns, prefix, elements, elementRefs, depth + 1);
+ if (res) collectElements(res, tns, prefix, elements, elementRefs, depth + 1);
+ }
+
+ // Recurse into simple content (might have attributes that are elements)
+ const simpleContent = node['xs:simpleContent'] || node['xsd:simpleContent'];
+ if (simpleContent) {
+ const ext = simpleContent['xs:extension'] || simpleContent['xsd:extension'];
+ const res = simpleContent['xs:restriction'] || simpleContent['xsd:restriction'];
+ if (ext) collectElements(ext, tns, prefix, elements, elementRefs, depth + 1);
+ if (res) collectElements(res, tns, prefix, elements, elementRefs, depth + 1);
+ }
+}
diff --git a/packages/ooxml-inspector/generator/src/builder/collect-elements.test.js b/packages/ooxml-inspector/generator/src/builder/collect-elements.test.js
new file mode 100644
index 0000000000..8d2efee571
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/collect-elements.test.js
@@ -0,0 +1,235 @@
+import { describe, it, expect, beforeEach, vi } from 'vitest';
+import { collectElements } from './collect-elements.js';
+
+vi.mock('./index.js', () => ({
+ arr: vi.fn((x) => (Array.isArray(x) ? x : x ? [x] : [])),
+}));
+
+import { arr } from './index.js';
+
+const TNS = 'urn:example';
+const PFX = 'ex';
+
+let elements;
+let elementRefs;
+
+beforeEach(() => {
+ vi.clearAllMocks();
+ elements = new Map();
+ elementRefs = new Map();
+});
+
+describe('collectElements', () => {
+ it('no-ops on falsy node and respects depth guard', () => {
+ collectElements(null, TNS, PFX, elements, elementRefs, 0);
+ expect(elements.size).toBe(0);
+ expect(elementRefs.size).toBe(0);
+
+ collectElements({}, TNS, PFX, elements, elementRefs, 11); // depth > 10
+ expect(elements.size).toBe(0);
+ expect(elementRefs.size).toBe(0);
+ });
+
+ it('collects direct named elements (xs:element & xsd:element)', () => {
+ const node = {
+ 'xs:element': [{ name: 'Alpha' }],
+ 'xsd:element': [{ name: 'Beta' }],
+ };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+
+ expect([...elements.keys()].sort()).toEqual([`${TNS}::Alpha`, `${TNS}::Beta`]);
+ expect(elements.get(`${TNS}::Alpha`)).toMatchObject({
+ tns: TNS,
+ prefix: PFX,
+ name: 'Alpha',
+ });
+ expect(elements.get(`${TNS}::Beta`)).toMatchObject({
+ tns: TNS,
+ prefix: PFX,
+ name: 'Beta',
+ });
+ expect(elementRefs.size).toBe(0);
+ });
+
+ it('tracks element refs (xs/xsd) in elementRefs without expanding', () => {
+ const node = {
+ 'xs:element': [{ ref: 'a:Gamma' }],
+ 'xsd:element': [{ ref: 'Delta' }],
+ };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+
+ expect(elements.size).toBe(0);
+ expect([...elementRefs.keys()].sort()).toEqual(['Delta', 'a:Gamma']);
+ expect(elementRefs.get('a:Gamma')).toEqual({ tns: TNS, prefix: PFX });
+ expect(elementRefs.get('Delta')).toEqual({ tns: TNS, prefix: PFX });
+ });
+
+ it('does not duplicate existing named elements', () => {
+ const node = { 'xs:element': [{ name: 'Alpha' }, { name: 'Alpha' }] };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+ expect(elements.size).toBe(1);
+ expect(elements.has(`${TNS}::Alpha`)).toBe(true);
+ });
+
+ it('recurses into sequence/choice/all (xs & xsd variants)', () => {
+ const node = {
+ 'xs:sequence': {
+ 'xsd:element': [{ name: 'SeqChild' }],
+ 'xs:choice': {
+ 'xs:element': [{ name: 'ChoiceChild' }],
+ },
+ 'xsd:all': {
+ 'xsd:element': [{ name: 'AllChild' }],
+ },
+ },
+ };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+
+ expect(elements.has(`${TNS}::SeqChild`)).toBe(true);
+ expect(elements.has(`${TNS}::ChoiceChild`)).toBe(true);
+ expect(elements.has(`${TNS}::AllChild`)).toBe(true);
+ });
+
+ it('recurses through complexContent extension and restriction (xs/xsd)', () => {
+ const node = {
+ 'xs:complexContent': {
+ 'xs:extension': {
+ 'xs:sequence': { 'xs:element': [{ name: 'FromExtension' }] },
+ },
+ 'xsd:restriction': {
+ 'xsd:choice': { 'xsd:element': [{ name: 'FromRestriction' }] },
+ },
+ },
+ };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+
+ expect(elements.has(`${TNS}::FromExtension`)).toBe(true);
+ expect(elements.has(`${TNS}::FromRestriction`)).toBe(true);
+ });
+
+ it('recurses through simpleContent extension and restriction (xs/xsd)', () => {
+ const node = {
+ 'xsd:simpleContent': {
+ 'xsd:extension': {
+ 'xs:all': { 'xsd:element': [{ name: 'SCFromExt' }] },
+ },
+ 'xs:restriction': {
+ 'xs:sequence': { 'xs:element': [{ name: 'SCFromRes' }] },
+ },
+ },
+ };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+
+ expect(elements.has(`${TNS}::SCFromExt`)).toBe(true);
+ expect(elements.has(`${TNS}::SCFromRes`)).toBe(true);
+ });
+
+ it('depth guard includes items at depth 10 but prunes deeper', () => {
+ // Build nested sequences; place elements at depth 10 and 11
+ const makeDeep = (d) => (d === 0 ? {} : { 'xs:sequence': makeDeep(d - 1) });
+ const deep = makeDeep(12);
+
+ // Insert at depth 10 and 11
+ let cursor = deep;
+ for (let i = 0; i < 10; i++) cursor = cursor['xs:sequence'];
+ cursor['xs:element'] = [{ name: 'At10' }];
+ cursor = deep;
+ for (let i = 0; i < 11; i++) cursor = cursor['xs:sequence'];
+ cursor['xs:element'] = [{ name: 'At11' }];
+
+ collectElements(deep, TNS, PFX, elements, elementRefs);
+
+ expect(elements.has(`${TNS}::At10`)).toBe(true); // allowed
+ expect(elements.has(`${TNS}::At11`)).toBe(false); // pruned
+ });
+
+ it('uses arr() to normalize singletons and arrays', () => {
+ const node = {
+ 'xs:element': { name: 'Solo' }, // singleton
+ 'xsd:sequence': { 'xs:element': { name: 'NestedSolo' } }, // singleton nested
+ };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+
+ expect(arr).toHaveBeenCalled(); // sanity: we used arr
+ expect(elements.has(`${TNS}::Solo`)).toBe(true);
+ expect(elements.has(`${TNS}::NestedSolo`)).toBe(true);
+ });
+
+ it('handles complexContent with only extension (no restriction)', () => {
+ const node = {
+ 'xs:complexContent': {
+ 'xs:extension': {
+ 'xs:sequence': { 'xs:element': [{ name: 'OnlyExtension' }] },
+ },
+ // No restriction here - this covers the "false" branch of if (res)
+ },
+ };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+
+ expect(elements.has(`${TNS}::OnlyExtension`)).toBe(true);
+ });
+
+ it('handles complexContent with only restriction (no extension)', () => {
+ const node = {
+ 'xs:complexContent': {
+ 'xsd:restriction': {
+ 'xsd:choice': { 'xsd:element': [{ name: 'OnlyRestriction' }] },
+ },
+ // No extension here - this covers the "false" branch of if (ext)
+ },
+ };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+
+ expect(elements.has(`${TNS}::OnlyRestriction`)).toBe(true);
+ });
+
+ it('handles simpleContent with only extension (no restriction)', () => {
+ const node = {
+ 'xsd:simpleContent': {
+ 'xsd:extension': {
+ 'xs:all': { 'xsd:element': [{ name: 'SCOnlyExt' }] },
+ },
+ // No restriction here - this covers the "false" branch of if (res) in simpleContent
+ },
+ };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+
+ expect(elements.has(`${TNS}::SCOnlyExt`)).toBe(true);
+ });
+
+ it('handles simpleContent with only restriction (no extension)', () => {
+ const node = {
+ 'xsd:simpleContent': {
+ 'xs:restriction': {
+ 'xs:sequence': { 'xs:element': [{ name: 'SCOnlyRes' }] },
+ },
+ // No extension here - this covers the "false" branch of if (ext) in simpleContent
+ },
+ };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+
+ expect(elements.has(`${TNS}::SCOnlyRes`)).toBe(true);
+ });
+
+ it('handles complexContent with neither extension nor restriction', () => {
+ const node = {
+ 'xs:complexContent': {
+ // Neither extension nor restriction - covers both false branches
+ },
+ };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+
+ expect(elements.size).toBe(0); // No elements should be added
+ });
+
+ it('handles simpleContent with neither extension nor restriction', () => {
+ const node = {
+ 'xsd:simpleContent': {
+ // Neither extension nor restriction - covers both false branches
+ },
+ };
+ collectElements(node, TNS, PFX, elements, elementRefs);
+
+ expect(elements.size).toBe(0); // No elements should be added
+ });
+});
diff --git a/packages/ooxml-inspector/generator/src/builder/expand-content.js b/packages/ooxml-inspector/generator/src/builder/expand-content.js
new file mode 100644
index 0000000000..3353341fc9
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/expand-content.js
@@ -0,0 +1,115 @@
+import { arr, autoPrefix } from './index.js';
+
+/**
+ * Collect elements from a given node.
+ * Recursively collect xs:element nodes from sequences/choices/alls/groups
+ * Also collects element definitions found along the way
+ * @param {Object} node - The XML node to collect elements from.
+ * @param {Array} outEls - The output array to collect elements into.
+ * @param {string} contextTns - The current target namespace.
+ * @param {number} depth - The current depth in the XML structure.
+ * @param {Map} elementsMap - A map of known elements.
+ * @param {Record} nsMap - A map of namespace prefixes.
+ * @param {Map} groups - A map of group definitions.
+ * @returns {void}
+ */
+export function expandContent(node, outEls, contextTns, depth = 0, elementsMap, nsMap, groups) {
+ if (!node || depth > 10) return; // prevent infinite recursion
+
+ // Direct elements
+ const els = arr(node['xs:element']).concat(arr(node['xsd:element']));
+ for (const e of els) {
+ outEls.push({ ...e, _contextTns: contextTns });
+
+ // Also track this as a known element if it has a name
+ if (e.name) {
+ const elKey = `${contextTns}::${e.name}`;
+ const elPrefix = nsMap[contextTns] || autoPrefix(contextTns, nsMap);
+ if (!elementsMap.has(elKey)) {
+ elementsMap.set(elKey, {
+ tns: contextTns,
+ prefix: elPrefix,
+ name: e.name,
+ el: e,
+ });
+ }
+ } else if (e.ref) {
+ // Track element reference
+ let refTns, refName;
+ if (e.ref.includes(':')) {
+ const [refPrefix, local] = e.ref.split(':');
+ refName = local;
+ refTns = Object.entries(nsMap).find(([, v]) => v === refPrefix)?.[0];
+ } else {
+ refName = e.ref;
+ refTns = contextTns;
+ }
+
+ if (refTns && refName) {
+ const elKey = `${refTns}::${refName}`;
+ const elPrefix = nsMap[refTns] || autoPrefix(refTns, nsMap);
+ if (!elementsMap.has(elKey)) {
+ elementsMap.set(elKey, {
+ tns: refTns,
+ prefix: elPrefix,
+ name: refName,
+ el: { name: refName, type: `CT_${refName.charAt(0).toUpperCase() + refName.slice(1)}` },
+ });
+ }
+ }
+ }
+ }
+
+ // Nested content models
+ const nests = []
+ .concat(arr(node['xs:sequence']), arr(node['xsd:sequence']))
+ .concat(arr(node['xs:choice']), arr(node['xsd:choice']))
+ .concat(arr(node['xs:all']), arr(node['xsd:all']));
+
+ for (const n of nests) {
+ expandContent(n, outEls, contextTns, depth + 1, elementsMap, nsMap, groups);
+ }
+
+ // Group references
+ const gs = arr(node['xs:group']).concat(arr(node['xsd:group']));
+ for (const g of gs) {
+ if (g.name) {
+ // Inline group definition
+ const groupContent =
+ g['xs:sequence'] || g['xs:choice'] || g['xs:all'] || g['xsd:sequence'] || g['xsd:choice'] || g['xsd:all'];
+ if (groupContent) {
+ expandContent(groupContent, outEls, contextTns, depth + 1, elementsMap, nsMap, groups);
+ }
+ continue;
+ }
+
+ const ref = g.ref;
+ if (!ref) continue;
+
+ let groupTns, localName;
+ if (ref.includes(':')) {
+ const [pfx, local] = ref.split(':');
+ localName = local;
+ groupTns = Object.entries(nsMap).find(([, v]) => v === pfx)?.[0];
+ } else {
+ localName = ref;
+ groupTns = contextTns;
+ }
+
+ if (!groupTns) continue;
+
+ const groupDef = groups.get(`${groupTns}::${localName}`);
+ if (!groupDef) continue;
+
+ const groupContent =
+ groupDef['xs:sequence'] ||
+ groupDef['xs:choice'] ||
+ groupDef['xs:all'] ||
+ groupDef['xsd:sequence'] ||
+ groupDef['xsd:choice'] ||
+ groupDef['xsd:all'];
+ if (groupContent) {
+ expandContent(groupContent, outEls, groupTns, depth + 1, elementsMap, nsMap, groups);
+ }
+ }
+}
diff --git a/packages/ooxml-inspector/generator/src/builder/expand-content.test.js b/packages/ooxml-inspector/generator/src/builder/expand-content.test.js
new file mode 100644
index 0000000000..87ad8a248e
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/expand-content.test.js
@@ -0,0 +1,283 @@
+import { describe, it, expect, beforeEach, vi } from 'vitest';
+import { expandContent } from './expand-content.js';
+
+vi.mock('./index.js', () => {
+ return {
+ arr: vi.fn((x) => (Array.isArray(x) ? x : x ? [x] : [])),
+ autoPrefix: vi.fn(() => 'gen'),
+ };
+});
+
+import { arr, autoPrefix } from './index.js';
+
+const TNS_A = 'urn:a';
+const TNS_B = 'urn:b';
+
+let nsMap;
+let elementsMap;
+let groups;
+
+beforeEach(() => {
+ vi.clearAllMocks();
+ nsMap = {
+ [TNS_A]: 'a',
+ [TNS_B]: 'b',
+ };
+ elementsMap = new Map();
+ groups = new Map();
+});
+
+describe('expandContent', () => {
+ it('no-ops on falsy node and respects depth guard', () => {
+ const outEls = [];
+ expandContent(null, outEls, TNS_A, 0, elementsMap, nsMap, groups);
+ expect(outEls).toEqual([]);
+
+ expandContent({}, outEls, TNS_A, 11, elementsMap, nsMap, groups); // depth > 10
+ expect(outEls).toEqual([]);
+ });
+
+ it('collects direct elements (xs:element & xsd:element) and stamps _contextTns', () => {
+ const outEls = [];
+ const node = {
+ 'xs:element': [{ name: 'Alpha' }],
+ 'xsd:element': [{ ref: 'b:Beta' }],
+ };
+
+ expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups);
+
+ // outEls should contain both, with _contextTns
+ expect(outEls).toHaveLength(2);
+ expect(outEls[0]).toMatchObject({ name: 'Alpha', _contextTns: TNS_A });
+ expect(outEls[1]).toMatchObject({ ref: 'b:Beta', _contextTns: TNS_A });
+
+ // elementsMap should have a record for named element Alpha in context A
+ const alphaKey = `${TNS_A}::Alpha`;
+ expect(elementsMap.get(alphaKey)).toMatchObject({
+ tns: TNS_A,
+ prefix: 'a',
+ name: 'Alpha',
+ });
+
+ // and for referenced element Beta (resolved to TNS_B, local 'Beta')
+ const betaKey = `${TNS_B}::Beta`;
+ expect(elementsMap.get(betaKey)).toMatchObject({
+ tns: TNS_B,
+ prefix: 'b',
+ name: 'Beta',
+ });
+
+ // autoPrefix not needed here (both namespaces mapped)
+ expect(autoPrefix).not.toHaveBeenCalled();
+ });
+
+ it('uses autoPrefix for named element when contextTns is unmapped', () => {
+ const outEls = [];
+ autoPrefix.mockReturnValueOnce('ap'); // deterministic
+ const node = { 'xs:element': [{ name: 'Gamma' }] };
+
+ expandContent(node, outEls, 'urn:unmapped', 0, elementsMap, nsMap, groups);
+
+ // one element collected
+ expect(outEls).toHaveLength(1);
+ expect(outEls[0]).toMatchObject({ name: 'Gamma', _contextTns: 'urn:unmapped' });
+
+ // elementsMap entry uses autoPrefix result
+ const key = `urn:unmapped::Gamma`;
+ expect(elementsMap.get(key)).toMatchObject({
+ tns: 'urn:unmapped',
+ prefix: 'ap',
+ name: 'Gamma',
+ });
+
+ expect(autoPrefix).toHaveBeenCalledWith('urn:unmapped', nsMap);
+ });
+
+ it('uses autoPrefix for referenced element when ref TNS is unmapped', () => {
+ const outEls = [];
+ // Arrange: nsMap doesn’t have a prefix for this ref’s TNS
+ const UNMAPPED = 'urn:zzz';
+ nsMap[UNMAPPED] = undefined; // ensure missing
+ autoPrefix.mockReturnValueOnce('zp');
+
+ // e.ref without prefix -> uses contextTns (UNMAPPED) in this case
+ const node = { 'xs:element': [{ ref: 'Zed' }] };
+
+ expandContent(node, outEls, UNMAPPED, 0, elementsMap, nsMap, groups);
+
+ const key = `${UNMAPPED}::Zed`;
+ expect(elementsMap.get(key)).toMatchObject({
+ tns: UNMAPPED,
+ prefix: 'zp',
+ name: 'Zed',
+ el: expect.objectContaining({ name: 'Zed' }),
+ });
+ expect(autoPrefix).toHaveBeenCalledWith(UNMAPPED, nsMap);
+ });
+
+ it('recurses into nested content models (sequence/choice/all, xs/xsd)', () => {
+ const outEls = [];
+ const node = {
+ 'xs:sequence': {
+ 'xsd:element': [{ name: 'SeqEl' }],
+ 'xs:choice': {
+ 'xs:element': [{ name: 'ChoiceEl' }],
+ },
+ 'xsd:all': {
+ 'xsd:element': [{ name: 'AllEl' }],
+ },
+ },
+ };
+
+ expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups);
+
+ const names = outEls.map((e) => e.name || e.ref);
+ expect(names).toEqual(expect.arrayContaining(['SeqEl', 'ChoiceEl', 'AllEl']));
+
+ // all should be recorded into elementsMap too
+ expect(elementsMap.has(`${TNS_A}::SeqEl`)).toBe(true);
+ expect(elementsMap.has(`${TNS_A}::ChoiceEl`)).toBe(true);
+ expect(elementsMap.has(`${TNS_A}::AllEl`)).toBe(true);
+ });
+
+ it('handles inline group definitions (xs:group with name + inner sequence/choice/all)', () => {
+ const outEls = [];
+ const node = {
+ 'xs:group': [
+ {
+ name: 'InlineGroup',
+ 'xs:choice': { 'xs:element': [{ name: 'InlineEl' }] },
+ },
+ ],
+ };
+
+ expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups);
+
+ const names = outEls.map((e) => e.name || e.ref);
+ expect(names).toContain('InlineEl');
+ expect(elementsMap.has(`${TNS_A}::InlineEl`)).toBe(true);
+ });
+
+ it('expands group references by local name using current context TNS', () => {
+ const outEls = [];
+ // groups map stores definitions keyed by `${tns}::${name}`
+ groups.set(`${TNS_A}::MyGroup`, {
+ 'xs:sequence': { 'xs:element': [{ name: 'GEl' }] },
+ });
+
+ const node = {
+ 'xs:group': [{ ref: 'MyGroup' }],
+ };
+
+ expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups);
+
+ const names = outEls.map((e) => e.name || e.ref);
+ expect(names).toContain('GEl');
+ expect(elementsMap.has(`${TNS_A}::GEl`)).toBe(true);
+ });
+
+ it('expands group references with prefix using nsMap to resolve TNS', () => {
+ const outEls = [];
+ groups.set(`${TNS_B}::OtherGroup`, {
+ 'xsd:all': { 'xsd:element': [{ name: 'OtherEl' }] },
+ });
+
+ const node = {
+ 'xsd:group': [{ ref: 'b:OtherGroup' }],
+ };
+
+ expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups);
+
+ const names = outEls.map((e) => e.name || e.ref);
+ expect(names).toContain('OtherEl');
+ expect(elementsMap.has(`${TNS_B}::OtherEl`)).toBe(true);
+ });
+
+ it('does nothing for unknown group prefix or missing group definition', () => {
+ const outEls = [];
+ const node = {
+ 'xs:group': [{ ref: 'z:Nope' }, { ref: 'MissingGroup' }],
+ };
+
+ expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups);
+ expect(outEls).toHaveLength(0);
+ expect(elementsMap.size).toBe(0);
+ });
+
+ it('depth guard prevents collecting too-deep nested elements', () => {
+ const makeDeep = (depth) =>
+ depth === 0
+ ? { 'xs:element': [{ name: 'TooDeep' }] } // will land deeper than the guard
+ : { 'xs:sequence': makeDeep(depth - 1) };
+
+ // Build 12 levels of nested sequences; the base element is beyond depth 10
+ const deep = makeDeep(12);
+
+ // Insert an element exactly at depth 10 so it should be included
+ let cursor = deep;
+ for (let i = 0; i < 10; i++) cursor = cursor['xs:sequence'];
+ cursor['xs:element'] = [{ name: 'AtDepth10' }];
+
+ const outEls = [];
+ expandContent(deep, outEls, TNS_A, 0, elementsMap, nsMap, groups);
+
+ const names = outEls.map((e) => e.name || e.ref);
+ expect(names).toContain('AtDepth10'); // depth 10 is allowed
+ expect(names).not.toContain('TooDeep'); // pruned at depth > 10
+ });
+
+ it('handles element ref with unknown prefix (refTns becomes undefined)', () => {
+ const outEls = [];
+ const node = {
+ 'xs:element': [{ ref: 'unknown:Element' }], // prefix not in nsMap
+ };
+
+ expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups);
+
+ // Element should still be added to outEls but not to elementsMap
+ expect(outEls).toHaveLength(1);
+ expect(outEls[0]).toMatchObject({ ref: 'unknown:Element', _contextTns: TNS_A });
+
+ // No entry should be added to elementsMap because refTns is undefined
+ expect(elementsMap.size).toBe(0);
+ });
+
+ it('handles group definition with no content models', () => {
+ const outEls = [];
+
+ // Group exists but has no sequence/choice/all content
+ groups.set(`${TNS_A}::EmptyGroup`, {
+ // No xs:sequence, xs:choice, xs:all, etc.
+ someOtherProperty: 'value',
+ });
+
+ const node = {
+ 'xs:group': [{ ref: 'EmptyGroup' }],
+ };
+
+ expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups);
+
+ // Should find the group but do nothing since it has no content
+ expect(outEls).toHaveLength(0);
+ expect(elementsMap.size).toBe(0);
+ });
+
+ it('handles inline group definition with no content models', () => {
+ const outEls = [];
+ const node = {
+ 'xs:group': [
+ {
+ name: 'InlineEmptyGroup',
+ // No xs:sequence, xs:choice, xs:all content
+ someAttribute: 'value',
+ },
+ ],
+ };
+
+ expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups);
+
+ // Should process the inline group but do nothing since it has no content
+ expect(outEls).toHaveLength(0);
+ expect(elementsMap.size).toBe(0);
+ });
+});
diff --git a/packages/ooxml-inspector/generator/src/builder/index.js b/packages/ooxml-inspector/generator/src/builder/index.js
new file mode 100644
index 0000000000..67421c6b83
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/index.js
@@ -0,0 +1,6 @@
+export * from './collect-elements.js';
+export * from './autoprefix.js';
+export * from './resolve-child-q-name.js';
+export * from './xsd-helpers.js';
+export * from './resolve-type.js';
+export * from './expand-content.js';
diff --git a/packages/ooxml-inspector/generator/src/builder/resolve-child-q-name.js b/packages/ooxml-inspector/generator/src/builder/resolve-child-q-name.js
new file mode 100644
index 0000000000..df10ff90bc
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/resolve-child-q-name.js
@@ -0,0 +1,32 @@
+import { autoPrefix, qn } from './index.js';
+
+/**
+ * Resolve the qualified name of a child element.
+ * @param {Object} e - The element to resolve.
+ * @param {string} contextTns - The current target namespace.
+ * @param {Object} nsMap - The namespace map.
+ * @returns {string|null} - The resolved qualified name or null if not found.
+ */
+export function resolveChildQName(e, contextTns, nsMap) {
+ if (e.ref) {
+ // Element reference
+ if (e.ref.includes(':')) {
+ const [pfx, local] = e.ref.split(':');
+ const targetTns = Object.entries(nsMap).find(([, v]) => v === pfx)?.[0];
+ if (!targetTns) return null;
+ return qn(nsMap[targetTns], local);
+ } else {
+ // No prefix, assume same namespace
+ return qn(nsMap[contextTns] || 'unknown', e.ref);
+ }
+ }
+
+ if (e.name) {
+ // Inline element - use context TNS or the element's own _contextTns
+ const elementTns = e._contextTns || contextTns;
+ const prefix = nsMap[elementTns] || autoPrefix(elementTns, nsMap);
+ return qn(prefix, e.name);
+ }
+
+ return null;
+}
diff --git a/packages/ooxml-inspector/generator/src/builder/resolve-child-q-name.test.js b/packages/ooxml-inspector/generator/src/builder/resolve-child-q-name.test.js
new file mode 100644
index 0000000000..aaf7e7371e
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/resolve-child-q-name.test.js
@@ -0,0 +1,97 @@
+import { describe, it, expect, beforeEach, vi } from 'vitest';
+import { resolveChildQName } from './resolve-child-q-name.js';
+
+vi.mock('./index.js', () => {
+ return {
+ qn: vi.fn((pfx, local) => `${pfx}:${local}`),
+ autoPrefix: vi.fn(() => 'auto'),
+ };
+});
+
+import { qn, autoPrefix } from './index.js';
+
+const TNS_A = 'urn:a';
+const TNS_B = 'urn:b';
+const TNS_C = 'urn:c';
+
+let nsMap;
+
+beforeEach(() => {
+ vi.clearAllMocks();
+ nsMap = {
+ [TNS_A]: 'a',
+ [TNS_B]: 'b',
+ // note: TNS_C intentionally not present in default map
+ };
+});
+
+describe('resolveChildQName', () => {
+ it('returns null when neither ref nor name is provided', () => {
+ expect(resolveChildQName({}, TNS_A, nsMap)).toBeNull();
+ });
+
+ describe('when e.ref is present', () => {
+ it('resolves prefixed ref using nsMap -> qn(prefix, local)', () => {
+ const e = { ref: 'b:Child' }; // prefix "b" -> TNS_B
+ const out = resolveChildQName(e, TNS_A, nsMap);
+ expect(out).toBe('b:Child');
+ expect(qn).toHaveBeenCalledWith('b', 'Child');
+ expect(autoPrefix).not.toHaveBeenCalled();
+ });
+
+ it('returns null for unknown prefix', () => {
+ const e = { ref: 'z:Foo' }; // no matching prefix in nsMap
+ const out = resolveChildQName(e, TNS_A, nsMap);
+ expect(out).toBeNull();
+ expect(qn).not.toHaveBeenCalled();
+ expect(autoPrefix).not.toHaveBeenCalled();
+ });
+
+ it('uses context namespace when ref has no prefix', () => {
+ const e = { ref: 'LocalName' };
+ const out = resolveChildQName(e, TNS_A, nsMap);
+ expect(out).toBe('a:LocalName'); // nsMap[TNS_A] === 'a'
+ expect(qn).toHaveBeenCalledWith('a', 'LocalName');
+ expect(autoPrefix).not.toHaveBeenCalled();
+ });
+
+ it('falls back to "unknown" prefix when contextTns is unmapped', () => {
+ const e = { ref: 'Thing' };
+ const out = resolveChildQName(e, TNS_C, nsMap); // TNS_C not in nsMap
+ expect(out).toBe('unknown:Thing');
+ expect(qn).toHaveBeenCalledWith('unknown', 'Thing');
+ expect(autoPrefix).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when e.name is present (inline element)', () => {
+ it('uses contextTns mapping when _contextTns is not provided', () => {
+ const e = { name: 'Inline' };
+ const out = resolveChildQName(e, TNS_A, nsMap);
+ expect(out).toBe('a:Inline');
+ expect(qn).toHaveBeenCalledWith('a', 'Inline');
+ expect(autoPrefix).not.toHaveBeenCalled();
+ });
+
+ it('uses element _contextTns mapping when present', () => {
+ const e = { name: 'Inline', _contextTns: TNS_B };
+ const out = resolveChildQName(e, TNS_A, nsMap);
+ expect(out).toBe('b:Inline');
+ expect(qn).toHaveBeenCalledWith('b', 'Inline');
+ expect(autoPrefix).not.toHaveBeenCalled();
+ });
+
+ it('calls autoPrefix when _contextTns is unmapped and uses its returned prefix', () => {
+ // make autoPrefix return a deterministic value
+ autoPrefix.mockReturnValueOnce('gen');
+
+ const e = { name: 'Inline', _contextTns: TNS_C }; // TNS_C not in nsMap
+ const out = resolveChildQName(e, TNS_A, nsMap);
+
+ expect(autoPrefix).toHaveBeenCalledTimes(1);
+ expect(autoPrefix).toHaveBeenCalledWith(TNS_C, nsMap);
+ expect(out).toBe('gen:Inline');
+ expect(qn).toHaveBeenCalledWith('gen', 'Inline');
+ });
+ });
+});
diff --git a/packages/ooxml-inspector/generator/src/builder/resolve-type.js b/packages/ooxml-inspector/generator/src/builder/resolve-type.js
new file mode 100644
index 0000000000..f19db6d5d2
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/resolve-type.js
@@ -0,0 +1,52 @@
+/**
+ * Resolves a complex type by its name.
+ * @param {string} typeName - The name of the complex type.
+ * @param {string} contextTns - The current target namespace.
+ * @param {Object} nsMap - The namespace map.
+ * @param {Object} complexTypes - The map of complex types.
+ * @param {Object} simpleTypes - The map of simple types.
+ * @returns {Object|null} - The resolved complex type or null if not found.
+ */
+export function resolveType(typeName, contextTns, nsMap, complexTypes, simpleTypes) {
+ if (!typeName) return null;
+
+ let targetTns, localName;
+ if (typeName.includes(':')) {
+ const [pfx, local] = typeName.split(':');
+ localName = local;
+
+ // Handle XSD built-in types - these are simple types, not complex types
+ if (pfx === 'xsd' || pfx === 'xs') {
+ return null; // XSD built-in types don't have child elements
+ }
+
+ // Find TNS from prefix - check the context schema's namespace declarations
+ targetTns = Object.entries(nsMap).find(([, v]) => v === pfx)?.[0];
+ if (!targetTns) {
+ console.warn(`Unknown prefix '${pfx}' in type: ${typeName}`);
+ return null;
+ }
+ } else {
+ // No prefix, use context TNS
+ localName = typeName;
+ targetTns = contextTns;
+ }
+
+ const key = `${targetTns}::${localName}`;
+ const resolved = complexTypes.get(key);
+
+ if (!resolved) {
+ // Check if it's a simple type (which we don't need to resolve for child elements)
+ if (simpleTypes.has(key)) {
+ // This is a simple type - no warning needed
+ return null;
+ }
+
+ // Only warn if it's not a known simple type or XSD type
+ if (!typeName.startsWith('xsd:') && !typeName.startsWith('xs:')) {
+ console.warn(`Could not resolve complex type: ${typeName} in context ${contextTns}`);
+ }
+ }
+
+ return resolved || null;
+}
diff --git a/packages/ooxml-inspector/generator/src/builder/resolve-type.test.js b/packages/ooxml-inspector/generator/src/builder/resolve-type.test.js
new file mode 100644
index 0000000000..ae3925cbb2
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/resolve-type.test.js
@@ -0,0 +1,100 @@
+import { describe, it, expect, beforeEach, vi } from 'vitest';
+import { resolveType } from './index.js';
+
+const TNS_A = 'http://example.com/a';
+const TNS_B = 'http://example.com/b';
+
+/**
+ * nsMap is expected to be { [tns]: prefix }
+ * so Object.entries(nsMap).find(([, v]) => v === pfx)?.[0] yields the TNS.
+ */
+const nsMap = {
+ [TNS_A]: 'a',
+ [TNS_B]: 'b',
+};
+
+let complexTypes;
+let simpleTypes;
+
+beforeEach(() => {
+ complexTypes = new Map();
+ simpleTypes = new Map();
+ vi.restoreAllMocks();
+});
+
+describe('resolveType', () => {
+ it('returns null for falsy typeName', () => {
+ expect(resolveType('', TNS_A, nsMap, complexTypes, simpleTypes)).toBeNull();
+ expect(resolveType(null, TNS_A, nsMap, complexTypes, simpleTypes)).toBeNull();
+ expect(resolveType(undefined, TNS_A, nsMap, complexTypes, simpleTypes)).toBeNull();
+ });
+
+ it('returns null for built-in XSD types (xs: / xsd:) without warnings', () => {
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
+ expect(resolveType('xs:string', TNS_A, nsMap, complexTypes, simpleTypes)).toBeNull();
+ expect(resolveType('xsd:int', TNS_A, nsMap, complexTypes, simpleTypes)).toBeNull();
+ expect(warnSpy).not.toHaveBeenCalled();
+ });
+
+ it('resolves unprefixed name using contextTns', () => {
+ const key = `${TNS_A}::Foo`;
+ const resolved = { name: 'FooCT' };
+ complexTypes.set(key, resolved);
+
+ const out = resolveType('Foo', TNS_A, nsMap, complexTypes, simpleTypes);
+ expect(out).toBe(resolved);
+ });
+
+ it('resolves prefixed name using nsMap', () => {
+ const key = `${TNS_B}::Bar`;
+ const resolved = { name: 'BarCT' };
+ complexTypes.set(key, resolved);
+
+ const out = resolveType('b:Bar', TNS_A, nsMap, complexTypes, simpleTypes);
+ expect(out).toBe(resolved);
+ });
+
+ it('returns null and warns on unknown prefix', () => {
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
+ const out = resolveType('z:Thing', TNS_A, nsMap, complexTypes, simpleTypes);
+ expect(out).toBeNull();
+ expect(warnSpy).toHaveBeenCalledTimes(1);
+ expect(warnSpy.mock.calls[0][0]).toMatch(/Unknown prefix 'z'/);
+ });
+
+ it('returns null (no warning) when complex type missing but simple type exists', () => {
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
+ const key = `${TNS_A}::SimpleOne`;
+ simpleTypes.set(key, { kind: 'simple' });
+
+ const out = resolveType('SimpleOne', TNS_A, nsMap, complexTypes, simpleTypes);
+ expect(out).toBeNull();
+ expect(warnSpy).not.toHaveBeenCalled();
+ });
+
+ it('warns when not found in complexTypes and not a simple type (non-XSD)', () => {
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
+ const out = resolveType('MissingType', TNS_A, nsMap, complexTypes, simpleTypes);
+ expect(out).toBeNull();
+ expect(warnSpy).toHaveBeenCalledTimes(1);
+ expect(warnSpy.mock.calls[0][0]).toMatch(/Could not resolve complex type: MissingType/);
+ expect(warnSpy.mock.calls[0][0]).toMatch(TNS_A);
+ });
+
+ it('does not warn when not found but the name is an XSD built-in (defensive check)', () => {
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
+ // Even if someone passed "xs:unknownBuiltin", function guards against warning due to xs/xsd check.
+ const out = resolveType('xs:unknownBuiltin', TNS_A, nsMap, complexTypes, simpleTypes);
+ expect(out).toBeNull();
+ expect(warnSpy).not.toHaveBeenCalled();
+ });
+
+ it('constructs the key as `${targetTns}::${localName}`', () => {
+ const key = `${TNS_B}::Baz`;
+ const resolved = { id: 123, name: 'BazCT' };
+ complexTypes.set(key, resolved);
+
+ const out = resolveType('b:Baz', TNS_A, nsMap, complexTypes, simpleTypes);
+ expect(out).toEqual(resolved);
+ });
+});
diff --git a/packages/ooxml-inspector/generator/src/builder/xsd-helpers.js b/packages/ooxml-inspector/generator/src/builder/xsd-helpers.js
new file mode 100644
index 0000000000..c45da10243
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/xsd-helpers.js
@@ -0,0 +1,62 @@
+import { XMLParser } from 'fast-xml-parser';
+
+/** XML parser instance for parsing XSD files. */
+export const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '' });
+
+/**
+ * Converts a value to an array.
+ * @param {any} x - The value to convert.
+ * @returns {Array} - The converted array.
+ */
+export const arr = (x) => (Array.isArray(x) ? x : x ? [x] : []);
+
+/**
+ * Generates a qualified name (QName) from a prefix and local name.
+ * @param {string} pfx - The namespace prefix.
+ * @param {string} local - The local name.
+ * @returns {string} - The qualified name.
+ */
+export const qn = (pfx, local) => `${pfx}:${local}`;
+
+/**
+ * Resolves an inline complex type definition.
+ * @param {Object} el - The element to resolve.
+ * @returns {Object|null} - The resolved complex type or null if not found.
+ */
+export function inlineCT(el) {
+ return el['xs:complexType'] || el['xsd:complexType'] || null;
+}
+
+/**
+ * Get the content model for a complex type.
+ * @param {Object} complexType - The complex type definition.
+ * @returns {Object|null} - The content model or null if not found.
+ */
+export function contentRoot(complexType) {
+ // Check for complex content extensions first
+ const complexContent = complexType['xs:complexContent'] || complexType['xsd:complexContent'];
+ if (complexContent) {
+ const ext = complexContent['xs:extension'] || complexContent['xsd:extension'];
+ if (ext) {
+ return (
+ ext['xs:sequence'] ||
+ ext['xs:choice'] ||
+ ext['xs:all'] ||
+ ext['xsd:sequence'] ||
+ ext['xsd:choice'] ||
+ ext['xsd:all']
+ );
+ }
+ }
+
+ // Direct content model
+ return (
+ complexType['xs:sequence'] ||
+ complexType['xs:choice'] ||
+ complexType['xs:all'] ||
+ complexType['xsd:sequence'] ||
+ complexType['xsd:choice'] ||
+ complexType['xsd:all'] ||
+ null
+ );
+}
diff --git a/packages/ooxml-inspector/generator/src/builder/xsd-helpers.test.js b/packages/ooxml-inspector/generator/src/builder/xsd-helpers.test.js
new file mode 100644
index 0000000000..d2413edd29
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/builder/xsd-helpers.test.js
@@ -0,0 +1,137 @@
+import { describe, it, expect } from 'vitest';
+import { parser, arr, qn, inlineCT, contentRoot } from './index.js';
+
+describe('parser (fast-xml-parser) config', () => {
+ it('parses attributes (ignoreAttributes=false) with empty attributeNamePrefix', () => {
+ const xml = `text`;
+ const out = parser.parse(xml);
+
+ expect(out.root.id).toBe('42');
+ expect(out.root.child).toBe('text');
+ });
+
+ it('handles multiple attributes without prefix collisions', () => {
+ const xml = ``;
+ const out = parser.parse(xml);
+ expect(out.el.a).toBe('1');
+ expect(out.el.b).toBe('2');
+ expect(out.el.c).toBe('3');
+ });
+});
+
+describe('arr()', () => {
+ it('returns arrays unchanged (same reference)', () => {
+ const input = [1, 2];
+ expect(arr(input)).toBe(input);
+ });
+
+ it('wraps truthy non-arrays into an array', () => {
+ expect(arr('x')).toEqual(['x']);
+ expect(arr({ a: 1 })).toEqual([{ a: 1 }]);
+ expect(arr(true)).toEqual([true]);
+ });
+
+ it('returns [] for falsy values (null/undefined/0/empty string)', () => {
+ expect(arr(null)).toEqual([]);
+ expect(arr(undefined)).toEqual([]);
+ expect(arr(0)).toEqual([]);
+ expect(arr('')).toEqual([]);
+ });
+});
+
+describe('qn()', () => {
+ it('joins prefix and local with a colon', () => {
+ expect(qn('w', 'p')).toBe('w:p');
+ expect(qn('xs', 'sequence')).toBe('xs:sequence');
+ });
+});
+
+describe('inlineCT()', () => {
+ it('returns xs:complexType when present', () => {
+ const el = { 'xs:complexType': { name: 'CT_Something' } };
+ expect(inlineCT(el)).toEqual({ name: 'CT_Something' });
+ });
+
+ it('returns xsd:complexType when present', () => {
+ const el = { 'xsd:complexType': { name: 'CT_Other' } };
+ expect(inlineCT(el)).toEqual({ name: 'CT_Other' });
+ });
+
+ it('returns null when not present', () => {
+ const el = { foo: 'bar' };
+ expect(inlineCT(el)).toBeNull();
+ });
+});
+
+describe('contentRoot()', () => {
+ it('picks direct xs:sequence/xs:choice/xs:all', () => {
+ const withSeq = { 'xs:sequence': { tag: 'seq' } };
+ const withChoice = { 'xs:choice': { tag: 'choice' } };
+ const withAll = { 'xs:all': { tag: 'all' } };
+
+ expect(contentRoot(withSeq)).toEqual({ tag: 'seq' });
+ expect(contentRoot(withChoice)).toEqual({ tag: 'choice' });
+ expect(contentRoot(withAll)).toEqual({ tag: 'all' });
+ });
+
+ it('picks direct xsd:sequence/xsd:choice/xsd:all', () => {
+ const withSeq = { 'xsd:sequence': { tag: 'seq' } };
+ const withChoice = { 'xsd:choice': { tag: 'choice' } };
+ const withAll = { 'xsd:all': { tag: 'all' } };
+
+ expect(contentRoot(withSeq)).toEqual({ tag: 'seq' });
+ expect(contentRoot(withChoice)).toEqual({ tag: 'choice' });
+ expect(contentRoot(withAll)).toEqual({ tag: 'all' });
+ });
+
+ it('resolves through complexContent/extension (xs:*)', () => {
+ const ct = {
+ 'xs:complexContent': {
+ 'xs:extension': {
+ 'xs:sequence': { tag: 'ext-seq' },
+ },
+ },
+ };
+ expect(contentRoot(ct)).toEqual({ tag: 'ext-seq' });
+ });
+
+ it('resolves through complexContent/extension (xsd:*)', () => {
+ const ct = {
+ 'xsd:complexContent': {
+ 'xsd:extension': {
+ 'xsd:choice': { tag: 'ext-choice' },
+ },
+ },
+ };
+ expect(contentRoot(ct)).toEqual({ tag: 'ext-choice' });
+ });
+
+ it('resolves xsd:all through complexContent/extension', () => {
+ const ct = {
+ 'xsd:complexContent': {
+ 'xsd:extension': {
+ 'xsd:all': { tag: 'ext-all' },
+ },
+ },
+ };
+ expect(contentRoot(ct)).toEqual({ tag: 'ext-all' });
+ });
+
+ it('prefers extension child order: sequence > choice > all', () => {
+ const ct = {
+ 'xs:complexContent': {
+ 'xs:extension': {
+ 'xs:choice': { tag: 'choice' },
+ 'xs:sequence': { tag: 'seq' }, // sequence should win
+ 'xs:all': { tag: 'all' },
+ },
+ },
+ };
+ expect(contentRoot(ct)).toEqual({ tag: 'seq' });
+ });
+
+ it('returns null when no content model exists', () => {
+ const ct = { name: 'NoContent' };
+ expect(contentRoot(ct)).toBeNull();
+ });
+});
diff --git a/packages/ooxml-inspector/generator/src/constants.js b/packages/ooxml-inspector/generator/src/constants.js
new file mode 100644
index 0000000000..d9fd6855f6
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/constants.js
@@ -0,0 +1,45 @@
+/**
+ * Directory containing the XSP files.
+ */
+export const XSP_DIR = 'specification/OfficeOpenXML-XMLSchema-Transitional';
+
+/**
+ * Map of XML namespace URIs to their corresponding prefixes.
+ */
+export const NS_MAP = {
+ 'http://schemas.openxmlformats.org/wordprocessingml/2006/main': 'w',
+ 'http://schemas.openxmlformats.org/drawingml/2006/main': 'a',
+ 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing': 'wp',
+ 'http://schemas.openxmlformats.org/drawingml/2006/chartDrawing': 'cdr',
+ 'http://schemas.openxmlformats.org/officeDocument/2006/math': 'm',
+ 'http://schemas.openxmlformats.org/markup-compatibility/2006': 'mc',
+ 'http://schemas.openxmlformats.org/officeDocument/2006/relationships': 'r',
+ 'http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes': 's',
+ 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes': 'vt',
+ 'http://schemas.openxmlformats.org/presentationml/2006/main': 'p',
+ 'http://schemas.openxmlformats.org/spreadsheetml/2006/main': 'x',
+ 'http://www.w3.org/2001/XMLSchema': 'xsd',
+};
+
+/**
+ * Set of element names that should be passed through without modification.
+ */
+export const PASS_THROUGH = new Set([
+ 'mc:AlternateContent',
+ 'w:sdt',
+ 'w:customXml',
+ 'w:ins',
+ 'w:del',
+ 'w:moveFrom',
+ 'w:moveTo',
+ 'w:proofErr',
+ 'w:permStart',
+ 'w:permEnd',
+ 'w:bookmarkStart',
+ 'w:bookmarkEnd',
+]);
+
+/**
+ * Set of element names that require extra wrapper elements.
+ */
+export const EXTRA_WRAPPER_PARENTS = new Set(['w:p', 'w:tc', 'w:body', 'w:document']);
diff --git a/packages/ooxml-inspector/generator/src/generator.js b/packages/ooxml-inspector/generator/src/generator.js
new file mode 100644
index 0000000000..09441012ad
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/generator.js
@@ -0,0 +1,18 @@
+import { writeFileSync, mkdirSync } from 'node:fs';
+import { XSP_DIR, buildFromXsdDir } from './index.js';
+
+/**
+ * Run the XML Schema generator. Converts OOXML .xsp definitions to json in dist
+ */
+export function runGenerator() {
+ const out = buildFromXsdDir(XSP_DIR);
+ mkdirSync('dist', { recursive: true });
+ writeFileSync('dist/schema.transitional.json', JSON.stringify(out, null, 2));
+ console.log('Wrote dist/schema.transitional.json');
+
+ console.log('\nSample entries:');
+ const elements = out.elements;
+ for (const key of ['w:document', 'w:body', 'w:p', 'w:r', 'w:t', 'w:pPr', 'w:rPr']) {
+ console.log(`${key}: ${elements[key] ? elements[key].children.length : 'not found'} children`);
+ }
+}
diff --git a/packages/ooxml-inspector/generator/src/generator.test.js b/packages/ooxml-inspector/generator/src/generator.test.js
new file mode 100644
index 0000000000..4deb434f15
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/generator.test.js
@@ -0,0 +1,117 @@
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
+
+vi.mock('node:fs', () => {
+ return {
+ writeFileSync: vi.fn(),
+ mkdirSync: vi.fn(),
+ };
+});
+
+// Mock the sibling module that runGenerator imports from
+const buildFromXsdDirMock = vi.fn();
+const XSP_DIR_VALUE = '/fake/xsp';
+vi.mock('./index.js', () => ({
+ XSP_DIR: XSP_DIR_VALUE,
+ buildFromXsdDir: buildFromXsdDirMock,
+}));
+
+let runGenerator;
+let writeFileSync, mkdirSync;
+
+beforeEach(async () => {
+ vi.resetModules();
+
+ ({ writeFileSync, mkdirSync } = await import('node:fs'));
+
+ // spy on console
+ vi.spyOn(console, 'log').mockImplementation(() => {});
+
+ ({ runGenerator } = await import('./generator.js'));
+});
+
+afterEach(() => {
+ vi.restoreAllMocks();
+});
+
+describe('runGenerator', () => {
+ it('generates schema, writes file, and logs sample entries for present keys', () => {
+ // Arrange a schema with all the sample keys present
+ const out = {
+ elements: {
+ 'w:document': { children: [], attributes: {} },
+ 'w:body': { children: ['w:p'], attributes: {} },
+ 'w:p': { children: ['w:r'], attributes: {} },
+ 'w:r': { children: ['w:t'], attributes: {} },
+ 'w:t': { children: [], attributes: {} },
+ 'w:pPr': { children: ['w:spacing'], attributes: {} },
+ 'w:rPr': { children: [], attributes: {} },
+ },
+ };
+ buildFromXsdDirMock.mockReturnValue(out);
+
+ // Act
+ runGenerator();
+
+ // Assert: buildFromXsdDir called with XSP_DIR
+ expect(buildFromXsdDirMock).toHaveBeenCalledTimes(1);
+ expect(buildFromXsdDirMock).toHaveBeenCalledWith(XSP_DIR_VALUE);
+
+ // Assert: mkdirSync called with recursive true
+ expect(mkdirSync).toHaveBeenCalledWith('dist', { recursive: true });
+
+ // Assert: writeFileSync to correct path with pretty-printed JSON
+ expect(writeFileSync).toHaveBeenCalledTimes(1);
+ const [pathArg, dataArg] = writeFileSync.mock.calls[0];
+ expect(pathArg).toBe('dist/schema.transitional.json');
+ expect(dataArg).toBe(JSON.stringify(out, null, 2)); // pretty JSON
+
+ // Assert: mkdirSync happened before writeFileSync
+ const mkdirIndex = vi.mocked(mkdirSync).mock.invocationCallOrder[0];
+ const writeIndex = vi.mocked(writeFileSync).mock.invocationCallOrder[0];
+ expect(mkdirIndex).toBeLessThan(writeIndex);
+
+ // Assert: logs include header + each sample entry line
+ const logs = console.log.mock.calls.map((args) => args.join(' '));
+ expect(logs).toContain('Wrote dist/schema.transitional.json');
+ expect(logs).toContain('\nSample entries:');
+
+ // each key should print ": children"
+ expect(logs).toContain('w:document: 0 children');
+ expect(logs).toContain('w:body: 1 children');
+ expect(logs).toContain('w:p: 1 children');
+ expect(logs).toContain('w:r: 1 children');
+ expect(logs).toContain('w:t: 0 children');
+ expect(logs).toContain('w:pPr: 1 children');
+ expect(logs).toContain('w:rPr: 0 children');
+ });
+
+ it('prints "not found" for missing elements', () => {
+ // Arrange a schema with some missing keys
+ const out = {
+ elements: {
+ 'w:document': { children: [], attributes: {} },
+ // 'w:body' missing
+ 'w:p': { children: [], attributes: {} },
+ 'w:r': { children: [], attributes: {} },
+ // 'w:t' missing
+ 'w:pPr': { children: [], attributes: {} },
+ // 'w:rPr' missing
+ },
+ };
+ buildFromXsdDirMock.mockReturnValue(out);
+
+ runGenerator();
+
+ const logs = console.log.mock.calls.map((args) => args.join(' '));
+ // present keys show count
+ expect(logs).toContain('w:document: 0 children');
+ expect(logs).toContain('w:p: 0 children');
+ expect(logs).toContain('w:r: 0 children');
+ expect(logs).toContain('w:pPr: 0 children');
+
+ // missing keys show "not found"
+ expect(logs).toContain('w:body: not found children');
+ expect(logs).toContain('w:t: not found children');
+ expect(logs).toContain('w:rPr: not found children');
+ });
+});
diff --git a/packages/ooxml-inspector/generator/src/index.js b/packages/ooxml-inspector/generator/src/index.js
new file mode 100644
index 0000000000..f8088381fa
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/index.js
@@ -0,0 +1,3 @@
+export * from './constants.js';
+export * from './generator.js';
+export * from './schema-build.js';
diff --git a/packages/ooxml-inspector/generator/src/schema-build.js b/packages/ooxml-inspector/generator/src/schema-build.js
new file mode 100644
index 0000000000..a9b70d44e8
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/schema-build.js
@@ -0,0 +1,373 @@
+import { readdirSync, readFileSync } from 'node:fs';
+import { join } from 'node:path';
+import { NS_MAP, PASS_THROUGH } from './constants.js';
+import { arr, qn, parser, inlineCT, contentRoot } from './builder/index.js';
+import { expandContent, resolveType, collectElements, autoPrefix, resolveChildQName } from './builder/index.js';
+
+/**
+ * Build a schema from a directory of XSD files.
+ * @param {string} xsdDir - Directory containing .xsd files
+ * @returns {import('./types/index.js').BuiltSchema} - Array of parsed XML schemas
+ */
+export function buildFromXsdDir(xsdDir) {
+ const schemas = [];
+ for (const f of readdirSync(xsdDir))
+ if (f.endsWith('.xsd')) {
+ const xml = readFileSync(join(xsdDir, f), 'utf8');
+ const doc = parser.parse(xml);
+ const schema = doc['xs:schema'] || doc['xsd:schema'] || doc['schema'];
+ if (schema) {
+ schema._filename = f; // for debugging
+ schemas.push(schema);
+ }
+ }
+
+ console.log(`Loaded ${schemas.length} XSD files`);
+
+ /** @type {Record} */
+ const nsMap = NS_MAP;
+
+ // First, collect all namespace mappings from import statements
+ for (const s of schemas) {
+ // Check for xs:import or xsd:import elements which define namespace mappings
+ const imports = arr(s['xs:import']).concat(arr(s['xsd:import']));
+ for (const imp of imports) {
+ if (imp.namespace && !nsMap[imp.namespace]) {
+ // Auto-assign prefix if we don't have one
+ const prefix = 'g' + Object.keys(nsMap).length;
+ nsMap[imp.namespace] = prefix;
+ }
+ }
+ }
+
+ const complexTypes = new Map(); // `${tns}::${name}` -> complexType
+ const simpleTypes = new Map(); // `${tns}::${name}` -> simpleType (for tracking)
+ const groups = new Map(); // `${tns}::${name}` -> group
+ const attributeGroups = new Map(); // `${tns}::${name}` -> attributeGroup
+ const elements = new Map(); // `${tns}::${name}` -> { tns,prefix,name,el }
+ const elementRefs = new Map(); // Track element references to resolve later
+
+ // First pass: collect all types, groups, and top-level elements
+ for (const s of schemas) {
+ const tns = s.targetNamespace;
+ const prefix = autoPrefix(tns, nsMap);
+
+ // Collect complex types and their nested elements
+ for (const ct of arr(s['xs:complexType']).concat(arr(s['xsd:complexType']))) {
+ if (ct.name) {
+ complexTypes.set(`${tns}::${ct.name}`, ct);
+ // Also collect any elements defined within this complex type
+ collectElements(ct, tns, prefix, elements, elementRefs);
+ }
+ }
+
+ // Collect simple types (for tracking, not for resolution)
+ for (const st of arr(s['xs:simpleType']).concat(arr(s['xsd:simpleType']))) {
+ if (st.name) {
+ simpleTypes.set(`${tns}::${st.name}`, st);
+ }
+ }
+
+ // Collect groups and their nested elements
+ for (const g of arr(s['xs:group']).concat(arr(s['xsd:group']))) {
+ if (g.name) {
+ groups.set(`${tns}::${g.name}`, g);
+ // Also collect any elements defined within this group
+ collectElements(g, tns, prefix, elements, elementRefs);
+ }
+ }
+
+ // Collect attribute groups
+ for (const ag of arr(s['xs:attributeGroup']).concat(arr(s['xsd:attributeGroup']))) {
+ if (ag.name) {
+ attributeGroups.set(`${tns}::${ag.name}`, ag);
+ }
+ }
+
+ // Collect top-level elements
+ for (const el of arr(s['xs:element']).concat(arr(s['xsd:element']))) {
+ if (el.name) {
+ const key = `${tns}::${el.name}`;
+ if (!elements.has(key)) {
+ elements.set(key, { tns, prefix, name: el.name, el });
+ }
+ }
+ }
+ }
+
+ // Resolve element references
+ for (const [ref, { tns }] of elementRefs) {
+ let targetTns, localName;
+ if (ref.includes(':')) {
+ const [refPrefix, local] = ref.split(':');
+ localName = local;
+ targetTns = Object.entries(nsMap).find(([, v]) => v === refPrefix)?.[0];
+ } else {
+ localName = ref;
+ targetTns = tns;
+ }
+
+ if (targetTns && localName) {
+ const key = `${targetTns}::${localName}`;
+ if (!elements.has(key)) {
+ const targetPrefix = nsMap[targetTns] || autoPrefix(targetTns, nsMap);
+ // Create a synthetic element entry for the reference
+ elements.set(key, {
+ tns: targetTns,
+ prefix: targetPrefix,
+ name: localName,
+ el: { name: localName, type: `${targetPrefix}:${localName}Type` },
+ });
+ }
+ }
+ }
+
+ // Second pass: Check for complex types that imply elements (CT_ElementName pattern)
+ for (const [key] of complexTypes) {
+ const [tns, typeName] = key.split('::');
+
+ // Common OOXML pattern: CT_P type implies a 'p' element
+ if (typeName.startsWith('CT_')) {
+ const elementName = typeName.substring(3);
+ const elementKey = `${tns}::${elementName}`;
+
+ if (!elements.has(elementKey)) {
+ const prefix = nsMap[tns] || autoPrefix(tns, nsMap);
+ // Check if this looks like a real element name (starts with uppercase or is short)
+ if (elementName.length <= 10 && /^[A-Z]/.test(elementName)) {
+ const lowerName = elementName.charAt(0).toLowerCase() + elementName.slice(1);
+ const lowerKey = `${tns}::${lowerName}`;
+
+ if (!elements.has(lowerKey)) {
+ // Create synthetic element for this complex type
+ elements.set(lowerKey, {
+ tns,
+ prefix,
+ name: lowerName,
+ el: { name: lowerName, type: typeName },
+ });
+ }
+ }
+ }
+ }
+ }
+
+ console.log(
+ `Found ${complexTypes.size} complex types, ${simpleTypes.size} simple types, ${groups.size} groups, ${attributeGroups.size} attribute groups, ${elements.size} elements`,
+ );
+
+ // Debug: show some key elements we expect to find
+ const expectedElements = ['w:document', 'w:body', 'w:p', 'w:r', 'w:t', 'w:tbl'];
+ const foundExpected = expectedElements.filter((qname) => {
+ const [prefix, local] = qname.split(':');
+ const tns = Object.entries(nsMap).find(([, v]) => v === prefix)?.[0];
+ return tns && elements.has(`${tns}::${local}`);
+ });
+ if (foundExpected.length > 0) {
+ console.log(`Found expected elements: ${foundExpected.join(', ')}`);
+ }
+
+ // Helper function to extract attributes from a node
+ function extractDirectAttributes(node, attributes, tns) {
+ // Direct attributes
+ for (const attr of arr(node['xs:attribute']).concat(arr(node['xsd:attribute']))) {
+ const name = attr.name;
+ const ref = attr.ref;
+
+ if (name) {
+ const attrName = name.includes(':') ? name : `${nsMap[tns]}:${name}`;
+ attributes[attrName] = {
+ type: attr.type || 'xs:string',
+ use: attr.use || 'optional',
+ default: attr.default,
+ fixed: attr.fixed,
+ };
+ } else if (ref) {
+ // Resolve attribute reference
+ const [refPrefix, refLocal] = ref.includes(':') ? ref.split(':') : [nsMap[tns], ref];
+ const attrName = `${refPrefix}:${refLocal}`;
+ attributes[attrName] = {
+ type: 'referenced',
+ ref: ref,
+ use: attr.use || 'optional',
+ };
+ }
+ }
+
+ // Attribute groups
+ for (const attrGroup of arr(node['xs:attributeGroup']).concat(arr(node['xsd:attributeGroup']))) {
+ if (attrGroup.ref) {
+ // Resolve attribute group
+ let groupTns, groupName;
+ if (attrGroup.ref.includes(':')) {
+ const [prefix, local] = attrGroup.ref.split(':');
+ groupName = local;
+ groupTns = Object.entries(nsMap).find(([, v]) => v === prefix)?.[0];
+ } else {
+ groupName = attrGroup.ref;
+ groupTns = tns;
+ }
+
+ if (groupTns) {
+ const group = attributeGroups.get(`${groupTns}::${groupName}`);
+ if (group) {
+ // Recursively extract attributes from the group
+ extractDirectAttributes(group, attributes, groupTns);
+ }
+ }
+ }
+ }
+
+ // anyAttribute allows any attributes
+ if (node['xs:anyAttribute'] || node['xsd:anyAttribute']) {
+ attributes['@anyAttribute'] = true;
+ }
+ }
+
+ // Helper function to extract all attributes including inherited
+ function extractAttributesComplete(ct, tns) {
+ const attributes = {};
+
+ if (!ct) return attributes;
+
+ // Handle inheritance first
+ const complexContent = ct['xs:complexContent'] || ct['xsd:complexContent'];
+ if (complexContent) {
+ const extension = complexContent['xs:extension'] || complexContent['xsd:extension'];
+ const restriction = complexContent['xs:restriction'] || complexContent['xsd:restriction'];
+
+ const base = extension?.base || restriction?.base;
+ if (base) {
+ // Resolve base type and get its attributes
+ const baseType = resolveType(base, tns, nsMap, complexTypes, simpleTypes);
+ if (baseType) {
+ const baseAttrs = extractAttributesComplete(baseType, tns);
+ Object.assign(attributes, baseAttrs);
+ }
+ }
+
+ // Process extension/restriction's own attributes
+ const content = extension || restriction;
+ if (content) {
+ extractDirectAttributes(content, attributes, tns);
+ }
+ }
+
+ // Simple content (often has attributes)
+ const simpleContent = ct['xs:simpleContent'] || ct['xsd:simpleContent'];
+ if (simpleContent) {
+ const extension = simpleContent['xs:extension'] || simpleContent['xsd:extension'];
+ const restriction = simpleContent['xs:restriction'] || simpleContent['xsd:restriction'];
+ const content = extension || restriction;
+ if (content) {
+ extractDirectAttributes(content, attributes, tns);
+ }
+ }
+
+ // Direct attributes on the complex type
+ extractDirectAttributes(ct, attributes, tns);
+
+ return attributes;
+ }
+
+ /** @type {Record}>} */
+ const map = {}; // QName -> {children: [], attributes: {}}
+ let processedCount = 0;
+ let debugElements = ['w:p', 'w:r', 'w:pPr', 'w:rPr', 'w:tbl', 'w:document', 'w:body'];
+
+ // Also check for elements that appear as references but aren't defined
+ const referencedElements = new Set();
+
+ for (const { tns, prefix, name, el } of elements.values()) {
+ const qname = qn(prefix, name);
+ const ct = inlineCT(el) || resolveType(el.type, tns, nsMap, complexTypes, simpleTypes);
+ const childrenSet = new Set();
+ let attributes = {};
+
+ if (debugElements.includes(qname)) {
+ console.log(`\n=== Processing ${qname} ===`);
+ console.log(`Element type: ${el.type || 'inline'}`);
+ console.log(`Has inline complexType: ${!!inlineCT(el)}`);
+ console.log(`Resolved complexType: ${!!ct}`);
+ }
+
+ if (ct) {
+ // Extract attributes
+ attributes = extractAttributesComplete(ct, tns);
+
+ const root = contentRoot(ct);
+ if (debugElements.includes(qname)) {
+ console.log(`Content root: ${!!root}`);
+ console.log(`Attributes found: ${Object.keys(attributes).length}`);
+ }
+
+ if (root) {
+ const parts = [];
+ expandContent(root, parts, tns, 0, elements, nsMap, groups);
+
+ if (debugElements.includes(qname)) {
+ console.log(`Found ${parts.length} child elements in content model`);
+ }
+
+ for (const e of parts) {
+ const childQName = resolveChildQName(e, tns, nsMap);
+ if (childQName) {
+ childrenSet.add(childQName);
+ referencedElements.add(childQName); // Track that this element is referenced
+ if (debugElements.includes(qname)) {
+ console.log(` Child: ${childQName} (from ${e.name || e.ref})`);
+ }
+ }
+ }
+ }
+ } else if (debugElements.includes(qname)) {
+ console.log(`No complex type found for ${qname}`);
+ }
+
+ // Add pass-through elements for content containers
+ if (childrenSet.size > 0 || ['w:p', 'w:tc', 'w:body', 'w:document'].includes(qname)) {
+ for (const pt of PASS_THROUGH) {
+ childrenSet.add(pt);
+ }
+ }
+
+ // Store both children and attributes
+ map[qname] = {
+ children: Array.from(childrenSet).sort(),
+ attributes: attributes,
+ };
+
+ if (map[qname].children.length > 0) {
+ processedCount++;
+ }
+
+ // Show final result for debug elements
+ if (debugElements.includes(qname)) {
+ console.log(`Final children for ${qname}: [${map[qname].children.join(', ')}]`);
+ if (Object.keys(attributes).length > 0) {
+ console.log(`Attributes for ${qname}: ${Object.keys(attributes).join(', ')}`);
+ }
+ }
+ }
+
+ // Add entries for referenced elements that weren't defined
+ for (const refQName of referencedElements) {
+ if (!map[refQName]) {
+ // This element was referenced but not defined - add empty entry
+ map[refQName] = {
+ children: [],
+ attributes: {},
+ };
+
+ // Also add pass-through elements for known containers
+ if (['w:p', 'w:tc', 'w:body'].includes(refQName)) {
+ map[refQName].children = Array.from(PASS_THROUGH).sort();
+ }
+ }
+ }
+
+ console.log(`Generated schema with ${processedCount} elements having children`);
+ console.log(`Total elements in schema: ${Object.keys(map).length}`);
+
+ return { namespaces: nsMap, elements: map };
+}
diff --git a/packages/ooxml-inspector/generator/src/schema-build.test.js b/packages/ooxml-inspector/generator/src/schema-build.test.js
new file mode 100644
index 0000000000..daa6fa4e0e
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/schema-build.test.js
@@ -0,0 +1,584 @@
+// schema-build.test.js
+import { describe, it, expect, beforeEach, vi } from 'vitest';
+
+const H = vi.hoisted(() => ({
+ PASS_THROUGH: ['w:bookmarkStart', 'w:bookmarkEnd'],
+ parserParse: vi.fn(),
+}));
+
+// --- core mocks (must be defined before importing SUT) ---
+vi.mock('node:fs', () => ({
+ readdirSync: vi.fn(),
+ readFileSync: vi.fn(),
+}));
+vi.mock('node:path', () => ({
+ join: vi.fn((...p) => p.join('/')),
+}));
+vi.mock('./constants.js', () => {
+ const NS_MAP = { 'urn:w': 'w' }; // fresh object per module load; we reset per test
+ return { NS_MAP, PASS_THROUGH: H.PASS_THROUGH };
+});
+vi.mock('./builder/index.js', () => {
+ const arr = (x) => (Array.isArray(x) ? x : x ? [x] : []);
+ return {
+ arr: vi.fn(arr),
+ qn: vi.fn((p, l) => `${p}:${l}`),
+ parser: { parse: H.parserParse }, // hoist-safe
+ inlineCT: vi.fn(() => null),
+ contentRoot: vi.fn(() => null),
+ expandContent: vi.fn(),
+ resolveType: vi.fn(() => null),
+ collectElements: vi.fn(),
+ autoPrefix: vi.fn((tns, nsMap) => {
+ if (!nsMap[tns]) nsMap[tns] = `g${Object.keys(nsMap).length}`;
+ return nsMap[tns];
+ }),
+ resolveChildQName: vi.fn(),
+ };
+});
+
+// Import SUT after mocks
+import { readdirSync, readFileSync } from 'node:fs';
+import { buildFromXsdDir } from './schema-build.js';
+
+// Helpers to access mocked modules
+const getConstants = async () => await import('./constants.js');
+const getBuilder = async () => await import('./builder/index.js');
+
+beforeEach(async () => {
+ vi.clearAllMocks();
+ H.parserParse.mockReset();
+
+ // Reset mutable NS_MAP for isolation
+ const { NS_MAP } = await getConstants();
+ for (const k of Object.keys(NS_MAP)) delete NS_MAP[k];
+ Object.assign(NS_MAP, { 'urn:w': 'w' });
+
+ // Reset builder mocks (keep their identity)
+ const b = await getBuilder();
+ b.arr.mockClear();
+ b.qn.mockClear();
+ b.inlineCT.mockReset().mockImplementation(() => null);
+ b.contentRoot.mockReset().mockImplementation(() => null);
+ b.expandContent.mockReset();
+ b.resolveType.mockReset().mockImplementation(() => null);
+ b.collectElements.mockReset();
+ b.autoPrefix.mockClear(); // default impl ok
+ b.resolveChildQName.mockReset();
+});
+
+describe('schema-build', () => {
+ it('reads only .xsd files', async () => {
+ readdirSync.mockReturnValueOnce(['a.xsd', 'b.txt', 'c.xsd']);
+ H.parserParse
+ .mockReturnValueOnce({ 'xs:schema': { targetNamespace: 'urn:w' } })
+ .mockReturnValueOnce({ 'xs:schema': { targetNamespace: 'urn:w' } });
+
+ const res = buildFromXsdDir('/fake');
+ expect(H.parserParse).toHaveBeenCalledTimes(2);
+ expect(res.namespaces['urn:w']).toBe('w');
+ expect(typeof res.elements).toBe('object');
+ });
+
+ it('adds namespace mappings from xs:import and auto-assigns prefixes', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:import': [{ namespace: 'urn:a' }, { namespace: 'urn:b' }, { namespace: 'urn:a' }],
+ },
+ });
+
+ const res = buildFromXsdDir('/fake');
+ expect(res.namespaces['urn:w']).toBe('w');
+ expect(res.namespaces['urn:a']).toBeDefined();
+ expect(res.namespaces['urn:b']).toBeDefined();
+ expect(res.namespaces['urn:a']).not.toBe('w');
+ expect(res.namespaces['urn:b']).not.toBe('w');
+ });
+
+ it('collects top-level elements and resolves children via contentRoot/expandContent/resolveChildQName', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:element': [{ name: 'document', type: 'w:DocumentType' }],
+ 'xs:complexType': [{ name: 'DocumentType' }],
+ },
+ });
+
+ const b = await getBuilder();
+ b.resolveType.mockImplementation((t) => (t === 'w:DocumentType' ? { name: 'DocumentType' } : null));
+ b.contentRoot.mockReturnValueOnce({ tag: 'root' });
+ b.expandContent.mockImplementation((_root, parts) => {
+ parts.push({ name: 'body' }, { ref: 'w:p' });
+ });
+ b.resolveChildQName.mockImplementation((e, tns, nsMap) => (e.name ? `${nsMap[tns]}:${e.name}` : e.ref));
+
+ const res = buildFromXsdDir('/fake');
+ expect(res.elements['w:document']).toBeDefined();
+ const kids = res.elements['w:document'].children;
+ expect(kids).toEqual(expect.arrayContaining(['w:body', 'w:p', ...H.PASS_THROUGH]));
+ });
+
+ it('resolves elementRefs into synthetic elements when not already defined', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:element': [{ name: 'wrapper', type: 'w:WrapperType' }],
+ 'xs:complexType': [{ name: 'WrapperType' }],
+ },
+ });
+
+ const b = await getBuilder();
+ b.resolveType.mockReturnValueOnce({ name: 'WrapperType' });
+ b.contentRoot.mockReturnValueOnce({});
+ // When collectElements is called, stash an unresolved ref
+ b.collectElements.mockImplementation((_node, _tns, _pfx, _elements, elementRefs) => {
+ elementRefs.set('w:tbl', { tns: 'urn:w', prefix: 'w' });
+ });
+ // And reference it in children too, to mark it as "referenced"
+ b.expandContent.mockImplementation((_root, parts) => parts.push({ ref: 'w:tbl' }));
+ b.resolveChildQName.mockImplementation((e) => e.ref);
+
+ const res = buildFromXsdDir('/fake');
+ expect(res.elements['w:tbl']).toBeDefined();
+ expect(res.elements['w:tbl'].children).toEqual([]);
+ expect(res.elements['w:tbl'].attributes).toEqual({});
+ });
+
+ it('creates synthetic elements from CT_ pattern (CT_P -> w:p) when missing', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:complexType': [{ name: 'CT_P' }],
+ },
+ });
+
+ const res = buildFromXsdDir('/fake');
+ expect(res.elements['w:p']).toBeDefined();
+ // containers get pass-through
+ expect(res.elements['w:p'].children).toEqual([...H.PASS_THROUGH].sort());
+ });
+
+ it('extracts direct and simpleContent attributes', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:element': [{ name: 'r', type: 'w:RunType' }],
+ 'xs:complexType': [{ name: 'RunType' }],
+ },
+ });
+
+ const b = await getBuilder();
+ b.resolveType.mockImplementation((t) =>
+ t === 'w:RunType'
+ ? {
+ 'xs:simpleContent': {
+ 'xs:extension': {
+ 'xs:attribute': [{ name: 'val', type: 'xs:string', use: 'optional' }],
+ },
+ },
+ 'xs:attribute': [{ name: 'color', type: 'xs:string' }],
+ }
+ : null,
+ );
+ b.contentRoot.mockReturnValue(null);
+
+ const res = buildFromXsdDir('/fake');
+ const attrs = res.elements['w:r'].attributes;
+ expect(attrs['w:val']).toMatchObject({ type: 'xs:string', use: 'optional' });
+ expect(attrs['w:color']).toMatchObject({ type: 'xs:string' });
+ });
+
+ it('resolves attributeGroup refs and anyAttribute', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:element': [{ name: 'el', type: 'w:ElType' }],
+ 'xs:complexType': [
+ {
+ name: 'ElType',
+ 'xs:complexContent': {
+ 'xs:extension': {
+ base: 'w:Base',
+ 'xs:attributeGroup': [{ ref: 'w:runAttrs' }],
+ 'xs:anyAttribute': {},
+ },
+ },
+ },
+ {
+ name: 'Base',
+ 'xs:attribute': [{ name: 'baseAttr', type: 'xs:string' }],
+ },
+ ],
+ 'xs:attributeGroup': [
+ {
+ name: 'runAttrs',
+ 'xs:attribute': [{ name: 'id', type: 'xs:string' }],
+ },
+ ],
+ },
+ });
+
+ const b = await getBuilder();
+ // Resolve base to the second CT so inheritance pulls baseAttr
+ b.resolveType.mockImplementation((t) =>
+ t === 'w:ElType'
+ ? {
+ 'xs:complexContent': {
+ 'xs:extension': { base: 'w:Base', 'xs:attributeGroup': [{ ref: 'w:runAttrs' }], 'xs:anyAttribute': {} },
+ },
+ }
+ : t === 'w:Base'
+ ? { 'xs:attribute': [{ name: 'baseAttr', type: 'xs:string' }] }
+ : null,
+ );
+ b.contentRoot.mockReturnValue(null);
+
+ const res = buildFromXsdDir('/fake');
+ const attrs = res.elements['w:el'].attributes;
+ expect(attrs['w:baseAttr']).toMatchObject({ type: 'xs:string' });
+ expect(attrs['w:id']).toMatchObject({ type: 'xs:string' });
+ expect(attrs['@anyAttribute']).toBe(true);
+ });
+
+ it('adds pass-through when element has children OR is a known container', async () => {
+ // Case 1: known container with no type -> still gets pass-through
+ readdirSync.mockReturnValueOnce(['c1.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:element': [{ name: 'document' }], // no type, no ct
+ },
+ });
+
+ let res = buildFromXsdDir('/fake1');
+ expect(res.elements['w:document'].children).toEqual(expect.arrayContaining(H.PASS_THROUGH));
+
+ // Case 2: non-container but has children -> gets pass-through too
+ // Reset parser for new run
+ readdirSync.mockReturnValueOnce(['c2.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:element': [{ name: 'z', type: 'w:ZType' }],
+ 'xs:complexType': [{ name: 'ZType' }],
+ },
+ });
+ const b = await getBuilder();
+ b.resolveType.mockReturnValueOnce({ name: 'ZType' });
+ b.contentRoot.mockReturnValueOnce({});
+ b.expandContent.mockImplementation((_root, parts) => parts.push({ name: 'zz' }));
+ b.resolveChildQName.mockImplementation((e, tns, nsMap) => `${nsMap[tns]}:${e.name}`);
+
+ res = buildFromXsdDir('/fake2');
+ expect(res.elements['w:z'].children).toEqual(expect.arrayContaining(['w:zz', ...H.PASS_THROUGH]));
+ });
+
+ it('adds stub entries for referenced-but-undefined elements (non-container)', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:element': [{ name: 'wrapper', type: 'w:WrapperType' }],
+ 'xs:complexType': [{ name: 'WrapperType' }],
+ },
+ });
+
+ const b = await getBuilder();
+ b.resolveType.mockReturnValueOnce({ name: 'WrapperType' });
+ b.contentRoot.mockReturnValueOnce({});
+ b.expandContent.mockImplementation((_root, parts) => parts.push({ ref: 'w:foo' }));
+ b.resolveChildQName.mockImplementation((e) => e.ref);
+
+ const res = buildFromXsdDir('/fake');
+ expect(res.elements['w:foo']).toEqual({ children: [], attributes: {} });
+ });
+
+ it('supports xsd:schema and xsd:import variants', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ // Use xsd:schema (not xs:schema) and xsd:import (not xs:import)
+ H.parserParse.mockReturnValueOnce({
+ 'xsd:schema': {
+ targetNamespace: 'urn:w',
+ 'xsd:import': [{ namespace: 'urn:a' }],
+ },
+ });
+
+ const res = buildFromXsdDir('/fake');
+ // namespace map should include original and imported one (auto-assigned)
+ expect(res.namespaces['urn:w']).toBe('w');
+ expect(res.namespaces['urn:a']).toBeDefined();
+ expect(res.namespaces['urn:a']).not.toBe('w');
+ });
+
+ it('resolves elementRefs with unprefixed refs (falls back to same TNS)', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:element': [{ name: 'wrapper', type: 'w:WrapperType' }],
+ 'xs:complexType': [{ name: 'WrapperType' }],
+ },
+ });
+
+ const b = await getBuilder();
+ b.resolveType.mockReturnValueOnce({ name: 'WrapperType' });
+ b.contentRoot.mockReturnValueOnce({});
+ // collectElements adds an unresolved **unprefixed** ref: "tbl"
+ b.collectElements.mockImplementation((_node, tns, prefix, _elements, elementRefs) => {
+ elementRefs.set('tbl', { tns: 'urn:w', prefix: 'w' });
+ });
+ // also reference it in content to mark it "referenced"
+ b.expandContent.mockImplementation((_root, parts) => parts.push({ ref: 'tbl' }));
+ b.resolveChildQName.mockImplementation((e) => (e.ref.includes(':') ? e.ref : `w:${e.ref}`));
+
+ const res = buildFromXsdDir('/fake');
+ expect(res.elements['w:tbl']).toBeDefined();
+ // created as synthetic (empty children/attrs)
+ expect(res.elements['w:tbl'].children).toEqual([]);
+ expect(res.elements['w:tbl'].attributes).toEqual({});
+ });
+
+ it('does NOT create CT_ synthetic element when heuristic fails (name too long)', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ // CT_ name > 10 chars after "CT_" so heuristic should skip creating element
+ 'xs:complexType': [{ name: 'CT_ThisNameIsDefinitelyLong' }],
+ },
+ });
+
+ const res = buildFromXsdDir('/fake');
+ // Should NOT synthesize w:thisNameIsDefinitelyLong
+ const maybe = Object.keys(res.elements).find((q) => /thisNameIsDefinitelyLong/i.test(q));
+ expect(maybe).toBeUndefined();
+ });
+
+ it('extractDirectAttributes: resolves unprefixed attribute ref using current TNS', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:element': [{ name: 'el', type: 'w:ElType' }],
+ 'xs:complexType': [
+ {
+ name: 'ElType',
+ 'xs:complexContent': {
+ 'xs:extension': {
+ base: 'w:Base',
+ // attribute ref WITHOUT prefix; should attach as "w:id"
+ 'xs:attribute': [{ ref: 'id', use: 'optional' }],
+ },
+ },
+ },
+ {
+ name: 'Base',
+ 'xs:attribute': [{ name: 'baseAttr', type: 'xs:string' }],
+ },
+ ],
+ },
+ });
+
+ const b = await getBuilder();
+ b.resolveType
+ .mockImplementationOnce((_t) => ({
+ // resolve ElType
+ 'xs:complexContent': {
+ 'xs:extension': { base: 'w:Base', 'xs:attribute': [{ ref: 'id', use: 'optional' }] },
+ },
+ }))
+ .mockImplementationOnce((_t) => ({
+ // resolve Base
+ 'xs:attribute': [{ name: 'baseAttr', type: 'xs:string' }],
+ }));
+ b.contentRoot.mockReturnValue(null);
+
+ const res = buildFromXsdDir('/fake');
+ const attrs = res.elements['w:el'].attributes;
+ expect(attrs['w:baseAttr']).toMatchObject({ type: 'xs:string' });
+ // unprefixed ref -> prefix from current TNS (w)
+ expect(attrs['w:id']).toMatchObject({ type: 'referenced', ref: 'id', use: 'optional' });
+ });
+
+ it('attributeGroup ref without prefix resolves within same TNS', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:element': [{ name: 'el', type: 'w:ElType' }],
+ 'xs:complexType': [
+ {
+ name: 'ElType',
+ 'xs:complexContent': {
+ 'xs:extension': {
+ base: 'w:Base',
+ // attributeGroup ref WITHOUT prefix; should pull group from same TNS
+ 'xs:attributeGroup': [{ ref: 'runAttrs' }],
+ 'xs:anyAttribute': {}, // we’ll also hit the xsd:anyAttribute in the next test
+ },
+ },
+ },
+ { name: 'Base', 'xs:attribute': [{ name: 'fromBase', type: 'xs:string' }] },
+ ],
+ 'xs:attributeGroup': [{ name: 'runAttrs', 'xs:attribute': [{ name: 'id', type: 'xs:string' }] }],
+ },
+ });
+
+ const b = await getBuilder();
+ b.resolveType
+ .mockImplementationOnce((_t) => ({
+ // ElType
+ 'xs:complexContent': {
+ 'xs:extension': {
+ base: 'w:Base',
+ 'xs:attributeGroup': [{ ref: 'runAttrs' }],
+ 'xs:anyAttribute': {},
+ },
+ },
+ }))
+ .mockImplementationOnce((_t) => ({
+ // Base
+ 'xs:attribute': [{ name: 'fromBase', type: 'xs:string' }],
+ }));
+ b.contentRoot.mockReturnValue(null);
+
+ const res = buildFromXsdDir('/fake');
+ const attrs = res.elements['w:el'].attributes;
+ expect(attrs['w:fromBase']).toMatchObject({ type: 'xs:string' });
+ // group from same TNS (ref had no prefix)
+ expect(attrs['w:id']).toMatchObject({ type: 'xs:string' });
+ expect(attrs['@anyAttribute']).toBe(true);
+ });
+
+ it('recognizes xsd:anyAttribute as well as xs:anyAttribute', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:element': [{ name: 'el', type: 'w:ElType' }],
+ 'xs:complexType': [
+ {
+ name: 'ElType',
+ 'xs:simpleContent': {
+ 'xs:extension': {
+ // specifically test the xsd:anyAttribute branch here
+ 'xsd:anyAttribute': {},
+ },
+ },
+ },
+ ],
+ },
+ });
+
+ const b = await getBuilder();
+ b.resolveType.mockImplementation((_t) => ({
+ 'xs:simpleContent': { 'xs:extension': { 'xsd:anyAttribute': {} } },
+ }));
+ b.contentRoot.mockReturnValue(null);
+
+ const res = buildFromXsdDir('/fake');
+ const attrs = res.elements['w:el'].attributes;
+ expect(attrs['@anyAttribute']).toBe(true);
+ });
+
+ it('ignores xs:import entries without a namespace', async () => {
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ // imports include missing/empty namespace → should be ignored
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:import': [{}, { namespace: '' }],
+ },
+ });
+
+ const res = buildFromXsdDir('/fake');
+ // Should only have the original mapping; no new prefixes created
+ expect(res.namespaces['urn:w']).toBe('w');
+ // no bogus keys like '' or undefined
+ expect(Object.keys(res.namespaces)).toEqual(expect.arrayContaining(['urn:w']));
+ expect(Object.keys(res.namespaces)).not.toContain('');
+ });
+
+ it('does not overwrite an existing namespace mapping from xs:import', async () => {
+ // Pre-seed NS_MAP with an existing mapping
+ const { NS_MAP } = await getConstants();
+ NS_MAP['urn:a'] = 'a';
+
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ // one already-mapped (urn:a), one new (urn:b)
+ 'xs:import': [{ namespace: 'urn:a' }, { namespace: 'urn:b' }],
+ },
+ });
+
+ const res = buildFromXsdDir('/fake');
+
+ // Existing mapping preserved
+ expect(res.namespaces['urn:a']).toBe('a');
+
+ // New mapping auto-assigned (not 'w' or 'a')
+ expect(res.namespaces['urn:b']).toBeDefined();
+ expect(['w', 'a']).not.toContain(res.namespaces['urn:b']);
+ });
+
+ it('normalizes single-object xs:import and xsd:import via arr(...) and assigns prefixes for both', async () => {
+ // Two files so each schema variant is processed (the SUT picks one schema per file)
+ readdirSync.mockReturnValueOnce(['a.xsd', 'b.xsd']);
+
+ H.parserParse
+ // File 1: xs:schema with single-object xs:import
+ .mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:import': { namespace: 'urn:a' }, // not an array
+ },
+ })
+ // File 2: xsd:schema with single-object xsd:import
+ .mockReturnValueOnce({
+ 'xsd:schema': {
+ targetNamespace: 'urn:w',
+ 'xsd:import': { namespace: 'urn:b' }, // not an array
+ },
+ });
+
+ const res = buildFromXsdDir('/fake');
+
+ expect(res.namespaces['urn:w']).toBe('w');
+ expect(res.namespaces['urn:a']).toBeDefined();
+ expect(res.namespaces['urn:b']).toBeDefined();
+ expect(res.namespaces['urn:a']).not.toBe('w');
+ expect(res.namespaces['urn:b']).not.toBe('w');
+ expect(res.namespaces['urn:a']).not.toBe(res.namespaces['urn:b']); // distinct autoprefixes
+ });
+
+ it('re-assigns a prefix when the namespace exists with a falsy mapping (e.g., empty string)', async () => {
+ // Pre-seed NS_MAP with a falsy mapping for a namespace
+ const { NS_MAP } = await getConstants();
+ NS_MAP['urn:empty'] = ''; // falsy -> condition `!nsMap[imp.namespace]` should pass
+
+ readdirSync.mockReturnValueOnce(['doc.xsd']);
+ H.parserParse.mockReturnValueOnce({
+ 'xs:schema': {
+ targetNamespace: 'urn:w',
+ 'xs:import': [{ namespace: 'urn:empty' }],
+ },
+ });
+
+ const res = buildFromXsdDir('/fake');
+
+ // Should get a real auto-assigned prefix (non-empty string)
+ expect(res.namespaces['urn:empty']).toBeDefined();
+ expect(res.namespaces['urn:empty']).not.toBe('');
+ // And not collide with 'w'
+ expect(res.namespaces['urn:empty']).not.toBe('w');
+ });
+});
diff --git a/packages/ooxml-inspector/generator/src/types/index.js b/packages/ooxml-inspector/generator/src/types/index.js
new file mode 100644
index 0000000000..255a7e010e
--- /dev/null
+++ b/packages/ooxml-inspector/generator/src/types/index.js
@@ -0,0 +1,14 @@
+/**
+ * @typedef {Object} SchemaElement
+ * @property {string[]} children - List of child element QNames
+ * @property {Record} attributes - Attributes keyed by QName
+ * @property {string} [length] - The length of the element
+ */
+
+/**
+ * @typedef {Object} BuiltSchema
+ * @property {Record} namespaces - Mapping of namespace URI → prefix
+ * @property {Record} elements - Mapping of QName → schema element definition
+ */
+
+export {};
diff --git a/packages/ooxml-inspector/package.json b/packages/ooxml-inspector/package.json
new file mode 100644
index 0000000000..c2354d33c4
--- /dev/null
+++ b/packages/ooxml-inspector/package.json
@@ -0,0 +1,53 @@
+{
+ "name": "@superdoc-dev/ooxml-inspector",
+ "version": "1.0.1",
+ "type": "module",
+ "license": "AGPL-3.0",
+ "engines": {
+ "node": ">=18.17"
+ },
+ "module": "./dist/index.js",
+ "types": "./dist/index.d.ts",
+ "bin": {
+ "ooxml": "./dist/bin/cli.js"
+ },
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "import": "./dist/index.js"
+ },
+ "./schema": "./dist/schema.transitional.json",
+ "./cli": "./dist/bin/cli.js",
+ "./package.json": "./package.json"
+ },
+ "files": [
+ "dist/",
+ "README.md",
+ "LICENSE"
+ ],
+ "scripts": {
+ "clean": "rm -rf dist coverage",
+ "build:schema": "node generator/index.js",
+ "build:lib": "tsup src/index.js --format esm --dts --sourcemap --out-dir dist",
+ "build:cli": "tsup src/cli.js --format esm --sourcemap --out-dir dist/bin",
+ "build": "npm run clean && npm run build:schema && npm run build:lib && npm run build:cli",
+ "prepublishOnly": "npm run test && npm run build",
+ "test": "vitest run",
+ "test:watch": "vitest",
+ "test:cov": "vitest run --coverage"
+ },
+ "sideEffects": false,
+ "publishConfig": {
+ "access": "public"
+ },
+ "dependencies": {
+ "fast-xml-parser": "^4.4.0"
+ },
+ "devDependencies": {
+ "@types/node": "^24.3.0",
+ "@vitest/coverage-v8": "^3.2.4",
+ "tsup": "^8.1.0",
+ "typescript": "^5.9.2",
+ "vitest": "^3.2.4"
+ }
+}
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-chart.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-chart.xsd
new file mode 100644
index 0000000000..bc325f9f5e
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-chart.xsd
@@ -0,0 +1,1499 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-chartDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-chartDrawing.xsd
new file mode 100644
index 0000000000..afa4f463e3
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-chartDrawing.xsd
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-diagram.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-diagram.xsd
new file mode 100644
index 0000000000..40e4b12a8e
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-diagram.xsd
@@ -0,0 +1,1085 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-lockedCanvas.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-lockedCanvas.xsd
new file mode 100644
index 0000000000..687eea8297
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-lockedCanvas.xsd
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-main.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-main.xsd
new file mode 100644
index 0000000000..c8c127842a
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-main.xsd
@@ -0,0 +1,3081 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-picture.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-picture.xsd
new file mode 100644
index 0000000000..1dbf05140d
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-picture.xsd
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-spreadsheetDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-spreadsheetDrawing.xsd
new file mode 100644
index 0000000000..f1af17db4e
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-spreadsheetDrawing.xsd
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-wordprocessingDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-wordprocessingDrawing.xsd
new file mode 100644
index 0000000000..5c00a6ffc4
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-wordprocessingDrawing.xsd
@@ -0,0 +1,287 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/pml.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/pml.xsd
new file mode 100644
index 0000000000..2b0bc506a3
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/pml.xsd
@@ -0,0 +1,1676 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-additionalCharacteristics.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-additionalCharacteristics.xsd
new file mode 100644
index 0000000000..c20f3bf147
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-additionalCharacteristics.xsd
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-bibliography.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-bibliography.xsd
new file mode 100644
index 0000000000..ac60252262
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-bibliography.xsd
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-commonSimpleTypes.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-commonSimpleTypes.xsd
new file mode 100644
index 0000000000..7fa4d9277b
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-commonSimpleTypes.xsd
@@ -0,0 +1,172 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-customXmlDataProperties.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-customXmlDataProperties.xsd
new file mode 100644
index 0000000000..2bddce2921
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-customXmlDataProperties.xsd
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-customXmlSchemaProperties.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-customXmlSchemaProperties.xsd
new file mode 100644
index 0000000000..8a8c18ba2d
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-customXmlSchemaProperties.xsd
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesCustom.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesCustom.xsd
new file mode 100644
index 0000000000..5c42706a0d
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesCustom.xsd
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesExtended.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesExtended.xsd
new file mode 100644
index 0000000000..853c341c87
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesExtended.xsd
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesVariantTypes.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesVariantTypes.xsd
new file mode 100644
index 0000000000..da835ee82d
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesVariantTypes.xsd
@@ -0,0 +1,195 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-math.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-math.xsd
new file mode 100644
index 0000000000..a07f392784
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-math.xsd
@@ -0,0 +1,582 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-relationshipReference.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-relationshipReference.xsd
new file mode 100644
index 0000000000..9e86f1b2be
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-relationshipReference.xsd
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/sml.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/sml.xsd
new file mode 100644
index 0000000000..6f226ae413
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/sml.xsd
@@ -0,0 +1,4425 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-main.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-main.xsd
new file mode 100644
index 0000000000..eeb4ef8fa0
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-main.xsd
@@ -0,0 +1,570 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-officeDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-officeDrawing.xsd
new file mode 100644
index 0000000000..ca2575c753
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-officeDrawing.xsd
@@ -0,0 +1,509 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-presentationDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-presentationDrawing.xsd
new file mode 100644
index 0000000000..dd079e603f
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-presentationDrawing.xsd
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-spreadsheetDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-spreadsheetDrawing.xsd
new file mode 100644
index 0000000000..3dd6cf625a
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-spreadsheetDrawing.xsd
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-wordprocessingDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-wordprocessingDrawing.xsd
new file mode 100644
index 0000000000..f1041e34ef
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-wordprocessingDrawing.xsd
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/wml.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/wml.xsd
new file mode 100644
index 0000000000..28c23061a1
--- /dev/null
+++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/wml.xsd
@@ -0,0 +1,3644 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ooxml-inspector/src/children/cli.js b/packages/ooxml-inspector/src/children/cli.js
new file mode 100644
index 0000000000..3725f4e601
--- /dev/null
+++ b/packages/ooxml-inspector/src/children/cli.js
@@ -0,0 +1,106 @@
+import { childrenOf, allTags, namespaces } from './lookup.js';
+import { getAttributes } from './index.js';
+
+// Explicit namespace allowlist for now
+// Keeping: w*, a:, pic:, wp:, r:, mc:, cp:, dc:, dcterms:
+// Skipping for now: m:, v:, o:, p:, x:, g20:, cdr:, etc.
+const ALLOWED_PREFIXES = new Set(['w:', 'a:', 'pic:', 'wp:', 'r:', 'mc:', 'cp:', 'dc:', 'dcterms:']);
+
+export function runChildrenCLI(argv) {
+ const sub = argv[0];
+ const arg = argv[1];
+
+ switch (sub) {
+ case 'children': {
+ if (!arg) {
+ console.error('Usage: ooxml children ');
+ process.exit(2);
+ }
+ console.log(JSON.stringify(childrenOf(arg), null, 2));
+ break;
+ }
+
+ case 'tags': {
+ const prefix = arg && !arg.startsWith('--') ? arg : null;
+ const flags = new Set(argv.slice(prefix ? 2 : 1).filter((a) => a.startsWith('--')));
+ const parentsOnly = flags.has('--parents');
+ const plain = flags.has('--plain');
+
+ // look for --namespace
+ const nsIndex = argv.findIndex((a) => a === '--namespace');
+ const nsPrefix = nsIndex !== -1 ? argv[nsIndex + 1] : null;
+
+ let tags = allTags({ prefix, hasChildren: parentsOnly ? true : null });
+
+ // apply allowlist filter
+ tags = tags.filter((t) => {
+ for (const p of ALLOWED_PREFIXES) {
+ if (t.startsWith(p)) return true;
+ }
+ return false;
+ });
+
+ // apply explicit --namespace filter if given
+ if (nsPrefix) {
+ tags = tags.filter((t) => t.startsWith(nsPrefix + ':'));
+ }
+
+ console.log(plain ? tags.join('\n') : JSON.stringify({ count: tags.length, tags }, null, 2));
+ console.log(`Total tags (filtered): ${tags.length}`);
+ break;
+ }
+
+ case 'namespaces': {
+ console.log(JSON.stringify(namespaces(), null, 2));
+ break;
+ }
+
+ case 'attrs': {
+ if (!arg) return usage();
+ const attrs = getAttributes(arg);
+ if (attrs == null) notFound(arg);
+ else {
+ const keys = Object.keys(attrs);
+ if (!keys.length) {
+ console.log('(no attributes)');
+ break;
+ }
+ for (const k of keys) {
+ const spec = attrs[k];
+ const bits = [];
+ if (spec.use) bits.push(`use=${spec.use}`);
+ if (spec.type) bits.push(`type=${spec.type}`);
+ if (spec.default != null) bits.push(`default=${spec.default}`);
+ if (spec.fixed != null) bits.push(`fixed=${spec.fixed}`);
+ if (spec.ref) bits.push(`ref=${spec.ref}`);
+ console.log(`${k}${bits.length ? ' ' + bits.join(' ') : ''}`);
+ }
+ }
+ break;
+ }
+
+ default:
+ console.error(
+ 'Usage:\n ooxml children \n ooxml tags [prefix] [--parents] [--plain]\n ooxml namespaces',
+ );
+ process.exit(2);
+ }
+}
+
+function usage() {
+ console.error(
+ `Usage:
+ ooxml children # list allowed children for a tag
+ ooxml attrs # list allowed attributes for a tag
+ ooxml tags # list all known tags (QNames)
+ ooxml namespaces # list namespace prefix map
+Options:
+ -j, --json # JSON output`,
+ );
+ process.exit(2);
+}
+
+function notFound(q) {
+ console.error(`Unknown element: \${q}\\`);
+ process.exit(2);
+}
diff --git a/packages/ooxml-inspector/src/children/cli.test.js b/packages/ooxml-inspector/src/children/cli.test.js
new file mode 100644
index 0000000000..88cfe9e8a5
--- /dev/null
+++ b/packages/ooxml-inspector/src/children/cli.test.js
@@ -0,0 +1,169 @@
+import { describe, it, beforeEach, afterEach, expect, vi } from 'vitest';
+
+vi.mock('./lookup.js', () => ({
+ childrenOf: vi.fn(),
+ allTags: vi.fn(),
+ namespaces: vi.fn(),
+}));
+vi.mock('./index.js', () => ({
+ getAttributes: vi.fn(),
+}));
+
+import { childrenOf, allTags, namespaces } from './lookup.js';
+import { getAttributes } from './index.js';
+import { runChildrenCLI } from './cli.js';
+
+// Helper to make process.exit stop execution but assert exit code
+class ExitError extends Error {
+ constructor(code) {
+ super(`__EXIT__:${code}`);
+ this.code = code;
+ }
+}
+
+describe('runChildrenCLI', () => {
+ let logSpy, errSpy, exitSpy;
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
+ errSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
+ exitSpy = vi.spyOn(process, 'exit').mockImplementation((code) => {
+ throw new ExitError(code);
+ });
+ });
+
+ afterEach(() => {
+ logSpy.mockRestore();
+ errSpy.mockRestore();
+ exitSpy.mockRestore();
+ });
+
+ it('children: exits with usage when missing qname', () => {
+ expect(() => runChildrenCLI(['children'])).toThrow(ExitError);
+ expect(errSpy).toHaveBeenCalledWith('Usage: ooxml children ');
+ // exit code 2
+ try {
+ runChildrenCLI(['children']);
+ } catch (e) {
+ expect(e).toBeInstanceOf(ExitError);
+ expect(e.code).toBe(2);
+ }
+ expect(childrenOf).not.toHaveBeenCalled();
+ });
+
+ it('children: prints JSON children array for provided qname', () => {
+ childrenOf.mockReturnValue(['w:r', 'w:p']);
+ runChildrenCLI(['children', 'w:body']);
+ expect(childrenOf).toHaveBeenCalledWith('w:body');
+ // first arg to a JSON.stringify log is the stringified array (pretty-printed)
+ const out = logSpy.mock.calls.map((c) => c[0]).join('\n');
+ expect(out).toContain('"w:r"');
+ expect(out).toContain('"w:p"');
+ expect(errSpy).not.toHaveBeenCalled();
+ });
+
+ it('tags: no args → JSON with count & tags, then "Total tags:" line', () => {
+ allTags.mockReturnValue(['w:p', 'w:r', 'a:blip']);
+ runChildrenCLI(['tags']);
+ expect(allTags).toHaveBeenCalledWith({ prefix: null, hasChildren: null });
+ const calls = logSpy.mock.calls.map((c) => c[0]);
+ expect(calls[0]).toMatch(/"count":\s*3/);
+ expect(calls[0]).toMatch(/"tags":\s*\[/);
+ expect(calls[1]).toBe('Total tags: 3');
+ });
+
+ it('tags: with prefix and --parents → filters via hasChildren=true', () => {
+ allTags.mockReturnValue(['w:p', 'w:r']);
+ runChildrenCLI(['tags', 'w', '--parents']);
+ expect(allTags).toHaveBeenCalledWith({ prefix: 'w', hasChildren: true });
+ const calls = logSpy.mock.calls.map((c) => c[0]);
+ expect(calls[0]).toMatch(/"count":\s*2/);
+ expect(calls[1]).toBe('Total tags: 2');
+ });
+
+ it('tags: --plain outputs newline-joined list + Total tags', () => {
+ allTags.mockReturnValue(['w:p', 'w:r', 'w:tbl']);
+ runChildrenCLI(['tags', '--plain']);
+ // plain should not JSON.stringify the payload; just join with \n
+ const calls = logSpy.mock.calls.map((c) => c[0]);
+ expect(calls[0]).toBe('w:p\nw:r\nw:tbl');
+ expect(calls[1]).toBe('Total tags: 3');
+ });
+
+ it('tags: prefix + --plain + --parents parses flags after prefix', () => {
+ allTags.mockReturnValue(['w:p']);
+ runChildrenCLI(['tags', 'w', '--plain', '--parents']);
+ expect(allTags).toHaveBeenCalledWith({ prefix: 'w', hasChildren: true });
+ const calls = logSpy.mock.calls.map((c) => c[0]);
+ expect(calls[0]).toBe('w:p');
+ expect(calls[1]).toBe('Total tags: 1');
+ });
+
+ it('namespaces: prints JSON of namespaces()', () => {
+ namespaces.mockReturnValue({ w: 'http://schemas.openxmlformats.org/wordprocessingml/2006/main' });
+ runChildrenCLI(['namespaces']);
+ const first = logSpy.mock.calls[0][0];
+ expect(first).toContain('"w"');
+ expect(first).toContain('wordprocessingml');
+ });
+
+ it('attrs: no qname → usage() and exit 2', () => {
+ expect(() => runChildrenCLI(['attrs'])).toThrow(ExitError);
+ expect(errSpy.mock.calls.map((c) => c[0]).join('\n')).toMatch(/Usage:/);
+ try {
+ runChildrenCLI(['attrs']);
+ } catch (e) {
+ expect(e).toBeInstanceOf(ExitError);
+ expect(e.code).toBe(2);
+ }
+ expect(getAttributes).not.toHaveBeenCalled();
+ });
+
+ it('attrs: unknown element (null) → notFound and exit 2', () => {
+ getAttributes.mockReturnValue(null);
+ expect(() => runChildrenCLI(['attrs', 'w:oops'])).toThrow(ExitError);
+ expect(errSpy).toHaveBeenCalledWith('Unknown element: w:oops');
+ try {
+ runChildrenCLI(['attrs', 'w:oops']);
+ } catch (e) {
+ expect(e).toBeInstanceOf(ExitError);
+ expect(e.code).toBe(2);
+ }
+ });
+
+ it('attrs: empty object → prints "(no attributes)"', () => {
+ getAttributes.mockReturnValue({});
+ runChildrenCLI(['attrs', 'w:t']);
+ expect(logSpy).toHaveBeenCalledWith('(no attributes)');
+ });
+
+ it('attrs: prints spec lines including use/type/default/fixed/ref when present', () => {
+ getAttributes.mockReturnValue({
+ 'w:val': { use: 'optional', type: 'ST_String' },
+ 'w:color': { type: 'ST_HexColor', default: 'auto' },
+ 'w:foo': { fixed: 'bar', ref: 'w:bar' },
+ 'w:bare': {},
+ });
+ runChildrenCLI(['attrs', 'w:u']);
+
+ const lines = logSpy.mock.calls.map((c) => c[0]);
+
+ expect(lines).toContain('w:val use=optional type=ST_String');
+ expect(lines).toContain('w:color type=ST_HexColor default=auto');
+ expect(lines).toContain('w:foo fixed=bar ref=w:bar');
+ expect(lines).toContain('w:bare');
+ });
+
+ it('default: prints top-level usage and exits 2 on unknown subcommand', () => {
+ expect(() => runChildrenCLI(['wat', 'arg1'])).toThrow(ExitError);
+ const err = errSpy.mock.calls.map((c) => c[0]).join('\n');
+ expect(err).toMatch(/Usage:\n\s+ooxml children /);
+ try {
+ runChildrenCLI(['wat']);
+ } catch (e) {
+ expect(e).toBeInstanceOf(ExitError);
+ expect(e.code).toBe(2);
+ }
+ });
+});
diff --git a/packages/ooxml-inspector/src/children/get-attributes.js b/packages/ooxml-inspector/src/children/get-attributes.js
new file mode 100644
index 0000000000..2465123f58
--- /dev/null
+++ b/packages/ooxml-inspector/src/children/get-attributes.js
@@ -0,0 +1,15 @@
+import { getSchema } from './index.js';
+
+/**
+ * Return attributes map for a QName (e.g. "w:p")
+ * @param {string} qname
+ */
+export function getAttributes(qname) {
+ const schema = getSchema();
+ const entry = schema.elements[qname];
+ if (!entry) return null;
+
+ const attrs = entry.attributes || {};
+ // stable sort for predictable CLI output
+ return Object.fromEntries(Object.entries(attrs).sort(([a], [b]) => a.localeCompare(b)));
+}
diff --git a/packages/ooxml-inspector/src/children/get-attributes.test.js b/packages/ooxml-inspector/src/children/get-attributes.test.js
new file mode 100644
index 0000000000..d64a7a1a7a
--- /dev/null
+++ b/packages/ooxml-inspector/src/children/get-attributes.test.js
@@ -0,0 +1,95 @@
+import { describe, it, expect, beforeEach, vi } from 'vitest';
+
+const H = vi.hoisted(() => ({
+ getSchema: vi.fn(),
+}));
+
+// Mock the module that provides getSchema BEFORE importing the SUT
+vi.mock('./index.js', () => ({
+ getSchema: H.getSchema,
+}));
+
+import { getAttributes } from './get-attributes.js';
+
+beforeEach(() => {
+ vi.clearAllMocks();
+});
+
+describe('getAttributes(qname)', () => {
+ it('returns null when element entry is missing', () => {
+ H.getSchema.mockReturnValueOnce({ elements: {} });
+
+ const out = getAttributes('w:missing');
+ expect(H.getSchema).toHaveBeenCalledTimes(1);
+ expect(out).toBeNull();
+ });
+
+ it('returns {} when attributes are missing on the element', () => {
+ H.getSchema.mockReturnValueOnce({
+ elements: {
+ 'w:p': { children: [] }, // no attributes field
+ },
+ });
+
+ const out = getAttributes('w:p');
+ expect(H.getSchema).toHaveBeenCalledTimes(1);
+ expect(out).toEqual({});
+ });
+
+ it('returns a sorted copy of the attributes by key (stable/predictable order)', () => {
+ // Intentionally unsorted keys
+ const attrs = {
+ 'w:zeta': { type: 'xs:string' },
+ 'w:alpha': { type: 'xs:string' },
+ 'w:mid': { type: 'xs:int' },
+ };
+
+ H.getSchema.mockReturnValueOnce({
+ elements: {
+ 'w:p': { attributes: attrs },
+ },
+ });
+
+ const out = getAttributes('w:p');
+ expect(out).toEqual({
+ 'w:alpha': { type: 'xs:string' },
+ 'w:mid': { type: 'xs:int' },
+ 'w:zeta': { type: 'xs:string' },
+ });
+
+ // Returned object should not be the same reference as the source attrs
+ expect(out).not.toBe(attrs);
+ });
+
+ it('preserves attribute values while only reordering keys', () => {
+ const attrs = {
+ 'w:c': { type: 'xs:boolean', use: 'optional' },
+ 'w:a': { type: 'xs:string', default: 'x' },
+ 'w:b': { type: 'xs:int', fixed: 3 },
+ };
+
+ H.getSchema.mockReturnValueOnce({
+ elements: {
+ 'w:rPr': { attributes: attrs },
+ },
+ });
+
+ const out = getAttributes('w:rPr');
+ // Same entries, sorted by key
+ expect(Object.keys(out)).toEqual(['w:a', 'w:b', 'w:c']);
+ expect(out['w:a']).toEqual({ type: 'xs:string', default: 'x' });
+ expect(out['w:b']).toEqual({ type: 'xs:int', fixed: 3 });
+ expect(out['w:c']).toEqual({ type: 'xs:boolean', use: 'optional' });
+ });
+
+ // it('does not blow up with empty schema or missing elements key', () => {
+ // H.getSchema
+ // .mockReturnValueOnce({})
+ // .mockReturnValueOnce({ elements: null })
+ // .mockReturnValueOnce({ elements: undefined });
+
+ // expect(getAttributes('w:x')).toBeNull();
+ // expect(getAttributes('w:x')).toBeNull();
+ // expect(getAttributes('w:x')).toBeNull();
+ // });
+});
diff --git a/packages/ooxml-inspector/src/children/get-children.js b/packages/ooxml-inspector/src/children/get-children.js
new file mode 100644
index 0000000000..c1d0500240
--- /dev/null
+++ b/packages/ooxml-inspector/src/children/get-children.js
@@ -0,0 +1,42 @@
+import { allowedChildren, hasElement, getSchema } from './index.js';
+
+export const getChildren = (element) => {
+ console.debug(`Getting children for element: ${element}`);
+ if (!element) {
+ console.error('Error: Element name required');
+ console.log('Usage: node bin/ooxml children ');
+ process.exit(1);
+ }
+
+ try {
+ const children = allowedChildren(element);
+ if (children.length === 0) {
+ if (hasElement(element)) {
+ console.log(`${element} has no children (leaf element or simple content)`);
+ } else {
+ console.log(`Element ${element} not found in schema`);
+
+ // Try to suggest similar elements
+ const { elements } = getSchema();
+ const allElements = Object.keys(elements);
+ const prefix = element.split(':')[0];
+ const similar = allElements.filter((el) => el.startsWith(prefix + ':')).slice(0, 5);
+ if (similar.length > 0) {
+ console.log('\nDid you mean one of these?');
+ similar.forEach((el) => console.log(` - ${el}`));
+ }
+ }
+ } else {
+ console.log(`Allowed children for ${element}:`);
+ children.forEach((child) => console.log(` - ${child}`));
+ console.log(`\nTotal: ${children.length} allowed children`);
+ }
+ } catch (err) {
+ if (err.message.includes('No schema JSON found')) {
+ console.error('Error: Schema not found. Run generator first:');
+ console.log(' node bin/ooxml');
+ } else {
+ throw err;
+ }
+ }
+};
diff --git a/packages/ooxml-inspector/src/children/get-children.test.js b/packages/ooxml-inspector/src/children/get-children.test.js
new file mode 100644
index 0000000000..71c70928dd
--- /dev/null
+++ b/packages/ooxml-inspector/src/children/get-children.test.js
@@ -0,0 +1,126 @@
+import { describe, it, beforeEach, afterEach, expect, vi } from 'vitest';
+
+vi.mock('./index.js', () => ({
+ allowedChildren: vi.fn(),
+ hasElement: vi.fn(),
+ getSchema: vi.fn(),
+}));
+
+import { allowedChildren, hasElement, getSchema } from './index.js';
+import { getChildren } from './get-children.js';
+
+describe('getChildren CLI helper', () => {
+ let logSpy, errorSpy, exitSpy;
+
+ beforeEach(() => {
+ // fresh mocks per test
+ vi.clearAllMocks();
+ // capture console
+ logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
+ errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
+ // prevent the real process.exit from killing the test run
+ exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => {});
+ });
+
+ afterEach(() => {
+ logSpy.mockRestore();
+ errorSpy.mockRestore();
+ exitSpy.mockRestore();
+ });
+
+ it('exits with usage when no element is provided', async () => {
+ // Make exit actually stop execution
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => {
+ throw new Error('__EXIT__');
+ });
+ const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
+ const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
+
+ // Mocks to ensure we don't accidentally continue
+ const { allowedChildren } = await import('./index.js');
+
+ expect(() => getChildren(undefined)).toThrow('__EXIT__');
+
+ expect(errorSpy).toHaveBeenCalledWith('Error: Element name required');
+ expect(logSpy).toHaveBeenCalledWith('Usage: node bin/ooxml children ');
+ expect(allowedChildren).not.toHaveBeenCalled();
+
+ exitSpy.mockRestore();
+ logSpy.mockRestore();
+ errorSpy.mockRestore();
+ });
+
+ it('prints allowed children and total when children exist', () => {
+ allowedChildren.mockReturnValue(['w:r', 'w:p']);
+ getChildren('w:body');
+
+ expect(logSpy).toHaveBeenCalledWith('Allowed children for w:body:');
+ expect(logSpy).toHaveBeenCalledWith(' - w:r');
+ expect(logSpy).toHaveBeenCalledWith(' - w:p');
+ expect(logSpy).toHaveBeenCalledWith('\nTotal: 2 allowed children');
+ expect(errorSpy).not.toHaveBeenCalled();
+ expect(exitSpy).not.toHaveBeenCalled();
+ });
+
+ it('prints leaf/simple-content message when element exists but has no children', () => {
+ allowedChildren.mockReturnValue([]);
+ hasElement.mockReturnValue(true);
+
+ getChildren('w:t');
+
+ expect(logSpy).toHaveBeenCalledWith('w:t has no children (leaf element or simple content)');
+ expect(errorSpy).not.toHaveBeenCalled();
+ expect(exitSpy).not.toHaveBeenCalled();
+ });
+
+ it('prints "not found" and up to 5 suggestions for same prefix when element is unknown', () => {
+ allowedChildren.mockReturnValue([]);
+ hasElement.mockReturnValue(false);
+ // Elements order matters for slice(0, 5)
+ getSchema.mockReturnValue({
+ elements: {
+ 'w:p': [],
+ 'w:para': [],
+ 'w:r': [],
+ 'a:blip': [],
+ 'w:tbl': [],
+ 'w:tr': [],
+ 'w:tc': [],
+ },
+ });
+
+ getChildren('w:oops');
+
+ expect(logSpy).toHaveBeenCalledWith('Element w:oops not found in schema');
+ // "Did you mean one of these?" header should appear
+ expect(logSpy).toHaveBeenCalledWith('\nDid you mean one of these?');
+
+ // collect all console.log calls and count suggestion lines
+ const suggestionLines = logSpy.mock.calls.map((args) => args.join(' ')).filter((line) => line.startsWith(' - '));
+
+ // Only the first 5 "w:" keys should be listed
+ expect(suggestionLines).toEqual([' - w:p', ' - w:para', ' - w:r', ' - w:tbl', ' - w:tr']);
+
+ expect(errorSpy).not.toHaveBeenCalled();
+ expect(exitSpy).not.toHaveBeenCalled();
+ });
+
+ it('handles "No schema JSON found" by printing guidance (no throw)', () => {
+ allowedChildren.mockImplementation(() => {
+ throw new Error('No schema JSON found at dist/schema.transitional.json');
+ });
+
+ expect(() => getChildren('w:p')).not.toThrow();
+ expect(errorSpy).toHaveBeenCalledWith('Error: Schema not found. Run generator first:');
+ expect(logSpy).toHaveBeenCalledWith(' node bin/ooxml');
+ expect(exitSpy).not.toHaveBeenCalled();
+ });
+
+ it('rethrows unexpected errors', () => {
+ allowedChildren.mockImplementation(() => {
+ throw new Error('boom');
+ });
+ expect(() => getChildren('w:p')).toThrow(/boom/);
+ expect(exitSpy).not.toHaveBeenCalled();
+ });
+});
diff --git a/packages/ooxml-inspector/src/children/index.js b/packages/ooxml-inspector/src/children/index.js
new file mode 100644
index 0000000000..393dbd032f
--- /dev/null
+++ b/packages/ooxml-inspector/src/children/index.js
@@ -0,0 +1,5 @@
+export * from './get-children.js';
+export * from './lookup.js';
+export * from './schema.js';
+export * from './cli.js';
+export * from './get-attributes.js';
diff --git a/packages/ooxml-inspector/src/children/lookup.js b/packages/ooxml-inspector/src/children/lookup.js
new file mode 100644
index 0000000000..810c951e67
--- /dev/null
+++ b/packages/ooxml-inspector/src/children/lookup.js
@@ -0,0 +1,256 @@
+import { getSchema, loadSchemaSync } from './schema.js';
+
+/**
+ * @typedef {Object} SchemaOptions
+ * @property {string} [schemaPath] - Path to schema file
+ * @property {boolean} [cache] - Whether to cache schema
+ */
+
+/**
+ * @typedef {Object} ElementDefinition
+ * @property {string[]} [children] - Array of allowed child element qualified names
+ * @property {Object} [attributes] - Allowed attributes for this element
+ */
+
+/**
+ * @typedef {Object} Schema
+ * @property {Object.} elements - Map of qualified names to element definitions
+ * @property {Object.} namespaces - Map of namespace URIs to prefixes
+ */
+
+/**
+ * @typedef {Object} ValidationResult
+ * @property {boolean} ok - Whether validation passed
+ * @property {string[]} invalid - Array of invalid child qualified names
+ */
+
+/**
+ * @typedef {Object} SchemaStats
+ * @property {number} totalElements - Total number of elements in schema
+ * @property {number} elementsWithChildren - Number of elements that have children
+ * @property {number} namespaces - Number of namespaces in schema
+ * @property {Object.} byNamespace - Count of elements by namespace prefix
+ */
+
+/**
+ * @typedef {Object} AllTagsOptions
+ * @property {string|null} [prefix=null] - Filter by namespace prefix
+ * @property {boolean|null} [hasChildren=null] - Filter by whether elements have children
+ */
+
+/**
+ * Extracts the namespace prefix from a qualified name.
+ *
+ * @param {string} qname - The qualified name (e.g., 'html:div' or 'svg:circle')
+ * @returns {string} The namespace prefix, or empty string if no prefix exists
+ *
+ * @example
+ * getPrefix('html:div'); // returns 'html'
+ * getPrefix('div'); // returns ''
+ */
+export function getPrefix(qname) {
+ const i = qname.indexOf(':');
+ return i > 0 ? qname.slice(0, i) : '';
+}
+
+/**
+ * Extracts the local name from a qualified name.
+ *
+ * @param {string} qname - The qualified name (e.g., 'html:div' or 'svg:circle')
+ * @returns {string} The local name part of the qualified name
+ *
+ * @example
+ * getLocalName('html:div'); // returns 'div'
+ * getLocalName('div'); // returns 'div'
+ */
+export function getLocalName(qname) {
+ const i = qname.indexOf(':');
+ return i > 0 ? qname.slice(i + 1) : qname;
+}
+
+/**
+ * Gets the list of allowed child elements for a given parent element.
+ *
+ * @param {string} qname - The qualified name of the parent element
+ * @param {SchemaOptions} [opts] - Schema loading options
+ * @returns {string[]} Array of qualified names of allowed child elements
+ *
+ * @example
+ * allowedChildren('html:ul', opts); // returns ['html:li']
+ */
+export function allowedChildren(qname, opts) {
+ const { elements } = getSchema(opts);
+ const def = elements?.[qname];
+ return def?.children ?? [];
+}
+
+/**
+ * Checks if a child element is allowed under a parent element.
+ *
+ * @param {string} parent - The qualified name of the parent element
+ * @param {string} child - The qualified name of the child element
+ * @param {SchemaOptions} [opts] - Schema loading options
+ * @returns {boolean} True if the child is allowed under the parent
+ *
+ * @example
+ * isAllowedChild('html:ul', 'html:li', opts); // returns true
+ * isAllowedChild('html:ul', 'html:div', opts); // returns false
+ */
+export function isAllowedChild(parent, child, opts) {
+ const kids = allowedChildren(parent, opts);
+ return kids.includes(child);
+}
+
+/**
+ * Validates a list of child elements against a parent element's allowed children.
+ * Performs a shallow validation check.
+ *
+ * @param {string} parent - The qualified name of the parent element
+ * @param {string[]} childList - Array of qualified names of child elements to validate
+ * @param {SchemaOptions} [opts] - Schema loading options
+ * @returns {ValidationResult} Validation result with ok status and invalid children
+ *
+ * @example
+ * validateChildren('html:ul', ['html:li', 'html:div'], opts);
+ * // returns { ok: false, invalid: ['html:div'] }
+ */
+export function validateChildren(parent, childList, opts) {
+ const allowed = new Set(allowedChildren(parent, opts));
+ const invalid = childList.filter((c) => !allowed.has(c));
+ return { ok: invalid.length === 0, invalid };
+}
+
+/**
+ * Gets all elements that belong to a specific namespace.
+ *
+ * @param {string} namespace - The namespace URI to filter by
+ * @param {SchemaOptions} [opts] - Schema loading options
+ * @returns {string[]} Array of local names (without prefix) of elements in the namespace
+ *
+ * @example
+ * getElementsByNamespace('http://www.w3.org/1999/xhtml', opts);
+ * // returns ['div', 'span', 'p', ...]
+ */
+export function getElementsByNamespace(namespace, opts) {
+ const { elements, namespaces } = getSchema(opts);
+ const prefix = namespaces[namespace];
+ if (!prefix) return [];
+ return Object.keys(elements)
+ .filter((qn) => qn.startsWith(prefix + ':'))
+ .map(getLocalName);
+}
+
+/**
+ * Checks if an element exists in the schema.
+ *
+ * @param {string} qname - The qualified name of the element to check
+ * @param {SchemaOptions} [opts] - Schema loading options
+ * @returns {boolean} True if the element exists in the schema
+ *
+ * @example
+ * hasElement('html:div', opts); // returns true
+ * hasElement('fake:element', opts); // returns false
+ */
+export function hasElement(qname, opts) {
+ const { elements } = getSchema(opts);
+ return Object.prototype.hasOwnProperty.call(elements, qname);
+}
+
+/**
+ * Generates statistics about the loaded schema.
+ *
+ * @param {SchemaOptions} [opts] - Schema loading options
+ * @returns {SchemaStats} Object containing various statistics about the schema
+ *
+ * @example
+ * getSchemaStats(opts);
+ * // returns {
+ * // totalElements: 150,
+ * // elementsWithChildren: 75,
+ * // namespaces: 3,
+ * // byNamespace: { 'html': 120, 'svg': 25, 'math': 5 }
+ * // }
+ */
+export function getSchemaStats(opts) {
+ const { elements, namespaces } = getSchema(opts);
+ const stats = {
+ totalElements: Object.keys(elements).length,
+ elementsWithChildren: 0,
+ namespaces: Object.keys(namespaces).length,
+ byNamespace: {},
+ };
+
+ for (const [qname, def] of Object.entries(elements)) {
+ if ((def?.children?.length ?? 0) > 0) stats.elementsWithChildren++;
+ const pfx = getPrefix(qname);
+ if (pfx) stats.byNamespace[pfx] = (stats.byNamespace[pfx] || 0) + 1;
+ // note: attributes available at def.attributes if you need them elsewhere
+ }
+
+ return stats;
+}
+
+/**
+ * Gets the allowed child elements for a given element using synchronous schema loading.
+ *
+ * @param {string} qname - The qualified name of the parent element
+ * @returns {string[]} Array of qualified names of allowed child elements
+ *
+ * @example
+ * childrenOf('html:ul'); // returns ['html:li']
+ */
+export function childrenOf(qname) {
+ const { elements } = loadSchemaSync();
+ return elements?.[qname]?.children ?? [];
+}
+
+/**
+ * Gets all element tags from the schema with optional filtering.
+ * Uses synchronous schema loading.
+ *
+ * @param {AllTagsOptions} [options={}] - Filtering options
+ * @param {string|null} [options.prefix=null] - Filter by namespace prefix (with or without colon)
+ * @param {boolean|null} [options.hasChildren=null] - Filter by whether elements have children
+ * @returns {string[]} Sorted array of qualified element names matching the filters
+ *
+ * @example
+ * allTags(); // returns all tags
+ * allTags({ prefix: 'html' }); // returns only HTML tags
+ * allTags({ hasChildren: true }); // returns only tags that can have children
+ * allTags({ prefix: 'svg', hasChildren: false }); // returns SVG leaf elements
+ */
+export function allTags({ prefix = null, hasChildren = null } = {}) {
+ const { elements } = loadSchemaSync();
+ let tags = Object.keys(elements).sort();
+
+ if (prefix) {
+ const p = prefix.endsWith(':') ? prefix : `${prefix}:`;
+ tags = tags.filter((t) => t.startsWith(p));
+ }
+
+ if (hasChildren !== null) {
+ tags = tags.filter((t) => {
+ const n = elements[t]?.children?.length ?? 0;
+ return hasChildren ? n > 0 : n === 0;
+ });
+ }
+
+ return tags;
+}
+
+/**
+ * Gets all namespace mappings from the schema.
+ * Uses synchronous schema loading.
+ *
+ * @returns {Object.} Object mapping namespace URIs to prefixes
+ *
+ * @example
+ * namespaces();
+ * // returns {
+ * // 'http://www.w3.org/1999/xhtml': 'html',
+ * // 'http://www.w3.org/2000/svg': 'svg'
+ * // }
+ */
+export function namespaces() {
+ return loadSchemaSync().namespaces;
+}
diff --git a/packages/ooxml-inspector/src/children/lookup.test.js b/packages/ooxml-inspector/src/children/lookup.test.js
new file mode 100644
index 0000000000..8a31528350
--- /dev/null
+++ b/packages/ooxml-inspector/src/children/lookup.test.js
@@ -0,0 +1,250 @@
+import { describe, it, expect, beforeEach, vi } from 'vitest';
+
+vi.mock('./schema.js', () => {
+ return {
+ getSchema: vi.fn(),
+ loadSchemaSync: vi.fn(),
+ };
+});
+
+import {
+ getPrefix,
+ getLocalName,
+ allowedChildren,
+ isAllowedChild,
+ validateChildren,
+ getElementsByNamespace,
+ hasElement,
+ getSchemaStats,
+ childrenOf,
+ allTags,
+ namespaces,
+} from './lookup.js';
+
+import { getSchema, loadSchemaSync } from './schema.js';
+
+const makeSchema = (overrides = {}) => ({
+ elements: {
+ 'html:ul': { children: ['html:li'] },
+ 'html:li': { children: [] },
+ 'html:div': { children: ['html:span', 'html:div'] },
+ 'html:span': { children: [] },
+ 'svg:svg': { children: ['svg:g', 'svg:rect'] },
+ 'svg:g': { children: [] },
+ 'svg:rect': { children: [] },
+ 'math:math': { children: [] },
+ nopfx: { children: ['nopfx-child'] }, // demonstrates no prefix
+ 'nopfx-child': { children: [] },
+ // element with attributes but no children array:
+ 'html:img': { attributes: { src: 'string' } },
+ ...overrides.elements,
+ },
+ namespaces: {
+ 'http://www.w3.org/1999/xhtml': 'html',
+ 'http://www.w3.org/2000/svg': 'svg',
+ 'http://www.w3.org/1998/Math/MathML': 'math',
+ ...overrides.namespaces,
+ },
+});
+
+describe('lookup helpers', () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ describe('getPrefix', () => {
+ it('returns prefix when present', () => {
+ expect(getPrefix('html:div')).toBe('html');
+ expect(getPrefix('svg:rect')).toBe('svg');
+ });
+ it('returns empty string when no colon', () => {
+ expect(getPrefix('div')).toBe('');
+ expect(getPrefix('')).toBe('');
+ });
+ });
+
+ describe('getLocalName', () => {
+ it('returns local part with prefix', () => {
+ expect(getLocalName('html:div')).toBe('div');
+ expect(getLocalName('svg:rect')).toBe('rect');
+ });
+ it('returns whole string when no prefix', () => {
+ expect(getLocalName('div')).toBe('div');
+ });
+ });
+
+ describe('allowedChildren', () => {
+ it('returns children array when present', () => {
+ const schema = makeSchema();
+ getSchema.mockReturnValue(schema);
+ expect(allowedChildren('html:ul')).toEqual(['html:li']);
+ expect(allowedChildren('html:div')).toEqual(['html:span', 'html:div']);
+ });
+ it('returns empty array when element not found', () => {
+ getSchema.mockReturnValue(makeSchema());
+ expect(allowedChildren('html:table')).toEqual([]);
+ });
+ it('returns empty array when element has no children array', () => {
+ getSchema.mockReturnValue(makeSchema());
+ expect(allowedChildren('html:img')).toEqual([]);
+ });
+ });
+
+ describe('isAllowedChild', () => {
+ it('true for valid child; false otherwise', () => {
+ getSchema.mockReturnValue(makeSchema());
+ expect(isAllowedChild('html:ul', 'html:li')).toBe(true);
+ expect(isAllowedChild('html:ul', 'html:div')).toBe(false);
+ expect(isAllowedChild('html:img', 'html:span')).toBe(false);
+ });
+ });
+
+ describe('validateChildren', () => {
+ it('flags invalid children only', () => {
+ getSchema.mockReturnValue(makeSchema());
+ const res = validateChildren('html:div', ['html:span', 'html:div', 'html:li']);
+ expect(res.ok).toBe(false);
+ expect(res.invalid).toEqual(['html:li']);
+ });
+ it('ok when all valid', () => {
+ getSchema.mockReturnValue(makeSchema());
+ const res = validateChildren('html:ul', ['html:li']);
+ expect(res.ok).toBe(true);
+ expect(res.invalid).toEqual([]);
+ });
+ it('ok when no children to check', () => {
+ getSchema.mockReturnValue(makeSchema());
+ const res = validateChildren('html:img', []);
+ expect(res.ok).toBe(true);
+ expect(res.invalid).toEqual([]);
+ });
+ });
+
+ describe('getElementsByNamespace', () => {
+ it('returns local names for matching namespace', () => {
+ getSchema.mockReturnValue(makeSchema());
+ const out = getElementsByNamespace('http://www.w3.org/2000/svg');
+ // svg elements present: svg, g, rect
+ expect(out.sort()).toEqual(['g', 'rect', 'svg']);
+ });
+ it('returns empty for unknown namespace', () => {
+ getSchema.mockReturnValue(makeSchema());
+ expect(getElementsByNamespace('http://unknown/')).toEqual([]);
+ });
+ it('handles no elements gracefully', () => {
+ getSchema.mockReturnValue({ elements: {}, namespaces: { x: 'x' } });
+ expect(getElementsByNamespace('x')).toEqual([]);
+ });
+ });
+
+ describe('hasElement', () => {
+ it('true when element exists', () => {
+ getSchema.mockReturnValue(makeSchema());
+ expect(hasElement('html:ul')).toBe(true);
+ });
+ it('false when element missing', () => {
+ getSchema.mockReturnValue(makeSchema());
+ expect(hasElement('html:table')).toBe(false);
+ });
+ });
+
+ describe('getSchemaStats', () => {
+ it('computes totals, elementsWithChildren, namespaces, and byNamespace', () => {
+ const schema = makeSchema();
+ getSchema.mockReturnValue(schema);
+
+ const s = getSchemaStats();
+ // total elements is count of keys in elements
+ expect(s.totalElements).toBe(Object.keys(schema.elements).length);
+
+ // elements with children > 0
+ const expectedWithChildren = Object.values(schema.elements).filter(
+ (def) => (def.children?.length ?? 0) > 0,
+ ).length;
+ expect(s.elementsWithChildren).toBe(expectedWithChildren);
+
+ // namespaces count is keys in namespaces
+ expect(s.namespaces).toBe(Object.keys(schema.namespaces).length);
+
+ // byNamespace counts by prefix present in qname
+ const expectedByNs = {};
+ for (const qn of Object.keys(schema.elements)) {
+ const p = qn.includes(':') ? qn.split(':')[0] : '';
+ if (p) expectedByNs[p] = (expectedByNs[p] || 0) + 1;
+ }
+ expect(s.byNamespace).toEqual(expectedByNs);
+ });
+
+ it('handles empty schema structures', () => {
+ getSchema.mockReturnValue({ elements: {}, namespaces: {} });
+ const s = getSchemaStats();
+ expect(s).toEqual({
+ totalElements: 0,
+ elementsWithChildren: 0,
+ namespaces: 0,
+ byNamespace: {},
+ });
+ });
+ });
+
+ describe('childrenOf (sync path)', () => {
+ it('uses loadSchemaSync and returns children', () => {
+ const schema = makeSchema();
+ loadSchemaSync.mockReturnValue(schema);
+ expect(childrenOf('svg:svg')).toEqual(['svg:g', 'svg:rect']);
+ expect(childrenOf('html:img')).toEqual([]); // no children array
+ expect(childrenOf('missing:el')).toEqual([]);
+ });
+ });
+
+ describe('allTags (sync path)', () => {
+ it('returns all tags sorted by default', () => {
+ const schema = makeSchema();
+ loadSchemaSync.mockReturnValue(schema);
+ const out = allTags();
+ const expected = Object.keys(schema.elements).sort();
+ expect(out).toEqual(expected);
+ });
+
+ it('filters by prefix (with or without colon)', () => {
+ loadSchemaSync.mockReturnValue(makeSchema());
+ const htmlA = allTags({ prefix: 'html' });
+ const htmlB = allTags({ prefix: 'html:' });
+ expect(htmlA).toEqual(htmlB);
+ expect(htmlA.every((t) => t.startsWith('html:'))).toBe(true);
+ });
+
+ it('filters by hasChildren = true', () => {
+ loadSchemaSync.mockReturnValue(makeSchema());
+ const out = allTags({ hasChildren: true });
+ expect(out.length).toBeGreaterThan(0);
+ expect(out.every((t) => (loadSchemaSync().elements[t]?.children?.length ?? 0) > 0)).toBe(true);
+ });
+
+ it('filters by hasChildren = false', () => {
+ loadSchemaSync.mockReturnValue(makeSchema());
+ const out = allTags({ hasChildren: false });
+ expect(out.length).toBeGreaterThan(0);
+ expect(out.every((t) => (loadSchemaSync().elements[t]?.children?.length ?? 0) === 0)).toBe(true);
+ });
+
+ it('combines prefix and hasChildren filters', () => {
+ loadSchemaSync.mockReturnValue(makeSchema());
+ const out = allTags({ prefix: 'svg', hasChildren: false });
+ expect(out.every((t) => t.startsWith('svg:'))).toBe(true);
+ expect(out.every((t) => (loadSchemaSync().elements[t]?.children?.length ?? 0) === 0)).toBe(true);
+ });
+ });
+
+ describe('namespaces (sync path)', () => {
+ it('returns namespaces from sync schema', () => {
+ const schema = makeSchema();
+ loadSchemaSync.mockReturnValue(schema);
+ expect(namespaces()).toEqual(schema.namespaces);
+ });
+ it('works with empty namespaces', () => {
+ loadSchemaSync.mockReturnValue({ elements: {}, namespaces: {} });
+ expect(namespaces()).toEqual({});
+ });
+ });
+});
diff --git a/packages/ooxml-inspector/src/children/schema.js b/packages/ooxml-inspector/src/children/schema.js
new file mode 100644
index 0000000000..ee629541b7
--- /dev/null
+++ b/packages/ooxml-inspector/src/children/schema.js
@@ -0,0 +1,13 @@
+import schemaJson from '../../dist/schema.transitional.json' with { type: 'json' };
+
+let CACHE = null;
+
+/** Return the OOXML schema (bundled JSON). */
+export function getSchema() {
+ return (CACHE ??= schemaJson);
+}
+
+/** Legacy sync loader: just return the bundled JSON in runtime. */
+export function loadSchemaSync() {
+ return getSchema();
+}
diff --git a/packages/ooxml-inspector/src/cli.js b/packages/ooxml-inspector/src/cli.js
new file mode 100644
index 0000000000..7fe28b51b7
--- /dev/null
+++ b/packages/ooxml-inspector/src/cli.js
@@ -0,0 +1,20 @@
+#!/usr/bin/env node
+import { runGenerator } from '../generator/src/index.js';
+import { runChildrenCLI } from './children/index.js';
+
+const [, , cmd, ...rest] = process.argv;
+
+switch (cmd) {
+ case undefined:
+ runGenerator();
+ break;
+ case 'children':
+ case 'tags':
+ case 'namespaces':
+ case 'attrs':
+ runChildrenCLI([cmd, ...rest]);
+ break;
+ default:
+ console.error(`Unknown command: ${cmd}`);
+ process.exit(2);
+}
diff --git a/packages/ooxml-inspector/src/index.js b/packages/ooxml-inspector/src/index.js
new file mode 100644
index 0000000000..fbef3e3d1f
--- /dev/null
+++ b/packages/ooxml-inspector/src/index.js
@@ -0,0 +1,3 @@
+import { childrenOf } from './children/index.js';
+
+export { childrenOf };
diff --git a/packages/ooxml-inspector/tsconfig.json b/packages/ooxml-inspector/tsconfig.json
new file mode 100644
index 0000000000..e294c5fde2
--- /dev/null
+++ b/packages/ooxml-inspector/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "checkJs": true,
+ "allowJs": true,
+
+ "module": "NodeNext",
+ "moduleResolution": "NodeNext",
+
+ "target": "ES2020",
+ "lib": ["ES2020"],
+ "types": ["node"],
+
+ "skipLibCheck": true,
+ "declaration": true,
+ "emitDeclarationOnly": true,
+ "resolveJsonModule": true,
+ "esModuleInterop": true,
+ "outDir": "dist",
+ "baseUrl": "."
+ },
+ "exclude": ["node_modules", "dist", "**/*.test.js"]
+}
diff --git a/packages/ooxml-inspector/vitest.config.js b/packages/ooxml-inspector/vitest.config.js
new file mode 100644
index 0000000000..cae1aa6c36
--- /dev/null
+++ b/packages/ooxml-inspector/vitest.config.js
@@ -0,0 +1,44 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ include: ['**/*.test.js'],
+ environment: 'node',
+ exclude: [
+ 'node_modules/**',
+ '**/node_modules/**',
+ '**/dist/**',
+ 'coverage/**',
+ '**/example/**',
+ 'generator/types/**',
+ ],
+ coverage: {
+ provider: 'v8',
+ reportsDirectory: 'coverage',
+ reporter: ['text', 'html', 'lcov'],
+ all: false,
+ exclude: [
+ // always ignore deps + build outputs
+ 'node_modules/**',
+ '**/node_modules/**',
+ '**/dist/**',
+ '**/*.d.ts',
+ 'coverage/**',
+
+ // tsup helper assets sometimes appear via dep graph
+ '**/node_modules/tsup/**',
+
+ // config & metadata
+ 'vitest.config.*',
+ '**/constants.js',
+
+ 'packages/**/src/index.js',
+ 'packages/**/src/cli.js',
+
+ // ignore examples
+ 'packages/**/example/**',
+ 'generator/types/**',
+ ],
+ },
+ },
+});
diff --git a/packages/super-editor/package.json b/packages/super-editor/package.json
index 8b62a5977a..c3a0b6e680 100644
--- a/packages/super-editor/package.json
+++ b/packages/super-editor/package.json
@@ -48,6 +48,7 @@
"pack": "rm *.tgz 2>/dev/null || true && npm run build && npm pack && mv harbour-enterprises-super-editor-0.0.1-alpha.0.tgz ./super-editor.tgz"
},
"dependencies": {
+ "@superdoc-dev/ooxml-inspector": "^1.0.0",
"color2k": "^2.0.3",
"eventemitter3": "^5.0.1",
"he": "^1.2.0",
@@ -85,6 +86,7 @@
"@vue/test-utils": "^2.4.6",
"postcss-nested": "^6.0.1",
"postcss-nested-import": "^1.3.0",
+ "prosemirror-test-builder": "^1.1.1",
"tippy.js": "^6.3.7",
"typescript": "^5.7.3",
"vite": "^6.3.5",
diff --git a/packages/super-editor/src/components/SuperEditor.vue b/packages/super-editor/src/components/SuperEditor.vue
index c694365016..12df559869 100644
--- a/packages/super-editor/src/components/SuperEditor.vue
+++ b/packages/super-editor/src/components/SuperEditor.vue
@@ -1,6 +1,6 @@