feat: integrate XSLT Tools with toolbox portal
This commit is contained in:
89
README.md
89
README.md
@@ -1,6 +1,12 @@
|
||||
# XSLT tools
|
||||
|
||||
Browser-only MVP for testing local XML/XSLT transformations. Nothing is uploaded; the app uses browser APIs, LocalStorage, and local file open/save dialogs where available.
|
||||
Browser-based MVP for testing XML/XSLT transformations. The application itself
|
||||
does not intentionally upload opened files, and it uses LocalStorage plus local
|
||||
file dialogs where available. XSLT is executable code, however: a trusted
|
||||
stylesheet may access browser or network resources, so processing is not
|
||||
described as guaranteed local-only.
|
||||
|
||||
The application is independently deployable and also implements Toolbox Contract v1. When launched with a same-origin `?toolbox=<catalog URL>` context, the shared application shell adds toolbox navigation and an application switcher; without that context, the same build runs standalone.
|
||||
|
||||
## Features in this MVP
|
||||
|
||||
@@ -17,6 +23,9 @@ Browser-only MVP for testing local XML/XSLT transformations. Nothing is uploaded
|
||||
- Transformation engines:
|
||||
- SaxonJS 2.7 as the default engine for XSLT 1.0/2.0/3.0-style workflows
|
||||
- Browser-native `XSLTProcessor` as a lightweight XSLT 1.0 fallback
|
||||
- A mandatory SHA-256 trust confirmation for the exact executable stylesheet;
|
||||
every edit, replacement, format, or reset revokes trust for both engines
|
||||
- Defense-in-depth input/output limits and a best-effort asynchronous deadline
|
||||
- XML and XSLT well-formedness checks
|
||||
- Basic XSLT root/version checks
|
||||
- Snippet toolbox for common XSLT constructs
|
||||
@@ -27,12 +36,34 @@ Browser-only MVP for testing local XML/XSLT transformations. Nothing is uploaded
|
||||
- Confirmation dialog before destructive overwrites
|
||||
- LocalStorage persistence
|
||||
- Approximate “explain transformation” table after a run
|
||||
- Shared toolbox shell with standalone fallback, application switching, and the XSLT-specific Help action
|
||||
- Relocatable static output for deployment at root or nested paths
|
||||
|
||||
## SaxonJS note
|
||||
|
||||
SaxonJS is bundled through the `saxon-js` npm package and loaded lazily when the SaxonJS engine runs. The browser build may show Vite warnings about Node modules such as `fs`, `path`, or `stream` being externalized. Those warnings come from the package containing Node.js support as well; the app does not use file-based SaxonJS APIs in the browser.
|
||||
SaxonJS 2.7 is vendored as the unmodified browser distribution file at `public/vendor/saxon/SaxonJS2.js` and loaded lazily when the SaxonJS engine runs. It is not bundled from the npm package during the application build.
|
||||
|
||||
SaxonJS itself is free to use but not open source. Check `node_modules/saxon-js/LICENSE.txt` after installation before distributing a packaged version.
|
||||
SaxonJS is available free of charge but is not open source. Its separate redistribution terms are preserved at `public/vendor/saxon/LICENSE.txt`. Release archives include that notice as `LICENSES/SaxonJS-LICENSE.txt` alongside `LICENSES/xslt-tools-LICENSE.txt` for the AGPL-3.0-only application; do not describe the complete archive as AGPL-only.
|
||||
|
||||
## Executable stylesheet security
|
||||
|
||||
Treat every stylesheet like executable code. Transformation is disabled until
|
||||
the user reviews a warning and trusts the SHA-256 fingerprint of the exact
|
||||
current stylesheet. Trust is session-only and tied to both the content hash and
|
||||
an edit revision; changing and then reverting text still requires another
|
||||
confirmation. The same gate covers SaxonJS and native `XSLTProcessor`.
|
||||
|
||||
The application enforces conservative input/output limits and a best-effort
|
||||
asynchronous deadline, but transformations are not isolated from the browser or
|
||||
network and synchronous CPU exhaustion cannot be forcibly stopped. A trusted
|
||||
SaxonJS stylesheet may read data stored by other Toolbox apps on the same site,
|
||||
including PDF workspaces and portal preferences, then send it over the network
|
||||
or navigate the page away.
|
||||
|
||||
When served with the recommended portal CSP, cross-origin fetches and dynamic
|
||||
JavaScript evaluation are restricted without granting `unsafe-eval`. CSP is
|
||||
defense in depth, not complete containment. Only execute stylesheets from trusted
|
||||
sources.
|
||||
|
||||
## Run locally
|
||||
|
||||
@@ -50,6 +81,45 @@ npm run build
|
||||
npm run preview
|
||||
```
|
||||
|
||||
Vite uses `base: './'`, so a single build can be hosted at an unknown nested path such as `/apps/xslt/`. The SaxonJS runtime is resolved from that application base as well.
|
||||
|
||||
## Toolbox manifest
|
||||
|
||||
`src/toolboxApp.ts` is the typed source for both the shared shell and the published `public/toolbox-app.json` manifest. Keep the generated file current with:
|
||||
|
||||
```bash
|
||||
npm run manifest:generate
|
||||
npm run manifest:check
|
||||
```
|
||||
|
||||
Toolbox mode is contextual rather than a separate build:
|
||||
|
||||
```text
|
||||
/apps/xslt/ standalone
|
||||
/apps/xslt/?toolbox=/toolbox.catalog.json toolbox mode
|
||||
```
|
||||
|
||||
An unavailable or invalid catalogue falls back to standalone operation.
|
||||
|
||||
## Release archive
|
||||
|
||||
After a successful build, create the deterministic application ZIP and SHA-256 sidecar with:
|
||||
|
||||
```bash
|
||||
npm run release
|
||||
```
|
||||
|
||||
The command refuses to overwrite a same-version archive. Use
|
||||
`npm run release -- --force` only when intentionally replacing it.
|
||||
|
||||
The archive contains the static app and `toolbox-app.json`, plus `CHANGELOG.md`,
|
||||
`SOURCE.md` with the corresponding tagged source link,
|
||||
`THIRD_PARTY_NOTICES.md`, the application licence at
|
||||
`LICENSES/xslt-tools-LICENSE.txt`, the separate vendored SaxonJS licence, and
|
||||
licence/notice files for every installed production npm dependency below
|
||||
`LICENSES/npm/`. Generated artifacts are written below `release/` and are not
|
||||
committed.
|
||||
|
||||
## Suggested next steps
|
||||
|
||||
1. Add parameter handling for `xsl:param`.
|
||||
@@ -63,12 +133,13 @@ npm run preview
|
||||
|
||||
```text
|
||||
src/
|
||||
├── components/ # Layout, toolbar, editor panels, dialogs
|
||||
├── components/ # Toolbar, editor panels, dialogs, and app-specific actions
|
||||
├── editor/ # CodeMirror integration and XSLT snippets
|
||||
├── file/ # Local file open/save helpers
|
||||
├── transform/ # Transform engine abstraction, SaxonJS, native engine
|
||||
├── validation/ # XML/XSLT validation helpers
|
||||
└── workspace/ # LocalStorage-backed workbench state
|
||||
├── workspace/ # LocalStorage-backed workbench state
|
||||
└── toolboxApp.ts # Toolbox manifest and shared-shell application definition
|
||||
```
|
||||
|
||||
## Development checks
|
||||
@@ -89,6 +160,9 @@ npm run format:check # Prettier check
|
||||
npm run format # Prettier write
|
||||
npm run test # Vitest/jsdom test suite
|
||||
npm run build # Production build
|
||||
npm run smoke:static # Nested-path static build smoke test
|
||||
npm run smoke:toolbox # Contract, asset, standalone, and contextual checks
|
||||
npm run release # Deterministic ZIP and SHA-256 release artifacts
|
||||
npm run clean # Remove generated build/cache files
|
||||
```
|
||||
|
||||
@@ -98,7 +172,8 @@ The vendored SaxonJS browser file is intentionally excluded from ESLint and Pret
|
||||
|
||||
The app currently exposes two engines:
|
||||
|
||||
- **SaxonJS 2 dynamic XSLT 3.0**: default engine. It lazy-loads `public/vendor/saxon/SaxonJS2.js`, compiles raw XSLT text to SEF in the browser, then executes the generated SEF locally.
|
||||
- **SaxonJS 2 dynamic XSLT 3.0**: default engine. It loads the vendored `public/vendor/saxon/SaxonJS2.js`, compiles raw XSLT text to SEF in the browser, then executes the generated SEF after explicit trust confirmation.
|
||||
- **Native browser XSLTProcessor**: XSLT 1.0 fallback using the browser implementation.
|
||||
|
||||
The SaxonJS runtime is loaded only when a Saxon transformation is requested, so the initial app shell does not block on the large compiler/runtime file.
|
||||
The SaxonJS runtime is loaded only for a trusted Saxon transformation, so the
|
||||
initial app shell does not block on the large compiler/runtime file.
|
||||
|
||||
Reference in New Issue
Block a user