diff --git a/.github/instructions/general.instructions.md b/.github/instructions/general.instructions.md new file mode 100644 index 0000000000..7ddd034b53 --- /dev/null +++ b/.github/instructions/general.instructions.md @@ -0,0 +1,135 @@ +--- +applyTo: "**" +--- +# HPCC Visualization Framework - GitHub Copilot Instructions + +## Project Overview + +This is the **HPCC Visualization Framework** (also known as "Viz Framework 2.0"), a TypeScript/JavaScript-based data visualization library that provides comprehensive charting, graphing, and dashboard capabilities. The project is published as scoped NPM packages under `@hpcc-js`. + +## VSCode Terminal +- **Use the built-in git bash terminal** in VSCode for all commands + +## Architecture & Structure + +### Monorepo Organization +- **Lerna-based monorepo** with packages in `/packages/` directory +- Each package has its own `package.json`, build configuration, and TypeScript setup +- Packages are published independently to NPM under the `@hpcc-js/` scope +- Use `npm` commands in the root folder for common actions like `clean`, `build` and `lint` +- All sources code is written in TypeScript + +### Build System +- **Vite** is the primary compiler + bundler for all packages +- **Support for multiple module formats**: ESM + UMD +- **Source maps** are generated for all builds + +### Key Dependencies & Patterns +- **D3.js ecosystem** - Core visualization dependency, aliased through `@hpcc-js/common` +- **Widget pattern** - Most components extend base Widget classes +- **Property-driven APIs** - Components use property setters/getters for configuration +- **TypeScript interfaces** - Strong typing with API interfaces in `@hpcc-js/api` package + +## Package Categories + +### Core Packages +- **`@hpcc-js/common`** - Base widgets, utilities, and D3 re-exports +- **`@hpcc-js/api`** - TypeScript interfaces and API definitions +- **`@hpcc-js/util`** - Utility functions and helpers + +### Visualization Packages +- **`@hpcc-js/chart`** - Charts (Bar, Line, Pie, Scatter, etc.) +- **`@hpcc-js/graph`** - Graph visualizations and network diagrams +- **`@hpcc-js/map`** - Geographic visualizations with Leaflet integration +- **`@hpcc-js/tree`** - Tree and hierarchy visualizations +- **`@hpcc-js/timeline`** - Timeline and temporal visualizations + +### UI & Layout Packages +- **`@hpcc-js/layout`** - Layout containers and dashboard components +- **`@hpcc-js/form`** - Form controls and input widgets +- **`@hpcc-js/html`** - HTML-based components and React integration + +### Integration Packages +- **`@hpcc-js/marshaller`** - Data marshalling and dashboard orchestration +- **`@hpcc-js/comms`** - Communication with HPCC Systems platform +- **`@hpcc-js/codemirror`** - Code editors for various languages + +## Coding Standards & Conventions + +### TypeScript +- Use **strict TypeScript** configuration +- Export all public APIs through `index.ts` files +- Import from `@hpcc-js/*` packages, not from internal paths +- Use proper typing with interfaces from `@hpcc-js/api` + +### Class Structure +- Extend appropriate base classes (`Widget`, `SVGWidget`, `HTMLWidget`) +- Use property decorators for configurable properties +- Follow the Widget lifecycle: `enter()`, `update()`, `exit()` +- Implement proper `render()` methods + +### CSS & Styling +- Use CSS classes with package-specific prefixes +- Bundle CSS through PostCSS in Rollup configuration +- Support theming through CSS custom properties +- Minimize CSS in production builds + +### Dependencies +- **Avoid direct D3 imports** - use re-exports from `@hpcc-js/common` +- Use rollup aliases to map D3 modules to `@hpcc-js/common` +- External dependencies should be added to rollup `external` configuration +- Use the `@hpcc-js/bundle` for consistent external/globals configuration + +## Testing & Development + +### Test Structure +- Tests are in `/tests/` directory organized by package +- Use Vitest as the test runner +- Browser and Node.js test configurations in `vitest.workspace.ts` +- Visual regression testing for visualization components + +### Demo Applications +- `/demos/gallery/` - Interactive gallery with live code examples +- `/demos/imdb/` - Real-world application example +- Use SystemJS for dynamic module loading in demos + +### Development Workflow +- Use `npm run build` to build all packages +- Use `lerna run ` for package-specific operations +- Follow semantic versioning for releases +- Use conventional commits for changelog generation + +## Browser & Module Support + +### Target Environments +- **Modern browsers** (IE 11+, Chrome, Firefox, Edge) +- **Multiple module systems**: UMD, CommonJS, AMD, ES6 +- **CDN delivery** via unpkg with IIFE builds +- **Bundler compatibility** (Webpack, Rollup, Parcel) + +### Bundle Configuration +- Use `@hpcc-js/bundle` for consistent externals/globals +- Generate both development and minified builds +- Include source maps for debugging +- Support tree-shaking with ES6 modules + +## Common Tasks & Patterns + +When working with this codebase: + +1. **Adding new visualizations**: Extend appropriate base widget class, implement required interfaces +2. **Package dependencies**: Always use the monorepo's shared dependencies and build configuration +3. **CSS styling**: Use PostCSS processing and minimize for production +4. **Data handling**: Follow the property-driven API pattern for data binding +5. **TypeScript**: Maintain strict typing and export proper interfaces +6. **Testing**: Include both unit tests and visual regression tests +7. **Documentation**: Update gallery examples and README files +8. **Build configuration**: Use consistent Rollup setup across packages + +## HPCC Platform Integration + +This framework is designed to work with the **HPCC Systems** big data platform: +- ECL (Enterprise Control Language) integration +- Roxie query integration through `@hpcc-js/comms` +- Workunit result visualization +- ESP (Enterprise Services Platform) connectivity diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index eeb543004d..2c7e36ea31 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -5,7 +5,7 @@ on: - candidate-* pull_request: - branches: + branches: - trunk - candidate-* @@ -44,7 +44,7 @@ jobs: - name: Install OS Dependencies if: ${{ github.event_name == 'pull_request' || steps.release.outputs.release_created }} run: | - pip install pandas scikit-learn + pip install pandas scikit-learn - name: Export GitHub Actions cache environment variables if: ${{ github.event_name == 'pull_request' || steps.release.outputs.release_created }} @@ -90,6 +90,10 @@ jobs: CI: true run: | npm run test + npm run test-browser-esm + npm run test-browser-umd + npm run test-node-esm + npm run test-node-cjs # - name: Calculate Coverage # if: ${{ steps.release.outputs.release_created }} @@ -110,7 +114,7 @@ jobs: git remote add gh-token "https://${{ secrets.GITHUB_TOKEN}}@github.com/yargs/yargs.git" git commit -a -m 'chore: stamp files for release' git push origin - + - name: Publish if: ${{ steps.release.outputs.release_created }} env: diff --git a/README.md b/README.md index c08e3fc8eb..55dc30c1ef 100644 --- a/README.md +++ b/README.md @@ -3,92 +3,94 @@ ![Test PR](https://github.com/hpcc-systems/Visualization/workflows/Test%20PR/badge.svg) [![Join the chat at https://gitter.im/hpcc-systems/Visualization](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hpcc-systems/Visualization?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +The **HPCC Visualization Framework** is a comprehensive TypeScript/JavaScript-based data visualization library that provides charting, graphing, and dashboard capabilities. Published as scoped NPM packages under `@hpcc-js`, this framework is designed to work seamlessly with the HPCC Systems big data platform while being flexible enough for general-purpose visualization needs. + ## How to get started? -1. [Quick Start](https://github.com/hpcc-systems/Visualization/wiki/Quick-Start): Covers the basics on how to include the framework into your web application. -2. [Tutorials](https://github.com/hpcc-systems/Visualization/wiki/Tutorials): Starting with a simple "hello world", the tutorials walk through the basics of instantiating the visualizations, fetching data and creating dashboards. -3. [Gallery](https://raw.githack.com/hpcc-systems/Visualization/trunk/demos/gallery/gallery.html) + [Indexed Gallery (new)](https://raw.githack.com/hpcc-systems/Visualization/trunk/apps/docs/index.html): Many many samples (and growing weekly), includes an interactive playgound + property editor for discovering the capabilities of each visualization. -4. [Chat](https://gitter.im/hpcc-systems/Visualization): Join us in our chat room - all questions and suggestions welcomed! +1. [Quick Start](https://github.com/hpcc-systems/Visualization/wiki/Quick-Start): Covers the basics on how to include the framework into your web application. +2. [Tutorials](https://github.com/hpcc-systems/Visualization/wiki/Tutorials): Starting with a simple "hello world", the tutorials walk through the basics of instantiating visualizations, fetching data and creating dashboards. +3. [Gallery](https://raw.githack.com/hpcc-systems/Visualization/trunk/demos/gallery/index.html): Interactive gallery with live code examples and a property editor for discovering the capabilities of each visualization. -## Whats in the "box"? -The "@hpcc-js" repository contains several packages which fall into two main categories: -* Visualizations -* HPCC Platform browser/node.js connectors and utilities +## Architecture & Overview -All packages are available for use independently and are published to the NPM repository under the [@hpcc-js](https://www.npmjs.com/~hpcc-js) scope name. +### Monorepo Structure +This is a **Lerna-based monorepo** with packages organized in the `/packages/` directory. Each package has its own `package.json`, build configuration, and TypeScript setup. Packages are published independently to NPM under the `@hpcc-js/` scope. -They support all modern browsers including: -* IE 11 -* Chrome -* Firefox -* Edge +### Build System +- **Vite** is the primary compiler and bundler for all packages +- **TypeScript** source code with strict configuration +- **Multiple module formats**: ESM, UMD, and IIFE +- **Source maps** generated for all builds +- **PostCSS** for CSS processing and minification -They support the following module formats: -* iife -* commonjs -* AMD -* UMD -* es6 -* unpkg +### Package Categories -And work well with JavaScript bundlers: -* WebPack -* Rollup.js +#### Core Packages +- **`@hpcc-js/common`** - Base widgets, utilities, and D3 re-exports +- **`@hpcc-js/api`** - TypeScript interfaces and API definitions +- **`@hpcc-js/util`** - Utility functions and helpers -## Hello World Example +#### Visualization Packages +- **`@hpcc-js/chart`** - Charts (Bar, Line, Pie, Scatter, etc.) +- **`@hpcc-js/graph`** - Graph visualizations and network diagrams +- **`@hpcc-js/map`** - Geographic visualizations with Leaflet integration +- **`@hpcc-js/tree`** - Tree and hierarchy visualizations +- **`@hpcc-js/timeline`** - Timeline and temporal visualizations -The simplest example pulls the pre-built packages directly from NPM via unpkg and loads them into the the global namespace ("IIFE" style), when used this way you have to manually include all dependencies and need to be careful about global namespace pollution... +#### UI & Layout Packages +- **`@hpcc-js/layout`** - Layout containers and dashboard components +- **`@hpcc-js/form`** - Form controls and input widgets +- **`@hpcc-js/html`** - HTML-based components and React integration -```html - - +#### Integration Packages +- **`@hpcc-js/marshaller`** - Data marshalling and dashboard orchestration +- **`@hpcc-js/comms`** - Communication with HPCC Systems platform +- **`@hpcc-js/codemirror`** - Code editors for various languages - - - Simple Bar Chart - - - - - +### Browser & Module Support - -
- - +#### Target Environments +- **Modern browsers** (Chrome, Firefox, Edge, Safari) +- **Node.js** for server-side rendering and data processing - -``` -To explore this example see [Dermatology-Bar](https://rawgit.com/hpcc-systems/Visualization/trunk/demos/dermatology/index.html?src/chart/Bar.simple) and enable the "Properties" option (top right). +#### Module Formats +- **ES6 modules** (primary format for tree-shaking and modern bundlers) +- **UMD** (Universal Module Definition for broad compatibility) +- **IIFE** (Immediately Invoked Function Expression for direct browser usage) +- **CommonJS** support for Node.js environments -## Installing via npm +#### Bundler Compatibility +- **Vite** (recommended) +- **Webpack** +- **Rollup.js** +- **Parcel** +- **Direct CDN usage** via unpkg -To install via npm, simply use `npm install` as you would normally. Each package is "scoped" with "@hpcc-js" and you will need to specify each required package specifically, for example: +## Installation +### Via NPM (Recommended) + +To install via npm, use `npm install` with the specific packages you need. Each package is scoped with "@hpcc-js": + +```bash +npm install @hpcc-js/chart @hpcc-js/map @hpcc-js/common ``` -npm install @hpcc-js/chart @hpcc-js/map -``` -You can see the current status of each package here: [https://www.npmjs.com/](https://www.npmjs.com/search?q=maintainer:hpcc-js) +### Via CDN (Quick Start) + +For quick prototyping, you can load packages directly from unpkg CDN: + +```html + + + + +``` -## Referencing in your application +You can see all available packages at: [https://www.npmjs.com/search?q=maintainer:hpcc-js](https://www.npmjs.com/search?q=maintainer:hpcc-js) -@hpcc-js is written using TypeScript and generates ES2015 + UMD JavaScript modules which can be included into your normal development flow as is (this includes compatibility with both WebPack + Rollup.js). +## Usage Examples -To import @hpcc-js packages into an ES2015 application, simply import the required symbols from any @hpcc-js package: +### ES6 Modules (Recommended) ```javascript import { Bar } from "@hpcc-js/chart"; @@ -102,15 +104,14 @@ const chart = new Bar() ["Math", 98, 92, 90], ["Science", 66, 60, 72] ]) - .render() - ; + .render(); ``` -Using AMD +### AMD ```javascript require(["@hpcc-js/chart"], function(hpccChart) { - var chart = new hpccChart.Bar() + const chart = new hpccChart.Bar() .target("placeholder") .columns(["Subject", "Year 1", "Year 2", "Year 3"]) .data([ @@ -119,63 +120,143 @@ require(["@hpcc-js/chart"], function(hpccChart) { ["Math", 98, 92, 90], ["Science", 66, 60, 72] ]) - .render() - ; + .render(); }); ``` +### IIFE (Browser Global) + +```html + + + + + Simple Bar Chart + + + + + + +
+ + + +``` + ## Developer Zone ### Prerequisites -* NodeJS LTS (10.x at time of writing) - -### Building a development environment +- **Node.js** LTS (18.x or later recommended) +- **Git** for version control -These are the recommended steps for creating a development environment. +### Setting up a Development Environment +1. **Clone the repository:** +```bash +git clone https://github.com/hpcc-systems/Visualization.git Visualization +cd Visualization ``` -git clone https://github.com/hpcc-systems/Visualization.git hpcc-js -cd hpcc-js + +2. **Install dependencies:** +```bash npm install -npm run build-dev ``` -At which point the "demos" should now load. - -Note: In this development mode, there is no need to create any webpack or rollupjs bundles, but you will need to ensure that any modifications to the TypeScript files are re-compiled into JavaScript. The simplest way to do this is to run the TypeScript compiler in "watch" mode for the package you are editing: - +3. **Build all packages:** +```bash +npm run build ``` -cd ./packages/chart -tsc -w + +4. **Start the development server:** +```bash +cd demos/gallery +npm run bundle-watch ``` -### Building a release +The gallery will be available at `http://localhost:5500` with hot reloading for development. -Building a local release with min files +### Common Development Tasks -``` +#### Building +```bash +# Build all packages npm run build -npm run minimize + +# Clean all build artifacts +npm run clean ``` -### Running lint + unit tests +#### Linting +```bash +# Lint all packages +npm run lint +# Fix linting issues automatically +npm run lint-fix ``` -npm run lint -npm run build-all + +#### Testing +```bash +# Run all tests npm run test -``` -### Publishing a full release to NPM (require admin rights on https://github.com/hpcc-systems/Visualization) +# Run browser tests +npm run test-browser -``` -npm run tag +# Run Node.js tests +npm run test-node ``` -### Full clean (including removal of package dependencies) +#### Working with Individual Packages +```bash +# Navigate to a specific package +cd packages/chart +# Build just this package +npm run build + +# Run tests for this package +npm run test ``` + +### Full Clean + +To completely reset your development environment: + +```bash npm run clean npm run uninstall -rm -rf ./node_modules +rm -rf node_modules +npm install ``` + +## HPCC Platform Integration + +This framework is designed to work with the **HPCC Systems** big data platform, providing: + +- **ECL (Enterprise Control Language)** integration +- **Roxie query integration** through `@hpcc-js/comms` +- **Workunit result visualization** +- **ESP (Enterprise Services Platform)** connectivity +- **Real-time data streaming** capabilities + +## Contributing + +We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md). + +## License + +This project is licensed under the Apache-2.0 License - see the [LICENSE](LICENSE) file for details. diff --git a/package-lock.json b/package-lock.json index 60542bac50..547d47eb07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "license": "Apache-2.0", "workspaces": [ "packages/*", - "demos/*" + "demos/*", + "tests/*" ], "devDependencies": { "@typescript-eslint/eslint-plugin": "8.29.0", @@ -136,41 +137,41 @@ } }, "node_modules/@algolia/client-abtesting": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.27.0.tgz", - "integrity": "sha512-SITU5umoknxETtw67TxJu9njyMkWiH8pM+Bvw4dzfuIrIAT6Y1rmwV4y0A0didWoT+6xVuammIykbtBMolBcmg==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.29.0.tgz", + "integrity": "sha512-AM/6LYMSTnZvAT5IarLEKjYWOdV+Fb+LVs8JRq88jn8HH6bpVUtjWdOZXqX1hJRXuCAY8SdQfb7F8uEiMNXdYQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.27.0", - "@algolia/requester-browser-xhr": "5.27.0", - "@algolia/requester-fetch": "5.27.0", - "@algolia/requester-node-http": "5.27.0" + "@algolia/client-common": "5.29.0", + "@algolia/requester-browser-xhr": "5.29.0", + "@algolia/requester-fetch": "5.29.0", + "@algolia/requester-node-http": "5.29.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.27.0.tgz", - "integrity": "sha512-go1b9qIZK5vYEQ7jD2bsfhhhVsoh9cFxQ5xF8TzTsg2WOCZR3O92oXCkq15SOK0ngJfqDU6a/k0oZ4KuEnih1Q==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.29.0.tgz", + "integrity": "sha512-La34HJh90l0waw3wl5zETO8TuukeUyjcXhmjYZL3CAPLggmKv74mobiGRIb+mmBENybiFDXf/BeKFLhuDYWMMQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.27.0", - "@algolia/requester-browser-xhr": "5.27.0", - "@algolia/requester-fetch": "5.27.0", - "@algolia/requester-node-http": "5.27.0" + "@algolia/client-common": "5.29.0", + "@algolia/requester-browser-xhr": "5.29.0", + "@algolia/requester-fetch": "5.29.0", + "@algolia/requester-node-http": "5.29.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.27.0.tgz", - "integrity": "sha512-tnFOzdNuMzsz93kOClj3fKfuYoF3oYaEB5bggULSj075GJ7HUNedBEm7a6ScrjtnOaOtipbnT7veUpHA4o4wEQ==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.29.0.tgz", + "integrity": "sha512-T0lzJH/JiCxQYtCcnWy7Jf1w/qjGDXTi2npyF9B9UsTvXB97GRC6icyfXxe21mhYvhQcaB1EQ/J2575FXxi2rA==", "dev": true, "license": "MIT", "engines": { @@ -178,151 +179,151 @@ } }, "node_modules/@algolia/client-insights": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.27.0.tgz", - "integrity": "sha512-y1qgw39qZijjQBXrqZTiwK1cWgWGRiLpJNWBv9w36nVMKfl9kInrfsYmdBAfmlhVgF/+Woe0y1jQ7pa4HyShAw==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.29.0.tgz", + "integrity": "sha512-A39F1zmHY9aev0z4Rt3fTLcGN5AG1VsVUkVWy6yQG5BRDScktH+U5m3zXwThwniBTDV1HrPgiGHZeWb67GkR2Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.27.0", - "@algolia/requester-browser-xhr": "5.27.0", - "@algolia/requester-fetch": "5.27.0", - "@algolia/requester-node-http": "5.27.0" + "@algolia/client-common": "5.29.0", + "@algolia/requester-browser-xhr": "5.29.0", + "@algolia/requester-fetch": "5.29.0", + "@algolia/requester-node-http": "5.29.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.27.0.tgz", - "integrity": "sha512-XluG9qPZKEbiLoIfXTKbABsWDNOMPx0t6T2ImJTTeuX+U/zBdmfcqqgcgkqXp+vbXof/XX/4of9Eqo1JaqEmKw==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.29.0.tgz", + "integrity": "sha512-ibxmh2wKKrzu5du02gp8CLpRMeo+b/75e4ORct98CT7mIxuYFXowULwCd6cMMkz/R0LpKXIbTUl15UL5soaiUQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.27.0", - "@algolia/requester-browser-xhr": "5.27.0", - "@algolia/requester-fetch": "5.27.0", - "@algolia/requester-node-http": "5.27.0" + "@algolia/client-common": "5.29.0", + "@algolia/requester-browser-xhr": "5.29.0", + "@algolia/requester-fetch": "5.29.0", + "@algolia/requester-node-http": "5.29.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.27.0.tgz", - "integrity": "sha512-V8/To+SsAl2sdw2AAjeLJuCW1L+xpz+LAGerJK7HKqHzE5yQhWmIWZTzqYQcojkii4iBMYn0y3+uReWqT8XVSQ==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.29.0.tgz", + "integrity": "sha512-VZq4/AukOoJC2WSwF6J5sBtt+kImOoBwQc1nH3tgI+cxJBg7B77UsNC+jT6eP2dQCwGKBBRTmtPLUTDDnHpMgA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.27.0", - "@algolia/requester-browser-xhr": "5.27.0", - "@algolia/requester-fetch": "5.27.0", - "@algolia/requester-node-http": "5.27.0" + "@algolia/client-common": "5.29.0", + "@algolia/requester-browser-xhr": "5.29.0", + "@algolia/requester-fetch": "5.29.0", + "@algolia/requester-node-http": "5.29.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.27.0.tgz", - "integrity": "sha512-EJJ7WmvmUXZdchueKFCK8UZFyLqy4Hz64snNp0cTc7c0MKaSeDGYEDxVsIJKp15r7ORaoGxSyS4y6BGZMXYuCg==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.29.0.tgz", + "integrity": "sha512-cZ0Iq3OzFUPpgszzDr1G1aJV5UMIZ4VygJ2Az252q4Rdf5cQMhYEIKArWY/oUjMhQmosM8ygOovNq7gvA9CdCg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.27.0", - "@algolia/requester-browser-xhr": "5.27.0", - "@algolia/requester-fetch": "5.27.0", - "@algolia/requester-node-http": "5.27.0" + "@algolia/client-common": "5.29.0", + "@algolia/requester-browser-xhr": "5.29.0", + "@algolia/requester-fetch": "5.29.0", + "@algolia/requester-node-http": "5.29.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/ingestion": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.27.0.tgz", - "integrity": "sha512-xNCyWeqpmEo4EdmpG57Fs1fJIQcPwt5NnJ6MBdXnUdMVXF4f5PHgza+HQWQQcYpCsune96jfmR0v7us6gRIlCw==", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.29.0.tgz", + "integrity": "sha512-scBXn0wO5tZCxmO6evfa7A3bGryfyOI3aoXqSQBj5SRvNYXaUlFWQ/iKI70gRe/82ICwE0ICXbHT/wIvxOW7vw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.27.0", - "@algolia/requester-browser-xhr": "5.27.0", - "@algolia/requester-fetch": "5.27.0", - "@algolia/requester-node-http": "5.27.0" + "@algolia/client-common": "5.29.0", + "@algolia/requester-browser-xhr": "5.29.0", + "@algolia/requester-fetch": "5.29.0", + "@algolia/requester-node-http": "5.29.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.27.0.tgz", - "integrity": "sha512-P0NDiEFyt9UYQLBI0IQocIT7xHpjMpoFN3UDeerbztlkH9HdqT0GGh1SHYmNWpbMWIGWhSJTtz6kSIWvFu4+pw==", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.29.0.tgz", + "integrity": "sha512-FGWWG9jLFhsKB7YiDjM2dwQOYnWu//7Oxrb2vT96N7+s+hg1mdHHfHNRyEudWdxd4jkMhBjeqNA21VbTiOIPVg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.27.0", - "@algolia/requester-browser-xhr": "5.27.0", - "@algolia/requester-fetch": "5.27.0", - "@algolia/requester-node-http": "5.27.0" + "@algolia/client-common": "5.29.0", + "@algolia/requester-browser-xhr": "5.29.0", + "@algolia/requester-fetch": "5.29.0", + "@algolia/requester-node-http": "5.29.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.27.0.tgz", - "integrity": "sha512-cqfTMF1d1cc7hg0vITNAFxJZas7MJ4Obc36WwkKpY23NOtGb+4tH9X7UKlQa2PmTgbXIANoJ/DAQTeiVlD2I4Q==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.29.0.tgz", + "integrity": "sha512-xte5+mpdfEARAu61KXa4ewpjchoZuJlAlvQb8ptK6hgHlBHDnYooy1bmOFpokaAICrq/H9HpoqNUX71n+3249A==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.27.0", - "@algolia/requester-browser-xhr": "5.27.0", - "@algolia/requester-fetch": "5.27.0", - "@algolia/requester-node-http": "5.27.0" + "@algolia/client-common": "5.29.0", + "@algolia/requester-browser-xhr": "5.29.0", + "@algolia/requester-fetch": "5.29.0", + "@algolia/requester-node-http": "5.29.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.27.0.tgz", - "integrity": "sha512-ErenYTcXl16wYXtf0pxLl9KLVxIztuehqXHfW9nNsD8mz9OX42HbXuPzT7y6JcPiWJpc/UU/LY5wBTB65vsEUg==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.29.0.tgz", + "integrity": "sha512-og+7Em75aPHhahEUScq2HQ3J7ULN63Levtd87BYMpn6Im5d5cNhaC4QAUsXu6LWqxRPgh4G+i+wIb6tVhDhg2A==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.27.0" + "@algolia/client-common": "5.29.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.27.0.tgz", - "integrity": "sha512-CNOvmXsVi+IvT7z1d+6X7FveVkgEQwTNgipjQCHTIbF9KSMfZR7tUsJC+NpELrm10ALdOMauah84ybs9rw1cKQ==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.29.0.tgz", + "integrity": "sha512-JCxapz7neAy8hT/nQpCvOrI5JO8VyQ1kPvBiaXWNC1prVq0UMYHEL52o1BsPvtXfdQ7BVq19OIq6TjOI06mV/w==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.27.0" + "@algolia/client-common": "5.29.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.27.0.tgz", - "integrity": "sha512-Nx9EdLYZDsaYFTthqmc0XcVvsx6jqeEX8fNiYOB5i2HboQwl8pJPj1jFhGqoGd0KG7KFR+sdPO5/e0EDDAru2Q==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.29.0.tgz", + "integrity": "sha512-lVBD81RBW5VTdEYgnzCz7Pf9j2H44aymCP+/eHGJu4vhU+1O8aKf3TVBgbQr5UM6xoe8IkR/B112XY6YIG2vtg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.27.0" + "@algolia/client-common": "5.29.0" }, "engines": { "node": ">= 14.0.0" @@ -2278,9 +2279,9 @@ } }, "node_modules/@iconify-json/simple-icons": { - "version": "1.2.38", - "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.38.tgz", - "integrity": "sha512-mvMeFQgVjoHanQE9Q7ihmriEXAorjLZW+crUgQspDjFpzWuQp2RZMTppl1MN6TQztMVTsNFgF6LDKsp+v1RYRg==", + "version": "1.2.39", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.39.tgz", + "integrity": "sha512-XlhW73c4dHvUrwWckVY76HDjnaZ2fWKD6hNZtd5kuv23GC0g3Lu0MXnYscpkIYOeiXO+Gtlw8FM53J7C84mCtA==", "dev": true, "license": "CC0-1.0", "dependencies": { @@ -5122,9 +5123,9 @@ } }, "node_modules/@rollup/plugin-commonjs/node_modules/@rollup/pluginutils": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", - "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -5214,9 +5215,9 @@ } }, "node_modules/@rollup/plugin-json/node_modules/@rollup/pluginutils": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", - "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -5278,9 +5279,9 @@ } }, "node_modules/@rollup/plugin-node-resolve/node_modules/@rollup/pluginutils": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", - "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -5356,9 +5357,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.43.0.tgz", - "integrity": "sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz", + "integrity": "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==", "cpu": [ "arm" ], @@ -5369,9 +5370,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.43.0.tgz", - "integrity": "sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.0.tgz", + "integrity": "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==", "cpu": [ "arm64" ], @@ -5382,9 +5383,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.43.0.tgz", - "integrity": "sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz", + "integrity": "sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==", "cpu": [ "arm64" ], @@ -5395,9 +5396,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.43.0.tgz", - "integrity": "sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.0.tgz", + "integrity": "sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==", "cpu": [ "x64" ], @@ -5408,9 +5409,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.43.0.tgz", - "integrity": "sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.0.tgz", + "integrity": "sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==", "cpu": [ "arm64" ], @@ -5421,9 +5422,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.43.0.tgz", - "integrity": "sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.0.tgz", + "integrity": "sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==", "cpu": [ "x64" ], @@ -5434,9 +5435,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.43.0.tgz", - "integrity": "sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.0.tgz", + "integrity": "sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==", "cpu": [ "arm" ], @@ -5447,9 +5448,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.43.0.tgz", - "integrity": "sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.0.tgz", + "integrity": "sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==", "cpu": [ "arm" ], @@ -5460,9 +5461,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.43.0.tgz", - "integrity": "sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.0.tgz", + "integrity": "sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==", "cpu": [ "arm64" ], @@ -5473,9 +5474,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.43.0.tgz", - "integrity": "sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.0.tgz", + "integrity": "sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==", "cpu": [ "arm64" ], @@ -5486,9 +5487,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.43.0.tgz", - "integrity": "sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.0.tgz", + "integrity": "sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==", "cpu": [ "loong64" ], @@ -5499,9 +5500,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.43.0.tgz", - "integrity": "sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.0.tgz", + "integrity": "sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==", "cpu": [ "ppc64" ], @@ -5512,9 +5513,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.43.0.tgz", - "integrity": "sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.0.tgz", + "integrity": "sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==", "cpu": [ "riscv64" ], @@ -5525,9 +5526,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.43.0.tgz", - "integrity": "sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.0.tgz", + "integrity": "sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==", "cpu": [ "riscv64" ], @@ -5538,9 +5539,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.43.0.tgz", - "integrity": "sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.0.tgz", + "integrity": "sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==", "cpu": [ "s390x" ], @@ -5551,9 +5552,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.43.0.tgz", - "integrity": "sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.0.tgz", + "integrity": "sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==", "cpu": [ "x64" ], @@ -5564,9 +5565,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.43.0.tgz", - "integrity": "sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.0.tgz", + "integrity": "sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==", "cpu": [ "x64" ], @@ -5577,9 +5578,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.43.0.tgz", - "integrity": "sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.0.tgz", + "integrity": "sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==", "cpu": [ "arm64" ], @@ -5590,9 +5591,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.43.0.tgz", - "integrity": "sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.0.tgz", + "integrity": "sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==", "cpu": [ "ia32" ], @@ -5603,9 +5604,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.43.0.tgz", - "integrity": "sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz", + "integrity": "sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==", "cpu": [ "x64" ], @@ -6857,14 +6858,14 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.16.tgz", - "integrity": "sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.17.tgz", + "integrity": "sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.2", - "@vue/shared": "3.5.16", + "@babel/parser": "^7.27.5", + "@vue/shared": "3.5.17", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" @@ -6878,31 +6879,31 @@ "license": "MIT" }, "node_modules/@vue/compiler-dom": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.16.tgz", - "integrity": "sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz", + "integrity": "sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.16", - "@vue/shared": "3.5.16" + "@vue/compiler-core": "3.5.17", + "@vue/shared": "3.5.17" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.16.tgz", - "integrity": "sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz", + "integrity": "sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.2", - "@vue/compiler-core": "3.5.16", - "@vue/compiler-dom": "3.5.16", - "@vue/compiler-ssr": "3.5.16", - "@vue/shared": "3.5.16", + "@babel/parser": "^7.27.5", + "@vue/compiler-core": "3.5.17", + "@vue/compiler-dom": "3.5.17", + "@vue/compiler-ssr": "3.5.17", + "@vue/shared": "3.5.17", "estree-walker": "^2.0.2", "magic-string": "^0.30.17", - "postcss": "^8.5.3", + "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, @@ -6914,14 +6915,14 @@ "license": "MIT" }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.16.tgz", - "integrity": "sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz", + "integrity": "sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.16", - "@vue/shared": "3.5.16" + "@vue/compiler-dom": "3.5.17", + "@vue/shared": "3.5.17" } }, "node_modules/@vue/devtools-api": { @@ -6961,57 +6962,57 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.16.tgz", - "integrity": "sha512-FG5Q5ee/kxhIm1p2bykPpPwqiUBV3kFySsHEQha5BJvjXdZTUfmya7wP7zC39dFuZAcf/PD5S4Lni55vGLMhvA==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.17.tgz", + "integrity": "sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "3.5.16" + "@vue/shared": "3.5.17" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.16.tgz", - "integrity": "sha512-bw5Ykq6+JFHYxrQa7Tjr+VSzw7Dj4ldR/udyBZbq73fCdJmyy5MPIFR9IX/M5Qs+TtTjuyUTCnmK3lWWwpAcFQ==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.17.tgz", + "integrity": "sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.16", - "@vue/shared": "3.5.16" + "@vue/reactivity": "3.5.17", + "@vue/shared": "3.5.17" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.16.tgz", - "integrity": "sha512-T1qqYJsG2xMGhImRUV9y/RseB9d0eCYZQ4CWca9ztCuiPj/XWNNN+lkNBuzVbia5z4/cgxdL28NoQCvC0Xcfww==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz", + "integrity": "sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.16", - "@vue/runtime-core": "3.5.16", - "@vue/shared": "3.5.16", + "@vue/reactivity": "3.5.17", + "@vue/runtime-core": "3.5.17", + "@vue/shared": "3.5.17", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.16.tgz", - "integrity": "sha512-BrX0qLiv/WugguGsnQUJiYOE0Fe5mZTwi6b7X/ybGB0vfrPH9z0gD/Y6WOR1sGCgX4gc25L1RYS5eYQKDMoNIg==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.17.tgz", + "integrity": "sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.16", - "@vue/shared": "3.5.16" + "@vue/compiler-ssr": "3.5.17", + "@vue/shared": "3.5.17" }, "peerDependencies": { - "vue": "3.5.16" + "vue": "3.5.17" } }, "node_modules/@vue/shared": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.16.tgz", - "integrity": "sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.17.tgz", + "integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==", "dev": true, "license": "MIT" }, @@ -7572,25 +7573,25 @@ "license": "MIT" }, "node_modules/algoliasearch": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.27.0.tgz", - "integrity": "sha512-2PvAgvxxJzA3+dB+ERfS2JPdvUsxNf89Cc2GF5iCcFupTULOwmbfinvqrC4Qj9nHJJDNf494NqEN/1f9177ZTQ==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.29.0.tgz", + "integrity": "sha512-E2l6AlTWGznM2e7vEE6T6hzObvEyXukxMOlBmVlMyixZyK1umuO/CiVc6sDBbzVH0oEviCE5IfVY1oZBmccYPQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-abtesting": "5.27.0", - "@algolia/client-analytics": "5.27.0", - "@algolia/client-common": "5.27.0", - "@algolia/client-insights": "5.27.0", - "@algolia/client-personalization": "5.27.0", - "@algolia/client-query-suggestions": "5.27.0", - "@algolia/client-search": "5.27.0", - "@algolia/ingestion": "1.27.0", - "@algolia/monitoring": "1.27.0", - "@algolia/recommend": "5.27.0", - "@algolia/requester-browser-xhr": "5.27.0", - "@algolia/requester-fetch": "5.27.0", - "@algolia/requester-node-http": "5.27.0" + "@algolia/client-abtesting": "5.29.0", + "@algolia/client-analytics": "5.29.0", + "@algolia/client-common": "5.29.0", + "@algolia/client-insights": "5.29.0", + "@algolia/client-personalization": "5.29.0", + "@algolia/client-query-suggestions": "5.29.0", + "@algolia/client-search": "5.29.0", + "@algolia/ingestion": "1.29.0", + "@algolia/monitoring": "1.29.0", + "@algolia/recommend": "5.29.0", + "@algolia/requester-browser-xhr": "5.29.0", + "@algolia/requester-fetch": "5.29.0", + "@algolia/requester-node-http": "5.29.0" }, "engines": { "node": ">= 14.0.0" @@ -9177,6 +9178,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/d3-axis": { @@ -9300,6 +9302,7 @@ "version": "1.4.5", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/d3-geo": { @@ -9593,12 +9596,14 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/d3-time-format": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "d3-time": "1" @@ -9680,6 +9685,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 14" @@ -10419,9 +10425,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.167", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.167.tgz", - "integrity": "sha512-LxcRvnYO5ez2bMOFpbuuVuAI5QNeY1ncVytE/KXaL6ZNfzX1yPlAO0nSOyIHx2fVAuUprMqPs/TdVhUFZy7SIQ==", + "version": "1.5.170", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.170.tgz", + "integrity": "sha512-GP+M7aeluQo9uAyiTCxgIj/j+PrWhMlY7LFVj8prlsPljd0Fdg9AprlfUi+OCSFWy9Y5/2D/Jrj9HS8Z4rpKWA==", "dev": true, "license": "ISC" }, @@ -12524,6 +12530,22 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/hpcc-js-browser-esm-tests": { + "resolved": "tests/browser-esm", + "link": true + }, + "node_modules/hpcc-js-browser-umd-tests": { + "resolved": "tests/browser-umd", + "link": true + }, + "node_modules/hpcc-js-node-cjs-tests": { + "resolved": "tests/node-cjs", + "link": true + }, + "node_modules/hpcc-js-node-esm-tests": { + "resolved": "tests/node-esm", + "link": true + }, "node_modules/htl": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/htl/-/htl-0.3.1.tgz", @@ -16254,9 +16276,9 @@ } }, "node_modules/oauth4webapi": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.5.2.tgz", - "integrity": "sha512-VYz5BaP3izIrUc1GAVzIoz4JnljiW0YAUFObMBwsqDnfHxz2sjLu3W7/8vE8Ms9IbMewN9+1kcvhY3tMscAeGQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.5.3.tgz", + "integrity": "sha512-2bnHosmBLAQpXNBLOvaJMyMkr4Yya5ohE5Q9jqyxiN+aa7GFCzvDN1RRRMrp0NkfqRR2MTaQNkcSUCCjILD9oQ==", "dev": true, "license": "MIT", "funding": { @@ -17994,12 +18016,12 @@ } }, "node_modules/rollup": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.43.0.tgz", - "integrity": "sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==", + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.0.tgz", + "integrity": "sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==", "license": "MIT", "dependencies": { - "@types/estree": "1.0.7" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -18009,26 +18031,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.43.0", - "@rollup/rollup-android-arm64": "4.43.0", - "@rollup/rollup-darwin-arm64": "4.43.0", - "@rollup/rollup-darwin-x64": "4.43.0", - "@rollup/rollup-freebsd-arm64": "4.43.0", - "@rollup/rollup-freebsd-x64": "4.43.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.43.0", - "@rollup/rollup-linux-arm-musleabihf": "4.43.0", - "@rollup/rollup-linux-arm64-gnu": "4.43.0", - "@rollup/rollup-linux-arm64-musl": "4.43.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.43.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.43.0", - "@rollup/rollup-linux-riscv64-gnu": "4.43.0", - "@rollup/rollup-linux-riscv64-musl": "4.43.0", - "@rollup/rollup-linux-s390x-gnu": "4.43.0", - "@rollup/rollup-linux-x64-gnu": "4.43.0", - "@rollup/rollup-linux-x64-musl": "4.43.0", - "@rollup/rollup-win32-arm64-msvc": "4.43.0", - "@rollup/rollup-win32-ia32-msvc": "4.43.0", - "@rollup/rollup-win32-x64-msvc": "4.43.0", + "@rollup/rollup-android-arm-eabi": "4.44.0", + "@rollup/rollup-android-arm64": "4.44.0", + "@rollup/rollup-darwin-arm64": "4.44.0", + "@rollup/rollup-darwin-x64": "4.44.0", + "@rollup/rollup-freebsd-arm64": "4.44.0", + "@rollup/rollup-freebsd-x64": "4.44.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.44.0", + "@rollup/rollup-linux-arm-musleabihf": "4.44.0", + "@rollup/rollup-linux-arm64-gnu": "4.44.0", + "@rollup/rollup-linux-arm64-musl": "4.44.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.44.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.44.0", + "@rollup/rollup-linux-riscv64-gnu": "4.44.0", + "@rollup/rollup-linux-riscv64-musl": "4.44.0", + "@rollup/rollup-linux-s390x-gnu": "4.44.0", + "@rollup/rollup-linux-x64-gnu": "4.44.0", + "@rollup/rollup-linux-x64-musl": "4.44.0", + "@rollup/rollup-win32-arm64-msvc": "4.44.0", + "@rollup/rollup-win32-ia32-msvc": "4.44.0", + "@rollup/rollup-win32-x64-msvc": "4.44.0", "fsevents": "~2.3.2" } }, @@ -18051,12 +18073,6 @@ "rollup": "^1.20.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" } }, - "node_modules/rollup/node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "license": "MIT" - }, "node_modules/rrweb-cssom": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", @@ -18149,6 +18165,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, "funding": [ { "type": "github", @@ -19403,9 +19420,9 @@ } }, "node_modules/terser": { - "version": "5.42.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.42.0.tgz", - "integrity": "sha512-UYCvU9YQW2f/Vwl+P0GfhxJxbUGLwd+5QrrGgLajzWAtC/23AX0vcise32kkP7Eu0Wu9VlzzHAXkLObgjQfFlQ==", + "version": "5.43.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", + "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -19563,9 +19580,9 @@ "license": "MIT" }, "node_modules/tinypool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.0.tgz", - "integrity": "sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", "dev": true, "license": "MIT", "engines": { @@ -19603,6 +19620,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.14" @@ -21469,17 +21487,17 @@ } }, "node_modules/vue": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.16.tgz", - "integrity": "sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.17.tgz", + "integrity": "sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.16", - "@vue/compiler-sfc": "3.5.16", - "@vue/runtime-dom": "3.5.16", - "@vue/server-renderer": "3.5.16", - "@vue/shared": "3.5.16" + "@vue/compiler-dom": "3.5.17", + "@vue/compiler-sfc": "3.5.17", + "@vue/runtime-dom": "3.5.17", + "@vue/server-renderer": "3.5.17", + "@vue/shared": "3.5.17" }, "peerDependencies": { "typescript": "*" @@ -22375,13 +22393,7 @@ "@hpcc-js/util": "^3.3.1", "@xmldom/xmldom": "0.9.8", "abort-controller": "3.0.0", - "d3-array": "^1", - "d3-format": "^1", - "d3-time-format": "^2", - "data-uri-to-buffer": "6.0.2", "node-fetch": "3.3.2", - "safe-buffer": "5.2.1", - "tmp": "0.2.3", "undici": "6.21.2" }, "devDependencies": { @@ -22392,7 +22404,13 @@ "@types/d3-time-format": "2.3.4", "@types/node": "^18", "@types/xmldom": "0.1.34", + "d3-array": "^1", + "d3-format": "^1", + "d3-time-format": "^2", + "data-uri-to-buffer": "6.0.2", + "safe-buffer": "5.2.1", "soap": "1.1.10", + "tmp": "0.2.3", "typescript-formatter": "^7.2.2" } }, @@ -23372,6 +23390,42 @@ "devDependencies": { "@hpcc-js/esbuild-plugins": "^1.4.1" } + }, + "tests/browser-esm": { + "name": "hpcc-js-browser-esm-tests", + "version": "1.0.0", + "dependencies": { + "@hpcc-js/comms": "file:../../packages/comms", + "@hpcc-js/dataflow": "file:../../packages/dataflow", + "@hpcc-js/util": "file:../../packages/util" + } + }, + "tests/browser-umd": { + "name": "hpcc-js-browser-umd-tests", + "version": "1.0.0", + "dependencies": { + "@hpcc-js/comms": "file:../../packages/comms", + "@hpcc-js/dataflow": "file:../../packages/dataflow", + "@hpcc-js/util": "file:../../packages/util" + } + }, + "tests/node-cjs": { + "name": "hpcc-js-node-cjs-tests", + "version": "1.0.0", + "dependencies": { + "@hpcc-js/comms": "^3.6.0", + "@hpcc-js/dataflow": "^9.3.1", + "@hpcc-js/util": "^3.3.1" + } + }, + "tests/node-esm": { + "name": "hpcc-js-node-esm-tests", + "version": "1.0.0", + "dependencies": { + "@hpcc-js/comms": "^3.6.0", + "@hpcc-js/dataflow": "^9.3.1", + "@hpcc-js/util": "^3.3.1" + } } } } diff --git a/package.json b/package.json index b54b6bec98..f4008ef496 100644 --- a/package.json +++ b/package.json @@ -11,14 +11,18 @@ ], "scripts": { "install-deps": "npx -y playwright install --with-deps", - "uninstall": "lerna clean && rimraf --glob packages/**/node_modules demos/**/node_modules apps/**/node_modules package-lock.json node_modules", + "uninstall": "lerna clean && rimraf --glob packages/**/node_modules packages/**/package-lock.json demos/**/node_modules demos/**/package-lock.json tests/**/node_modules package-lock.json tests/**/package-lock.json node_modules", "clean-root": "rimraf --glob build coverage dist lib* types temp tmp *.tsbuildinfo .vitepress/dist .vitepress/cache docs/api", "clean": "lerna run clean --no-sort && npm run clean-root", "build": "lerna run build", "lint": "lerna run --no-bail lint", "lint-fix": "lerna run --no-bail lint -- --fix", "test-browser": "vitest run --project browser", + "test-browser-esm": "cd tests/browser-esm && npm i && npm test", + "test-browser-umd": "cd tests/browser-umd && npm i && npm test", "test-node": "vitest run --project node", + "test-node-esm": "cd tests/node-esm && npm i && npm test", + "test-node-cjs": "cd tests/node-cjs && npm i && npm test", "test": "lerna run test", "test-all": "vitest run", "publish": "lerna publish from-package --yes", diff --git a/packages/comms/package.json b/packages/comms/package.json index 504dbb3634..ee33277c49 100644 --- a/packages/comms/package.json +++ b/packages/comms/package.json @@ -75,13 +75,7 @@ "@hpcc-js/util": "^3.3.1", "@xmldom/xmldom": "0.9.8", "abort-controller": "3.0.0", - "d3-array": "^1", - "d3-format": "^1", - "d3-time-format": "^2", - "data-uri-to-buffer": "6.0.2", "node-fetch": "3.3.2", - "safe-buffer": "5.2.1", - "tmp": "0.2.3", "undici": "6.21.2" }, "devDependencies": { @@ -92,6 +86,12 @@ "@types/d3-time-format": "2.3.4", "@types/node": "^18", "@types/xmldom": "0.1.34", + "d3-array": "^1", + "d3-format": "^1", + "d3-time-format": "^2", + "data-uri-to-buffer": "6.0.2", + "safe-buffer": "5.2.1", + "tmp": "0.2.3", "soap": "1.1.10", "typescript-formatter": "^7.2.2" }, diff --git a/packages/markdown-it-plugins/tests/index.browser.spec.ts b/packages/markdown-it-plugins/tests/index.browser.spec.ts index 5e2231810b..a411c279f0 100644 --- a/packages/markdown-it-plugins/tests/index.browser.spec.ts +++ b/packages/markdown-it-plugins/tests/index.browser.spec.ts @@ -15,7 +15,7 @@ describe("markdown-it-observable", () => { it("minimal example", async () => { md.use(observable); - const minimalMd = fetch("/tests/Basic usage/Minimal Example.md").then(response => { + const minimalMd = fetch("./tests/Basic usage/Minimal Example.md").then(response => { return response.text(); }); const minimalMdText = await minimalMd; diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000000..cdd1c8126b --- /dev/null +++ b/tests/README.md @@ -0,0 +1,190 @@ +# HPCC Visualization Framework Tests + +This directory contains various test suites for the HPCC Visualization Framework. + +## Test Structure + +### Node.js Compatibility Tests + +#### `/node-cjs/` - Node.js CommonJS Tests + +Tests that verify packages work correctly with Node.js using CommonJS `require()` syntax. + +- **Purpose**: Ensure compatibility with Node.js CommonJS environments +- **Coverage**: Package imports, core functionality, export validation using `require()` +- **Current Tests**: + - `@hpcc-js/util` package + - `@hpcc-js/dataflow` package + +#### `/node-esm/` - Node.js ESM Tests + +Tests that verify packages work correctly with Node.js using ES modules. + +- **Purpose**: Ensure compatibility with Node.js ESM environments +- **Coverage**: Package imports, named imports, core functionality using `import` +- **Current Tests**: + - `@hpcc-js/util` package + - `@hpcc-js/comms` package + - `@hpcc-js/dataflow` package + +### Browser Compatibility Tests + +#### `/browser-esm/` - Browser ESM Tests + +Tests that verify packages work correctly in browser environments using ES modules. + +- **Purpose**: Ensure compatibility with browser ESM environments +- **Coverage**: Package imports, named imports, core functionality, browser-specific features using `import` +- **Current Tests**: + - `@hpcc-js/util` package + - `@hpcc-js/comms` package + - `@hpcc-js/dataflow` package + +#### `/node-comms-cjs/` - Communications CommonJS Tests + +Tests that verify the communications package works correctly with CommonJS. + +- **Purpose**: Ensure HPCC Systems communication compatibility in CommonJS environments +- **Coverage**: ESPConnection, services, utilities using `require()` +- **Current Tests**: + - `@hpcc-js/comms` package + +#### `/node-comms-esm/` - Communications ESM Tests + +Tests that verify the communications package works correctly with ES modules. + +- **Purpose**: Ensure HPCC Systems communication compatibility in ESM environments +- **Coverage**: ESPConnection, services, utilities using `import` +- **Current Tests**: + - `@hpcc-js/comms` package + +### `/temp/` - Temporary Test Files + +Auto-generated test files used during development and CI processes. + +## Running Tests + +### All Compatibility Tests + +```bash +npm run test-node-compatibility +npm run test-browser-compatibility +``` + +### Individual Test Suites + +From the project root: + +```bash +# Utility package tests +npm run test-node-cjs # @hpcc-js/util CommonJS +npm run test-node-esm # @hpcc-js/util ESM +npm run test-browser-esm # @hpcc-js/util Browser ESM + +# Communications package tests +npm run test-node-comms-cjs # @hpcc-js/comms CommonJS +npm run test-node-comms-esm # @hpcc-js/comms ESM +``` + +### From Individual Test Directories + +```bash +cd tests/node-cjs && npm test # CommonJS util tests +cd tests/node-esm && npm test # ESM util tests +cd tests/browser-esm && npm test # Browser ESM tests +cd tests/node-comms-cjs && npm test # CommonJS comms tests +cd tests/node-comms-esm && npm test # ESM comms tests +``` + +## Test Framework + +All Node.js and Browser compatibility tests use: + +- **Vitest** - Modern test runner with excellent TypeScript, ES modules, and browser support +- **Playwright** - Browser automation for browser-based tests +- **Node.js Environment** - Node.js tests run in a Node.js environment to verify server-side compatibility +- **Browser Environment** - Browser tests run in headless Chromium to verify client-side compatibility +- **Hybrid Approach** - Uses ESM for Vitest imports but the appropriate module system for testing the actual packages + +## Purpose + +These tests ensure that the HPCC Visualization Framework packages work correctly in: + +1. **Legacy CommonJS environments** - Using `require()` syntax +2. **Modern ESM environments** - Using `import` syntax in Node.js +3. **Browser ESM environments** - Using `import` syntax in browsers + +This provides confidence that the packages are compatible with a wide range of Node.js applications, browser applications, and deployment scenarios. + +## Test Coverage + +### @hpcc-js/util Package + +- Dictionary class operations +- hashSum function consistency +- SAXStackParser instantiation +- Platform utilities +- Export validation (61+ exports) + +### @hpcc-js/comms Package + +- ESPConnection class instantiation +- WorkunitsService and other service classes +- Workunit and other entity classes +- Communication utilities +- Exception handling classes +- Export validation (131+ exports) + +### @hpcc-js/dataflow Package + +- Activity functions (map, filter, sort, group, join, etc.) +- Observer functions (count, max, min, mean, median, etc.) +- Utility functions (pipe, generate, isSource) +- Pipeline operations and data transformations +- Statistical computations +- Export validation (25+ exports) + +```` + +### NodeJS CommonJS Tests Only +```bash +cd tests/node-cjs +npm test +```` + +### Package-Specific Tests + +Individual packages have their own test suites in their respective directories: + +```bash +cd packages/util +npm test +``` + +## Test Categories + +1. **Unit Tests** - Located in each package's `tests/` directory +2. **Integration Tests** - Browser and Node.js compatibility tests +3. **Type Tests** - TypeScript definition validation +4. **CommonJS Tests** - Node.js CommonJS compatibility +5. **ESM Tests** - Node.js and Browser ESM compatibility + +## Adding New Tests + +When adding new compatibility tests: + +1. Create test files in the appropriate directory (`/node-cjs/`, `/node-esm/`, `/browser-esm/`) +2. Follow the established naming patterns: + - Node.js: `[package].node.spec.js` + - Browser: `[package].browser.spec.js` +3. Ensure tests verify both import and basic functionality +4. Include environment-specific tests where appropriate +5. Update this README with new test information + +## CI Integration + +These tests are integrated into the project's continuous integration pipeline to ensure: + +- Package compatibility across environments +- Proper module exports +- Functional correctness in different module systems diff --git a/tests/browser-esm/README.md b/tests/browser-esm/README.md new file mode 100644 index 0000000000..7a51233e52 --- /dev/null +++ b/tests/browser-esm/README.md @@ -0,0 +1,98 @@ +# Browser ESM Compatibility Tests + +This directory contains tests to verify that `@hpcc-js` packages work correctly in browser environments using ES modules. + +## Purpose + +These tests ensure that: +- The packages can be successfully imported using ESM `import` statements in a browser environment +- Named imports work correctly in browsers +- All major exports are available and functional +- Core functionality works as expected in a browser ESM environment +- Browser-specific features and APIs work correctly with the packages + +## Running Tests + +From this directory: +```bash +npm test +``` + +From the monorepo root: +```bash +npm run test-browser-esm +``` + +## Test Framework + +- **Vitest** - Modern test runner with excellent browser testing support +- **Playwright** - Browser automation for running tests in real browser environments +- **Browser Environment** - Tests run in a headless Chromium browser to verify client-side compatibility + +## What's Tested + +### @hpcc-js/util Package +- Basic package import functionality +- Named import functionality (ESM-specific) +- Dictionary class creation and operations +- hashSum function consistency +- SAXStackParser class instantiation +- Platform utility availability (isBrowser, isNode) +- Browser-specific DOM operations +- Export count validation + +### @hpcc-js/comms Package +- ESPConnection class instantiation +- WorkunitsService and other service classes +- Workunit and other entity classes +- Communication utilities +- Exception handling classes +- Browser-specific connection options +- Export count validation + +### @hpcc-js/dataflow Package +- Activity functions (map, filter, sort, group, join, etc.) +- Observer functions (count, max, min, mean, median, etc.) +- Utility functions (pipe, generate, isSource) +- Pipeline operations and data transformations +- Statistical computations +- Browser-specific data processing +- Export count validation + +## Configuration + +- `package.json` - Configured with `"type": "module"` to test ESM behavior +- `vitest.config.js` - Configured for browser testing with Playwright +- Uses both dynamic imports (`await import()`) and static named imports +- Tests are in `*.browser.spec.js` files following browser test conventions + +## Test Files + +- `util.browser.spec.js` - Comprehensive tests for the `@hpcc-js/util` package including browser-specific features +- `comms.browser.spec.js` - Tests for the `@hpcc-js/comms` package including browser communication features +- `dataflow.browser.spec.js` - Tests for the `@hpcc-js/dataflow` package including browser data processing + +## Browser vs Node.js + +Key differences from the Node.js tests: + +1. **Environment**: Tests run in a browser environment with access to `window`, `document`, and browser APIs +2. **Platform Detection**: `isBrowser` should be `true`, `isNode` should be `false` +3. **DOM Integration**: Tests verify that packages work correctly with DOM elements and browser-specific features +4. **Additional Tests**: Includes extra tests for browser-specific functionality and DOM operations +5. **Longer Timeouts**: Browser tests may take longer due to browser startup and DOM operations + +## Browser-Specific Features Tested + +- DOM element access and manipulation +- Browser platform detection +- Window and document object availability +- Browser-specific configuration options +- Client-side data processing scenarios +- Integration with browser APIs + +## Requirements + +- Playwright browsers must be installed: `npx playwright install` +- Tests require a browser environment and cannot run in Node.js +- Packages must be built and available for import before running tests diff --git a/tests/browser-esm/comms.browser.spec.ts b/tests/browser-esm/comms.browser.spec.ts new file mode 100644 index 0000000000..be3e544d12 --- /dev/null +++ b/tests/browser-esm/comms.browser.spec.ts @@ -0,0 +1,113 @@ +import { describe, it, expect } from "vitest"; + +describe("@hpcc-js/comms Browser ESM compatibility", () => { + it("should successfully import the package", async () => { + const comms = await import("@hpcc-js/comms"); + expect(comms).toBeDefined(); + expect(Object.keys(comms).length).toBeGreaterThan(0); + }); + + it("should export ESPConnection class", async () => { + const { ESPConnection } = await import("@hpcc-js/comms"); + expect(ESPConnection).toBeDefined(); + const connection = new ESPConnection({ baseUrl: "http://localhost:8010" }, "", ""); + expect(connection).toBeDefined(); + expect(typeof connection).toBe("object"); + }); + + it("should export WorkunitsService class", async () => { + const { WorkunitsService } = await import("@hpcc-js/comms"); + expect(WorkunitsService).toBeDefined(); + + const service = new WorkunitsService({ baseUrl: "http://localhost:8010" }); + expect(service).toBeDefined(); + expect(typeof service).toBe("object"); + }); + + it("should export Workunit class", async () => { + const { Workunit } = await import("@hpcc-js/comms"); + expect(Workunit).toBeDefined(); + const wu = Workunit.attach({ baseUrl: "http://localhost:8010" }, "W12345"); + expect(wu).toBeDefined(); + expect(typeof wu).toBe("object"); + }); + + it("should export utility functions", async () => { + const { createConnection, isArray, parseXSD, serializeRequest, deserializeResponse } = await import("@hpcc-js/comms"); + + expect(createConnection).toBeDefined(); + expect(isArray).toBeDefined(); + expect(parseXSD).toBeDefined(); + expect(serializeRequest).toBeDefined(); + expect(deserializeResponse).toBeDefined(); + }); + + it("should export exception classes", async () => { + const { ESPExceptions } = await import("@hpcc-js/comms"); + expect(ESPExceptions).toBeDefined(); + + const exception = new ESPExceptions("test", {}, { Source: "test", Exception: [] }); + expect(exception).toBeDefined(); + expect(exception).toBeInstanceOf(Error); + }); + + it("should support named imports", async () => { + const { ESPConnection, WorkunitsService, Workunit, ESPExceptions } = await import("@hpcc-js/comms"); + + expect(ESPConnection).toBeDefined(); + expect(WorkunitsService).toBeDefined(); + expect(Workunit).toBeDefined(); + expect(ESPExceptions).toBeDefined(); + const connection = new ESPConnection({ baseUrl: "http://localhost:8010" }, "", ""); + expect(connection).toBeDefined(); + + const service = new WorkunitsService({ baseUrl: "http://localhost:8010" }); + expect(service).toBeDefined(); + }); + + it("should support mixed imports", async () => { + const { + ESPConnection, + WorkunitsService, + DFUService, + LogicalFile, + createConnection + } = await import("@hpcc-js/comms"); + + expect(ESPConnection).toBeDefined(); + expect(WorkunitsService).toBeDefined(); + expect(DFUService).toBeDefined(); + expect(LogicalFile).toBeDefined(); + expect(createConnection).toBeDefined(); + const connection = new ESPConnection({ baseUrl: "http://localhost:8010" }, "", ""); + const wuService = new WorkunitsService({ baseUrl: "http://localhost:8010" }); + const dfuService = new DFUService({ baseUrl: "http://localhost:8010" }); + + expect(connection).toBeDefined(); + expect(wuService).toBeDefined(); + expect(dfuService).toBeDefined(); + }); + + it("should work in browser environment", async () => { + expect(typeof window).toBe("object"); + expect(typeof document).toBe("object"); + + const comms = await import("@hpcc-js/comms"); + expect(comms).toBeDefined(); + + const exportKeys = Object.keys(comms); + expect(exportKeys.length).toBeGreaterThan(100); + }); + + it("should handle browser-specific features", async () => { + const { ESPConnection } = await import("@hpcc-js/comms"); + const connection = new ESPConnection({ + baseUrl: "http://localhost:8010", + userID: "testuser", + password: "testpass" + }, "", ""); + + expect(connection).toBeDefined(); + expect(typeof connection).toBe("object"); + }); +}); diff --git a/tests/browser-esm/dataflow.browser.spec.ts b/tests/browser-esm/dataflow.browser.spec.ts new file mode 100644 index 0000000000..6c1d1611c8 --- /dev/null +++ b/tests/browser-esm/dataflow.browser.spec.ts @@ -0,0 +1,178 @@ +// Test ESM imports for @hpcc-js/dataflow package in browser environment +import { describe, it, expect } from "vitest"; + +describe("@hpcc-js/dataflow Browser ESM compatibility", () => { + it("should successfully import the package", async () => { + const dataflow = await import("@hpcc-js/dataflow"); + expect(dataflow).toBeDefined(); + expect(Object.keys(dataflow).length).toBeGreaterThan(0); + }); + + it("should export activity functions", async () => { + const { map, filter, sort, group, join } = await import("@hpcc-js/dataflow"); + expect(map).toBeDefined(); + expect(filter).toBeDefined(); + expect(sort).toBeDefined(); + expect(group).toBeDefined(); + expect(join).toBeDefined(); + expect(typeof map).toBe("function"); + expect(typeof filter).toBe("function"); + }); + + it("should export observer functions", async () => { + const { count, max, min, mean, median } = await import("@hpcc-js/dataflow"); + expect(count).toBeDefined(); + expect(max).toBeDefined(); + expect(min).toBeDefined(); + expect(mean).toBeDefined(); + expect(median).toBeDefined(); + expect(typeof count).toBe("function"); + expect(typeof max).toBe("function"); + }); + + it("should export utility functions", async () => { + const { pipe, generate } = await import("@hpcc-js/dataflow"); + expect(pipe).toBeDefined(); + expect(generate).toBeDefined(); + expect(typeof pipe).toBe("function"); + expect(typeof generate).toBe("function"); + }); + + it("should export activity types", async () => { + const { isSource } = await import("@hpcc-js/dataflow"); + expect(isSource).toBeDefined(); + expect(typeof isSource).toBe("function"); + }); + + it("should support named imports", async () => { + const { map, filter, count, pipe, isSource, scalar } = await import("@hpcc-js/dataflow"); + + expect(map).toBeDefined(); + expect(filter).toBeDefined(); + expect(count).toBeDefined(); + expect(pipe).toBeDefined(); + expect(isSource).toBeDefined(); + expect(scalar).toBeDefined(); + }); + + it("should work with basic map operation", async () => { + const { map } = await import("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5]; + const doubled = [...map(data, x => x * 2)]; + + expect(doubled).toEqual([2, 4, 6, 8, 10]); + }); + + it("should work with basic filter operation", async () => { + const { filter } = await import("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5]; + const evens = [...filter(data, x => x % 2 === 0)]; + + expect(evens).toEqual([2, 4]); + }); + + it("should work with basic count operation", async () => { + const { count, scalar } = await import("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5]; + const result = scalar(count())(data); + + expect(result).toBe(5); + }); it("should work with basic pipe operation", async () => { + const { pipe, map, filter, sort } = await import("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5, 6]; + const pipeline = pipe( + filter(x => x % 2 === 0), + map(x => x * x), + sort((a, b) => b - a) + ); + const result = [...pipeline(data)]; + + expect(result).toEqual([36, 16, 4]); + }); + + it("should work with isSource utility", async () => { + const { isSource } = await import("@hpcc-js/dataflow"); + + expect(isSource([1, 2, 3])).toBe(true); + expect(isSource("string is iterable")).toBe(true); // Strings are iterable + expect(isSource(42)).toBe(false); + expect(isSource(null)).toBe(null); // Returns the falsy value itself + expect(isSource(undefined)).toBe(undefined); // Returns the falsy value itself + expect(isSource({})).toBe(false); + }); + + it("should work with statistical observers", async () => { + const { max, min, mean, scalar } = await import("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5]; + + expect(scalar(max())(data)).toBe(5); + expect(scalar(min())(data)).toBe(1); + expect(scalar(mean())(data)).toBe(3); + }); + + it("should work with sort activity", async () => { + const { sort } = await import("@hpcc-js/dataflow"); const data = [3, 1, 4, 1, 5, 9, 2, 6]; + const sorted = [...sort(data, (a, b) => a - b)]; + + expect(sorted).toEqual([1, 1, 2, 3, 4, 5, 6, 9]); + }); + + it("should work with advanced pipeline operations", async () => { + const { pipe, map, filter, sort } = await import("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + const pipeline = pipe( + filter(x => x % 2 === 0), + map(x => x * x), + sort((a, b) => b - a) + ); + const result = [...pipeline(data)]; + + expect(result).toEqual([100, 64, 36, 16, 4]); + }); + + it("should work in browser environment", async () => { + // Browser-specific tests + expect(typeof window).toBe("object"); + expect(typeof document).toBe("object"); + + const dataflow = await import("@hpcc-js/dataflow"); + expect(dataflow).toBeDefined(); + + // Test that dataflow operations work with browser data + const { map, filter } = dataflow; + const browserData = Array.from(document.querySelectorAll("*")).slice(0, 5).map((_, i) => i + 1); + const processed = [...filter(map(browserData, x => x * 2), x => x > 2)]; + expect(processed).toEqual([4, 6, 8, 10]); + }); + + it("should handle browser-specific data processing", async () => { + const { pipe, map, filter, count, scalar } = await import("@hpcc-js/dataflow"); + + // Test processing DOM-related data + const bodyLength = document.body ? document.body.innerHTML.length : 100; + const testData = Array.from({ length: 10 }, (_, i) => i + bodyLength); + + const pipeline = pipe( + filter(x => x % 2 === 0), + map(x => x / 2) + ); + + const processed = [...pipeline(testData)]; + const processedCount = scalar(count())(processed); + + expect(processedCount).toBeGreaterThan(0); + expect(Array.isArray(processed)).toBe(true); + }); + + it("should have expected number of exports", async () => { + const dataflow = await import("@hpcc-js/dataflow"); + const exportKeys = Object.keys(dataflow); + expect(exportKeys.length).toBeGreaterThan(20); // Should have many exports + }); +}); diff --git a/tests/browser-esm/package.json b/tests/browser-esm/package.json new file mode 100644 index 0000000000..eb702b573c --- /dev/null +++ b/tests/browser-esm/package.json @@ -0,0 +1,16 @@ +{ + "name": "hpcc-js-browser-esm-tests", + "version": "1.0.0", + "description": "Browser ESM tests for HPCC Visualization Framework", + "type": "module", + "private": true, + "scripts": { + "test": "vitest run", + "test-watch": "vitest" + }, + "dependencies": { + "@hpcc-js/comms": "file:../../packages/comms", + "@hpcc-js/dataflow": "file:../../packages/dataflow", + "@hpcc-js/util": "file:../../packages/util" + } +} \ No newline at end of file diff --git a/tests/browser-esm/tsconfig.json b/tests/browser-esm/tsconfig.json new file mode 100644 index 0000000000..a7ee32fc67 --- /dev/null +++ b/tests/browser-esm/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../packages/tsconfig.settings.json", + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "skipLibCheck": true, + "strict": false, + "noImplicitAny": false, + "types": [ + "vitest/globals" + ] + }, + "include": [ + "./**/*.ts", + "./**/*.js" + ] +} \ No newline at end of file diff --git a/tests/browser-esm/util.browser.spec.ts b/tests/browser-esm/util.browser.spec.ts new file mode 100644 index 0000000000..24e8d450e4 --- /dev/null +++ b/tests/browser-esm/util.browser.spec.ts @@ -0,0 +1,102 @@ +// Test ESM imports for @hpcc-js/util package in browser environment +import { describe, it, expect } from "vitest"; + +describe("@hpcc-js/util Browser ESM compatibility", () => { + it("should successfully import the package", async () => { + const util = await import("@hpcc-js/util"); + expect(util).toBeDefined(); + expect(Object.keys(util).length).toBeGreaterThan(0); + }); + + it("should export Dictionary class", async () => { + const { Dictionary } = await import("@hpcc-js/util"); + expect(Dictionary).toBeDefined(); + + const dict = new Dictionary(); + dict.set("test", "value"); + const result = dict.get("test"); + expect(result).toBe("value"); + }); + + it("should export hashSum function", async () => { + const { hashSum } = await import("@hpcc-js/util"); + expect(hashSum).toBeDefined(); + + const hash1 = hashSum("test"); + const hash2 = hashSum("test"); + expect(hash1).toBe(hash2); + expect(typeof hash1).toBe("string"); + }); + + it("should export SAXStackParser class", async () => { + const { SAXStackParser } = await import("@hpcc-js/util"); + expect(SAXStackParser).toBeDefined(); + + const parser = new SAXStackParser(); + expect(typeof parser).toBe("object"); + expect(parser).toBeInstanceOf(SAXStackParser); + }); + + it("should export platform utilities", async () => { + const { isBrowser, isNode } = await import("@hpcc-js/util"); + expect(isBrowser).toBeDefined(); + expect(isNode).toBeDefined(); + expect(typeof isBrowser).toBe("boolean"); + expect(typeof isNode).toBe("boolean"); + + // In browser environment, these should have expected values + expect(isBrowser).toBe(true); + expect(isNode).toBe(false); + }); + + it("should support named imports", async () => { + const { Dictionary, hashSum, SAXStackParser, isBrowser, isNode } = await import("@hpcc-js/util"); + + expect(Dictionary).toBeDefined(); + expect(hashSum).toBeDefined(); + expect(SAXStackParser).toBeDefined(); + expect(isBrowser).toBeDefined(); + expect(isNode).toBeDefined(); + + // Test that they work + const dict = new Dictionary(); + dict.set("esm-test", "works"); + expect(dict.get("esm-test")).toBe("works"); + + const hash = hashSum("esm-test"); + expect(typeof hash).toBe("string"); + }); + + it("should work in browser environment", async () => { + // Browser-specific tests + expect(typeof window).toBe("object"); + expect(typeof document).toBe("object"); + + const util = await import("@hpcc-js/util"); + expect(util).toBeDefined(); + + // Test browser-specific utilities + const { isBrowser, isNode } = util; + expect(isBrowser).toBe(true); + expect(isNode).toBe(false); + }); + + it("should handle DOM-related operations", async () => { + const { Dictionary } = await import("@hpcc-js/util"); + + // Test that util classes work with browser DOM + const dict = new Dictionary(); + dict.set("dom-test", document.title || "test"); + expect(dict.get("dom-test")).toBeDefined(); + + // Test that we can store DOM references + dict.set("body-ref", document.body); + expect(dict.get("body-ref")).toBe(document.body); + }); + + it("should have expected number of exports", async () => { + const util = await import("@hpcc-js/util"); + const exportKeys = Object.keys(util); + expect(exportKeys.length).toBeGreaterThan(50); // Should have many exports + }); +}); diff --git a/tests/browser-esm/vitest.config.ts b/tests/browser-esm/vitest.config.ts new file mode 100644 index 0000000000..0ebc8eaf51 --- /dev/null +++ b/tests/browser-esm/vitest.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + globals: false, + testTimeout: 15000, + browser: { + enabled: true, + provider: "playwright", + instances: [{ + name: "chromium", + browser: "chromium", + headless: true, + }], + screenshotFailures: false, + }, + }, +}); diff --git a/tests/browser-umd/README.md b/tests/browser-umd/README.md new file mode 100644 index 0000000000..150a27eed7 --- /dev/null +++ b/tests/browser-umd/README.md @@ -0,0 +1,91 @@ +# Browser UMD Compatibility Tests + +This directory contains tests to verify that `@hpcc-js` packages work correctly in browser environments using UMD (Universal Module Definition) builds. + +## Purpose + +These tests ensure that: +- The UMD package builds can be successfully loaded in browser environments +- Named imports work correctly with UMD builds +- All major exports are available and functional +- Core functionality works as expected in a browser UMD environment +- Browser-specific features work correctly with UMD builds + +## Running Tests + +From this directory: +```bash +npm test +``` + +From the monorepo root: +```bash +npm run test-browser-umd +``` + +## Test Framework + +- **Vitest** - Modern test runner with excellent browser support +- **Playwright** - Browser automation for real browser testing +- **Browser Environment** - Tests run in headless Chromium to verify client-side compatibility +- **UMD Loading** - Uses module resolution aliases to test actual UMD build files + +## What's Tested + +### @hpcc-js/util Package +- Dictionary class creation and operations +- hashSum function consistency +- SAXStackParser class instantiation +- Platform utility availability (isBrowser, isNode) +- DOM integration capabilities +- Export count validation + +### @hpcc-js/comms Package +- ESPConnection class instantiation +- WorkunitsService and other service classes +- Workunit and other entity classes +- Communication utilities +- Exception handling classes +- Browser-specific connection options +- Export count validation + +### @hpcc-js/dataflow Package +- Activity functions (map, filter, sort, group, join, etc.) +- Observer functions (count, max, min, mean, median, etc.) +- Utility functions (pipe, generate, isSource) +- Pipeline operations and data transformations +- Statistical computations +- Browser data processing capabilities +- Export count validation + +## Configuration + +- `package.json` - Configured for UMD testing with appropriate dependencies +- `vitest.config.js` - Set up for browser testing with module resolution aliases pointing to UMD builds +- Uses both dynamic imports and module resolution to test UMD functionality + +## Test Files + +- `util.browser.spec.js` - Comprehensive tests for the `@hpcc-js/util` package UMD build +- `comms.browser.spec.js` - Tests for the `@hpcc-js/comms` package UMD build +- `dataflow.browser.spec.js` - Tests for the `@hpcc-js/dataflow` package UMD build + +## UMD vs ESM vs CommonJS + +Key differences from other test suites: + +1. **Module Loading**: Tests UMD builds specifically (`dist/index.umd.cjs` files) +2. **Browser Environment**: Runs in actual browser context using Playwright +3. **Resolution Aliases**: Uses Vite aliases to ensure UMD files are loaded +4. **Universal Compatibility**: Verifies that UMD builds work in browser environments +5. **Build Verification**: Confirms that the actual built UMD files are functional + +## UMD Build Testing + +The tests verify that: +- UMD builds are properly generated and accessible +- Modules can be imported in browser environments +- All exports are available through the UMD interface +- Functionality is identical to ESM versions +- Browser-specific features work correctly with UMD builds +- Performance characteristics are appropriate for browser usage diff --git a/tests/browser-umd/comms.browser.spec.ts b/tests/browser-umd/comms.browser.spec.ts new file mode 100644 index 0000000000..ec1ce47876 --- /dev/null +++ b/tests/browser-umd/comms.browser.spec.ts @@ -0,0 +1,127 @@ +import { describe, it, expect, beforeAll } from "vitest"; +import { simpleRequire } from "./util.js"; + +describe("@hpcc-js/comms Browser UMD compatibility", () => { + let commsUMD; + + beforeAll(async () => { + await simpleRequire("@hpcc-js/util", "./node_modules/@hpcc-js/util/dist/index.umd.cjs"); + const module = await simpleRequire("@hpcc-js/comms", "./node_modules/@hpcc-js/comms/dist/browser/index.umd.cjs"); + commsUMD = module.default || module; + }); + + it("should successfully load the UMD package", () => { + expect(commsUMD).toBeDefined(); + expect(typeof commsUMD).toBe("object"); + expect(Object.keys(commsUMD).length).toBeGreaterThan(0); + }); + + it("should export ESPConnection class", async () => { + const { ESPConnection } = commsUMD; + expect(ESPConnection).toBeDefined(); + + const connection = new ESPConnection({ baseUrl: "http://localhost:8010" }); + expect(connection).toBeDefined(); + expect(typeof connection).toBe("object"); + }); + + it("should export WorkunitsService class", async () => { + const { WorkunitsService } = commsUMD; + expect(WorkunitsService).toBeDefined(); + + const service = new WorkunitsService({ baseUrl: "http://localhost:8010" }); + expect(service).toBeDefined(); + expect(typeof service).toBe("object"); + }); + + it("should export Workunit class", async () => { + const { Workunit } = commsUMD; + expect(Workunit).toBeDefined(); + + const wu = new Workunit({ baseUrl: "http://localhost:8010" }, "W12345"); + expect(wu).toBeDefined(); + expect(typeof wu).toBe("object"); + }); + + it("should export utility functions", async () => { + const { createConnection, isArray, parseXSD, serializeRequest, deserializeResponse } = commsUMD; + + expect(createConnection).toBeDefined(); + expect(isArray).toBeDefined(); + expect(parseXSD).toBeDefined(); + expect(serializeRequest).toBeDefined(); + expect(deserializeResponse).toBeDefined(); + }); + + it("should export exception classes", async () => { + const { ESPExceptions } = commsUMD; + expect(ESPExceptions).toBeDefined(); + + const exception = new ESPExceptions("test", {}, { Source: "test", Exception: [] }); + expect(exception).toBeDefined(); + expect(exception).toBeInstanceOf(Error); + }); + + it("should support named imports", async () => { + const { ESPConnection, WorkunitsService, Workunit, ESPExceptions } = commsUMD; + + expect(ESPConnection).toBeDefined(); + expect(WorkunitsService).toBeDefined(); + expect(Workunit).toBeDefined(); + expect(ESPExceptions).toBeDefined(); + + const connection = new ESPConnection({ baseUrl: "http://localhost:8010" }); + expect(connection).toBeDefined(); + + const service = new WorkunitsService({ baseUrl: "http://localhost:8010" }); + expect(service).toBeDefined(); + }); + + it("should support mixed imports", async () => { + const { + ESPConnection, + WorkunitsService, + DFUService, + LogicalFile, + createConnection + } = commsUMD; + + expect(ESPConnection).toBeDefined(); + expect(WorkunitsService).toBeDefined(); + expect(DFUService).toBeDefined(); + expect(LogicalFile).toBeDefined(); + expect(createConnection).toBeDefined(); + + const connection = new ESPConnection({ baseUrl: "http://localhost:8010" }); + const wuService = new WorkunitsService({ baseUrl: "http://localhost:8010" }); + const dfuService = new DFUService({ baseUrl: "http://localhost:8010" }); + + expect(connection).toBeDefined(); + expect(wuService).toBeDefined(); + expect(dfuService).toBeDefined(); + }); + + it("should work in browser environment", async () => { + expect(typeof window).toBe("object"); + expect(typeof document).toBe("object"); + + const comms = commsUMD; + expect(comms).toBeDefined(); + + const exportKeys = Object.keys(comms); + expect(exportKeys.length).toBeGreaterThan(100); + }); + + it("should handle browser-specific features", async () => { + const { ESPConnection } = commsUMD; + + const connection = new ESPConnection({ + baseUrl: "http://localhost:8010", + userID: "testuser", + password: "testpass" + }); + + expect(connection).toBeDefined(); + expect(typeof connection).toBe("object"); + }); +}); diff --git a/tests/browser-umd/dataflow.browser.spec.ts b/tests/browser-umd/dataflow.browser.spec.ts new file mode 100644 index 0000000000..1abf3cb2f7 --- /dev/null +++ b/tests/browser-umd/dataflow.browser.spec.ts @@ -0,0 +1,185 @@ +import { describe, it, expect, beforeAll } from "vitest"; +import { simpleRequire } from "./util.js"; + +describe("@hpcc-js/dataflow Browser UMD compatibility", () => { + let dataflowUMD; + + beforeAll(async () => { + const module = await simpleRequire("@hpcc-js/dataflow", "./node_modules/@hpcc-js/dataflow/dist/index.umd.cjs"); + dataflowUMD = module.default || module; + }); + + it("should successfully load the UMD package", () => { + expect(dataflowUMD).toBeDefined(); + expect(typeof dataflowUMD).toBe("object"); + expect(Object.keys(dataflowUMD).length).toBeGreaterThan(0); + }); + + it("should export activity functions", async () => { + const { map, filter, sort, group, join } = dataflowUMD; + expect(map).toBeDefined(); + expect(filter).toBeDefined(); + expect(sort).toBeDefined(); + expect(group).toBeDefined(); + expect(join).toBeDefined(); + expect(typeof map).toBe("function"); + expect(typeof filter).toBe("function"); + }); + + it("should export observer functions", async () => { + const { count, max, min, mean, median } = dataflowUMD; + expect(count).toBeDefined(); + expect(max).toBeDefined(); + expect(min).toBeDefined(); + expect(mean).toBeDefined(); + expect(median).toBeDefined(); + expect(typeof count).toBe("function"); + expect(typeof max).toBe("function"); + }); + + it("should export utility functions", async () => { + const { pipe, generate } = dataflowUMD; + expect(pipe).toBeDefined(); + expect(generate).toBeDefined(); + expect(typeof pipe).toBe("function"); + expect(typeof generate).toBe("function"); + }); + + it("should export activity types", async () => { + const { isSource } = dataflowUMD; + expect(isSource).toBeDefined(); + expect(typeof isSource).toBe("function"); + }); + + it("should support named imports", async () => { + const { map, filter, count, pipe, isSource, scalar } = dataflowUMD; + + expect(map).toBeDefined(); + expect(filter).toBeDefined(); + expect(count).toBeDefined(); + expect(pipe).toBeDefined(); + expect(isSource).toBeDefined(); + expect(scalar).toBeDefined(); + }); + + it("should work with basic map operation", async () => { + const { map } = dataflowUMD; + + const data = [1, 2, 3, 4, 5]; + const doubled = [...map(data, x => x * 2)]; + + expect(doubled).toEqual([2, 4, 6, 8, 10]); + }); + + it("should work with basic filter operation", async () => { + const { filter } = dataflowUMD; + + const data = [1, 2, 3, 4, 5]; + const evens = [...filter(data, x => x % 2 === 0)]; + + expect(evens).toEqual([2, 4]); + }); + + it("should work with basic count operation", async () => { + const { count, scalar } = dataflowUMD; + + const data = [1, 2, 3, 4, 5]; + const result = scalar(count())(data); + + expect(result).toBe(5); + }); + + it("should work with basic pipe operation", async () => { + const { pipe, map, filter } = dataflowUMD; + + const data = [1, 2, 3, 4, 5, 6]; + const pipeline = pipe( + map(x => x * 2), + filter(x => x > 5) + ); + const result = [...pipeline(data)]; + + expect(result).toEqual([6, 8, 10, 12]); + }); + + it("should work with isSource utility", async () => { + const { isSource } = dataflowUMD; + + expect(isSource([1, 2, 3])).toBe(true); + expect(isSource("string is iterable")).toBe(true); + expect(isSource(42)).toBe(false); + expect(isSource(null)).toBe(null); + expect(isSource(undefined)).toBe(undefined); + expect(isSource({})).toBe(false); + }); + + it("should work with statistical observers", async () => { + const { max, min, mean, scalar } = dataflowUMD; + + const data = [1, 2, 3, 4, 5]; + + expect(scalar(max())(data)).toBe(5); + expect(scalar(min())(data)).toBe(1); + expect(scalar(mean())(data)).toBe(3); + }); + + it("should work with sort activity", async () => { + const { sort } = dataflowUMD; + + const data = [3, 1, 4, 1, 5, 9, 2, 6]; + const sorted = [...sort(data)]; + + expect(sorted).toEqual([1, 1, 2, 3, 4, 5, 6, 9]); + }); + + it("should work with advanced pipeline operations", async () => { + const { pipe, map, filter, sort } = dataflowUMD; + + const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + const pipeline = pipe( + filter(x => x % 2 === 0), + map(x => x * x), + sort((a, b) => b - a) + ); + const result = [...pipeline(data)]; + + expect(result).toEqual([100, 64, 36, 16, 4]); + }); + + it("should work in browser environment", async () => { + expect(typeof window).toBe("object"); + expect(typeof document).toBe("object"); + + const dataflow = dataflowUMD; + expect(dataflow).toBeDefined(); + + const { map, filter } = dataflow; + const browserData = Array.from(document.querySelectorAll("*")).slice(0, 5).map((_, i) => i + 1); + const processed = [...filter(map(browserData, x => x * 2), x => x > 2)]; + expect(processed).toEqual([4, 6, 8, 10]); + }); + + it("should handle browser-specific data processing", async () => { + const { pipe, map, filter, count, scalar } = dataflowUMD; + + const bodyLength = document.body ? document.body.innerHTML.length : 100; + const testData = Array.from({ length: 10 }, (_, i) => i + bodyLength); + + const pipeline = pipe( + filter(x => x % 2 === 0), + map(x => x / 2) + ); + + const processed = [...pipeline(testData)]; + const processedCount = scalar(count())(processed); + + expect(processedCount).toBeGreaterThan(0); + expect(Array.isArray(processed)).toBe(true); + }); + + it("should have expected number of exports", async () => { + const dataflow = dataflowUMD; + const exportKeys = Object.keys(dataflow); + expect(exportKeys.length).toBeGreaterThan(20); + }); +}); diff --git a/tests/browser-umd/package.json b/tests/browser-umd/package.json new file mode 100644 index 0000000000..295b6d4e8c --- /dev/null +++ b/tests/browser-umd/package.json @@ -0,0 +1,16 @@ +{ + "name": "hpcc-js-browser-umd-tests", + "version": "1.0.0", + "description": "Browser UMD tests for HPCC Visualization Framework", + "type": "commonjs", + "private": true, + "scripts": { + "test": "vitest run", + "test-watch": "vitest" + }, + "dependencies": { + "@hpcc-js/comms": "file:../../packages/comms", + "@hpcc-js/dataflow": "file:../../packages/dataflow", + "@hpcc-js/util": "file:../../packages/util" + } +} \ No newline at end of file diff --git a/tests/browser-umd/tsconfig.json b/tests/browser-umd/tsconfig.json new file mode 100644 index 0000000000..9058f157db --- /dev/null +++ b/tests/browser-umd/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../packages/tsconfig.settings.json", + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "skipLibCheck": true, + "strict": false, + "types": [ + "vitest/globals" + ] + }, + "include": [ + "./**/*.ts", + "./**/*.js" + ] +} \ No newline at end of file diff --git a/tests/browser-umd/util.browser.spec.ts b/tests/browser-umd/util.browser.spec.ts new file mode 100644 index 0000000000..a65c645be8 --- /dev/null +++ b/tests/browser-umd/util.browser.spec.ts @@ -0,0 +1,97 @@ +import { describe, it, expect, beforeAll } from "vitest"; +import { simpleRequire } from "./util.js"; + +describe("@hpcc-js/util Browser UMD compatibility", () => { + let utilUMD; + + beforeAll(async () => { + const module = await simpleRequire("@hpcc-js/util", "./node_modules/@hpcc-js/util/dist/index.umd.cjs"); + utilUMD = module.default || module; + }); + + it("should export Dictionary class", async () => { + const { Dictionary } = utilUMD; + expect(Dictionary).toBeDefined(); + + const dict = new Dictionary(); + dict.set("test", "value"); + const result = dict.get("test"); + expect(result).toBe("value"); + }); + + it("should export hashSum function", async () => { + const { hashSum } = utilUMD; + expect(hashSum).toBeDefined(); + + const hash1 = hashSum("test"); + const hash2 = hashSum("test"); + expect(hash1).toBe(hash2); + expect(typeof hash1).toBe("string"); + }); + + it("should export SAXStackParser class", async () => { + const { SAXStackParser } = utilUMD; + expect(SAXStackParser).toBeDefined(); + + const parser = new SAXStackParser(); + expect(typeof parser).toBe("object"); + expect(parser).toBeInstanceOf(SAXStackParser); + }); + + it("should export platform utilities", async () => { + const { isBrowser, isNode } = utilUMD; + expect(isBrowser).toBeDefined(); + expect(isNode).toBeDefined(); + expect(typeof isBrowser).toBe("boolean"); + expect(typeof isNode).toBe("boolean"); + + expect(isBrowser).toBe(true); + expect(isNode).toBe(false); + }); + + it("should support named imports", async () => { + const { Dictionary, hashSum, SAXStackParser, isBrowser, isNode } = utilUMD; + + expect(Dictionary).toBeDefined(); + expect(hashSum).toBeDefined(); + expect(SAXStackParser).toBeDefined(); + expect(isBrowser).toBeDefined(); + expect(isNode).toBeDefined(); + + const dict = new Dictionary(); + dict.set("esm-test", "works"); + expect(dict.get("esm-test")).toBe("works"); + + const hash = hashSum("esm-test"); + expect(typeof hash).toBe("string"); + }); + + it("should work in browser environment", async () => { + expect(typeof window).toBe("object"); + expect(typeof document).toBe("object"); + + const util = utilUMD; + expect(util).toBeDefined(); + + const { isBrowser, isNode } = util; + expect(isBrowser).toBe(true); + expect(isNode).toBe(false); + }); + + it("should handle DOM-related operations", async () => { + const { Dictionary } = utilUMD; + + const dict = new Dictionary(); + dict.set("dom-test", document.title || "test"); + expect(dict.get("dom-test")).toBeDefined(); + + dict.set("body-ref", document.body); + expect(dict.get("body-ref")).toBe(document.body); + }); + + it("should have expected number of exports", async () => { + const util = utilUMD; + const exportKeys = Object.keys(util); + expect(exportKeys.length).toBeGreaterThan(50); + }); +}); diff --git a/tests/browser-umd/util.ts b/tests/browser-umd/util.ts new file mode 100644 index 0000000000..1bd72139d4 --- /dev/null +++ b/tests/browser-umd/util.ts @@ -0,0 +1,41 @@ + + +export async function simpleRequire(id: string, path: string): Promise { + // Check if module is already loaded + if ((window as any)[id]) { + return (window as any)[id]; + } + + // Load the UMD bundle + const script = document.createElement("script"); + script.src = import.meta.resolve(path); + script.type = "text/javascript"; + script.async = false; // Ensure synchronous execution order + document.head.appendChild(script); + + return new Promise((resolve, reject) => { + script.onload = () => { + // UMD modules typically expose themselves on the global object + const module = (window as any)[id]; + if (module) { + resolve(module); + } else { + reject(new Error(`Module '${id}' not found on global object after loading ${path}`)); + } + }; + + script.onerror = () => { + reject(new Error(`Failed to load UMD bundle: ${script.src}`)); + }; + + // Timeout fallback for cases where onload doesn't fire + setTimeout(() => { + const module = (window as any)[id]; + if (module) { + resolve(module); + } else { + reject(new Error(`Timeout loading UMD bundle: ${script.src}`)); + } + }, 10000); // 10 second timeout + }); +} diff --git a/tests/browser-umd/vitest.config.ts b/tests/browser-umd/vitest.config.ts new file mode 100644 index 0000000000..7c39461b0f --- /dev/null +++ b/tests/browser-umd/vitest.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + globals: false, + testTimeout: 15000, + browser: { + enabled: true, + provider: "playwright", + instances: [{ + name: "chromium", + browser: "chromium", + headless: true, + }], + screenshotFailures: false, + } + } +}); diff --git a/tests/node-cjs/README.md b/tests/node-cjs/README.md new file mode 100644 index 0000000000..1f98ef66f0 --- /dev/null +++ b/tests/node-cjs/README.md @@ -0,0 +1,58 @@ +# Node.js CommonJS Compatibility Tests + +This directory contains tests to verify that `@hpcc-js/util` works correctly in Node.js environments using CommonJS module loading. + +## Purpose + +These tests ensure that: +- The package can be successfully imported using CommonJS `require()` syntax +- All major exports are available and functional +- Core functionality works as expected in a CommonJS context +- Both namespace imports and destructuring assignment work with `require()` + +## Running Tests + +From this directory: +```bash +npm test +``` + +From the monorepo root: +```bash +npm run test-node-cjs +``` + +## Test Framework + +- **Vitest** - Modern test runner with excellent TypeScript and ES modules support +- **Node.js Environment** - Tests run in a Node.js environment to verify server-side compatibility +- **Hybrid Approach** - Uses ESM for Vitest imports but CommonJS `require()` for testing the actual package + +## What's Tested + +- Basic package `require()` functionality +- Dictionary class creation and operations +- hashSum function consistency +- SAXStackParser class instantiation +- Platform utility availability +- Destructuring assignment with `require()` +- Export count validation + +## Configuration + +- `package.json` - Configured with `"type": "commonjs"` to test CommonJS behavior +- Uses `require()` statements for testing the actual package (with ESLint exemption) +- Uses `import` for Vitest test framework (required by modern Vitest) +- Tests are in `*.spec.js` files following Vitest conventions + +## Test Files + +- `util-cjs.spec.js` - Comprehensive tests for the `@hpcc-js/util` package using CommonJS `require()` + +## Implementation Notes + +The tests use a hybrid approach: +1. **Vitest Framework**: Imported using ESM `import` (required by Vitest) +2. **Package Under Test**: Imported using CommonJS `require()` (what we're actually testing) + +This ensures we properly test CommonJS compatibility while using a modern test runner. diff --git a/tests/node-cjs/comms.node.spec.ts b/tests/node-cjs/comms.node.spec.ts new file mode 100644 index 0000000000..fd9e3ee371 --- /dev/null +++ b/tests/node-cjs/comms.node.spec.ts @@ -0,0 +1,77 @@ +/* eslint-disable @typescript-eslint/no-require-imports */ +import { describe, it, expect } from "vitest"; + +describe("@hpcc-js/comms CommonJS compatibility", () => { + it("should successfully require the package", () => { + const comms = require("@hpcc-js/comms"); + expect(comms).toBeDefined(); + expect(Object.keys(comms).length).toBeGreaterThan(0); + }); + + it("should export ESPConnection class", () => { + const comms = require("@hpcc-js/comms"); + expect(comms.ESPConnection).toBeDefined(); + + const connection = new comms.ESPConnection({ baseUrl: "http://localhost:8010" }); + expect(connection).toBeDefined(); + expect(typeof connection).toBe("object"); + }); + + it("should export WorkunitsService class", () => { + const comms = require("@hpcc-js/comms"); + expect(comms.WorkunitsService).toBeDefined(); + + const service = new comms.WorkunitsService({ baseUrl: "http://localhost:8010" }); + expect(service).toBeDefined(); + expect(typeof service).toBe("object"); + }); + + it("should export Workunit class", () => { + const comms = require("@hpcc-js/comms"); + expect(comms.Workunit).toBeDefined(); + + const wu = new comms.Workunit({ baseUrl: "http://localhost:8010" }, "W12345"); + expect(wu).toBeDefined(); + expect(typeof wu).toBe("object"); + }); + + it("should export utility functions", () => { + const comms = require("@hpcc-js/comms"); + + expect(comms.createConnection).toBeDefined(); + expect(comms.isArray).toBeDefined(); + expect(comms.parseXSD).toBeDefined(); + expect(comms.serializeRequest).toBeDefined(); + expect(comms.deserializeResponse).toBeDefined(); + }); + + it("should export exception classes", () => { + const comms = require("@hpcc-js/comms"); + expect(comms.ESPExceptions).toBeDefined(); + + const exception = new comms.ESPExceptions("test", {}, { Source: "test", Exception: [] }); + expect(exception).toBeDefined(); + expect(exception).toBeInstanceOf(Error); + }); + + it("should support destructuring require", () => { + const { ESPConnection, WorkunitsService, Workunit, ESPExceptions } = require("@hpcc-js/comms"); + + expect(ESPConnection).toBeDefined(); + expect(WorkunitsService).toBeDefined(); + expect(Workunit).toBeDefined(); + expect(ESPExceptions).toBeDefined(); + + const connection = new ESPConnection({ baseUrl: "http://localhost:8010" }); + expect(connection).toBeDefined(); + + const service = new WorkunitsService({ baseUrl: "http://localhost:8010" }); + expect(service).toBeDefined(); + }); + + it("should have expected number of exports", () => { + const comms = require("@hpcc-js/comms"); + const exportKeys = Object.keys(comms); + expect(exportKeys.length).toBeGreaterThan(100); + }); +}); diff --git a/tests/node-cjs/dataflow.node.spec.ts b/tests/node-cjs/dataflow.node.spec.ts new file mode 100644 index 0000000000..a1a957ac81 --- /dev/null +++ b/tests/node-cjs/dataflow.node.spec.ts @@ -0,0 +1,108 @@ +/* eslint-disable @typescript-eslint/no-require-imports */ +import { describe, it, expect } from "vitest"; + +describe("@hpcc-js/dataflow CommonJS compatibility", () => { + it("should successfully require the package", () => { + const dataflow = require("@hpcc-js/dataflow"); + expect(dataflow).toBeDefined(); + expect(Object.keys(dataflow).length).toBeGreaterThan(0); + }); + + it("should export activity functions", () => { + const dataflow = require("@hpcc-js/dataflow"); + expect(dataflow.map).toBeDefined(); + expect(dataflow.filter).toBeDefined(); + expect(dataflow.sort).toBeDefined(); + expect(dataflow.group).toBeDefined(); + expect(dataflow.join).toBeDefined(); + expect(typeof dataflow.map).toBe("function"); + expect(typeof dataflow.filter).toBe("function"); + }); + + it("should export observer functions", () => { + const dataflow = require("@hpcc-js/dataflow"); + expect(dataflow.count).toBeDefined(); + expect(dataflow.max).toBeDefined(); + expect(dataflow.min).toBeDefined(); + expect(dataflow.mean).toBeDefined(); + expect(dataflow.median).toBeDefined(); + expect(typeof dataflow.count).toBe("function"); + expect(typeof dataflow.max).toBe("function"); + }); + + it("should export utility functions", () => { + const dataflow = require("@hpcc-js/dataflow"); + expect(dataflow.pipe).toBeDefined(); + expect(dataflow.generate).toBeDefined(); + expect(typeof dataflow.pipe).toBe("function"); + expect(typeof dataflow.generate).toBe("function"); + }); + + it("should export activity types", () => { + const dataflow = require("@hpcc-js/dataflow"); + expect(dataflow.isSource).toBeDefined(); + expect(typeof dataflow.isSource).toBe("function"); + }); + + it("should support destructuring require", () => { + const { map, filter, count, pipe, isSource, scalar } = require("@hpcc-js/dataflow"); + + expect(map).toBeDefined(); + expect(filter).toBeDefined(); + expect(count).toBeDefined(); + expect(pipe).toBeDefined(); + expect(isSource).toBeDefined(); + expect(scalar).toBeDefined(); + }); + + it("should work with basic map operation", () => { + const { map } = require("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5]; + const doubled = [...map(data, x => x * 2)]; + + expect(doubled).toEqual([2, 4, 6, 8, 10]); + }); + + it("should work with basic filter operation", () => { + const { filter } = require("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5]; + const evens = [...filter(data, x => x % 2 === 0)]; + + expect(evens).toEqual([2, 4]); + }); + + it("should work with basic count operation", () => { + const { count, scalar } = require("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5]; + const result = scalar(count())(data); + + expect(result).toBe(5); + }); + + it("should work with basic pipe operation", () => { + const { pipe, map, filter } = require("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5, 6]; + const pipeline = pipe( + map(x => x * 2), + filter(x => x > 5) + ); + const result = [...pipeline(data)]; + + expect(result).toEqual([6, 8, 10, 12]); + }); + + it("should work with isSource utility", () => { + const { isSource } = require("@hpcc-js/dataflow"); + + expect(isSource([1, 2, 3])).toBe(true); + expect(isSource("string is iterable")).toBe(true); // Strings are iterable + expect(isSource(42)).toBe(false); + expect(isSource(null)).toBe(null); // Returns the falsy value itself + expect(isSource(undefined)).toBe(undefined); // Returns the falsy value itself + expect(isSource({})).toBe(false); + }); +}); diff --git a/tests/node-cjs/package.json b/tests/node-cjs/package.json new file mode 100644 index 0000000000..ccb3fdfea7 --- /dev/null +++ b/tests/node-cjs/package.json @@ -0,0 +1,16 @@ +{ + "name": "hpcc-js-node-cjs-tests", + "version": "1.0.0", + "description": "NodeJS CommonJS tests for HPCC Visualization Framework", + "type": "commonjs", + "private": true, + "scripts": { + "test": "vitest run", + "test-watch": "vitest" + }, + "dependencies": { + "@hpcc-js/comms": "file:../../packages/comms", + "@hpcc-js/dataflow": "file:../../packages/dataflow", + "@hpcc-js/util": "file:../../packages/util" + } +} \ No newline at end of file diff --git a/tests/node-cjs/tsconfig.json b/tests/node-cjs/tsconfig.json new file mode 100644 index 0000000000..3cb3166d43 --- /dev/null +++ b/tests/node-cjs/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../packages/tsconfig.settings.json", + "compilerOptions": { + "target": "ES2020", + "module": "CommonJS", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "skipLibCheck": true, + "strict": false, + "types": [ + "vitest/globals", + "node" + ] + }, + "include": [ + "./**/*.ts", + "./**/*.js" + ] +} \ No newline at end of file diff --git a/tests/node-cjs/util.node.spec.ts b/tests/node-cjs/util.node.spec.ts new file mode 100644 index 0000000000..efb071d89d --- /dev/null +++ b/tests/node-cjs/util.node.spec.ts @@ -0,0 +1,67 @@ +/* eslint-disable @typescript-eslint/no-require-imports */ +import { describe, it, expect } from "vitest"; + +describe("@hpcc-js/util CommonJS compatibility", () => { + it("should successfully require the package", () => { + const util = require("@hpcc-js/util"); + expect(util).toBeDefined(); + expect(Object.keys(util).length).toBeGreaterThan(0); + }); + + it("should export Dictionary class", () => { + const util = require("@hpcc-js/util"); + expect(util.Dictionary).toBeDefined(); + + const dict = new util.Dictionary(); + dict.set("test", "value"); + const result = dict.get("test"); + expect(result).toBe("value"); + }); + + it("should export hashSum function", () => { + const util = require("@hpcc-js/util"); + expect(util.hashSum).toBeDefined(); + + const hash1 = util.hashSum("test"); + const hash2 = util.hashSum("test"); + expect(hash1).toBe(hash2); + expect(typeof hash1).toBe("string"); + }); + + it("should export SAXStackParser class", () => { + const util = require("@hpcc-js/util"); + expect(util.SAXStackParser).toBeDefined(); + + const parser = new util.SAXStackParser(); + expect(typeof parser).toBe("object"); + expect(parser).toBeInstanceOf(util.SAXStackParser); + }); + + it("should export platform utilities", () => { + const util = require("@hpcc-js/util"); + expect(util.isNode).toBeDefined(); + expect(typeof util.isNode).toBe("boolean"); + }); + + it("should support destructuring require", () => { + const { Dictionary, hashSum, SAXStackParser, isNode } = require("@hpcc-js/util"); + + expect(Dictionary).toBeDefined(); + expect(hashSum).toBeDefined(); + expect(SAXStackParser).toBeDefined(); + expect(isNode).toBeDefined(); + + const dict = new Dictionary(); + dict.set("cjs-test", "works"); + expect(dict.get("cjs-test")).toBe("works"); + + const hash = hashSum("cjs-test"); + expect(typeof hash).toBe("string"); + }); + + it("should have expected number of exports", () => { + const util = require("@hpcc-js/util"); + const exportKeys = Object.keys(util); + expect(exportKeys.length).toBeGreaterThan(50); + }); +}); diff --git a/tests/node-cjs/vitest.config.ts b/tests/node-cjs/vitest.config.ts new file mode 100644 index 0000000000..30e1cc5d02 --- /dev/null +++ b/tests/node-cjs/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "node", + globals: false + }, +}); diff --git a/tests/node-esm/README.md b/tests/node-esm/README.md new file mode 100644 index 0000000000..e04b2e9bf6 --- /dev/null +++ b/tests/node-esm/README.md @@ -0,0 +1,57 @@ +# Node.js ESM Compatibility Tests + +This directory contains tests to verify that `@hpcc-js/util` works correctly in Node.js environments using ES modules. + +## Purpose + +These tests ensure that: +- The package can be successfully imported using ESM `import` statements +- Named imports work correctly +- All major exports are available and functional +- Core functionality works as expected in an ESM environment + +## Running Tests + +From this directory: +```bash +npm test +``` + +From the monorepo root: +```bash +npm run test-node-esm +``` + +## Test Framework + +- **Vitest** - Modern test runner with excellent TypeScript and ES modules support +- **Node.js Environment** - Tests run in a Node.js environment to verify server-side compatibility + +## What's Tested + +- Basic package import functionality +- Named import functionality (ESM-specific) +- Dictionary class creation and operations +- hashSum function consistency +- SAXStackParser class instantiation +- Platform utility availability +- Export count validation + +## Configuration + +- `package.json` - Configured with `"type": "module"` to test ESM behavior +- Uses both dynamic imports (`await import()`) and static named imports +- Tests are in `*.spec.js` files following Vitest conventions + +## Test Files + +- `util-esm.spec.js` - Comprehensive tests for the `@hpcc-js/util` package including ESM-specific features + +## ESM vs CommonJS + +Key differences from the CommonJS tests: + +1. **Import Syntax**: Uses `import()` instead of `require()` +2. **Module Type**: `package.json` has `"type": "module"` +3. **Named Imports**: Tests ESM-specific destructuring import patterns +4. **Additional Tests**: Includes extra test for named import functionality diff --git a/tests/node-esm/comms.node.spec.ts b/tests/node-esm/comms.node.spec.ts new file mode 100644 index 0000000000..b277926af6 --- /dev/null +++ b/tests/node-esm/comms.node.spec.ts @@ -0,0 +1,101 @@ +// Test ESM imports for @hpcc-js/comms package +import { describe, it, expect } from "vitest"; + +describe("@hpcc-js/comms ESM compatibility", () => { + it("should successfully import the package", async () => { + const comms = await import("@hpcc-js/comms"); + expect(comms).toBeDefined(); + expect(Object.keys(comms).length).toBeGreaterThan(0); + }); + + it("should export ESPConnection class", async () => { + const { ESPConnection } = await import("@hpcc-js/comms"); + expect(ESPConnection).toBeDefined(); + + const connection = new ESPConnection({ baseUrl: "http://localhost:8010" }, "WsWorkunits", "1.76"); + expect(connection).toBeDefined(); + expect(typeof connection).toBe("object"); + }); + + it("should export WorkunitsService class", async () => { + const { WorkunitsService } = await import("@hpcc-js/comms"); + expect(WorkunitsService).toBeDefined(); + + const service = new WorkunitsService({ baseUrl: "http://localhost:8010" }); + expect(service).toBeDefined(); + expect(typeof service).toBe("object"); + }); + + it("should export Workunit class", async () => { + const { Workunit } = await import("@hpcc-js/comms"); + expect(Workunit).toBeDefined(); + + const wu = Workunit.attach({ baseUrl: "http://localhost:8010" }, "W12345"); + expect(wu).toBeDefined(); + expect(typeof wu).toBe("object"); + }); + + it("should export utility functions", async () => { + const { createConnection, isArray, parseXSD, serializeRequest, deserializeResponse } = await import("@hpcc-js/comms"); + + expect(createConnection).toBeDefined(); + expect(isArray).toBeDefined(); + expect(parseXSD).toBeDefined(); + expect(serializeRequest).toBeDefined(); + expect(deserializeResponse).toBeDefined(); + }); + + it("should export exception classes", async () => { + const { ESPExceptions } = await import("@hpcc-js/comms"); + expect(ESPExceptions).toBeDefined(); + + const exception = new ESPExceptions("test", {}, { Source: "test", Exception: [] }); + expect(exception).toBeDefined(); + expect(exception).toBeInstanceOf(Error); + }); + + it("should support named imports", async () => { + const { ESPConnection, WorkunitsService, Workunit, ESPExceptions } = await import("@hpcc-js/comms"); + + expect(ESPConnection).toBeDefined(); + expect(WorkunitsService).toBeDefined(); + expect(Workunit).toBeDefined(); + expect(ESPExceptions).toBeDefined(); + + const connection = new ESPConnection({ baseUrl: "http://localhost:8010" }, "WsWorkunits", "1.76"); + expect(connection).toBeDefined(); + + const service = new WorkunitsService({ baseUrl: "http://localhost:8010" }); + expect(service).toBeDefined(); + }); + + it("should support mixed imports", async () => { + const { + ESPConnection, + WorkunitsService, + DFUService, + LogicalFile, + createConnection + } = await import("@hpcc-js/comms"); + + expect(ESPConnection).toBeDefined(); + expect(WorkunitsService).toBeDefined(); + expect(DFUService).toBeDefined(); + expect(LogicalFile).toBeDefined(); + expect(createConnection).toBeDefined(); + + const connection = new ESPConnection({ baseUrl: "http://localhost:8010" }, "WsWorkunits", "1.76"); + const wuService = new WorkunitsService({ baseUrl: "http://localhost:8010" }); + const dfuService = new DFUService({ baseUrl: "http://localhost:8010" }); + + expect(connection).toBeDefined(); + expect(wuService).toBeDefined(); + expect(dfuService).toBeDefined(); + }); + + it("should have expected number of exports", async () => { + const comms = await import("@hpcc-js/comms"); + const exportKeys = Object.keys(comms); + expect(exportKeys.length).toBeGreaterThan(100); + }); +}); diff --git a/tests/node-esm/dataflow.node.spec.ts b/tests/node-esm/dataflow.node.spec.ts new file mode 100644 index 0000000000..566bc71463 --- /dev/null +++ b/tests/node-esm/dataflow.node.spec.ts @@ -0,0 +1,140 @@ +// Test ESM imports for @hpcc-js/dataflow package +import { describe, it, expect } from "vitest"; + +describe("@hpcc-js/dataflow ESM compatibility", () => { + it("should successfully import the package", async () => { + const dataflow = await import("@hpcc-js/dataflow"); + expect(dataflow).toBeDefined(); + expect(Object.keys(dataflow).length).toBeGreaterThan(0); + }); + + it("should export activity functions", async () => { + const { map, filter, sort, group, join } = await import("@hpcc-js/dataflow"); + expect(map).toBeDefined(); + expect(filter).toBeDefined(); + expect(sort).toBeDefined(); + expect(group).toBeDefined(); + expect(join).toBeDefined(); + expect(typeof map).toBe("function"); + expect(typeof filter).toBe("function"); + }); + + it("should export observer functions", async () => { + const { count, max, min, mean, median } = await import("@hpcc-js/dataflow"); + expect(count).toBeDefined(); + expect(max).toBeDefined(); + expect(min).toBeDefined(); + expect(mean).toBeDefined(); + expect(median).toBeDefined(); + expect(typeof count).toBe("function"); + expect(typeof max).toBe("function"); + }); + + it("should export utility functions", async () => { + const { pipe, generate } = await import("@hpcc-js/dataflow"); + expect(pipe).toBeDefined(); + expect(generate).toBeDefined(); + expect(typeof pipe).toBe("function"); + expect(typeof generate).toBe("function"); + }); + + it("should export activity types", async () => { + const { isSource } = await import("@hpcc-js/dataflow"); + expect(isSource).toBeDefined(); expect(typeof isSource).toBe("function"); + }); + + it("should support named imports", async () => { + const { map, filter, count, pipe, isSource, scalar } = await import("@hpcc-js/dataflow"); + + expect(map).toBeDefined(); + expect(filter).toBeDefined(); + expect(count).toBeDefined(); + expect(pipe).toBeDefined(); + expect(isSource).toBeDefined(); + expect(scalar).toBeDefined(); + }); + + it("should work with basic map operation", async () => { + const { map } = await import("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5]; + const doubled = [...map(data, x => x * 2)]; + + expect(doubled).toEqual([2, 4, 6, 8, 10]); + }); + + it("should work with basic filter operation", async () => { + const { filter } = await import("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5]; + const evens = [...filter(data, x => x % 2 === 0)]; + + expect(evens).toEqual([2, 4]); + }); + + it("should work with basic count operation", async () => { + const { count, scalar } = await import("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5]; + const result = scalar(count())(data); + + expect(result).toBe(5); + }); + + it("should work with basic pipe operation", async () => { + const { pipe, map, filter } = await import("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5, 6]; + const pipeline = pipe( + map(x => x * 2), + filter(x => x > 5) + ); + const result = [...pipeline(data)]; + + expect(result).toEqual([6, 8, 10, 12]); + }); + + it("should work with isSource utility", async () => { + const { isSource } = await import("@hpcc-js/dataflow"); + + expect(isSource([1, 2, 3])).toBe(true); + expect(isSource("string is iterable")).toBe(true); // Strings are iterable + expect(isSource(42)).toBe(false); + expect(isSource(null)).toBe(null); // Returns the falsy value itself + expect(isSource(undefined)).toBe(undefined); // Returns the falsy value itself + expect(isSource({})).toBe(false); + }); + + it("should work with statistical observers", async () => { + const { max, min, mean, scalar } = await import("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5]; + + expect(scalar(max())(data)).toBe(5); + expect(scalar(min())(data)).toBe(1); + expect(scalar(mean())(data)).toBe(3); + }); + + it("should work with sort activity", async () => { + const { sort } = await import("@hpcc-js/dataflow"); + + const data = [3, 1, 4, 1, 5, 9, 2, 6]; + const sorted = [...sort(data)]; + + expect(sorted).toEqual([1, 1, 2, 3, 4, 5, 6, 9]); + }); + + it("should work with advanced pipeline operations", async () => { + const { pipe, map, filter, sort } = await import("@hpcc-js/dataflow"); + + const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + const pipeline = pipe( + filter(x => x % 2 === 0), + map(x => x * x), + sort((a, b) => b - a) + ); + const result = [...pipeline(data)]; + + expect(result).toEqual([100, 64, 36, 16, 4]); + }); +}); diff --git a/tests/node-esm/package.json b/tests/node-esm/package.json new file mode 100644 index 0000000000..9a2b90f5bf --- /dev/null +++ b/tests/node-esm/package.json @@ -0,0 +1,16 @@ +{ + "name": "hpcc-js-node-esm-tests", + "version": "1.0.0", + "description": "NodeJS ESM tests for HPCC Visualization Framework", + "type": "module", + "private": true, + "scripts": { + "test": "vitest run", + "test-watch": "vitest" + }, + "dependencies": { + "@hpcc-js/comms": "file:../../packages/comms", + "@hpcc-js/dataflow": "file:../../packages/dataflow", + "@hpcc-js/util": "file:../../packages/util" + } +} \ No newline at end of file diff --git a/tests/node-esm/tsconfig.json b/tests/node-esm/tsconfig.json new file mode 100644 index 0000000000..fb16c860c1 --- /dev/null +++ b/tests/node-esm/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../../packages/tsconfig.settings.json", + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "skipLibCheck": true, + "strict": false, + "noImplicitAny": false, + "types": [ + "vitest/globals", + "node" + ] + }, + "include": [ + "./**/*.ts", + "./**/*.js" + ] +} \ No newline at end of file diff --git a/tests/node-esm/util.node.spec.ts b/tests/node-esm/util.node.spec.ts new file mode 100644 index 0000000000..76ec1eae11 --- /dev/null +++ b/tests/node-esm/util.node.spec.ts @@ -0,0 +1,67 @@ +// Test ESM imports for @hpcc-js/util package +import { describe, it, expect } from "vitest"; + +describe("@hpcc-js/util ESM compatibility", () => { + it("should successfully import the package", async () => { + const util = await import("@hpcc-js/util"); + expect(util).toBeDefined(); + expect(Object.keys(util).length).toBeGreaterThan(0); + }); + + it("should export Dictionary class", async () => { + const { Dictionary } = await import("@hpcc-js/util"); + expect(Dictionary).toBeDefined(); + + const dict = new Dictionary(); + dict.set("test", "value"); + const result = dict.get("test"); + expect(result).toBe("value"); + }); + + it("should export hashSum function", async () => { + const { hashSum } = await import("@hpcc-js/util"); + expect(hashSum).toBeDefined(); + + const hash1 = hashSum("test"); + const hash2 = hashSum("test"); + expect(hash1).toBe(hash2); + expect(typeof hash1).toBe("string"); + }); + + it("should export SAXStackParser class", async () => { + const { SAXStackParser } = await import("@hpcc-js/util"); + expect(SAXStackParser).toBeDefined(); + + const parser = new SAXStackParser(); + expect(typeof parser).toBe("object"); + expect(parser).toBeInstanceOf(SAXStackParser); + }); + + it("should export platform utilities", async () => { + const { isNode } = await import("@hpcc-js/util"); + expect(isNode).toBeDefined(); + expect(typeof isNode).toBe("boolean"); + }); + + it("should support named imports", async () => { + const { Dictionary, hashSum, SAXStackParser, isNode } = await import("@hpcc-js/util"); + + expect(Dictionary).toBeDefined(); + expect(hashSum).toBeDefined(); + expect(SAXStackParser).toBeDefined(); + expect(isNode).toBeDefined(); + + const dict = new Dictionary(); + dict.set("esm-test", "works"); + expect(dict.get("esm-test")).toBe("works"); + + const hash = hashSum("esm-test"); + expect(typeof hash).toBe("string"); + }); + + it("should have expected number of exports", async () => { + const util = await import("@hpcc-js/util"); + const exportKeys = Object.keys(util); + expect(exportKeys.length).toBeGreaterThan(50); + }); +}); diff --git a/tests/node-esm/vitest.config.ts b/tests/node-esm/vitest.config.ts new file mode 100644 index 0000000000..30e1cc5d02 --- /dev/null +++ b/tests/node-esm/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "node", + globals: false + }, +});