diff --git a/.husky/post-checkout b/.husky/post-checkout
index 06336fb057..d53af76677 100755
--- a/.husky/post-checkout
+++ b/.husky/post-checkout
@@ -6,3 +6,15 @@ if [ "$HUSKY_POST_CHECKOUT" != 0 ]; then
npm install >/dev/null 2>&1
fi
fi
+
+if [ ! -d "build/js/src" ]; then
+ if [ -d "build" ]; then
+ if [ "$OSTYPE" = "msys" ]; then
+ # Windows (Git Bash/MSYS)
+ cmd.exe /C "rmdir /s /q build"
+ else
+ # POSIX
+ rm -rf build
+ fi
+ fi
+fi
diff --git a/.husky/pre-commit b/.husky/pre-commit
index f9b68dec5b..7aa2a09d54 100755
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -37,4 +37,19 @@ if [ "$HUSKY_PRE_COMMIT" != 0 ]; then
# Css wrap check
node .husky/css_check.js
+
+ # Check that all package.json versions are the same as the root
+ root_version=$(node -p "require('./package.json').version")
+ mismatch=0
+ for pkg in $(find packages -name package.json); do
+ pkg_version=$(node -p "require('./$pkg').version")
+ if [ "$pkg_version" != "$root_version" ]; then
+ echo "Version mismatch: $pkg ($pkg_version) != root ($root_version)"
+ mismatch=1
+ fi
+ done
+ if [ $mismatch -ne 0 ]; then
+ echo "❌ All package.json versions must match the root version."
+ exit 1
+ fi
fi
diff --git a/demo/minimalist.html b/demo/minimalist.html
index 22acc6f821..113213e051 100644
--- a/demo/minimalist.html
+++ b/demo/minimalist.html
@@ -24,7 +24,7 @@
-
+
diff --git a/doc/add_function.md b/doc/add_function.md
index 414756ae0f..4d5a127961 100644
--- a/doc/add_function.md
+++ b/doc/add_function.md
@@ -17,7 +17,7 @@
## Adding a new custom function
The `addFunction` method takes a name, and a function description which should
-implement the [`AddFunctionDescription`](https://github.com/odoo/o-spreadsheet/blob/49285322f75dda2d5bab4aea04daa2a3d6c28370/src/types/functions.ts#L31) interface. `addFunction` will return an object to allow chain calls.
+implement the [`Functions`](https://github.com/odoo/o-spreadsheet/blob/49285322f75dda2d5bab4aea04daa2a3d6c28370/src/types/functions.ts#L31) interface. `addFunction` will return an object to allow chain calls.
Below is a skeleton example to add multiple functions.
diff --git a/package-lock.json b/package-lock.json
index f10a83c331..3bec71a72f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,7 +8,11 @@
"name": "@odoo/o-spreadsheet",
"version": "19.1.0-alpha.3",
"license": "LGPL-3.0-or-later",
+ "workspaces": [
+ "packages/o-spreadsheet-engine"
+ ],
"dependencies": {
+ "@odoo/o-spreadsheet-engine": "*",
"@odoo/owl": "2.5.1",
"bootstrap": "^5.3.3",
"font-awesome": "^4.7.0",
@@ -16,6 +20,7 @@
},
"devDependencies": {
"@prettier/plugin-xml": "^2.2.0",
+ "@rollup/plugin-alias": "^5.1.1",
"@rollup/plugin-node-resolve": "^15.2.0",
"@rollup/plugin-terser": "^0.4.3",
"@swc/core": "1.6.7",
@@ -1098,11 +1103,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@jest/core/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/@jest/core/node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -1356,11 +1356,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/@jest/reporters/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/@jest/reporters/node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -1417,11 +1412,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/@jest/source-map/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/@jest/test-result": {
"version": "29.6.1",
"dev": true,
@@ -1450,11 +1440,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/@jest/test-sequencer/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/@jest/transform": {
"version": "29.6.1",
"dev": true,
@@ -1530,11 +1515,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@jest/transform/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/@jest/transform/node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -1735,6 +1715,10 @@
"node": ">= 8"
}
},
+ "node_modules/@odoo/o-spreadsheet-engine": {
+ "resolved": "packages/o-spreadsheet-engine",
+ "link": true
+ },
"node_modules/@odoo/owl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@odoo/owl/-/owl-2.5.1.tgz",
@@ -1748,6 +1732,7 @@
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+ "license": "MIT",
"peer": true,
"funding": {
"type": "opencollective",
@@ -1764,6 +1749,24 @@
"prettier": ">=2.4.0"
}
},
+ "node_modules/@rollup/plugin-alias": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz",
+ "integrity": "sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rollup/plugin-node-resolve": {
"version": "15.2.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.0.tgz",
@@ -2871,11 +2874,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/babel-jest/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/babel-jest/node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -3115,9 +3113,9 @@
"license": "MIT"
},
"node_modules/bootstrap": {
- "version": "5.3.3",
- "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
- "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
+ "version": "5.3.8",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz",
+ "integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==",
"funding": [
{
"type": "github",
@@ -3128,6 +3126,7 @@
"url": "https://opencollective.com/bootstrap"
}
],
+ "license": "MIT",
"peerDependencies": {
"@popperjs/core": "^2.11.8"
}
@@ -5266,6 +5265,7 @@
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
"integrity": "sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==",
+ "license": "(OFL-1.1 AND MIT)",
"engines": {
"node": ">=0.10.3"
}
@@ -5429,11 +5429,6 @@
"node": ">=10"
}
},
- "node_modules/fs-extra/node_modules/graceful-fs": {
- "version": "4.2.10",
- "dev": true,
- "license": "ISC"
- },
"node_modules/fs-extra/node_modules/universalify": {
"version": "2.0.0",
"dev": true,
@@ -5605,7 +5600,9 @@
}
},
"node_modules/graceful-fs": {
- "version": "4.1.15",
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true,
"license": "ISC"
},
@@ -6651,11 +6648,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/jest-cli/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/jest-cli/node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -6786,11 +6778,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/jest-config/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/jest-config/node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -7143,11 +7130,6 @@
"fsevents": "^2.3.2"
}
},
- "node_modules/jest-haste-map/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/jest-leak-detector": {
"version": "29.6.1",
"dev": true,
@@ -7398,11 +7380,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/jest-message-util/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/jest-message-util/node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -7564,11 +7541,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/jest-resolve/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/jest-resolve/node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -7664,11 +7636,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/jest-runner/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/jest-runner/node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -7816,11 +7783,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/jest-runtime/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/jest-runtime/node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -7924,11 +7886,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/jest-snapshot/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/jest-snapshot/node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -8074,11 +8031,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/jest-util/node_modules/graceful-fs": {
- "version": "4.2.11",
- "dev": true,
- "license": "ISC"
- },
"node_modules/jest-util/node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -10132,7 +10084,8 @@
"node_modules/quickselect": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
- "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw=="
+ "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==",
+ "license": "ISC"
},
"node_modules/random-bytes": {
"version": "1.0.0",
@@ -10176,6 +10129,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz",
"integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==",
+ "license": "MIT",
"dependencies": {
"quickselect": "^2.0.0"
}
@@ -10581,11 +10535,6 @@
"node": ">=12"
}
},
- "node_modules/rollup-plugin-typescript2/node_modules/graceful-fs": {
- "version": "4.2.10",
- "dev": true,
- "license": "ISC"
- },
"node_modules/rollup-plugin-typescript2/node_modules/semver": {
"version": "7.3.8",
"dev": true,
@@ -12325,6 +12274,60 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "packages/o-spreadsheet": {
+ "extraneous": true
+ },
+ "packages/o-spreadsheet-engine": {
+ "name": "@odoo/o-spreadsheet-engine",
+ "version": "19.1.0-alpha.3",
+ "dependencies": {
+ "rbush": "^3.0.1"
+ },
+ "devDependencies": {
+ "@prettier/plugin-xml": "^2.2.0",
+ "@rollup/plugin-alias": "^5.1.1",
+ "@rollup/plugin-node-resolve": "^15.2.0",
+ "@rollup/plugin-terser": "^0.4.3",
+ "@swc/core": "1.6.7",
+ "@swc/jest": "0.2.36",
+ "@types/jest": "^27.0.1",
+ "@types/node": "^20.17.24",
+ "@types/rbush": "^3.0.3",
+ "@typescript-eslint/eslint-plugin": "^8.30.1",
+ "babel-eslint": "^10.1.0",
+ "fs": "^0.0.1-security",
+ "glob": "^11.0.1",
+ "husky": "^7.0.4",
+ "jest": "^29.5.0",
+ "jest-environment-jsdom": "^29.5.0",
+ "mockdate": "^3.0.2",
+ "npm-run-all": "^4.1.5",
+ "prettier": "^2.8.0",
+ "prettier-plugin-organize-imports": "^3.2.2",
+ "rollup": "^3.28.0",
+ "rollup-plugin-dts": "^5.3.1",
+ "rollup-plugin-typescript2": "^0.35.0",
+ "seedrandom": "^3.0.5",
+ "typescript": "^5.8.2",
+ "typescript-eslint": "^8.30.1",
+ "xml-formatter": "^2.4.0"
+ },
+ "engines": {
+ "node": ">=22.0.0"
+ }
+ },
+ "packages/o-spreadsheet-ui": {
+ "name": "@odoo/o-spreadsheet-ui",
+ "version": "19.1.0-alpha.3",
+ "extraneous": true,
+ "dependencies": {
+ "@odoo/o-spreadsheet-engine": "*",
+ "@odoo/owl": "2.5.1",
+ "bootstrap": "^5.3.3",
+ "font-awesome": "^4.7.0",
+ "rbush": "^3.0.1"
+ }
}
}
}
diff --git a/package.json b/package.json
index 1d898a5b28..ba0d61cac8 100644
--- a/package.json
+++ b/package.json
@@ -15,31 +15,38 @@
"engines": {
"node": ">=22.0.0"
},
+ "workspaces": [
+ "packages/o-spreadsheet-engine"
+ ],
"scripts": {
- "serve-static": "live-server --open=demo --watch=build/o_spreadsheet.iife.js,build/o_spreadsheet.xml,build/o_spreadsheet.css,main.css,demo",
- "dev": "npm-run-all --print-label bundle:dev --parallel server serve-static watch",
- "server": "node tools/server/main.cjs",
+ "prepare": "husky install",
+ "prettier": "prettier . --write",
+ "check-formatting": "prettier . --check && eslint",
+ "lint": "eslint --fix",
+ "dev": "npm-run-all --print-label build --parallel build:watch:engine build:watch server serve-static",
+ "prebuild": "npm run build --workspaces --if-present",
+ "build": "npm-run-all build:js bundle:esm bundle:iife \"bundle:xml -- --outDir build\" \"bundle:css -- --out build\"",
+ "build:watch": "npm-run-all --parallel build:watch:engine build:js:watch bundle:iife:watch bundle:xml:watch bundle:css:watch",
+ "build:watch:engine": "npm run build:watch --workspace=@odoo/o-spreadsheet-engine",
"build:js": "tsc --module es6 --incremental",
+ "build:js:watch": "npm run build:js -- --watch",
"bundle:iife": "rollup -c -m -- --format iife",
+ "bundle:iife:watch": "npm run bundle:iife -- --watch",
"bundle:esm": "rollup -c -m -- --format esm",
"bundle:xml": "node tools/bundle_xml/main.cjs",
- "bundle:dev": "npm-run-all build:js bundle:iife \"bundle:xml -- --outDir build\" && node tools/bundle_css/main.cjs --out build",
- "dist": "tsc --module es6 --declaration --declarationDir dist/types && rollup -c && npm run bundle:xml -- --outDir dist && node tools/bundle_css/main.cjs --out dist",
- "monkey": "SPREADSHEET_MONKEY_COUNT=$npm_config_monkey_count jest 'tests/collaborative/collaborative_monkey_party.test.ts'",
+ "bundle:xml:watch": "node tools/bundle_xml/watch_xml_templates.cjs",
+ "bundle:css": "node tools/bundle_css/main.cjs",
+ "bundle:css:watch": "node tools/bundle_css/watch_css_files.cjs",
+ "serve-static": "live-server --open=demo --watch=build/o-spreadsheet.iife.js,build/o_spreadsheet.xml,build/o_spreadsheet.css,demo",
+ "server": "node tools/server/main.cjs",
+ "predist": "npm run dist --workspaces --if-present",
+ "dist": "tsc --module es6 --declaration --declarationDir dist/types && rollup -c",
+ "postdist": " npm run bundle:xml -- --outDir dist && npm run bundle:css -- --out dist",
+ "pretest": "npm run test --workspaces --if-present",
"test": "tsc --noEmit --project tsconfig.jest.json && jest",
- "test:watch": "jest --watch",
- "prettier": "prettier . --write",
- "check-formatting": "prettier . --check && eslint",
- "prepare": "husky install",
- "watch": "npm-run-all -p watch:*",
- "watch:bundle": "npm run bundle:iife -- --watch",
- "watch:ts": "npm run build:js -- --watch",
- "watch:xml": "node tools/bundle_xml/watch_xml_templates.cjs",
- "watch:css": "node tools/bundle_css/watch_css_files.cjs",
- "unzipXlsx": "node tools/bundle_xlsx/unzip_xlsx_demo.cjs",
+ "monkey": "SPREADSHEET_MONKEY_COUNT=$npm_config_monkey_count jest 'tests/collaborative/collaborative_monkey_party.test.ts'",
"zipXlsx": "node tools/bundle_xlsx/zip_xlsx_demo.cjs",
- "build": "npm-run-all build:js bundle:esm \"bundle:xml -- --outDir build\" && node tools/bundle_css/main.cjs --out build",
- "lint": "eslint --fix"
+ "unzipXlsx": "node tools/bundle_xlsx/unzip_xlsx_demo.cjs"
},
"browserslist": [
"last 1 Chrome versions"
@@ -62,6 +69,7 @@
"homepage": "https://github.com/odoo/o-spreadsheet#readme",
"devDependencies": {
"@prettier/plugin-xml": "^2.2.0",
+ "@rollup/plugin-alias": "^5.1.1",
"@rollup/plugin-node-resolve": "^15.2.0",
"@rollup/plugin-terser": "^0.4.3",
"@swc/jest": "0.2.36",
@@ -125,7 +133,8 @@
"@odoo/owl": "2.5.1",
"bootstrap": "^5.3.3",
"font-awesome": "^4.7.0",
- "rbush": "^3.0.1"
+ "rbush": "^3.0.1",
+ "@odoo/o-spreadsheet-engine": "*"
},
"jest": {
"roots": [
@@ -137,6 +146,10 @@
"@swc/jest"
]
},
+ "moduleNameMapper": {
+ "^@odoo/o-spreadsheet-engine$": "/packages/o-spreadsheet-engine/src",
+ "^@odoo/o-spreadsheet-engine/(.*)$": "/packages/o-spreadsheet-engine/src/$1"
+ },
"verbose": false,
"testEnvironment": "jsdom",
"testRegex": "(/tests/.*(test|spec))\\.ts?$",
diff --git a/packages/o-spreadsheet-engine/package.json b/packages/o-spreadsheet-engine/package.json
new file mode 100644
index 0000000000..8b251e0442
--- /dev/null
+++ b/packages/o-spreadsheet-engine/package.json
@@ -0,0 +1,74 @@
+{
+ "name": "@odoo/o-spreadsheet-engine",
+ "version": "19.1.0-alpha.3",
+ "type": "module",
+ "scripts": {
+ "build": "npm-run-all build:js bundle:iife",
+ "build:watch": "npm-run-all --parallel build:js:watch bundle:iife:watch",
+ "build:js": "tsc --module es6 --incremental",
+ "build:js:watch": "npm run build:js -- --watch",
+ "bundle:esm": "rollup -c -m -- --format esm",
+ "bundle:iife": "rollup -c -m -- --format iife",
+ "bundle:iife:watch": "npm run bundle:iife -- --watch",
+ "dist": "tsc --module es6 --declaration --declarationDir ../../dist/types/packages/o-spreadsheet-engine/ && rollup -c",
+ "test": "tsc --noEmit --project tsconfig.jest.json && jest"
+ },
+ "engines": {
+ "node": ">=22.0.0"
+ },
+ "dependencies": {
+ "rbush": "^3.0.1"
+ },
+ "devDependencies": {
+ "@prettier/plugin-xml": "^2.2.0",
+ "@rollup/plugin-alias": "^5.1.1",
+ "@rollup/plugin-node-resolve": "^15.2.0",
+ "@rollup/plugin-terser": "^0.4.3",
+ "@swc/core": "1.6.7",
+ "@swc/jest": "0.2.36",
+ "@types/jest": "^27.0.1",
+ "@types/node": "^20.17.24",
+ "@types/rbush": "^3.0.3",
+ "@typescript-eslint/eslint-plugin": "^8.30.1",
+ "babel-eslint": "^10.1.0",
+ "fs": "^0.0.1-security",
+ "glob": "^11.0.1",
+ "husky": "^7.0.4",
+ "jest": "^29.5.0",
+ "jest-environment-jsdom": "^29.5.0",
+ "mockdate": "^3.0.2",
+ "npm-run-all": "^4.1.5",
+ "prettier": "^2.8.0",
+ "prettier-plugin-organize-imports": "^3.2.2",
+ "rollup": "^3.28.0",
+ "rollup-plugin-dts": "^5.3.1",
+ "rollup-plugin-typescript2": "^0.35.0",
+ "seedrandom": "^3.0.5",
+ "typescript": "^5.8.2",
+ "typescript-eslint": "^8.30.1",
+ "xml-formatter": "^2.4.0"
+ },
+ "jest": {
+ "roots": [
+ "/src",
+ "/tests"
+ ],
+ "transform": {
+ "^.+\\.ts?$": [
+ "@swc/jest"
+ ]
+ },
+ "verbose": false,
+ "testEnvironment": "jsdom",
+ "testRegex": "(/tests/.*(test|spec))\\.ts?$",
+ "moduleFileExtensions": [
+ "ts",
+ "tsx",
+ "js",
+ "jsx",
+ "json",
+ "node"
+ ],
+ "workerIdleMemoryLimit": "800MB"
+ }
+}
diff --git a/packages/o-spreadsheet-engine/rollup.config.js b/packages/o-spreadsheet-engine/rollup.config.js
new file mode 100644
index 0000000000..c10a2978c4
--- /dev/null
+++ b/packages/o-spreadsheet-engine/rollup.config.js
@@ -0,0 +1,77 @@
+import { nodeResolve } from "@rollup/plugin-node-resolve";
+import terser from "@rollup/plugin-terser";
+import dts from "rollup-plugin-dts";
+import typescript from "rollup-plugin-typescript2";
+import { bundle } from "../../tools/bundle.cjs";
+
+const outro = bundle.outro();
+
+/**
+ * Get the rollup config based on the arguments
+ * @param {"esm" | "cjs" | "iife"} format format of the bundle
+ * @param {string} generatedFileName generated file name
+ * @param {boolean} minified should it be minified
+ */
+function getConfigForFormat(format, minified = false) {
+ return {
+ file: minified
+ ? `../../dist/o-spreadsheet-engine.${format}.min.js`
+ : `../../dist/o-spreadsheet-engine.${format}.js`,
+ format,
+ name: "o_spreadsheet_engine",
+ extend: true,
+ outro,
+ banner: bundle.jsBanner(),
+ plugins: minified ? [terser()] : [],
+ };
+}
+
+export default (commandLineArgs) => {
+ let output = [];
+ let input = "";
+ let plugins = [nodeResolve()];
+ let config = {};
+
+ if (commandLineArgs.format) {
+ // Only build one version to improve speed
+ config = {
+ input: "build/js/o-spreadsheet-engine/src/index.js",
+ external: [],
+ output: [
+ {
+ name: "o_spreadsheet_engine",
+ extend: true,
+ outro,
+ banner: bundle.jsBanner(),
+ file: `build/o-spreadsheet-engine.${commandLineArgs.format}.js`,
+ format: commandLineArgs.format,
+ },
+ ],
+ plugins,
+ };
+ } else {
+ input = "src/index.ts";
+ output = [
+ getConfigForFormat("esm"),
+ getConfigForFormat("cjs"),
+ getConfigForFormat("iife"),
+ getConfigForFormat("iife", true),
+ ];
+ plugins.push(typescript({ useTsconfigDeclarationDir: true }));
+ config = [
+ {
+ input,
+ external: [],
+ output,
+ plugins,
+ },
+ {
+ input: "../../dist/types/packages/o-spreadsheet-engine/index.d.ts",
+ output: [{ file: "../../dist/o-spreadsheet-engine.d.ts", format: "es" }],
+ plugins: [dts(), nodeResolve()],
+ },
+ ];
+ }
+
+ return config;
+};
diff --git a/packages/o-spreadsheet-engine/src/constants.ts b/packages/o-spreadsheet-engine/src/constants.ts
new file mode 100644
index 0000000000..ac3d016072
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/constants.ts
@@ -0,0 +1 @@
+export const NEWLINE = "\n";
diff --git a/src/formulas/code_builder.ts b/packages/o-spreadsheet-engine/src/formulas/code_builder.ts
similarity index 86%
rename from src/formulas/code_builder.ts
rename to packages/o-spreadsheet-engine/src/formulas/code_builder.ts
index 63a84aa562..c1308350a5 100644
--- a/src/formulas/code_builder.ts
+++ b/packages/o-spreadsheet-engine/src/formulas/code_builder.ts
@@ -1,16 +1,10 @@
-/**
- * Block of code that produces a value.
- */
export interface FunctionCode {
readonly returnExpression: string;
- /**
- * Return the same function code but with the return expression assigned to a variable.
- */
assignResultToVariable(): FunctionCode;
}
export class FunctionCodeBuilder {
- private code: string = "";
+ private code = "";
constructor(private scope: Scope = new Scope()) {}
@@ -64,10 +58,6 @@ export class Scope {
}
}
-/**
- * Takes a list of strings that might be single or multiline
- * and maps them in a list of single line strings.
- */
function splitLines(str: string): string[] {
return str
.split("\n")
diff --git a/packages/o-spreadsheet-engine/src/formulas/compiler.ts b/packages/o-spreadsheet-engine/src/formulas/compiler.ts
new file mode 100644
index 0000000000..d0930942f7
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/formulas/compiler.ts
@@ -0,0 +1,355 @@
+import { unquote } from "../helpers/misc";
+import { parseNumber } from "../helpers/numbers";
+import { _t } from "../translation";
+import { CompiledFormula, FormulaToExecute } from "../types/base";
+import { BadExpressionError, UnknownFunctionError } from "../types/errors";
+import { DEFAULT_LOCALE } from "../types/locale";
+import { FunctionCode, FunctionCodeBuilder, Scope } from "./code_builder";
+import { parseTokens } from "./parser";
+import { rangeTokenize } from "./range_tokenizer";
+import { Token } from "./tokenizer";
+
+interface ArgDefinitionLike {
+ type?: string[];
+}
+
+interface FunctionDescriptionLike {
+ args: ArgDefinitionLike[];
+ minArgRequired: number;
+ maxArgPossible: number;
+ nbrArgRepeating: number;
+ nbrArgOptional: number;
+}
+
+interface FunctionRegistryLike {
+ content: Record;
+}
+
+type ArgTargetingFn = (
+ fn: FunctionDescriptionLike,
+ argCount: number
+) => (argIndex: number) => number | undefined;
+
+let functionRegistryProvider: (() => FunctionRegistryLike) | null = null;
+let argTargetingImpl: ArgTargetingFn | null = null;
+
+export function setFunctionRegistryProvider(provider: () => FunctionRegistryLike) {
+ functionRegistryProvider = provider;
+}
+
+export function setArgTargetingImplementation(fn: ArgTargetingFn) {
+ argTargetingImpl = fn;
+}
+
+function getFunctionRegistry(): FunctionRegistryLike {
+ if (!functionRegistryProvider) {
+ throw new Error("Function registry provider has not been set.");
+ }
+ return functionRegistryProvider();
+}
+
+function getArgTargeting(): ArgTargetingFn {
+ if (!argTargetingImpl) {
+ throw new Error("argTargeting implementation has not been set.");
+ }
+ return argTargetingImpl;
+}
+
+export const OPERATOR_MAP = {
+ "=": "EQ",
+ "+": "ADD",
+ "-": "MINUS",
+ "*": "MULTIPLY",
+ "/": "DIVIDE",
+ ">=": "GTE",
+ "<>": "NE",
+ ">": "GT",
+ "<=": "LTE",
+ "<": "LT",
+ "^": "POWER",
+ "&": "CONCATENATE",
+} as const;
+
+export const UNARY_OPERATOR_MAP = {
+ "-": "UMINUS",
+ "+": "UPLUS",
+ "%": "UNARY.PERCENT",
+} as const;
+
+interface LiteralValues {
+ numbers: { value: number }[];
+ strings: { value: string }[];
+}
+
+type InternalCompiledFormula = CompiledFormula & {
+ literalValues: LiteralValues;
+ symbols: string[];
+};
+
+export const functionCache: Record = {};
+
+export function compile(formula: string): CompiledFormula {
+ const tokens = rangeTokenize(formula);
+ return compileTokens(tokens);
+}
+
+export function compileTokens(tokens: Token[]): CompiledFormula {
+ try {
+ return compileTokensOrThrow(tokens);
+ } catch (error) {
+ return {
+ tokens,
+ dependencies: [],
+ execute() {
+ return error;
+ },
+ isBadExpression: true,
+ normalizedFormula: tokens.map((t) => t.value).join(""),
+ };
+ }
+}
+
+function compileTokensOrThrow(tokens: Token[]): CompiledFormula {
+ const registry = getFunctionRegistry();
+ const functions = registry.content;
+ const argTargeting = getArgTargeting();
+
+ const { dependencies, literalValues, symbols } = formulaArguments(tokens);
+ const cacheKey = compilationCacheKey(tokens);
+ if (!functionCache[cacheKey]) {
+ const ast = parseTokens([...tokens]);
+ const scope = new Scope();
+
+ let stringCount = 0;
+ let numberCount = 0;
+ let dependencyCount = 0;
+
+ if (ast.type === "BIN_OPERATION" && ast.value === ":") {
+ throw new BadExpressionError(_t("Invalid formula"));
+ }
+ if (ast.type === "EMPTY") {
+ throw new BadExpressionError(_t("Invalid formula"));
+ }
+
+ const compiledAST = compileAST(ast);
+ const code = new FunctionCodeBuilder();
+ code.append(`// ${cacheKey}`);
+ code.append(compiledAST);
+ code.append(`return ${compiledAST.returnExpression};`);
+ const baseFunction = new Function(
+ "deps",
+ "ref",
+ "range",
+ "getSymbolValue",
+ "ctx",
+ code.toString()
+ );
+
+ // @ts-ignore - constructed function
+ functionCache[cacheKey] = baseFunction;
+
+ function compileFunctionArgs(astFuncall: any): FunctionCode[] {
+ const { args } = astFuncall;
+ const functionName = astFuncall.value.toUpperCase();
+ const functionDefinition = functions[functionName];
+
+ if (!functionDefinition) {
+ throw new UnknownFunctionError(_t('Unknown function: "%s"', astFuncall.value));
+ }
+
+ assertEnoughArgs(args, functionDefinition, functionName);
+
+ const compiledArgs: FunctionCode[] = [];
+ const argToFocus = argTargeting(functionDefinition, args.length);
+
+ for (let i = 0; i < args.length; i++) {
+ const argIndex = argToFocus(i) ?? -1;
+ const argDefinition =
+ functionDefinition.args[argIndex] ??
+ functionDefinition.args[i] ??
+ ({} as ArgDefinitionLike);
+ const currentArg = args[i];
+ const argTypes = argDefinition?.type || [];
+ const isMeta = argTypes.includes("META") || argTypes.includes("RANGE");
+ const hasRange = argTypes.some((t: string) => isRangeType(t));
+ compiledArgs.push(compileAST(currentArg, isMeta, hasRange));
+ }
+
+ return compiledArgs;
+ }
+
+ function compileAST(ast: any, isMeta = false, hasRange = false): FunctionCode {
+ const codeBuilder = new FunctionCodeBuilder(scope);
+ if (ast.type !== "REFERENCE" && !(ast.type === "BIN_OPERATION" && ast.value === ":")) {
+ if (isMeta) {
+ throw new BadExpressionError(_t("Argument must be a reference to a cell or range."));
+ }
+ }
+ if (ast.debug) {
+ codeBuilder.append("debugger;");
+ codeBuilder.append(`ctx["debug"] = true;`);
+ }
+ switch (ast.type) {
+ case "BOOLEAN":
+ return codeBuilder.return(`{ value: ${ast.value} }`);
+ case "NUMBER":
+ return codeBuilder.return(`this.literalValues.numbers[${numberCount++}]`);
+ case "STRING":
+ return codeBuilder.return(`this.literalValues.strings[${stringCount++}]`);
+ case "REFERENCE":
+ return codeBuilder.return(
+ `${ast.value.includes(":") || hasRange ? "range" : "ref"}(deps[${dependencyCount++}], ${
+ isMeta ? "true" : "false"
+ })`
+ );
+ case "FUNCALL": {
+ const args = compileFunctionArgs(ast).map((argCode) => argCode.assignResultToVariable());
+ codeBuilder.append(...args);
+ const fnName = ast.value.toUpperCase();
+ return codeBuilder.return(`ctx['${fnName}'](${args.map((arg) => arg.returnExpression)})`);
+ }
+ case "UNARY_OPERATION": {
+ const fnName = UNARY_OPERATOR_MAP[ast.value as keyof typeof UNARY_OPERATOR_MAP];
+ const operand = compileAST(ast.operand, false, false).assignResultToVariable();
+ codeBuilder.append(operand);
+ return codeBuilder.return(`ctx['${fnName}'](${operand.returnExpression})`);
+ }
+ case "BIN_OPERATION": {
+ const fnName = OPERATOR_MAP[ast.value as keyof typeof OPERATOR_MAP];
+ const left = compileAST(ast.left, false, false).assignResultToVariable();
+ const right = compileAST(ast.right, false, false).assignResultToVariable();
+ codeBuilder.append(left);
+ codeBuilder.append(right);
+ return codeBuilder.return(
+ `ctx['${fnName}'](${left.returnExpression}, ${right.returnExpression})`
+ );
+ }
+ case "SYMBOL": {
+ const symbolIndex = symbols.indexOf(ast.value);
+ return codeBuilder.return(`getSymbolValue(this.symbols[${symbolIndex}])`);
+ }
+ case "EMPTY":
+ return codeBuilder.return("undefined");
+ default:
+ return codeBuilder.return("undefined");
+ }
+ }
+ }
+
+ const compiledFormula: InternalCompiledFormula = {
+ execute: functionCache[cacheKey],
+ dependencies,
+ literalValues,
+ symbols,
+ tokens,
+ isBadExpression: false,
+ normalizedFormula: cacheKey,
+ };
+ return compiledFormula;
+}
+
+function compilationCacheKey(tokens: Token[]): string {
+ let cacheKey = "";
+ for (const token of tokens) {
+ switch (token.type) {
+ case "STRING":
+ cacheKey += "|S|";
+ break;
+ case "NUMBER":
+ cacheKey += "|N|";
+ break;
+ case "REFERENCE":
+ case "INVALID_REFERENCE":
+ cacheKey += token.value.includes(":") ? "|R|" : "|C|";
+ break;
+ case "SPACE":
+ break;
+ default:
+ cacheKey += token.value;
+ }
+ }
+ return cacheKey;
+}
+
+function formulaArguments(tokens: Token[]) {
+ const literalValues: LiteralValues = {
+ numbers: [],
+ strings: [],
+ };
+ const dependencies: string[] = [];
+ const symbols: string[] = [];
+ for (const token of tokens) {
+ switch (token.type) {
+ case "INVALID_REFERENCE":
+ case "REFERENCE":
+ dependencies.push(token.value);
+ break;
+ case "STRING":
+ literalValues.strings.push({ value: unquote(token.value) });
+ break;
+ case "NUMBER":
+ literalValues.numbers.push({ value: parseNumber(token.value, DEFAULT_LOCALE) });
+ break;
+ case "SYMBOL":
+ symbols.push(unquote(token.value, "'"));
+ break;
+ default:
+ break;
+ }
+ }
+ return { dependencies, literalValues, symbols };
+}
+
+function assertEnoughArgs(
+ args: any[],
+ functionDefinition: FunctionDescriptionLike,
+ functionName: string
+) {
+ const nbrArgSupplied = args.length;
+ const { nbrArgRepeating, minArgRequired } = functionDefinition;
+
+ if (nbrArgSupplied < minArgRequired) {
+ throw new BadExpressionError(
+ _t(
+ "Invalid number of arguments for the %s function. Expected %s minimum, but got %s instead.",
+ functionName,
+ minArgRequired,
+ nbrArgSupplied
+ )
+ );
+ }
+
+ if (nbrArgSupplied > functionDefinition.maxArgPossible) {
+ throw new BadExpressionError(
+ _t(
+ "Invalid number of arguments for the %s function. Expected %s maximum, but got %s instead.",
+ functionName,
+ functionDefinition.maxArgPossible,
+ nbrArgSupplied
+ )
+ );
+ }
+
+ if (nbrArgRepeating > 1) {
+ const nbrValueRepeating =
+ nbrArgRepeating * Math.floor((nbrArgSupplied - minArgRequired) / nbrArgRepeating);
+ const nbrValueRemaining =
+ nbrArgSupplied - minArgRequired - nbrValueRepeating - functionDefinition.nbrArgOptional;
+
+ if (nbrValueRemaining > 0) {
+ throw new BadExpressionError(
+ _t(
+ "Invalid number of arguments for the %s function. Repeatable arguments should be supplied in groups of %s, with up to %s optional. Got %s too many.",
+ functionName,
+ nbrArgRepeating,
+ functionDefinition.nbrArgOptional,
+ nbrValueRemaining
+ )
+ );
+ }
+ }
+}
+
+function isRangeType(type: string) {
+ return type.startsWith("RANGE");
+}
diff --git a/src/formulas/helpers.ts b/packages/o-spreadsheet-engine/src/formulas/isExportableToExcel.ts
similarity index 95%
rename from src/formulas/helpers.ts
rename to packages/o-spreadsheet-engine/src/formulas/isExportableToExcel.ts
index f3c2f270df..b0b0ac7755 100644
--- a/src/formulas/helpers.ts
+++ b/packages/o-spreadsheet-engine/src/formulas/isExportableToExcel.ts
@@ -1,4 +1,4 @@
-import { functionRegistry } from "../functions";
+import { functionRegistry } from "../functions/functionRegistry";
import { AST, ASTFuncall, iterateAstNodes, parseTokens } from "./parser";
import { Token } from "./tokenizer";
diff --git a/packages/o-spreadsheet-engine/src/formulas/parser.ts b/packages/o-spreadsheet-engine/src/formulas/parser.ts
new file mode 100644
index 0000000000..ffba10afef
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/formulas/parser.ts
@@ -0,0 +1,384 @@
+import { parseNumber, unquote } from "../helpers";
+import { _t } from "../translation";
+import { BadExpressionError, CellErrorType } from "../types/errors";
+import { DEFAULT_LOCALE } from "../types/locale";
+import { rangeTokenize } from "./range_tokenizer";
+import { Token } from "./tokenizer";
+
+const functionRegex = /[a-zA-Z0-9\_]+(\.[a-zA-Z0-9\_]+)*/;
+
+const UNARY_OPERATORS_PREFIX = ["-", "+"];
+const UNARY_OPERATORS_POSTFIX = ["%"];
+
+interface RichToken extends Token {
+ tokenIndex: number;
+}
+
+export class TokenList {
+ private tokens: RichToken[];
+ currentIndex = 0;
+ current: RichToken | undefined;
+ length: number;
+
+ constructor(tokens: RichToken[]) {
+ this.tokens = tokens;
+ this.current = tokens[0];
+ this.length = tokens.length;
+ }
+
+ shift() {
+ const current = this.tokens[this.currentIndex];
+ this.current = this.tokens[++this.currentIndex];
+ return current;
+ }
+
+ get next(): RichToken | undefined {
+ return this.tokens[this.currentIndex + 1];
+ }
+}
+
+interface ASTBase {
+ debug?: boolean;
+ tokenStartIndex: number;
+ tokenEndIndex: number;
+}
+
+interface ASTNumber extends ASTBase {
+ type: "NUMBER";
+ value: number;
+}
+
+interface ASTReference extends ASTBase {
+ type: "REFERENCE";
+ value: string;
+}
+
+export interface ASTString extends ASTBase {
+ type: "STRING";
+ value: string;
+}
+
+interface ASTBoolean extends ASTBase {
+ type: "BOOLEAN";
+ value: boolean;
+}
+
+export interface ASTUnaryOperation extends ASTBase {
+ type: "UNARY_OPERATION";
+ value: any;
+ operand: AST;
+ postfix?: boolean;
+}
+
+export interface ASTOperation extends ASTBase {
+ type: "BIN_OPERATION";
+ value: any;
+ left: AST;
+ right: AST;
+}
+
+export interface ASTFuncall extends ASTBase {
+ type: "FUNCALL";
+ value: string;
+ args: AST[];
+}
+
+export interface ASTSymbol extends ASTBase {
+ type: "SYMBOL";
+ value: string;
+}
+
+interface ASTEmpty extends ASTBase {
+ type: "EMPTY";
+ value: "";
+}
+
+export type AST =
+ | ASTOperation
+ | ASTUnaryOperation
+ | ASTFuncall
+ | ASTSymbol
+ | ASTNumber
+ | ASTBoolean
+ | ASTString
+ | ASTReference
+ | ASTEmpty;
+
+export const OP_PRIORITY = {
+ "%": 40,
+ "^": 30,
+ "*": 20,
+ "/": 20,
+ "+": 15,
+ "-": 15,
+ "&": 13,
+ ">": 10,
+ "<>": 10,
+ ">=": 10,
+ "<": 10,
+ "<=": 10,
+ "=": 10,
+};
+
+function parseOperand(tokens: TokenList): AST {
+ const current = tokens.shift();
+ if (!current) {
+ throw new BadExpressionError();
+ }
+ switch (current.type) {
+ case "DEBUGGER":
+ const next = parseExpression(tokens, 1000);
+ next.debug = true;
+ return next;
+ case "NUMBER":
+ return {
+ type: "NUMBER",
+ value: parseNumber(current.value, DEFAULT_LOCALE),
+ tokenStartIndex: current.tokenIndex,
+ tokenEndIndex: current.tokenIndex,
+ };
+ case "STRING":
+ return {
+ type: "STRING",
+ value: unquote(current.value),
+ tokenStartIndex: current.tokenIndex,
+ tokenEndIndex: current.tokenIndex,
+ };
+ case "INVALID_REFERENCE":
+ return {
+ type: "REFERENCE",
+ value: CellErrorType.InvalidReference,
+ tokenStartIndex: current.tokenIndex,
+ tokenEndIndex: current.tokenIndex,
+ };
+ case "REFERENCE":
+ if (tokens.current?.value === ":" && tokens.next?.type === "REFERENCE") {
+ tokens.shift();
+ const rightReference = tokens.shift();
+ return {
+ type: "REFERENCE",
+ value: `${current.value}:${rightReference?.value}`,
+ tokenStartIndex: current.tokenIndex,
+ tokenEndIndex: rightReference.tokenIndex,
+ };
+ }
+ return {
+ type: "REFERENCE",
+ value: current.value,
+ tokenStartIndex: current.tokenIndex,
+ tokenEndIndex: current.tokenIndex,
+ };
+ case "SYMBOL":
+ const value = current.value;
+ const nextToken = tokens.current;
+ if (
+ nextToken?.type === "LEFT_PAREN" &&
+ functionRegex.test(current.value) &&
+ value === unquote(value, "'")
+ ) {
+ const { args, rightParen } = parseFunctionArgs(tokens);
+ return {
+ type: "FUNCALL",
+ value,
+ args,
+ tokenStartIndex: current.tokenIndex,
+ tokenEndIndex: rightParen.tokenIndex,
+ };
+ }
+ const upperCaseValue = value.toUpperCase();
+ if (upperCaseValue === "TRUE" || upperCaseValue === "FALSE") {
+ return {
+ type: "BOOLEAN",
+ value: upperCaseValue === "TRUE",
+ tokenStartIndex: current.tokenIndex,
+ tokenEndIndex: current.tokenIndex,
+ };
+ }
+ return {
+ type: "SYMBOL",
+ value: unquote(current.value, "'"),
+ tokenStartIndex: current.tokenIndex,
+ tokenEndIndex: current.tokenIndex,
+ };
+ case "LEFT_PAREN":
+ const result = parseExpression(tokens);
+ const rightParen = consumeOrThrow(tokens, "RIGHT_PAREN", _t("Missing closing parenthesis"));
+ return {
+ ...result,
+ tokenStartIndex: current.tokenIndex,
+ tokenEndIndex: rightParen.tokenIndex,
+ };
+ case "OPERATOR":
+ const operator = current.value;
+ if (UNARY_OPERATORS_PREFIX.includes(operator)) {
+ const operand = parseExpression(tokens, OP_PRIORITY[operator]);
+ return {
+ type: "UNARY_OPERATION",
+ value: operator,
+ operand,
+ tokenStartIndex: current.tokenIndex,
+ tokenEndIndex: operand.tokenEndIndex,
+ };
+ }
+ throw new BadExpressionError(_t("Unexpected token: %s", current.value));
+ default:
+ throw new BadExpressionError(_t("Unexpected token: %s", current.value));
+ }
+}
+
+function parseFunctionArgs(tokens: TokenList) {
+ consumeOrThrow(tokens, "LEFT_PAREN", _t("Missing opening parenthesis"));
+ const nextToken = tokens.current;
+ if (nextToken?.type === "RIGHT_PAREN") {
+ const rightParen = consumeOrThrow(tokens, "RIGHT_PAREN");
+ return { args: [], rightParen };
+ }
+ const args: AST[] = [];
+ args.push(parseOneFunctionArg(tokens));
+ while (tokens.current?.type !== "RIGHT_PAREN") {
+ consumeOrThrow(tokens, "ARG_SEPARATOR", _t("Wrong function call"));
+ args.push(parseOneFunctionArg(tokens));
+ }
+ const rightParen = consumeOrThrow(tokens, "RIGHT_PAREN");
+ return { args, rightParen };
+}
+
+function parseOneFunctionArg(tokens: TokenList): AST {
+ const nextToken = tokens.current;
+ if (nextToken?.type === "ARG_SEPARATOR" || nextToken?.type === "RIGHT_PAREN") {
+ return {
+ type: "EMPTY",
+ value: "",
+ tokenStartIndex: nextToken.tokenIndex,
+ tokenEndIndex: nextToken.tokenIndex,
+ };
+ }
+ return parseExpression(tokens);
+}
+
+function consumeOrThrow(tokens: TokenList, type, message?: string) {
+ const token = tokens.shift();
+ if (!token || token.type !== type) {
+ throw new BadExpressionError(message);
+ }
+ return token;
+}
+
+function parseExpression(tokens: TokenList, parentPriority = 0): AST {
+ if (tokens.length === 0) {
+ throw new BadExpressionError();
+ }
+ let left = parseOperand(tokens);
+ while (
+ tokens.current?.type === "OPERATOR" &&
+ OP_PRIORITY[tokens.current.value] > parentPriority
+ ) {
+ const operatorToken = tokens.shift();
+ const operator = operatorToken.value;
+ if (UNARY_OPERATORS_POSTFIX.includes(operator)) {
+ left = {
+ type: "UNARY_OPERATION",
+ value: operator,
+ operand: left,
+ postfix: true,
+ tokenStartIndex: left.tokenStartIndex,
+ tokenEndIndex: operatorToken.tokenIndex,
+ };
+ } else {
+ const right = parseExpression(tokens, OP_PRIORITY[operator]);
+ left = {
+ type: "BIN_OPERATION",
+ value: operator,
+ left,
+ right,
+ tokenStartIndex: left.tokenStartIndex,
+ tokenEndIndex: right.tokenEndIndex,
+ };
+ }
+ }
+ return left;
+}
+
+export function parse(str: string): AST {
+ return parseTokens(rangeTokenize(str));
+}
+
+export function parseTokens(tokens: Token[]): AST {
+ const richTokens = tokens.map((token, index) => ({
+ type: token.type,
+ value: token.value,
+ tokenIndex: index,
+ }));
+ const tokensToParse = richTokens.filter((token) => token.type !== "SPACE");
+ const tokenList = new TokenList(tokensToParse);
+ if (tokenList.current?.value === "=") {
+ tokenList.shift();
+ }
+ const result = parseExpression(tokenList);
+ if (tokenList.current) {
+ throw new BadExpressionError();
+ }
+ return result;
+}
+
+export function convertAstNodes(
+ ast: AST,
+ type: T,
+ fn: (ast: Extract) => AST
+): AST {
+ return mapAst(ast, (candidate) => {
+ if (candidate.type === type) {
+ return fn(candidate as Extract);
+ }
+ return candidate;
+ });
+}
+
+export function iterateAstNodes(ast: AST): AST[] {
+ return Array.from(astIterator(ast));
+}
+
+function* astIterator(ast: AST): Iterable {
+ yield ast;
+ switch (ast.type) {
+ case "FUNCALL":
+ for (const arg of ast.args) {
+ yield* astIterator(arg);
+ }
+ break;
+ case "UNARY_OPERATION":
+ yield* astIterator(ast.operand);
+ break;
+ case "BIN_OPERATION":
+ yield* astIterator(ast.left);
+ yield* astIterator(ast.right);
+ break;
+ }
+}
+
+export function mapAst(
+ ast: AST,
+ fn: (ast: Extract) => AST
+): AST {
+ ast = fn(ast as Extract);
+ switch (ast.type) {
+ case "FUNCALL":
+ return {
+ ...ast,
+ args: ast.args.map((child) => mapAst(child, fn)),
+ };
+ case "UNARY_OPERATION":
+ return {
+ ...ast,
+ operand: mapAst(ast.operand, fn),
+ };
+ case "BIN_OPERATION":
+ return {
+ ...ast,
+ right: mapAst(ast.right, fn),
+ left: mapAst(ast.left, fn),
+ };
+ default:
+ return ast;
+ }
+}
diff --git a/packages/o-spreadsheet-engine/src/formulas/range_tokenizer.ts b/packages/o-spreadsheet-engine/src/formulas/range_tokenizer.ts
new file mode 100644
index 0000000000..e0de49485d
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/formulas/range_tokenizer.ts
@@ -0,0 +1,121 @@
+import {
+ isColHeader,
+ isColReference,
+ isRowHeader,
+ isRowReference,
+ isSingleCellReference,
+} from "../helpers";
+import { DEFAULT_LOCALE } from "../types/locale";
+import { Token, tokenize } from "./tokenizer";
+
+enum State {
+ LeftRef,
+ RightRef,
+ Separator,
+ FullColumnSeparator,
+ FullRowSeparator,
+ RightColumnRef,
+ RightRowRef,
+ Found,
+}
+
+const goTo = (state: State, guard: (token: Token) => boolean = () => true) => [
+ {
+ goTo: state,
+ guard,
+ },
+];
+
+const goToMulti = (state: State, guard: (token: Token) => boolean = () => true) => ({
+ goTo: state,
+ guard,
+});
+
+interface Transition {
+ goTo: State;
+ guard: (token: Token) => boolean;
+}
+
+type Machine = {
+ [s in State]: Record;
+};
+
+const machine: Machine = {
+ [State.LeftRef]: {
+ REFERENCE: goTo(State.Separator),
+ NUMBER: goTo(State.FullRowSeparator),
+ SYMBOL: [
+ goToMulti(State.FullColumnSeparator, (token) => isColReference(token.value)),
+ goToMulti(State.FullRowSeparator, (token) => isRowReference(token.value)),
+ ],
+ },
+ [State.FullColumnSeparator]: {
+ SPACE: goTo(State.FullColumnSeparator),
+ OPERATOR: goTo(State.RightColumnRef, (token) => token.value === ":"),
+ },
+ [State.FullRowSeparator]: {
+ SPACE: goTo(State.FullRowSeparator),
+ OPERATOR: goTo(State.RightRowRef, (token) => token.value === ":"),
+ },
+ [State.Separator]: {
+ SPACE: goTo(State.Separator),
+ OPERATOR: goTo(State.RightRef, (token) => token.value === ":"),
+ },
+ [State.RightRef]: {
+ SPACE: goTo(State.RightRef),
+ NUMBER: goTo(State.Found),
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
+ },
+ [State.RightColumnRef]: {
+ SPACE: goTo(State.RightColumnRef),
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
+ },
+ [State.RightRowRef]: {
+ SPACE: goTo(State.RightRowRef),
+ NUMBER: goTo(State.Found),
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
+ SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
+ },
+ [State.Found]: {},
+};
+
+function matchReference(tokens: Token[]): Token | null {
+ let head = 0;
+ let transitions = machine[State.LeftRef];
+ let matchedTokens = "";
+ while (transitions !== undefined) {
+ const token = tokens[head++];
+ if (!token) {
+ return null;
+ }
+ const transition = transitions[token.type]?.find((candidate) => candidate.guard(token));
+ const nextState = transition ? transition.goTo : undefined;
+ switch (nextState) {
+ case undefined:
+ return null;
+ case State.Found:
+ matchedTokens += token.value;
+ tokens.splice(0, head);
+ return {
+ type: "REFERENCE",
+ value: matchedTokens,
+ };
+ default:
+ transitions = machine[nextState];
+ matchedTokens += token.value;
+ break;
+ }
+ }
+ return null;
+}
+
+export function rangeTokenize(formula: string, locale = DEFAULT_LOCALE): Token[] {
+ const tokens = tokenize(formula, locale);
+ const result: Token[] = [];
+ while (tokens.length) {
+ result.push(matchReference(tokens) || tokens.shift()!);
+ }
+ return result;
+}
diff --git a/packages/o-spreadsheet-engine/src/formulas/tokenizer.ts b/packages/o-spreadsheet-engine/src/formulas/tokenizer.ts
new file mode 100644
index 0000000000..8530c076d3
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/formulas/tokenizer.ts
@@ -0,0 +1,223 @@
+import { NEWLINE } from "../constants";
+import { TokenizingChars, replaceNewLines, specialWhiteSpaceRegexp } from "../helpers/misc";
+import { getFormulaNumberRegex } from "../helpers/numbers";
+import { rangeReference } from "../helpers/references";
+import { CellErrorType } from "../types/errors";
+import { DEFAULT_LOCALE, type Locale } from "../types/locale";
+
+export const POSTFIX_UNARY_OPERATORS = ["%"];
+const OPERATORS = "+,-,*,/,:,=,<>,>=,>,<=,<,^,&".split(",").concat(POSTFIX_UNARY_OPERATORS);
+
+type TokenType =
+ | "OPERATOR"
+ | "NUMBER"
+ | "STRING"
+ | "SYMBOL"
+ | "SPACE"
+ | "DEBUGGER"
+ | "ARG_SEPARATOR"
+ | "LEFT_PAREN"
+ | "RIGHT_PAREN"
+ | "REFERENCE"
+ | "INVALID_REFERENCE"
+ | "UNKNOWN";
+
+export interface Token {
+ readonly type: TokenType;
+ readonly value: string;
+}
+
+export function tokenize(str: string, locale: Locale = DEFAULT_LOCALE): Token[] {
+ str = replaceNewLines(str);
+ const chars = new TokenizingChars(str);
+ const result: Token[] = [];
+ const tokenizeSpace = specialWhiteSpaceRegexp.test(str)
+ ? tokenizeSpecialCharacterSpace
+ : tokenizeSimpleSpace;
+
+ while (!chars.isOver()) {
+ let token =
+ tokenizeNewLine(chars) ||
+ tokenizeSpace(chars) ||
+ tokenizeArgsSeparator(chars, locale) ||
+ tokenizeParenthesis(chars) ||
+ tokenizeOperator(chars) ||
+ tokenizeString(chars) ||
+ tokenizeDebugger(chars) ||
+ tokenizeInvalidRange(chars) ||
+ tokenizeNumber(chars, locale) ||
+ tokenizeSymbol(chars);
+
+ if (!token) {
+ token = { type: "UNKNOWN", value: chars.shift() };
+ }
+
+ result.push(token);
+ }
+ return result;
+}
+
+function tokenizeDebugger(chars: TokenizingChars): Token | null {
+ if (chars.current === "?") {
+ chars.shift();
+ return { type: "DEBUGGER", value: "?" };
+ }
+ return null;
+}
+
+const parenthesis = {
+ "(": { type: "LEFT_PAREN", value: "(" },
+ ")": { type: "RIGHT_PAREN", value: ")" },
+} as const;
+
+function tokenizeParenthesis(chars: TokenizingChars): Token | null {
+ if (chars.current === "(" || chars.current === ")") {
+ const value = chars.shift();
+ return parenthesis[value];
+ }
+ return null;
+}
+
+function tokenizeArgsSeparator(chars: TokenizingChars, locale: Locale): Token | null {
+ if (chars.current === locale.formulaArgSeparator) {
+ const value = chars.shift();
+ const type = "ARG_SEPARATOR";
+ return { type, value };
+ }
+
+ return null;
+}
+
+function tokenizeOperator(chars: TokenizingChars): Token | null {
+ for (const op of OPERATORS) {
+ if (chars.currentStartsWith(op)) {
+ chars.advanceBy(op.length);
+ return { type: "OPERATOR", value: op };
+ }
+ }
+ return null;
+}
+
+const FIRST_POSSIBLE_NUMBER_CHARS = new Set("0123456789");
+
+function tokenizeNumber(chars: TokenizingChars, locale: Locale): Token | null {
+ if (
+ !FIRST_POSSIBLE_NUMBER_CHARS.has(chars.current) &&
+ chars.current !== locale.decimalSeparator
+ ) {
+ return null;
+ }
+ const match = chars.remaining().match(getFormulaNumberRegex(locale.decimalSeparator));
+ if (match) {
+ chars.advanceBy(match[0].length);
+ return { type: "NUMBER", value: match[0] };
+ }
+ return null;
+}
+
+function tokenizeString(chars: TokenizingChars): Token | null {
+ if (chars.current === '"') {
+ const startChar = chars.shift();
+ let letters: string = startChar;
+ while (chars.current && (chars.current !== startChar || letters[letters.length - 1] === "\\")) {
+ letters += chars.shift();
+ }
+ if (chars.current === '"') {
+ letters += chars.shift();
+ }
+ return {
+ type: "STRING",
+ value: letters,
+ };
+ }
+ return null;
+}
+
+const unicodeSymbolCharRegexp = /\p{L}|\p{N}|_|\.|!|\$/u;
+const SYMBOL_CHARS = new Set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!$");
+
+function tokenizeSymbol(chars: TokenizingChars): Token | null {
+ let result: string = "";
+ if (chars.current === "'") {
+ let lastChar = chars.shift();
+ result += lastChar;
+ while (chars.current) {
+ lastChar = chars.shift();
+ result += lastChar;
+ if (lastChar === "'") {
+ if (chars.current && chars.current === "'") {
+ lastChar = chars.shift();
+ result += lastChar;
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (lastChar !== "'") {
+ return {
+ type: "UNKNOWN",
+ value: result,
+ };
+ }
+ }
+ while (
+ chars.current &&
+ (SYMBOL_CHARS.has(chars.current) || chars.current.match(unicodeSymbolCharRegexp))
+ ) {
+ result += chars.shift();
+ }
+ if (result.length) {
+ const value = result;
+ const isReference = rangeReference.test(value);
+ if (isReference) {
+ return { type: "REFERENCE", value };
+ }
+ return { type: "SYMBOL", value };
+ }
+ return null;
+}
+
+function tokenizeSpecialCharacterSpace(chars: TokenizingChars): Token | null {
+ let spaces = "";
+ while (chars.current === " " || (chars.current && chars.current.match(specialWhiteSpaceRegexp))) {
+ spaces += chars.shift();
+ }
+
+ if (spaces) {
+ return { type: "SPACE", value: spaces };
+ }
+ return null;
+}
+
+function tokenizeSimpleSpace(chars: TokenizingChars): Token | null {
+ let spaces = "";
+ while (chars.current === " ") {
+ spaces += chars.shift();
+ }
+
+ if (spaces) {
+ return { type: "SPACE", value: spaces };
+ }
+ return null;
+}
+
+function tokenizeNewLine(chars: TokenizingChars): Token | null {
+ let length = 0;
+ while (chars.current === NEWLINE) {
+ length++;
+ chars.shift();
+ }
+ if (length) {
+ return { type: "SPACE", value: NEWLINE.repeat(length) };
+ }
+ return null;
+}
+
+function tokenizeInvalidRange(chars: TokenizingChars): Token | null {
+ if (chars.currentStartsWith(CellErrorType.InvalidReference)) {
+ chars.advanceBy(CellErrorType.InvalidReference.length);
+ return { type: "INVALID_REFERENCE", value: CellErrorType.InvalidReference };
+ }
+ return null;
+}
diff --git a/src/functions/arguments.ts b/packages/o-spreadsheet-engine/src/functions/arguments.ts
similarity index 98%
rename from src/functions/arguments.ts
rename to packages/o-spreadsheet-engine/src/functions/arguments.ts
index 9c4c80ac97..503f167e58 100644
--- a/src/functions/arguments.ts
+++ b/packages/o-spreadsheet-engine/src/functions/arguments.ts
@@ -1,13 +1,13 @@
import {
- AddFunctionDescription,
ArgDefinition,
ArgProposal,
ArgType,
FunctionDescription,
-} from "../types";
+ Functions,
+} from "../types/functions";
//------------------------------------------------------------------------------
-// Arg description DSL
+// Arg description DSLÒ
//------------------------------------------------------------------------------
const ARG_REGEXP = /(.*?)\((.*?)\)(.*)/;
@@ -97,10 +97,7 @@ function makeArg(str: string, description: string, proposals?: ArgProposal[]): A
*
* This information is useful during compilation.
*/
-export function addMetaInfoFromArg(
- name: string,
- addDescr: AddFunctionDescription
-): FunctionDescription {
+export function addMetaInfoFromArg(name: string, addDescr: Functions): FunctionDescription {
let countArg = 0;
let minArg = 0;
let repeatingArg = 0;
diff --git a/packages/o-spreadsheet-engine/src/functions/functionRegistry.ts b/packages/o-spreadsheet-engine/src/functions/functionRegistry.ts
new file mode 100644
index 0000000000..38045bf712
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/functions/functionRegistry.ts
@@ -0,0 +1,211 @@
+import { _t } from "../translation";
+import {
+ Arg,
+ BadExpressionError,
+ ComputeFunction,
+ EvalContext,
+ FunctionDescription,
+ FunctionResultObject,
+ Functions,
+ isMatrix,
+ Matrix,
+} from "../types";
+
+import { addMetaInfoFromArg, validateArguments } from "./arguments";
+import { FunctionRegistry } from "./function_registry";
+import * as array from "./module_array";
+import * as misc from "./module_custom";
+import * as database from "./module_database";
+import * as date from "./module_date";
+import * as engineering from "./module_engineering";
+import * as filter from "./module_filter";
+import * as financial from "./module_financial";
+import * as info from "./module_info";
+import * as logical from "./module_logical";
+import * as lookup from "./module_lookup";
+import * as math from "./module_math";
+import * as operators from "./module_operators";
+import * as parser from "./module_parser";
+import * as pivots from "./module_pivot";
+import * as statistical from "./module_statistical";
+import * as text from "./module_text";
+import * as web from "./module_web";
+
+type Functions = { [functionName: string]: Functions };
+export type Category = { name: string; functions: Functions };
+export const categories: Category[] = [
+ { name: _t("Array"), functions: array },
+ { name: _t("Database"), functions: database },
+ { name: _t("Date"), functions: date },
+ { name: _t("Filter"), functions: filter },
+ { name: _t("Financial"), functions: financial },
+ { name: _t("Info"), functions: info },
+ { name: _t("Lookup"), functions: { ...lookup, ...pivots } },
+ { name: _t("Logical"), functions: logical },
+ { name: _t("Math"), functions: math },
+ { name: _t("Misc"), functions: misc },
+ { name: _t("Operator"), functions: operators },
+ { name: _t("Statistical"), functions: statistical },
+ { name: _t("Text"), functions: text },
+ { name: _t("Engineering"), functions: engineering },
+ { name: _t("Web"), functions: web },
+ { name: _t("Parser"), functions: parser },
+];
+const functionNameRegex = /^[A-Z0-9\_\.]+$/;
+
+class SpreadsheetFunctionRegistry extends FunctionRegistry<
+ Functions,
+ FunctionDescription,
+ ComputeFunction | FunctionResultObject>
+> {
+ protected process(name: string, addDescr: Functions) {
+ const normalizedName = name.toUpperCase();
+ if (!functionNameRegex.test(normalizedName)) {
+ throw new Error(
+ _t(
+ "Invalid function name %s. Function names can exclusively contain alphanumerical values separated by dots (.) or underscore (_)",
+ normalizedName
+ )
+ );
+ }
+ const descr = addMetaInfoFromArg(normalizedName, addDescr);
+ validateArguments(descr);
+ const compute = createComputeFunction(descr);
+ return {
+ key: normalizedName,
+ stored: descr,
+ mapped: compute,
+ };
+ }
+}
+
+export const functionRegistry = new SpreadsheetFunctionRegistry();
+
+function createComputeFunction(
+ descr: FunctionDescription
+): ComputeFunction | FunctionResultObject> {
+ function vectorizedCompute(
+ this: EvalContext,
+ ...args: Arg[]
+ ): FunctionResultObject | Matrix {
+ const acceptToVectorize: boolean[] = [];
+
+ const getArgToFocus = argTargeting(descr, args.length);
+ //#region Compute vectorisation limits
+ for (let i = 0; i < args.length; i++) {
+ const argIndex = getArgToFocus(i) ?? -1;
+ const argDefinition = descr.args[argIndex];
+ const arg = args[i];
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
+ throw new BadExpressionError(
+ _t(
+ "Function %s expects the parameter '%s' to be reference to a cell or range.",
+ descr.name,
+ (i + 1).toString()
+ )
+ );
+ }
+ acceptToVectorize.push(!argDefinition.acceptMatrix);
+ }
+
+ return applyVectorization(errorHandlingCompute.bind(this), args, acceptToVectorize);
+ }
+
+ function errorHandlingCompute(
+ this: EvalContext,
+ ...args: Arg[]
+ ): Matrix | FunctionResultObject {
+ for (let i = 0; i < args.length; i++) {
+ const arg = args[i];
+ const getArgToFocus = argTargeting(descr, args.length);
+ const argDefinition = descr.args[getArgToFocus(i) || i];
+
+ // Early exit if the argument is an error and the function does not accept errors
+ // We only check scalar arguments, not matrix arguments for performance reasons.
+ // Casting helpers are responsible for handling errors in matrix arguments.
+ if (!argDefinition.acceptErrors && !isMatrix(arg) && isEvaluationError(arg?.value)) {
+ return arg;
+ }
+ }
+ try {
+ return computeFunctionToObject.apply(this, args);
+ } catch (e) {
+ return handleError(e, descr.name);
+ }
+ }
+
+ function computeFunctionToObject(
+ this: EvalContext,
+ ...args: Arg[]
+ ): FunctionResultObject | Matrix {
+ if (this.debug) {
+ // eslint-disable-next-line no-debugger
+ debugger;
+ }
+ const result = descr.compute.apply(this, args);
+
+ if (!isMatrix(result)) {
+ if (typeof result === "object" && result !== null && "value" in result) {
+ replaceFunctionNamePlaceholder(result, descr.name);
+ return result;
+ }
+ return { value: result };
+ }
+
+ if (typeof result[0][0] === "object" && result[0][0] !== null && "value" in result[0][0]) {
+ matrixForEach(result as Matrix, (result) =>
+ replaceFunctionNamePlaceholder(result, descr.name)
+ );
+ return result as Matrix;
+ }
+
+ return matrixMap(result as Matrix, (row) => ({ value: row }));
+ }
+
+ return vectorizedCompute;
+}
+
+export function handleError(e: unknown, functionName: string): FunctionResultObject {
+ // the error could be an user error (instance of EvaluationError)
+ // or a javascript error (instance of Error)
+ // we don't want block the user with an implementation error
+ // so we fallback to a generic error
+ if (hasStringValue(e) && isEvaluationError(e.value)) {
+ if (hasStringMessage(e)) {
+ replaceFunctionNamePlaceholder(e, functionName);
+ }
+ return e;
+ }
+ console.error(e);
+ return new EvaluationError(
+ implementationErrorMessage + (hasStringMessage(e) ? " " + e.message : "")
+ );
+}
+
+function hasStringValue(obj: unknown): obj is { value: string } {
+ return (
+ (obj as { value: string })?.value !== undefined &&
+ typeof (obj as { value: string }).value === "string"
+ );
+}
+
+function replaceFunctionNamePlaceholder(
+ functionResult: FunctionResultObject,
+ functionName: string
+) {
+ // for performance reasons: change in place and only if needed
+ if (functionResult.message?.includes("[[FUNCTION_NAME]]")) {
+ functionResult.message = functionResult.message.replace("[[FUNCTION_NAME]]", functionName);
+ }
+}
+
+export const implementationErrorMessage = _t(
+ "An unexpected error occurred. Submit a support ticket at odoo.com/help."
+);
+
+function hasStringMessage(obj: unknown): obj is { message: string } {
+ return (
+ (obj as { message: string })?.message !== undefined &&
+ typeof (obj as { message: string }).message === "string"
+ );
+}
diff --git a/packages/o-spreadsheet-engine/src/functions/function_registry.ts b/packages/o-spreadsheet-engine/src/functions/function_registry.ts
new file mode 100644
index 0000000000..c0cc895c5b
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/functions/function_registry.ts
@@ -0,0 +1,58 @@
+import { Registry } from "../registry";
+
+export interface ProcessResult {
+ key: string;
+ stored: TStored;
+ mapped: TMapped;
+}
+
+export abstract class FunctionRegistry {
+ private registry = new Registry();
+ mapping: Record = {} as Record;
+
+ public get content(): Record {
+ return this.registry.content;
+ }
+
+ add(name: string, descriptor: TInput): this {
+ const prepared = this.process(name, descriptor);
+ if (this.registry.contains(prepared.key)) {
+ throw new Error(`${prepared.key} is already present in this registry!`);
+ }
+ return this.set(prepared);
+ }
+
+ replace(name: string, descriptor: TInput): this {
+ const prepared = this.process(name, descriptor);
+ return this.set(prepared);
+ }
+
+ get(key: string): TStored {
+ return this.registry.get(key);
+ }
+
+ contains(key: string): boolean {
+ return this.registry.contains(key);
+ }
+
+ getAll(): TStored[] {
+ return this.registry.getAll();
+ }
+
+ getKeys(): string[] {
+ return this.registry.getKeys();
+ }
+
+ remove(key: string): void {
+ delete this.mapping[key];
+ this.registry.remove(key);
+ }
+
+ protected abstract process(name: string, descriptor: TInput): ProcessResult;
+
+ private set(prepared: ProcessResult): this {
+ this.mapping[prepared.key] = prepared.mapped;
+ this.registry.replace(prepared.key, prepared.stored);
+ return this;
+ }
+}
diff --git a/src/functions/helper_assert.ts b/packages/o-spreadsheet-engine/src/functions/helper_assert.ts
similarity index 92%
rename from src/functions/helper_assert.ts
rename to packages/o-spreadsheet-engine/src/functions/helper_assert.ts
index e27ff4da17..c1d4577acd 100644
--- a/src/functions/helper_assert.ts
+++ b/packages/o-spreadsheet-engine/src/functions/helper_assert.ts
@@ -1,6 +1,7 @@
import { _t } from "../translation";
-import { Arg, FunctionResultNumber, FunctionResultObject, Matrix, isMatrix } from "../types";
+import { Arg, FunctionResultObject, Matrix, isMatrix } from "../types";
import { DivisionByZeroError, EvaluationError } from "../types/errors";
+import { FunctionResultNumber } from "../types/misc";
export function assert(condition: boolean, message: string): asserts condition {
if (!condition) {
diff --git a/src/functions/helper_logical.ts b/packages/o-spreadsheet-engine/src/functions/helper_logical.ts
similarity index 94%
rename from src/functions/helper_logical.ts
rename to packages/o-spreadsheet-engine/src/functions/helper_logical.ts
index 9d2f52e61e..1a0d4c20fd 100644
--- a/src/functions/helper_logical.ts
+++ b/packages/o-spreadsheet-engine/src/functions/helper_logical.ts
@@ -1,4 +1,4 @@
-import { Arg } from "../types";
+import { Arg } from "../index";
import { conditionalVisitBoolean } from "./helpers";
export function boolAnd(args: Arg[]) {
diff --git a/src/functions/helper_math.ts b/packages/o-spreadsheet-engine/src/functions/helper_math.ts
similarity index 84%
rename from src/functions/helper_math.ts
rename to packages/o-spreadsheet-engine/src/functions/helper_math.ts
index fa78dfd26a..c28d0aed2a 100644
--- a/src/functions/helper_math.ts
+++ b/packages/o-spreadsheet-engine/src/functions/helper_math.ts
@@ -1,4 +1,5 @@
-import { Arg, Locale } from "../types";
+import { Arg } from "../index";
+import { Locale } from "../types";
import { isDataNonEmpty, reduceAny, reduceNumbers } from "./helpers";
export function sum(values: Arg[], locale: Locale): number {
diff --git a/src/functions/helper_matrices.ts b/packages/o-spreadsheet-engine/src/functions/helper_matrices.ts
similarity index 100%
rename from src/functions/helper_matrices.ts
rename to packages/o-spreadsheet-engine/src/functions/helper_matrices.ts
diff --git a/src/functions/helper_statistical.ts b/packages/o-spreadsheet-engine/src/functions/helper_statistical.ts
similarity index 90%
rename from src/functions/helper_statistical.ts
rename to packages/o-spreadsheet-engine/src/functions/helper_statistical.ts
index 0e13d8855b..b7d3b75db9 100644
--- a/src/functions/helper_statistical.ts
+++ b/packages/o-spreadsheet-engine/src/functions/helper_statistical.ts
@@ -1,18 +1,16 @@
-import { Point } from "chart.js";
-import { DEFAULT_WINDOW_SIZE } from "../constants";
-import { isNumber, parseDateTime, range } from "../helpers";
-import { _t } from "../translation";
-import { Arg, Locale, Matrix, isMatrix } from "../types";
-import { EvaluationError } from "../types/errors";
-import { assert, assertNotZero } from "./helper_assert";
-import { invertMatrix, multiplyMatrices } from "./helper_matrices";
+import { isMatrix } from "..";
+import { invertMatrix, multiplyMatrices } from "../functions/helper_matrices";
import {
isEvaluationError,
reduceAny,
reduceNumbers,
transposeMatrix,
visitNumbers,
-} from "./helpers";
+} from "../functions/helpers";
+import { isNumber, parseDateTime, range } from "../helpers";
+import { _t } from "../translation";
+import { Arg, EvaluationError, Locale, Matrix } from "../types";
+import { assert, assertNotZero } from "./helper_assert";
export function assertSameNumberOfElements(...args: any[][]) {
const dims = args[0].length;
@@ -285,23 +283,3 @@ export function predictLinearValues(
});
return newY.length === newX.length ? newY : transposeMatrix(newY);
}
-
-export function getMovingAverageValues(
- dataset: number[],
- labels: number[],
- windowSize = DEFAULT_WINDOW_SIZE
-): Point[] {
- const values: Point[] = [];
- // Fill the starting values with null until we have a full window
- for (let i = 0; i < windowSize - 1; i++) {
- values.push({ x: labels[i], y: NaN });
- }
- for (let i = 0; i <= dataset.length - windowSize; i++) {
- let sum = 0;
- for (let j = i; j < i + windowSize; j++) {
- sum += dataset[j];
- }
- values.push({ x: labels[i + windowSize - 1], y: sum / windowSize });
- }
- return values;
-}
diff --git a/src/functions/helpers.ts b/packages/o-spreadsheet-engine/src/functions/helpers.ts
similarity index 99%
rename from src/functions/helpers.ts
rename to packages/o-spreadsheet-engine/src/functions/helpers.ts
index ed21181f4a..8426c2d446 100644
--- a/src/functions/helpers.ts
+++ b/packages/o-spreadsheet-engine/src/functions/helpers.ts
@@ -3,25 +3,16 @@ import { DateTime, isDateTime, numberToJsDate, parseDateTime } from "../helpers/
import { memoize } from "../helpers/misc";
import { isNumber, parseNumber } from "../helpers/numbers";
import { _t } from "../translation";
-import {
- Arg,
- CellValue,
- FunctionResultNumber,
- FunctionResultObject,
- Locale,
- Matrix,
- Maybe,
- SortDirection,
- isMatrix,
-} from "../types";
+import { CellValue, FunctionResultNumber, Locale, SortDirection } from "../types";
import {
CellErrorType,
+ errorTypes,
ErrorValue,
EvaluationError,
NotAvailableError,
- errorTypes,
} from "../types/errors";
-import { LookupCaches } from "../types/functions";
+
+import { Arg, FunctionResultObject, isMatrix, LookupCaches, Matrix, Maybe } from "../types";
const SORT_TYPES_ORDER = ["number", "string", "boolean", "undefined"];
diff --git a/src/functions/module_array.ts b/packages/o-spreadsheet-engine/src/functions/module_array.ts
similarity index 97%
rename from src/functions/module_array.ts
rename to packages/o-spreadsheet-engine/src/functions/module_array.ts
index 68caa11334..01f73dd97b 100644
--- a/src/functions/module_array.ts
+++ b/packages/o-spreadsheet-engine/src/functions/module_array.ts
@@ -1,5 +1,5 @@
+import { Arg, FunctionResultObject, Functions, Matrix, Maybe } from "../index";
import { _t } from "../translation";
-import { AddFunctionDescription, Arg, FunctionResultObject, Matrix, Maybe } from "../types";
import { EvaluationError, NotAvailableError } from "../types/errors";
import { arg } from "./arguments";
import { areSameDimensions, isSingleColOrRow, isSquareMatrix } from "./helper_assert";
@@ -52,7 +52,7 @@ export const ARRAY_CONSTRAIN = {
return generateMatrix(_nbColumns, _nbRows, (col, row) => _array[col][row]);
},
isExported: false,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// CHOOSECOLS
@@ -98,7 +98,7 @@ export const CHOOSECOLS = {
return result;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// CHOOSEROWS
@@ -138,7 +138,7 @@ export const CHOOSEROWS = {
});
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// EXPAND
@@ -191,7 +191,7 @@ export const EXPAND = {
);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// FLATTEN
@@ -206,7 +206,7 @@ export const FLATTEN = {
return [flattenRowFirst(ranges, (val) => (val === undefined ? { value: "" } : val))];
},
isExported: false,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// FREQUENCY
@@ -266,7 +266,7 @@ export const FREQUENCY = {
return [result];
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// HSTACK
@@ -296,7 +296,7 @@ export const HSTACK = {
return result;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MDETERM
@@ -321,7 +321,7 @@ export const MDETERM = {
return invertMatrix(_matrix).determinant;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MINVERSE
@@ -350,7 +350,7 @@ export const MINVERSE = {
return inverted;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MMULT
@@ -391,7 +391,7 @@ export const MMULT = {
return multiplyMatrices(_matrix1, _matrix2);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SUMPRODUCT
@@ -435,7 +435,7 @@ export const SUMPRODUCT = {
return result;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SUMX2MY2
@@ -500,7 +500,7 @@ export const SUMX2MY2 = {
return getSumXAndY(arrayX, arrayY, (x, y) => x ** 2 - y ** 2);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SUMX2PY2
@@ -525,7 +525,7 @@ export const SUMX2PY2 = {
return getSumXAndY(arrayX, arrayY, (x, y) => x ** 2 + y ** 2);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SUMXMY2
@@ -550,7 +550,7 @@ export const SUMXMY2 = {
return getSumXAndY(arrayX, arrayY, (x, y) => (x - y) ** 2);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TOCOL
@@ -617,7 +617,7 @@ export const TOCOL = {
return [result];
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TOROW
@@ -644,7 +644,7 @@ export const TOROW = {
return result;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TRANSPOSE
@@ -660,7 +660,7 @@ export const TRANSPOSE = {
return generateMatrix(nbColumns, nbRows, (col, row) => _array[row][col]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// VSTACK
@@ -693,7 +693,7 @@ export const VSTACK = {
return result;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// WRAPCOLS
@@ -734,7 +734,7 @@ export const WRAPCOLS = {
});
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// WRAPROWS
@@ -775,4 +775,4 @@ export const WRAPROWS = {
});
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_custom.ts b/packages/o-spreadsheet-engine/src/functions/module_custom.ts
similarity index 87%
rename from src/functions/module_custom.ts
rename to packages/o-spreadsheet-engine/src/functions/module_custom.ts
index 1bae8277da..0a7c9950b2 100644
--- a/src/functions/module_custom.ts
+++ b/packages/o-spreadsheet-engine/src/functions/module_custom.ts
@@ -1,11 +1,6 @@
import { formatLargeNumber } from "../helpers";
import { _t } from "../translation";
-import {
- AddFunctionDescription,
- FunctionResultNumber,
- FunctionResultObject,
- Maybe,
-} from "../types";
+import { FunctionResultNumber, FunctionResultObject, Functions, Maybe } from "../types";
import { arg } from "./arguments";
import { toNumber } from "./helpers";
@@ -36,4 +31,4 @@ export const FORMAT_LARGE_NUMBER = {
format: formatLargeNumber(value, unite, this.locale),
};
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_database.ts b/packages/o-spreadsheet-engine/src/functions/module_database.ts
similarity index 94%
rename from src/functions/module_database.ts
rename to packages/o-spreadsheet-engine/src/functions/module_database.ts
index 285441243a..12489ea711 100644
--- a/src/functions/module_database.ts
+++ b/packages/o-spreadsheet-engine/src/functions/module_database.ts
@@ -1,16 +1,9 @@
+import { arg } from "../functions/arguments";
+import { toString, visitMatchingRanges } from "../functions/helpers";
+import { Arg, FunctionResultObject, Functions, Matrix, Maybe } from "../index";
import { _t } from "../translation";
-import {
- AddFunctionDescription,
- Arg,
- FunctionResultNumber,
- FunctionResultObject,
- Locale,
- Matrix,
- Maybe,
-} from "../types";
+import { FunctionResultNumber, Locale } from "../types";
import { EvaluationError } from "../types/errors";
-import { arg } from "./arguments";
-import { toString, visitMatchingRanges } from "./helpers";
import { PRODUCT, SUM } from "./module_math";
import { AVERAGE, COUNT, COUNTA, MAX, MIN, STDEV, STDEVP, VAR, VARP } from "./module_statistical";
@@ -178,7 +171,7 @@ export const DAVERAGE = {
return AVERAGE.compute.bind(this)([cells]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DCOUNT
@@ -195,7 +188,7 @@ export const DCOUNT = {
return COUNT.compute.bind(this)([cells]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DCOUNTA
@@ -212,7 +205,7 @@ export const DCOUNTA = {
return COUNTA.compute.bind(this)([cells]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DGET
@@ -232,7 +225,7 @@ export const DGET = {
return cells[0];
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DMAX
@@ -249,7 +242,7 @@ export const DMAX = {
return MAX.compute.bind(this)([cells]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DMIN
@@ -266,7 +259,7 @@ export const DMIN = {
return MIN.compute.bind(this)([cells]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DPRODUCT
@@ -283,7 +276,7 @@ export const DPRODUCT = {
return PRODUCT.compute.bind(this)([cells]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DSTDEV
@@ -300,7 +293,7 @@ export const DSTDEV = {
return STDEV.compute.bind(this)([cells]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DSTDEVP
@@ -317,7 +310,7 @@ export const DSTDEVP = {
return STDEVP.compute.bind(this)([cells]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DSUM
@@ -334,7 +327,7 @@ export const DSUM = {
return SUM.compute.bind(this)([cells]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DVAR
@@ -351,7 +344,7 @@ export const DVAR = {
return VAR.compute.bind(this)([cells]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DVARP
@@ -368,4 +361,4 @@ export const DVARP = {
return VARP.compute.bind(this)([cells]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_date.ts b/packages/o-spreadsheet-engine/src/functions/module_date.ts
similarity index 97%
rename from src/functions/module_date.ts
rename to packages/o-spreadsheet-engine/src/functions/module_date.ts
index ff150d99e0..f1507eb251 100644
--- a/src/functions/module_date.ts
+++ b/packages/o-spreadsheet-engine/src/functions/module_date.ts
@@ -1,3 +1,5 @@
+import { Arg, FunctionResultObject, Functions, Maybe } from "@odoo/o-spreadsheet-engine";
+import { FunctionResultNumber } from "@odoo/o-spreadsheet-engine/types";
import {
addMonthsToDate,
areTwoDatesWithinOneYear,
@@ -15,13 +17,6 @@ import {
} from "../helpers/dates";
import { getDateTimeFormat } from "../helpers/locale";
import { _t } from "../translation";
-import {
- AddFunctionDescription,
- Arg,
- FunctionResultNumber,
- FunctionResultObject,
- Maybe,
-} from "../types";
import { EvaluationError } from "../types/errors";
import { arg } from "./arguments";
import { assert } from "./helper_assert";
@@ -85,7 +80,7 @@ export const DATE = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DATEDIF
@@ -199,7 +194,7 @@ export const DATEDIF = {
}
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DATEVALUE
@@ -220,7 +215,7 @@ export const DATEVALUE = {
return Math.trunc(internalDate!.value);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DAY
@@ -232,7 +227,7 @@ export const DAY = {
return toJsDate(date, this.locale).getDate();
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DAYS
@@ -254,7 +249,7 @@ export const DAYS = {
return Math.round(dateDif / MS_PER_DAY);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DAYS360
@@ -287,7 +282,7 @@ export const DAYS360 = {
return Math.sign(_endDate - _startDate) * Math.round(yearFrac * 360);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// EDATE
@@ -315,7 +310,7 @@ export const EDATE = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// EOMONTH
@@ -345,7 +340,7 @@ export const EOMONTH = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// HOUR
@@ -357,7 +352,7 @@ export const HOUR = {
return toJsDate(date, this.locale).getHours();
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISOWEEKNUM
@@ -445,7 +440,7 @@ export const ISOWEEKNUM = {
return Math.floor(diff / 7) + 1;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MINUTE
@@ -457,7 +452,7 @@ export const MINUTE = {
return toJsDate(date, this.locale).getMinutes();
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MONTH
@@ -469,7 +464,7 @@ export const MONTH = {
return toJsDate(date, this.locale).getMonth() + 1;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// NETWORKDAYS
@@ -498,7 +493,7 @@ export const NETWORKDAYS = {
return NETWORKDAYS_INTL.compute.bind(this)(startDate, endDate, { value: 1 }, holidays);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// NETWORKDAYS.INTL
@@ -648,7 +643,7 @@ export const NETWORKDAYS_INTL = {
return invertDate ? -netWorkingDay : netWorkingDay;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// NOW
@@ -667,7 +662,7 @@ export const NOW = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SECOND
@@ -679,7 +674,7 @@ export const SECOND = {
return toJsDate(date, this.locale).getSeconds();
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TIME
@@ -718,7 +713,7 @@ export const TIME = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TIMEVALUE
@@ -740,7 +735,7 @@ export const TIMEVALUE = {
return result < 0 ? 1 + result : result;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TODAY
@@ -757,7 +752,7 @@ export const TODAY = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// WEEKDAY
@@ -817,7 +812,7 @@ export const WEEKDAY = {
return result === 0 ? 7 : result;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// WEEKNUM
@@ -888,7 +883,7 @@ export const WEEKNUM = {
return Math.floor(dif / 7) + (dayStart === 1 ? 1 : 2);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// WORKDAY
@@ -914,7 +909,7 @@ export const WORKDAY = {
return WORKDAY_INTL.compute.bind(this)(startDate, numDays, { value: 1 }, holidays);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// WORKDAY.INTL
@@ -981,7 +976,7 @@ export const WORKDAY_INTL = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// YEAR
@@ -993,7 +988,7 @@ export const YEAR = {
return toJsDate(date, this.locale).getFullYear();
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// YEARFRAC
@@ -1043,7 +1038,7 @@ export const YEARFRAC = {
return getYearFrac(_startDate, _endDate, _dayCountConvention);
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MONTH.START
@@ -1061,7 +1056,7 @@ export const MONTH_START = {
format: this.locale.dateFormat,
};
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MONTH.END
@@ -1072,7 +1067,7 @@ export const MONTH_END = {
compute: function (date: Maybe): FunctionResultNumber {
return EOMONTH.compute.bind(this)(date, { value: 0 });
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// QUARTER
@@ -1083,7 +1078,7 @@ export const QUARTER = {
compute: function (date: Maybe): number {
return Math.ceil((toJsDate(date, this.locale).getMonth() + 1) / 3);
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// QUARTER.START
@@ -1100,7 +1095,7 @@ export const QUARTER_START = {
format: this.locale.dateFormat,
};
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// QUARTER.END
@@ -1117,7 +1112,7 @@ export const QUARTER_END = {
format: this.locale.dateFormat,
};
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// YEAR.START
@@ -1133,7 +1128,7 @@ export const YEAR_START = {
format: this.locale.dateFormat,
};
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// YEAR.END
@@ -1149,4 +1144,4 @@ export const YEAR_END = {
format: this.locale.dateFormat,
};
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_engineering.ts b/packages/o-spreadsheet-engine/src/functions/module_engineering.ts
similarity index 88%
rename from src/functions/module_engineering.ts
rename to packages/o-spreadsheet-engine/src/functions/module_engineering.ts
index c6d7e24f6b..9aac64cc37 100644
--- a/src/functions/module_engineering.ts
+++ b/packages/o-spreadsheet-engine/src/functions/module_engineering.ts
@@ -1,5 +1,5 @@
+import { FunctionResultObject, Functions, Maybe } from "../index";
import { _t } from "../translation";
-import { AddFunctionDescription, FunctionResultObject, Maybe } from "../types";
import { arg } from "./arguments";
import { toNumber } from "./helpers";
@@ -23,4 +23,4 @@ export const DELTA = {
return _number1 === _number2 ? 1 : 0;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_filter.ts b/packages/o-spreadsheet-engine/src/functions/module_filter.ts
similarity index 97%
rename from src/functions/module_filter.ts
rename to packages/o-spreadsheet-engine/src/functions/module_filter.ts
index 970fda3cc3..d2d16c7dc5 100644
--- a/src/functions/module_filter.ts
+++ b/packages/o-spreadsheet-engine/src/functions/module_filter.ts
@@ -1,19 +1,15 @@
import { range } from "../helpers";
import { cellsSortingCriterion } from "../helpers/sort";
+import { Arg, FunctionResultObject, Functions, isMatrix, Matrix, Maybe } from "../index";
import { _t } from "../translation";
import {
- AddFunctionDescription,
- Arg,
CellValue,
CellValueType,
- FunctionResultObject,
+ EvaluationError,
Locale,
- Matrix,
- Maybe,
+ NotAvailableError,
SortDirection,
- isMatrix,
} from "../types";
-import { EvaluationError, NotAvailableError } from "../types/errors";
import { arg } from "./arguments";
import { areSameDimensions, assert, isSingleColOrRow } from "./helper_assert";
import { toScalar } from "./helper_matrices";
@@ -159,12 +155,12 @@ export const FILTER = {
return mode === "row" ? transposeMatrix(result) : result;
},
isExported: false,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SORT
// -----------------------------------------------------------------------------
-export const SORT: AddFunctionDescription = {
+export const SORT: Functions = {
description: _t("Sorts the rows of a given array or range by the values in one or more columns."),
args: [
arg("range (range)", _t("The data to be sorted.")),
@@ -196,7 +192,7 @@ export const SORT: AddFunctionDescription = {
// -----------------------------------------------------------------------------
// SORTN
// -----------------------------------------------------------------------------
-export const SORTN: AddFunctionDescription = {
+export const SORTN: Functions = {
description: _t("Returns the first n items in a data set after performing a sort."),
args: [
arg("range (range)", _t("The data to be sorted.")),
@@ -366,4 +362,4 @@ export const UNIQUE = {
return _byColumn ? result : transposeMatrix(result);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_financial.ts b/packages/o-spreadsheet-engine/src/functions/module_financial.ts
similarity index 98%
rename from src/functions/module_financial.ts
rename to packages/o-spreadsheet-engine/src/functions/module_financial.ts
index abbd60b070..b23e0c8e12 100644
--- a/src/functions/module_financial.ts
+++ b/packages/o-spreadsheet-engine/src/functions/module_financial.ts
@@ -1,3 +1,4 @@
+import { Arg, FunctionResultObject, Functions, Matrix, Maybe } from "@odoo/o-spreadsheet-engine";
import {
addMonthsToDate,
getYearFrac,
@@ -6,7 +7,7 @@ import {
range,
} from "../helpers";
import { _t } from "../translation";
-import { AddFunctionDescription, Arg, FunctionResultObject, Locale, Matrix, Maybe } from "../types";
+import { Locale } from "../types";
import { EvaluationError } from "../types/errors";
import { arg } from "./arguments";
import { areSameDimensions, assert } from "./helper_assert";
@@ -216,7 +217,7 @@ export const ACCRINTM = {
return _redemption * _rate * yearFrac;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// AMORLINC
@@ -313,7 +314,7 @@ export const AMORLINC = {
return _salvage - valueAtPeriod < deprec ? deprec - (_salvage - valueAtPeriod) : 0;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUPDAYS
@@ -364,7 +365,7 @@ export const COUPDAYS = {
return daysInYear / _frequency;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUPDAYBS
@@ -447,7 +448,7 @@ export const COUPDAYBS = {
return (y2 - y1) * 360 + (m2 - m1) * 30 + (d2 - d1);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUPDAYSNC
@@ -508,7 +509,7 @@ export const COUPDAYSNC = {
return toNumber(coupDays, this.locale) - toNumber(coupDayBs, this.locale);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUPNCD
@@ -552,7 +553,7 @@ export const COUPNCD = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUPNUM
@@ -595,7 +596,7 @@ export const COUPNUM = {
return num - 1;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUPPCD
@@ -635,7 +636,7 @@ export const COUPPCD = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// CUMIPMT
@@ -705,7 +706,7 @@ export const CUMIPMT = {
return cumSum;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// CUMPRINC
@@ -775,7 +776,7 @@ export const CUMPRINC = {
return cumSum;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DB
@@ -849,7 +850,7 @@ export const DB = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DDB
@@ -929,7 +930,7 @@ export const DDB = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DISC
@@ -998,7 +999,7 @@ export const DISC = {
return (_redemption - _price) / _redemption / yearsFrac;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DOLLARDE
@@ -1031,7 +1032,7 @@ export const DOLLARDE = {
return truncatedPrice + priceFractionalPart * frac;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DOLLARFR
@@ -1061,7 +1062,7 @@ export const DOLLARFR = {
return truncatedPrice + priceFractionalPart * frac;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DURATION
@@ -1146,7 +1147,7 @@ export const DURATION = {
return count === 0 ? 0 : sum / count;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// EFFECT
@@ -1175,7 +1176,7 @@ export const EFFECT = {
return Math.pow(1 + nominal / periods, periods) - 1;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// FV
@@ -1226,7 +1227,7 @@ export const FV = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// FVSCHEDULE
@@ -1249,7 +1250,7 @@ export const FVSCHEDULE = {
);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// INTRATE
@@ -1314,7 +1315,7 @@ export const INTRATE = {
return (_redemption - _investment) / _investment / yearFrac;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// IPMT
@@ -1360,7 +1361,7 @@ export const IPMT = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// IRR
@@ -1448,7 +1449,7 @@ export const IRR = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISPMT
@@ -1480,7 +1481,7 @@ export const ISPMT = {
return -1 * currentInvestment * interestRate;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MDURATION
@@ -1531,7 +1532,7 @@ export const MDURATION = {
return toNumber(duration, this.locale) / (1 + y / k);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MIRR
@@ -1603,7 +1604,7 @@ export const MIRR = {
return (-fv / pv) ** exponent - 1;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// NOMINAL
@@ -1632,7 +1633,7 @@ export const NOMINAL = {
return (Math.pow(effective + 1, 1 / periods) - 1) * periods;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// NPER
@@ -1689,7 +1690,7 @@ export const NPER = {
return Math.log((c - fv) / (pv + c)) / Math.log(1 + r);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// NPV
@@ -1731,7 +1732,7 @@ export const NPV = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// PDURATION
@@ -1765,7 +1766,7 @@ export const PDURATION = {
return (Math.log(_futureValue) - Math.log(_presentValue)) / Math.log(1 + _rate);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// PMT
@@ -1822,7 +1823,7 @@ export const PMT = {
return { value: pmt(r, n, pv, fv, t), format: "#,##0.00" };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// PPMT
@@ -1887,7 +1888,7 @@ export const PPMT = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// PV
@@ -1932,7 +1933,7 @@ export const PV = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// PRICE
@@ -2032,7 +2033,7 @@ export const PRICE = {
);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// PRICEDISC
@@ -2100,7 +2101,7 @@ export const PRICEDISC = {
return _redemption - _discount * _redemption * yearsFrac;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// PRICEMAT
@@ -2199,7 +2200,7 @@ export const PRICEMAT = {
return numerator / denominator - term2;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// RATE
@@ -2278,7 +2279,7 @@ export const RATE = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// RECEIVED
@@ -2351,7 +2352,7 @@ export const RECEIVED = {
return _investment / (1 - _discount * yearsFrac);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// RRI
@@ -2386,7 +2387,7 @@ export const RRI = {
return (fv / pv) ** (1 / n) - 1;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SLN
@@ -2416,7 +2417,7 @@ export const SLN = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SYD
@@ -2471,7 +2472,7 @@ export const SYD = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TBILLPRICE
@@ -2531,7 +2532,7 @@ export const TBILLPRICE = {
return tBillPrice(start, end, disc);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TBILLEQ
@@ -2615,7 +2616,7 @@ export const TBILLEQ = {
return num / denom;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TBILLYIELD
@@ -2671,7 +2672,7 @@ export const TBILLYIELD = {
return ((100 - p) / p) * (1 / yearFrac);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// VDB
@@ -2789,7 +2790,7 @@ export const VDB = {
return resultDeprec;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// XIRR
@@ -2884,7 +2885,7 @@ export const XIRR = {
return newtonMethod(func, derivFunc, guess, 40, 1e-5, nanFallback);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// XNPV
@@ -2961,7 +2962,7 @@ export const XNPV = {
return pv;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// YIELD
@@ -3113,7 +3114,7 @@ export const YIELD = {
return (methodResult - 1) * _frequency;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// YIELDDISC
@@ -3179,7 +3180,7 @@ export const YIELDDISC = {
return (_redemption / _price - 1) / yearFrac;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// YIELDMAT
@@ -3251,4 +3252,4 @@ export const YIELDMAT = {
return numerator / settlementToMaturity;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_lookup.ts b/packages/o-spreadsheet-engine/src/functions/module_lookup.ts
similarity index 76%
rename from src/functions/module_lookup.ts
rename to packages/o-spreadsheet-engine/src/functions/module_lookup.ts
index 6ed95bf8e9..da88851a9b 100644
--- a/src/functions/module_lookup.ts
+++ b/packages/o-spreadsheet-engine/src/functions/module_lookup.ts
@@ -1,26 +1,9 @@
-import { getPivotTooBigErrorMessage } from "../components/translations_terms";
-import { PIVOT_MAX_NUMBER_OF_CELLS } from "../constants";
-import { getFullReference, range, splitReference, toXC, toZone } from "../helpers/index";
-import { addAlignFormatToPivotHeader } from "../helpers/pivot/pivot_helpers";
+import { getFullReference, splitReference, toXC, toZone } from "../helpers";
+import { Arg, FunctionResultObject, Functions, Matrix, Maybe, Zone } from "../index";
import { _t } from "../translation";
-import {
- AddFunctionDescription,
- Arg,
- FunctionResultObject,
- Matrix,
- Maybe,
- PivotVisibilityOptions,
- Zone,
-} from "../types";
-import { CellErrorType, EvaluationError, InvalidReferenceError } from "../types/errors";
+import { CellErrorType, EvaluationError, InvalidReferenceError } from "../types";
import { arg } from "./arguments";
import { expectNumberGreaterThanOrEqualToOne } from "./helper_assert";
-import {
- addPivotDependencies,
- assertDomainLength,
- assertMeasureExist,
- getPivotId,
-} from "./helper_lookup";
import {
LinearSearchMode,
dichotomicSearch,
@@ -35,7 +18,6 @@ import {
toString,
valueNotAvailable,
} from "./helpers";
-
const DEFAULT_IS_SORTED = true;
const DEFAULT_MATCH_MODE = 0;
const DEFAULT_SEARCH_MODE = 1;
@@ -120,7 +102,7 @@ export const ADDRESS = {
return cellReference;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COLUMN
@@ -163,7 +145,7 @@ export const COLUMN = {
return generateMatrix(cellReference.length, 1, (col, row) => ({ value: left + col + 1 }));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COLUMNS
@@ -183,7 +165,7 @@ export const COLUMNS = {
return _range.length;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// HLOOKUP
@@ -248,12 +230,12 @@ export const HLOOKUP = {
return col[_index - 1];
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// INDEX
// -----------------------------------------------------------------------------
-export const INDEX: AddFunctionDescription = {
+export const INDEX: Functions = {
description: _t("Returns the content of a cell, specified by row and column offset."),
args: [
arg("reference (any, range)", _t("The range of cells from which the values are returned.")),
@@ -299,7 +281,7 @@ export const INDEX: AddFunctionDescription = {
// -----------------------------------------------------------------------------
// INDIRECT
// -----------------------------------------------------------------------------
-export const INDIRECT: AddFunctionDescription = {
+export const INDIRECT: Functions = {
description: _t("Returns the content of a cell, specified by a string."),
args: [
arg("reference (string)", _t("The range of cells from which the values are returned.")),
@@ -438,7 +420,7 @@ export const LOOKUP = {
return _resultRange[0][index];
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MATCH
@@ -514,7 +496,7 @@ export const MATCH = {
return index + 1;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ROW
@@ -557,7 +539,7 @@ export const ROW = {
return generateMatrix(1, cellReference[0].length, (col, row) => ({ value: top + row + 1 }));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ROWS
@@ -577,7 +559,7 @@ export const ROWS = {
return _range[0].length;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// VLOOKUP
@@ -651,7 +633,7 @@ export const VLOOKUP = {
return value;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// XLOOKUP
@@ -781,212 +763,7 @@ export const XLOOKUP = {
return [[defaultValue]];
},
isExported: true,
-} satisfies AddFunctionDescription;
-
-//--------------------------------------------------------------------------
-// Pivot functions
-//--------------------------------------------------------------------------
-
-// PIVOT.VALUE
-
-export const PIVOT_VALUE = {
- description: _t("Get the value from a pivot."),
- args: [
- arg("pivot_id (number,string)", _t("ID of the pivot.")),
- arg("measure_name (string)", _t("Name of the measure.")),
- arg("domain_field_name (string,repeating)", _t("Field name.")),
- arg("domain_value (number,string,boolean,repeating)", _t("Value.")),
- ],
- compute: function (
- formulaId: Maybe,
- measureName: Maybe,
- ...domainArgs: Maybe[]
- ) {
- const _pivotFormulaId = toString(formulaId);
- const _measure = toString(measureName);
- const pivotId = getPivotId(_pivotFormulaId, this.getters);
- assertMeasureExist(pivotId, _measure, this.getters);
- assertDomainLength(domainArgs);
- const pivot = this.getters.getPivot(pivotId);
- const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
-
- addPivotDependencies(
- this,
- coreDefinition,
- coreDefinition.measures.filter((m) => m.id === _measure)
- );
- pivot.init({ reload: pivot.needsReevaluation });
- const error = pivot.assertIsValid({ throwOnError: false });
- if (error) {
- return error;
- }
-
- if (!pivot.areDomainArgsFieldsValid(domainArgs)) {
- const suggestion = _t(
- "Consider using a dynamic pivot formula: %s. Or re-insert the static pivot from the Data menu.",
- `=PIVOT(${_pivotFormulaId})`
- );
- return {
- value: CellErrorType.GenericError,
- message: _t("Dimensions don't match the pivot definition") + ". " + suggestion,
- };
- }
- const domain = pivot.parseArgsToPivotDomain(domainArgs);
- if (this.getters.getActiveSheetId() === this.__originSheetId) {
- this.getters.getPivotPresenceTracker(pivotId)?.trackValue(_measure, domain);
- }
- return pivot.getPivotCellValueAndFormat(_measure, domain);
- },
-} satisfies AddFunctionDescription;
-
-// PIVOT.HEADER
-
-export const PIVOT_HEADER = {
- description: _t("Get the header of a pivot."),
- args: [
- arg("pivot_id (number,string)", _t("ID of the pivot.")),
- arg("domain_field_name (string,repeating)", _t("Field name.")),
- arg("domain_value (number,string,value,repeating)", _t("Value.")),
- ],
- compute: function (
- pivotId: Maybe,
- ...domainArgs: Maybe[]
- ) {
- const _pivotFormulaId = toString(pivotId);
- const _pivotId = getPivotId(_pivotFormulaId, this.getters);
- assertDomainLength(domainArgs);
- const pivot = this.getters.getPivot(_pivotId);
- const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
- addPivotDependencies(this, coreDefinition, []);
- pivot.init({ reload: pivot.needsReevaluation });
- const error = pivot.assertIsValid({ throwOnError: false });
- if (error) {
- return error;
- }
- if (!pivot.areDomainArgsFieldsValid(domainArgs)) {
- const suggestion = _t(
- "Consider using a dynamic pivot formula: %s. Or re-insert the static pivot from the Data menu.",
- `=PIVOT(${_pivotFormulaId})`
- );
- return {
- value: CellErrorType.GenericError,
- message: _t("Dimensions don't match the pivot definition") + ". " + suggestion,
- };
- }
- const domain = pivot.parseArgsToPivotDomain(domainArgs);
- if (this.getters.getActiveSheetId() === this.__originSheetId) {
- this.getters.getPivotPresenceTracker(_pivotId)?.trackHeader(domain);
- }
- const lastNode = domain.at(-1);
- if (lastNode?.field === "measure") {
- return pivot.getPivotMeasureValue(toString(lastNode.value), domain);
- }
- const { value, format } = pivot.getPivotHeaderValueAndFormat(domain);
- return {
- value,
- format:
- !lastNode || lastNode.field === "measure" || lastNode.value === "false"
- ? undefined
- : format,
- };
- },
-} satisfies AddFunctionDescription;
-
-export const PIVOT = {
- description: _t("Get a pivot table."),
- args: [
- arg("pivot_id (string)", _t("ID of the pivot.")),
- arg("row_count (number, optional)", _t("number of rows")),
- arg("include_total (boolean, default=TRUE)", _t("Whether to include total/sub-totals or not.")),
- arg(
- "include_column_titles (boolean, default=TRUE)",
- _t("Whether to include the column titles or not.")
- ),
- arg("column_count (number, optional)", _t("number of columns")),
- arg(
- "include_measure_titles (boolean, default=TRUE)",
- _t("Whether to include the measure titles row or not.")
- ),
- ],
- compute: function (
- pivotFormulaId: Maybe,
- rowCount: Maybe = { value: 10000 },
- includeTotal: Maybe = { value: true },
- includeColumnHeaders: Maybe = { value: true },
- columnCount: Maybe = { value: Number.MAX_VALUE },
- includeMeasureTitles: Maybe = { value: true }
- ) {
- const _pivotFormulaId = toString(pivotFormulaId);
- const _rowCount = toNumber(rowCount, this.locale);
- if (_rowCount < 0) {
- return new EvaluationError(_t("The number of rows must be positive."));
- }
- const _columnCount = toNumber(columnCount, this.locale);
- if (_columnCount < 0) {
- return new EvaluationError(_t("The number of columns must be positive."));
- }
- const visibilityOptions: PivotVisibilityOptions = {
- displayColumnHeaders: toBoolean(includeColumnHeaders),
- displayTotals: toBoolean(includeTotal),
- displayMeasuresRow: toBoolean(includeMeasureTitles),
- };
-
- const pivotId = getPivotId(_pivotFormulaId, this.getters);
- const pivot = this.getters.getPivot(pivotId);
- const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
- addPivotDependencies(this, coreDefinition, coreDefinition.measures);
- pivot.init({ reload: pivot.needsReevaluation });
- const error = pivot.assertIsValid({ throwOnError: false });
- if (error) {
- return error;
- }
- const table = pivot.getCollapsedTableStructure();
- if (table.numberOfCells > PIVOT_MAX_NUMBER_OF_CELLS) {
- return new EvaluationError(getPivotTooBigErrorMessage(table.numberOfCells, this.locale));
- }
- const cells = table.getPivotCells(visibilityOptions);
-
- let headerRows = 0;
- if (visibilityOptions.displayColumnHeaders) {
- headerRows = table.columns.length - 1;
- }
- if (visibilityOptions.displayMeasuresRow) {
- headerRows++;
- }
- const pivotTitle = this.getters.getPivotName(pivotId);
- const tableHeight = Math.min(headerRows + _rowCount, cells[0].length);
- if (tableHeight === 0) {
- return [[{ value: pivotTitle }]];
- }
- const tableWidth = Math.min(1 + _columnCount, cells.length);
- const result: Matrix = [];
- for (const col of range(0, tableWidth)) {
- result[col] = [];
- for (const row of range(0, tableHeight)) {
- const pivotCell = cells[col][row];
- switch (pivotCell.type) {
- case "EMPTY":
- result[col].push({ value: "" });
- break;
- case "HEADER":
- const valueAndFormat = pivot.getPivotHeaderValueAndFormat(pivotCell.domain);
- result[col].push(addAlignFormatToPivotHeader(pivotCell.domain, valueAndFormat));
- break;
- case "MEASURE_HEADER":
- result[col].push(pivot.getPivotMeasureValue(pivotCell.measure, pivotCell.domain));
- break;
- case "VALUE":
- result[col].push(pivot.getPivotCellValueAndFormat(pivotCell.measure, pivotCell.domain));
- break;
- }
- }
- }
- if (visibilityOptions.displayColumnHeaders || visibilityOptions.displayMeasuresRow) {
- result[0][0] = { value: pivotTitle };
- }
- return result;
- },
-} satisfies AddFunctionDescription;
+} satisfies Functions;
//--------------------------------------------------------------------------
// OFFSET
@@ -1100,4 +877,4 @@ export const OFFSET = {
})
);
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_math.ts b/packages/o-spreadsheet-engine/src/functions/module_math.ts
similarity index 95%
rename from src/functions/module_math.ts
rename to packages/o-spreadsheet-engine/src/functions/module_math.ts
index c79d13cd4c..2a7d5cb59b 100644
--- a/src/functions/module_math.ts
+++ b/packages/o-spreadsheet-engine/src/functions/module_math.ts
@@ -1,16 +1,9 @@
+import { FunctionResultNumber } from "@odoo/o-spreadsheet-engine/types";
import { splitReference, toZone } from "../helpers";
-import { isSubtotalCell } from "../plugins/ui_feature/subtotal_evaluation";
+import { isSubtotalCell } from "../helpers/is_subtotal_cell";
+import { Arg, FunctionResultObject, Functions, isMatrix, Matrix, Maybe } from "../index";
import { _t } from "../translation";
-import {
- AddFunctionDescription,
- Arg,
- EvaluatedCell,
- FunctionResultNumber,
- FunctionResultObject,
- Matrix,
- Maybe,
- isMatrix,
-} from "../types";
+import { EvaluatedCell } from "../types";
import { DivisionByZeroError, EvaluationError } from "../types/errors";
import { arg } from "./arguments";
import { assertNotZero } from "./helper_assert";
@@ -47,7 +40,7 @@ export const ABS = {
return Math.abs(toNumber(value, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ACOS
@@ -70,7 +63,7 @@ export const ACOS = {
return Math.acos(_value);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ACOSH
@@ -93,7 +86,7 @@ export const ACOSH = {
return Math.acosh(_value);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ACOT
@@ -110,7 +103,7 @@ export const ACOT = {
return (sign * Math.PI) / 2 - Math.atan(_value);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ACOTH
@@ -135,7 +128,7 @@ export const ACOTH = {
return Math.log((_value + 1) / (_value - 1)) / 2;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ASIN
@@ -156,7 +149,7 @@ export const ASIN = {
return Math.asin(_value);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ASINH
@@ -170,7 +163,7 @@ export const ASINH = {
return Math.asinh(toNumber(value, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ATAN
@@ -182,7 +175,7 @@ export const ATAN = {
return Math.atan(toNumber(value, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ATAN2
@@ -214,7 +207,7 @@ export const ATAN2 = {
return Math.atan2(_y, _x);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ATANH
@@ -237,7 +230,7 @@ export const ATANH = {
return Math.atanh(_value);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// CEILING
@@ -269,7 +262,7 @@ export const CEILING = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// CEILING.MATH
@@ -322,7 +315,7 @@ export const CEILING_MATH = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// CEILING.PRECISE
@@ -351,7 +344,7 @@ export const CEILING_PRECISE = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COS
@@ -363,7 +356,7 @@ export const COS = {
return Math.cos(toNumber(angle, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COSH
@@ -375,7 +368,7 @@ export const COSH = {
return Math.cosh(toNumber(value, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COT
@@ -393,7 +386,7 @@ export const COT = {
return 1 / Math.tan(_angle);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COTH
@@ -411,7 +404,7 @@ export const COTH = {
return 1 / Math.tanh(_value);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUNTBLANK
@@ -447,7 +440,7 @@ export const COUNTBLANK = {
);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUNTIF
@@ -470,7 +463,7 @@ export const COUNTIF = {
return count;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUNTIFS
@@ -500,7 +493,7 @@ export const COUNTIFS = {
return count;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUNTUNIQUE
@@ -518,7 +511,7 @@ export const COUNTUNIQUE = {
compute: function (...args: Arg[]): number {
return countUnique(args);
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUNTUNIQUEIFS
@@ -560,7 +553,7 @@ export const COUNTUNIQUEIFS = {
);
return uniqueValues.size;
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// CSC
@@ -578,7 +571,7 @@ export const CSC = {
return 1 / Math.sin(_angle);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// CSCH
@@ -596,7 +589,7 @@ export const CSCH = {
return 1 / Math.sinh(_value);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DECIMAL
@@ -640,7 +633,7 @@ export const DECIMAL = {
return deci;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DEGREES
@@ -652,7 +645,7 @@ export const DEGREES = {
return (toNumber(angle, this.locale) * 180) / Math.PI;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// EXP
@@ -664,7 +657,7 @@ export const EXP = {
return Math.exp(toNumber(value, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// FLOOR
@@ -695,7 +688,7 @@ export const FLOOR = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// FLOOR.MATH
@@ -749,7 +742,7 @@ export const FLOOR_MATH = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// FLOOR.PRECISE
@@ -778,7 +771,7 @@ export const FLOOR_PRECISE = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISEVEN
@@ -792,7 +785,7 @@ export const ISEVEN = {
return Math.floor(Math.abs(_value)) & 1 ? false : true;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISO.CEILING
@@ -821,7 +814,7 @@ export const ISO_CEILING = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISODD
@@ -835,7 +828,7 @@ export const ISODD = {
return Math.floor(Math.abs(_value)) & 1 ? true : false;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// LN
@@ -851,7 +844,7 @@ export const LN = {
return Math.log(_value);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// LOG
@@ -880,7 +873,7 @@ export const LOG = {
return Math.log10(_value) / Math.log10(_base);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MOD
@@ -913,7 +906,7 @@ export const MOD = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MUNIT
@@ -934,7 +927,7 @@ export const MUNIT = {
return getUnitMatrix(_n);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ODD
@@ -953,7 +946,7 @@ export const ODD = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// PI
@@ -965,7 +958,7 @@ export const PI = {
return Math.PI;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// POWER
@@ -987,7 +980,7 @@ export const POWER = {
return { value: Math.pow(_base, _exponent), format: base?.format };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// PRODUCT
@@ -1032,7 +1025,7 @@ export const PRODUCT = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// RAND
@@ -1044,7 +1037,7 @@ export const RAND = {
return Math.random();
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// RANDARRAY
@@ -1111,7 +1104,7 @@ export const RANDARRAY = {
return result;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// RANDBETWEEN
@@ -1144,7 +1137,7 @@ export const RANDBETWEEN = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ROUND
@@ -1181,7 +1174,7 @@ export const ROUND = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ROUNDDOWN
@@ -1221,7 +1214,7 @@ export const ROUNDDOWN = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ROUNDUP
@@ -1258,7 +1251,7 @@ export const ROUNDUP = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SEC
@@ -1270,7 +1263,7 @@ export const SEC = {
return 1 / Math.cos(toNumber(angle, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SECH
@@ -1282,7 +1275,7 @@ export const SECH = {
return 1 / Math.cosh(toNumber(value, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SEQUENCE
@@ -1321,7 +1314,7 @@ export const SEQUENCE = {
});
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SIN
@@ -1333,7 +1326,7 @@ export const SIN = {
return Math.sin(toNumber(angle, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SINH
@@ -1345,7 +1338,7 @@ export const SINH = {
return Math.sinh(toNumber(value, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SQRT
@@ -1361,7 +1354,7 @@ export const SQRT = {
return { value: Math.sqrt(_value), format: value?.format };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SUBTOTAL
@@ -1453,7 +1446,7 @@ export const SUBTOTAL = {
return this[subtotalFunctionAggregateByCode[code]].apply(this, [[evaluatedCellToKeep]]);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SUM
@@ -1475,7 +1468,7 @@ export const SUM = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SUMIF
@@ -1513,7 +1506,7 @@ export const SUMIF = {
return sum;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SUMIFS
@@ -1542,7 +1535,7 @@ export const SUMIFS = {
return sum;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TAN
@@ -1554,7 +1547,7 @@ export const TAN = {
return Math.tan(toNumber(angle, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TANH
@@ -1566,7 +1559,7 @@ export const TANH = {
return Math.tanh(toNumber(value, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TRUNC
@@ -1599,7 +1592,7 @@ export const TRUNC = {
return { value: trunc(_value, _places), format: value?.format };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// INT
@@ -1611,4 +1604,4 @@ export const INT = {
return Math.floor(toNumber(value, this.locale));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_operators.ts b/packages/o-spreadsheet-engine/src/functions/module_operators.ts
similarity index 94%
rename from src/functions/module_operators.ts
rename to packages/o-spreadsheet-engine/src/functions/module_operators.ts
index 1edc722b6e..827a0d90fc 100644
--- a/src/functions/module_operators.ts
+++ b/packages/o-spreadsheet-engine/src/functions/module_operators.ts
@@ -1,10 +1,6 @@
+import { FunctionResultObject, Functions, Maybe } from "../index";
import { _t } from "../translation";
-import {
- AddFunctionDescription,
- FunctionResultNumber,
- FunctionResultObject,
- Maybe,
-} from "../types";
+import { FunctionResultNumber } from "../types";
import { DivisionByZeroError } from "../types/errors";
import { arg } from "./arguments";
import { isEvaluationError, toNumber, toString } from "./helpers";
@@ -28,7 +24,7 @@ export const ADD = {
format: value1?.format || value2?.format,
};
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// CONCAT
@@ -46,7 +42,7 @@ export const CONCAT = {
return toString(value1) + toString(value2);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// DIVIDE
@@ -67,7 +63,7 @@ export const DIVIDE = {
format: dividend?.format || divisor?.format,
};
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// EQ
@@ -108,7 +104,7 @@ export const EQ = {
}
return { value: _value1 === _value2 };
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// GT
@@ -157,7 +153,7 @@ export const GT = {
return v1 > v2;
});
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// GTE
@@ -179,7 +175,7 @@ export const GTE = {
return v1 >= v2;
});
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// LT
@@ -197,7 +193,7 @@ export const LT = {
}
return { value: !result.value };
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// LTE
@@ -218,7 +214,7 @@ export const LTE = {
}
return { value: !result.value };
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MINUS
@@ -238,7 +234,7 @@ export const MINUS = {
format: value1?.format || value2?.format,
};
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MULTIPLY
@@ -258,7 +254,7 @@ export const MULTIPLY = {
format: factor1?.format || factor2?.format,
};
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// NE
@@ -276,7 +272,7 @@ export const NE = {
}
return { value: !result.value };
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// POW
@@ -290,7 +286,7 @@ export const POW = {
compute: function (base: Maybe, exponent: Maybe) {
return POWER.compute.bind(this)(base, exponent);
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// UMINUS
@@ -309,7 +305,7 @@ export const UMINUS = {
format: value?.format,
};
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// UNARY_PERCENT
@@ -320,7 +316,7 @@ export const UNARY_PERCENT = {
compute: function (percentage: Maybe): number {
return toNumber(percentage, this.locale) / 100;
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// UPLUS
@@ -331,4 +327,4 @@ export const UPLUS = {
compute: function (value: Maybe = { value: null }): FunctionResultObject {
return value;
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_statistical.ts b/packages/o-spreadsheet-engine/src/functions/module_statistical.ts
similarity index 96%
rename from src/functions/module_statistical.ts
rename to packages/o-spreadsheet-engine/src/functions/module_statistical.ts
index a3f82d280f..050c5039f6 100644
--- a/src/functions/module_statistical.ts
+++ b/packages/o-spreadsheet-engine/src/functions/module_statistical.ts
@@ -1,15 +1,7 @@
import { percentile } from "../helpers/index";
+import { Arg, FunctionResultObject, Functions, isMatrix, Matrix, Maybe } from "../index";
import { _t } from "../translation";
-import {
- AddFunctionDescription,
- Arg,
- FunctionResultNumber,
- FunctionResultObject,
- Locale,
- Matrix,
- Maybe,
- isMatrix,
-} from "../types";
+import { FunctionResultNumber, Locale } from "../types";
import { DivisionByZeroError, EvaluationError, NotAvailableError } from "../types/errors";
import { arg } from "./arguments";
import { areSameDimensions, assert, assertNotZero } from "./helper_assert";
@@ -237,7 +229,7 @@ export const AVEDEV = {
return reduceNumbers(values, (acc, a) => acc + Math.abs(average - a), 0, this.locale) / count;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// AVERAGE
@@ -261,7 +253,7 @@ export const AVERAGE = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// AVERAGE.WEIGHTED
@@ -332,7 +324,7 @@ export const AVERAGE_WEIGHTED = {
}
return { value: sum / count, format: inferFormat(args[0]) };
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// AVERAGEA
@@ -371,7 +363,7 @@ export const AVERAGEA = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// AVERAGEIF
@@ -416,7 +408,7 @@ export const AVERAGEIF = {
return sum / count;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// AVERAGEIFS
@@ -456,7 +448,7 @@ export const AVERAGEIFS = {
return sum / count;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUNT
@@ -477,7 +469,7 @@ export const COUNT = {
return countNumbers(values, this.locale);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COUNTA
@@ -495,7 +487,7 @@ export const COUNTA = {
return countAny(values);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COVAR
@@ -516,7 +508,7 @@ export const COVAR = {
return covariance(dataY, dataX, false);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COVARIANCE.P
@@ -534,7 +526,7 @@ export const COVARIANCE_P = {
return covariance(dataY, dataX, false);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// COVARIANCE.S
@@ -552,12 +544,12 @@ export const COVARIANCE_S = {
return covariance(dataY, dataX, true);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// FORECAST
// -----------------------------------------------------------------------------
-export const FORECAST: AddFunctionDescription = {
+export const FORECAST: Functions = {
description: _t(
"Calculates the expected y-value for a specified x based on a linear regression of a dataset."
),
@@ -595,7 +587,7 @@ export const FORECAST: AddFunctionDescription = {
// -----------------------------------------------------------------------------
// GROWTH
// -----------------------------------------------------------------------------
-export const GROWTH: AddFunctionDescription = {
+export const GROWTH: Functions = {
description: _t("Fits points to exponential growth trend."),
args: [
arg(
@@ -643,7 +635,7 @@ export const GROWTH: AddFunctionDescription = {
// -----------------------------------------------------------------------------
// INTERCEPT
// -----------------------------------------------------------------------------
-export const INTERCEPT: AddFunctionDescription = {
+export const INTERCEPT: Functions = {
description: _t("Compute the intercept of the linear regression."),
args: [
arg(
@@ -710,12 +702,12 @@ export const LARGE = {
return result!;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// LINEST
// -----------------------------------------------------------------------------
-export const LINEST: AddFunctionDescription = {
+export const LINEST: Functions = {
description: _t(
"Given partial data about a linear trend, calculates various parameters about the ideal linear trend using the least-squares method."
),
@@ -763,7 +755,7 @@ export const LINEST: AddFunctionDescription = {
// -----------------------------------------------------------------------------
// LOGEST
// -----------------------------------------------------------------------------
-export const LOGEST: AddFunctionDescription = {
+export const LOGEST: Functions = {
description: _t(
"Given partial data about an exponential growth curve, calculates various parameters about the best fit ideal exponential growth curve."
),
@@ -815,7 +807,7 @@ export const LOGEST: AddFunctionDescription = {
// -----------------------------------------------------------------------------
// MATTHEWS
// -----------------------------------------------------------------------------
-export const MATTHEWS: AddFunctionDescription = {
+export const MATTHEWS: Functions = {
description: _t("Compute the Matthews correlation coefficient of a dataset."),
args: [
arg("data_x (range)", _t("The range representing the array or matrix of observed data.")),
@@ -878,7 +870,7 @@ export const MAX = {
return max(values, this.locale);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MAXA
@@ -907,7 +899,7 @@ export const MAXA = {
return { value: maxa === -Infinity ? 0 : maxa, format: inferFormat(args[0]) };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MAXIFS
@@ -946,7 +938,7 @@ export const MAXIFS = {
return result === -Infinity ? 0 : result;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MEDIAN
@@ -978,7 +970,7 @@ export const MEDIAN = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MIN
@@ -999,7 +991,7 @@ export const MIN = {
return min(values, this.locale);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MINA
@@ -1028,7 +1020,7 @@ export const MINA = {
return { value: mina === Infinity ? 0 : mina, format: inferFormat(args[0]) };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MINIFS
@@ -1067,7 +1059,7 @@ export const MINIFS = {
return result === Infinity ? 0 : result;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// PEARSON
@@ -1100,7 +1092,7 @@ function pearson(dataY: Matrix, dataX: Matrix)", _t("The value(s) on the x-axis to forecast.")),
@@ -1291,7 +1283,7 @@ export const QUARTILE = {
return QUARTILE_INC.compute.bind(this)(data, quartileNumber);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// QUARTILE.EXC
@@ -1315,7 +1307,7 @@ export const QUARTILE_EXC = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// QUARTILE.INC
@@ -1334,11 +1326,11 @@ export const QUARTILE_INC = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// RANK
// -----------------------------------------------------------------------------
-export const RANK: AddFunctionDescription = {
+export const RANK: Functions = {
description: _t("Returns the rank of a specified value in a dataset."),
args: [
arg("value (number)", _t("The value whose rank will be determined.")),
@@ -1385,7 +1377,7 @@ export const RANK: AddFunctionDescription = {
// -----------------------------------------------------------------------------
// RSQ
// -----------------------------------------------------------------------------
-export const RSQ: AddFunctionDescription = {
+export const RSQ: Functions = {
description: _t(
"Compute the square of r, the Pearson product-moment correlation coefficient of a dataset."
),
@@ -1415,7 +1407,7 @@ export const RSQ: AddFunctionDescription = {
// -----------------------------------------------------------------------------
// SLOPE
// -----------------------------------------------------------------------------
-export const SLOPE: AddFunctionDescription = {
+export const SLOPE: Functions = {
description: _t("Compute the slope of the linear regression."),
args: [
arg(
@@ -1482,12 +1474,12 @@ export const SMALL = {
return result!;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SPEARMAN
// -----------------------------------------------------------------------------
-export const SPEARMAN: AddFunctionDescription = {
+export const SPEARMAN: Functions = {
description: _t("Compute the Spearman rank correlation coefficient of a dataset."),
args: [
arg(
@@ -1539,7 +1531,7 @@ export const STDEV = {
return Math.sqrt(VAR.compute.bind(this)(...args));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// STDEV.P
@@ -1557,7 +1549,7 @@ export const STDEV_P = {
return Math.sqrt(VAR_P.compute.bind(this)(...args));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// STDEV.S
@@ -1575,7 +1567,7 @@ export const STDEV_S = {
return Math.sqrt(VAR_S.compute.bind(this)(...args));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// STDEVA
@@ -1593,7 +1585,7 @@ export const STDEVA = {
return Math.sqrt(VARA.compute.bind(this)(...args));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// STDEVP
@@ -1611,7 +1603,7 @@ export const STDEVP = {
return Math.sqrt(VARP.compute.bind(this)(...args));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// STDEVPA
@@ -1629,12 +1621,12 @@ export const STDEVPA = {
return Math.sqrt(VARPA.compute.bind(this)(...args));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// STEYX
// -----------------------------------------------------------------------------
-export const STEYX: AddFunctionDescription = {
+export const STEYX: Functions = {
description: _t(
"Calculates the standard error of the predicted y-value for each x in the regression of a dataset."
),
@@ -1662,7 +1654,7 @@ export const STEYX: AddFunctionDescription = {
// -----------------------------------------------------------------------------
// TREND
// -----------------------------------------------------------------------------
-export const TREND: AddFunctionDescription = {
+export const TREND: Functions = {
description: _t("Fits points to linear trend derived via least-squares."),
args: [
arg(
@@ -1721,7 +1713,7 @@ export const VAR = {
return variance(args, true, false, this.locale);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// VAR.P
@@ -1739,7 +1731,7 @@ export const VAR_P = {
return variance(args, false, false, this.locale);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// VAR.S
@@ -1757,7 +1749,7 @@ export const VAR_S = {
return variance(args, true, false, this.locale);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// VARA
@@ -1775,7 +1767,7 @@ export const VARA = {
return variance(args, true, true, this.locale);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// VARP
@@ -1793,7 +1785,7 @@ export const VARP = {
return variance(args, false, false, this.locale);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// VARPA
@@ -1811,4 +1803,4 @@ export const VARPA = {
return variance(args, false, true, this.locale);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/helpers/coordinates.ts b/packages/o-spreadsheet-engine/src/helpers/coordinates.ts
similarity index 97%
rename from src/helpers/coordinates.ts
rename to packages/o-spreadsheet-engine/src/helpers/coordinates.ts
index 6829912cfc..6069759e14 100644
--- a/src/helpers/coordinates.ts
+++ b/packages/o-spreadsheet-engine/src/helpers/coordinates.ts
@@ -2,7 +2,8 @@
// Coordinate
//------------------------------------------------------------------------------
-import { HeaderIndex, Position, RangePart } from "../types";
+import { HeaderIndex, Position } from "../index";
+import { RangePart } from "../types";
import { TokenizingChars } from "./misc";
/**
diff --git a/src/helpers/dates.ts b/packages/o-spreadsheet-engine/src/helpers/dates.ts
similarity index 100%
rename from src/helpers/dates.ts
rename to packages/o-spreadsheet-engine/src/helpers/dates.ts
diff --git a/src/helpers/format/format.ts b/packages/o-spreadsheet-engine/src/helpers/format/format.ts
similarity index 99%
rename from src/helpers/format/format.ts
rename to packages/o-spreadsheet-engine/src/helpers/format/format.ts
index e17c64f7fa..762c5b38f0 100644
--- a/src/helpers/format/format.ts
+++ b/packages/o-spreadsheet-engine/src/helpers/format/format.ts
@@ -1,16 +1,15 @@
import { toNumber } from "../../functions/helpers";
+import { FunctionResultObject, Maybe } from "../../index";
import { _t } from "../../translation";
import {
CellValue,
Currency,
+ EvaluationError,
Format,
FormattedValue,
- FunctionResultObject,
Locale,
LocaleFormat,
- Maybe,
} from "../../types";
-import { EvaluationError } from "../../types/errors";
import { DateTime, INITIAL_1900_DAY, isDateTime, numberToJsDate, parseDateTime } from "../dates";
import {
escapeRegExp,
diff --git a/src/helpers/format/format_parser.ts b/packages/o-spreadsheet-engine/src/helpers/format/format_parser.ts
similarity index 99%
rename from src/helpers/format/format_parser.ts
rename to packages/o-spreadsheet-engine/src/helpers/format/format_parser.ts
index 579fb4afbb..ea8aaa422a 100644
--- a/src/helpers/format/format_parser.ts
+++ b/packages/o-spreadsheet-engine/src/helpers/format/format_parser.ts
@@ -1,5 +1,5 @@
+import { isDefined } from "@odoo/o-spreadsheet-engine";
import { Format } from "../../types";
-import { isDefined } from "../misc";
import {
CharToken,
DatePartToken,
diff --git a/src/helpers/format/format_tokenizer.ts b/packages/o-spreadsheet-engine/src/helpers/format/format_tokenizer.ts
similarity index 100%
rename from src/helpers/format/format_tokenizer.ts
rename to packages/o-spreadsheet-engine/src/helpers/format/format_tokenizer.ts
diff --git a/packages/o-spreadsheet-engine/src/helpers/index.ts b/packages/o-spreadsheet-engine/src/helpers/index.ts
new file mode 100644
index 0000000000..d97d5e2f2a
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/helpers/index.ts
@@ -0,0 +1,9 @@
+export * from "./coordinates";
+export * from "./dates";
+export * from "./misc";
+export * from "./numbers";
+export * from "./references";
+export * from "./sort";
+export * from "./state_manager_helpers";
+export * from "./uuid";
+export * from "./zones";
diff --git a/packages/o-spreadsheet-engine/src/helpers/is_subtotal_cell.ts b/packages/o-spreadsheet-engine/src/helpers/is_subtotal_cell.ts
new file mode 100644
index 0000000000..d1604d2d20
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/helpers/is_subtotal_cell.ts
@@ -0,0 +1,10 @@
+import { Cell } from "../../../../src";
+
+export function isSubtotalCell(cell: Cell): boolean {
+ return (
+ cell.isFormula &&
+ cell.compiledFormula.tokens.some(
+ (t) => t.type === "SYMBOL" && t.value.toUpperCase() === "SUBTOTAL"
+ )
+ );
+}
diff --git a/src/helpers/locale.ts b/packages/o-spreadsheet-engine/src/helpers/locale.ts
similarity index 100%
rename from src/helpers/locale.ts
rename to packages/o-spreadsheet-engine/src/helpers/locale.ts
diff --git a/packages/o-spreadsheet-engine/src/helpers/misc.ts b/packages/o-spreadsheet-engine/src/helpers/misc.ts
new file mode 100644
index 0000000000..ac070506bd
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/helpers/misc.ts
@@ -0,0 +1,512 @@
+import { NEWLINE } from "../constants";
+import { DebouncedFunction, Lazy, UID } from "../types";
+
+/**
+ * Compares n objects.
+ */
+
+export function deepEquals(...o: any[]): boolean {
+ if (o.length <= 1) return true;
+ for (let index = 1; index < o.length; index++) {
+ if (!_deepEquals(o[0], o[index])) return false;
+ }
+ return true;
+}
+
+function _deepEquals(o1: any, o2: any): boolean {
+ if (o1 === o2) return true;
+ if ((o1 && !o2) || (o2 && !o1)) return false;
+ if (typeof o1 !== typeof o2) return false;
+ if (typeof o1 !== "object") return false;
+
+ // Objects can have different keys if the values are undefined
+ for (const key in o2) {
+ if (!(key in o1) && o2[key] !== undefined) {
+ return false;
+ }
+ }
+
+ for (const key in o1) {
+ if (typeof o1[key] !== typeof o2[key]) return false;
+ if (typeof o1[key] === "object") {
+ if (!_deepEquals(o1[key], o2[key])) return false;
+ } else {
+ if (o1[key] !== o2[key]) return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Compares two arrays.
+ * For performance reasons, this function is to be preferred
+ * to 'deepEquals' in the case we know that the inputs are arrays.
+ */
+export function deepEqualsArray(arr1: unknown[], arr2: unknown[]): boolean {
+ if (arr1.length !== arr2.length) {
+ return false;
+ }
+ for (let i = 0; i < arr1.length; i++) {
+ if (!deepEquals(arr1[i], arr2[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * Escapes a string to use as a literal string in a RegExp.
+ */
+export function escapeRegExp(str: string): string {
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+}
+
+/**
+ * Remove quotes from a quoted string.
+ */
+export function unquote(string: string, quoteChar: "'" | '"' = '"'): string {
+ if (string.startsWith(quoteChar)) {
+ string = string.slice(1);
+ }
+ if (string.endsWith(quoteChar)) {
+ string = string.slice(0, -1);
+ }
+ return string;
+}
+
+/**
+ * Sanitize the name of a sheet, by eventually removing quotes.
+ */
+export function getUnquotedSheetName(sheetName: string): string {
+ return unquote(sheetName, "'");
+}
+
+/**
+ * Add quotes around the sheet name or any symbol name if it contains at least one non alphanumeric character.
+ */
+export function getCanonicalSymbolName(symbolName: string): string {
+ if (symbolName.match(/\w/g)?.length !== symbolName.length) {
+ symbolName = `'${symbolName}'`;
+ }
+ return symbolName;
+}
+
+const specialWhiteSpaceSpecialCharacters = [
+ "\t",
+ "\f",
+ "\v",
+ String.fromCharCode(parseInt("00a0", 16)),
+ String.fromCharCode(parseInt("1680", 16)),
+ String.fromCharCode(parseInt("2000", 16)),
+ String.fromCharCode(parseInt("200a", 16)),
+ String.fromCharCode(parseInt("2028", 16)),
+ String.fromCharCode(parseInt("2029", 16)),
+ String.fromCharCode(parseInt("202f", 16)),
+ String.fromCharCode(parseInt("205f", 16)),
+ String.fromCharCode(parseInt("3000", 16)),
+ String.fromCharCode(parseInt("feff", 16)),
+];
+
+export const specialWhiteSpaceRegexp = new RegExp(
+ specialWhiteSpaceSpecialCharacters.join("|"),
+ "g"
+);
+const newLineRegexp = /(\r\n|\r)/g;
+
+export const whiteSpaceCharacters = specialWhiteSpaceSpecialCharacters.concat([" "]);
+
+/**
+ * Replace all different newlines characters by \n.
+ */
+export function replaceNewLines(text: string | undefined): string {
+ if (!text) return "";
+ return text.replace(newLineRegexp, NEWLINE);
+}
+
+/**
+ * Creates a version of the function that's memoized on the value of its first argument, if any.
+ */
+export function memoize(func: (...args: T) => U): (...args: T) => U {
+ const cache = new Map();
+ const funcName = func.name ? func.name + " (memoized)" : "memoized";
+ return {
+ [funcName](...args: T) {
+ if (!cache.has(args[0])) {
+ cache.set(args[0], func(...args));
+ }
+ return cache.get(args[0])!;
+ },
+ }[funcName];
+}
+
+export class TokenizingChars {
+ private text: string;
+ private currentIndex: number = 0;
+ current: string;
+
+ constructor(text: string) {
+ this.text = text;
+ this.current = text[0];
+ }
+
+ shift() {
+ const current = this.current;
+ const next = this.text[++this.currentIndex];
+ this.current = next;
+ return current;
+ }
+
+ advanceBy(length: number) {
+ this.currentIndex += length;
+ this.current = this.text[this.currentIndex];
+ }
+
+ isOver() {
+ return this.currentIndex >= this.text.length;
+ }
+
+ remaining() {
+ return this.text.substring(this.currentIndex);
+ }
+
+ currentStartsWith(str: string) {
+ if (this.current !== str[0]) {
+ return false;
+ }
+ for (let j = 1; j < str.length; j++) {
+ if (this.text[this.currentIndex + j] !== str[j]) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+const O_SPREADSHEET_LINK_PREFIX = "o-spreadsheet://";
+
+/**
+ * This helper function can be used as a type guard when filtering arrays.
+ * const foo: number[] = [1, 2, undefined, 4].filter(isDefined)
+ */
+export function isDefined(argument: T | undefined): argument is T {
+ return argument !== undefined;
+}
+export function isSheetUrl(url: string) {
+ return url.startsWith(O_SPREADSHEET_LINK_PREFIX);
+}
+
+export function buildSheetLink(sheetId: UID) {
+ return `${O_SPREADSHEET_LINK_PREFIX}${sheetId}`;
+}
+
+/**
+ * Parse a sheet link and return the sheet id
+ */
+export function parseSheetUrl(sheetLink: string) {
+ if (sheetLink.startsWith(O_SPREADSHEET_LINK_PREFIX)) {
+ return sheetLink.slice(O_SPREADSHEET_LINK_PREFIX.length);
+ }
+ throw new Error(`${sheetLink} is not a valid sheet link`);
+}
+
+export function isNotNull(argument: T | null): argument is T {
+ return argument !== null;
+}
+
+/**
+ * Check if all the values of an object, and all the values of the objects inside of it, are undefined.
+ */
+export function isObjectEmptyRecursive(argument: T | undefined): boolean {
+ if (argument === undefined) return true;
+ return Object.values(argument).every((value) =>
+ typeof value === "object" ? isObjectEmptyRecursive(value) : !value
+ );
+}
+
+/**
+ * Returns a function, that, as long as it continues to be invoked, will not
+ * be triggered. The function will be called after it stops being called for
+ * N milliseconds. If `immediate` is passed, trigger the function on the
+ * leading edge, instead of the trailing.
+ *
+ * Also decorate the argument function with two methods: stopDebounce and isDebouncePending.
+ *
+ * Inspired by https://davidwalsh.name/javascript-debounce-function
+ */
+export function debounce void>(
+ func: T,
+ wait: number,
+ immediate?: boolean
+): DebouncedFunction {
+ let timeout: any | undefined = undefined;
+ const debounced = function (this: any): void {
+ const context = this;
+ const args = Array.from(arguments);
+ function later() {
+ timeout = undefined;
+ if (!immediate) {
+ func.apply(context, args);
+ }
+ }
+ const callNow = immediate && !timeout;
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ if (callNow) {
+ func.apply(context, args);
+ }
+ };
+ debounced.isDebouncePending = () => timeout !== undefined;
+ debounced.stopDebounce = () => {
+ clearTimeout(timeout);
+ };
+ return debounced as DebouncedFunction;
+}
+
+/**
+ * Creates a batched version of a callback so that all calls to it in the same
+ * microtick will only call the original callback once.
+ *
+ * @param callback the callback to batch
+ * @returns a batched version of the original callback
+ *
+ * Copied from odoo/owl repo.
+ */
+export function batched(callback: () => void): () => void {
+ let scheduled = false;
+ return async (...args) => {
+ if (!scheduled) {
+ scheduled = true;
+ await Promise.resolve();
+ scheduled = false;
+ callback(...args);
+ }
+ };
+}
+
+/*
+ * Concatenate an array of strings.
+ */
+export function concat(chars: string[]): string {
+ // ~40% faster than chars.join("")
+ let output = "";
+ for (let i = 0, len = chars.length; i < len; i++) {
+ output += chars[i];
+ }
+ return output;
+}
+
+/**
+ * Lazy value computed by the provided function.
+ */
+export function lazy(fn: (() => T) | T): Lazy {
+ let isMemoized = false;
+ let memo: T | undefined;
+ const lazyValue = () => {
+ if (!isMemoized) {
+ memo = fn instanceof Function ? fn() : fn;
+ isMemoized = true;
+ }
+ return memo!;
+ };
+ lazyValue.map = (callback) => lazy(() => callback(lazyValue()));
+ return lazyValue as Lazy;
+}
+
+/**
+ * Find the next defined value after the given index in an array of strings. If there is no defined value
+ * after the index, return the closest defined value before the index. Return an empty string if no
+ * defined value was found.
+ *
+ */
+export function findNextDefinedValue(arr: string[], index: number): string {
+ let value = arr.slice(index).find((val) => val);
+ if (!value) {
+ value = arr
+ .slice(0, index)
+ .reverse()
+ .find((val) => val);
+ }
+ return value || "";
+}
+
+/**
+ * Check if the given array contains all the values of the other array.
+ * It makes the assumption that both array do not contain duplicates.
+ */
+export function includesAll(arr: T[], values: T[]): boolean {
+ if (arr.length < values.length) {
+ return false;
+ }
+
+ const set = new Set(arr);
+ return values.every((value) => set.has(value));
+}
+
+/**
+ * Return an object with all the keys in the object that have a falsy value removed.
+ */
+export function removeFalsyAttributes(obj: T): T {
+ if (!obj) return obj;
+ const cleanObject = { ...obj };
+ Object.keys(cleanObject).forEach((key) => !cleanObject[key] && delete cleanObject[key]);
+ return cleanObject;
+}
+
+/**
+ * Determine if the numbers are consecutive.
+ */
+export function isConsecutive(iterable: Iterable): boolean {
+ const array = Array.from(iterable).sort((a, b) => a - b); // sort numerically rather than lexicographically
+ for (let i = 1; i < array.length; i++) {
+ if (array[i] - array[i - 1] !== 1) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * Removes the specified indexes from the array.
+ * Sparse (empty) elements are transformed to undefined (unless their index is explicitly removed).
+ */
+export function removeIndexesFromArray(array: readonly T[], indexes: number[]): T[] {
+ const toRemove = new Set(indexes);
+ const newArray: T[] = [];
+ for (let i = 0; i < array.length; i++) {
+ if (!toRemove.has(i)) {
+ newArray.push(array[i]);
+ }
+ }
+ return newArray;
+}
+
+export function insertItemsAtIndex(array: readonly T[], items: T[], index: number): T[] {
+ const newArray = [...array];
+ newArray.splice(index, 0, ...items);
+ return newArray;
+}
+
+export function replaceItemAtIndex(array: readonly T[], newItem: T, index: number): T[] {
+ const newArray = [...array];
+ newArray[index] = newItem;
+ return newArray;
+}
+
+export function trimContent(content: string): string {
+ const contentLines = content.split("\n");
+ return contentLines.map((line) => line.replace(/\s+/g, " ").trim()).join("\n");
+}
+
+export function isNumberBetween(value: number, min: number, max: number): boolean {
+ if (min > max) {
+ return isNumberBetween(value, max, min);
+ }
+ return value >= min && value <= max;
+}
+
+/**
+ * Get a Regex for the find & replace that matches the given search string and options.
+ */
+export function getSearchRegex(searchStr: string, searchOptions: SearchOptions): RegExp {
+ let searchValue = engineEscapeRegExp(searchStr);
+ const flags = !searchOptions.matchCase ? "i" : "";
+ if (searchOptions.exactMatch) {
+ searchValue = `^${searchValue}$`;
+ }
+ return RegExp(searchValue, flags);
+}
+
+/**
+ * Alternative to Math.max that works with large arrays.
+ * Typically useful for arrays bigger than 100k elements.
+ */
+export function largeMax(array: number[]) {
+ let len = array.length;
+
+ if (len < 100_000) return Math.max(...array);
+
+ let max: number = -Infinity;
+ while (len--) {
+ max = array[len] > max ? array[len] : max;
+ }
+ return max;
+}
+
+/**
+ * Alternative to Math.min that works with large arrays.
+ * Typically useful for arrays bigger than 100k elements.
+ */
+export function largeMin(array: number[]) {
+ let len = array.length;
+
+ if (len < 100_000) return Math.min(...array);
+
+ let min: number = +Infinity;
+ while (len--) {
+ min = array[len] < min ? array[len] : min;
+ }
+ return min;
+}
+
+/**
+ * Remove duplicates from an array.
+ *
+ * @param array The array to remove duplicates from.
+ * @param cb A callback to get an element value.
+ */
+export function removeDuplicates(array: T[], cb: (a: T) => any = (a) => a): T[] {
+ const set = new Set();
+ return array.filter((item) => {
+ const key = cb(item);
+ if (set.has(key)) {
+ return false;
+ }
+ set.add(key);
+ return true;
+ });
+}
+
+/**
+ * Similar to transposing and array, but with POJOs instead of arrays. Useful, for example, when manipulating
+ * a POJO grid[col][row] and you want to transpose it to grid[row][col].
+ *
+ * The resulting object is created such as result[key1][key2] = pojo[key2][key1]
+ */
+export function transpose2dPOJO(
+ pojo: Record>
+): Record> {
+ const result: Record> = {};
+ for (const key in pojo) {
+ for (const subKey in pojo[key]) {
+ if (!result[subKey]) {
+ result[subKey] = {};
+ }
+ result[subKey][key] = pojo[key][subKey];
+ }
+ }
+ return result;
+}
+
+export function getUniqueText(
+ text: string,
+ texts: string[],
+ options: {
+ compute?: (text: string, increment: number) => string;
+ start?: number;
+ computeFirstOne?: boolean;
+ } = {}
+): string {
+ const compute = options.compute ?? ((text, i) => `${text} (${i})`);
+ const computeFirstOne = options.computeFirstOne ?? false;
+ let i = options.start ?? 1;
+ let newText = computeFirstOne ? compute(text, i) : text;
+ while (texts.includes(newText)) {
+ newText = compute(text, i++);
+ }
+ return newText;
+}
+
+export function isFormula(content: string): boolean {
+ return content.startsWith("=") || content.startsWith("+");
+}
diff --git a/packages/o-spreadsheet-engine/src/helpers/numbers.ts b/packages/o-spreadsheet-engine/src/helpers/numbers.ts
new file mode 100644
index 0000000000..053bd29c00
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/helpers/numbers.ts
@@ -0,0 +1,101 @@
+import { Locale } from "../types/locale";
+import { escapeRegExp, memoize } from "./misc";
+
+/**
+ * This function returns a regexp that is supposed to be as close as possible as the numberRegexp,
+ * but its purpose is to be used by the tokenizer.
+ *
+ * - it tolerates extra characters at the end. This is useful because the tokenizer
+ * only needs to find the number at the start of a string
+ * - it does not support % symbol, in formulas % is an operator
+ */
+export const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(
+ decimalSeparator: string
+) {
+ decimalSeparator = escapeRegExp(decimalSeparator);
+ return new RegExp(
+ `(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e(\\+|-)?\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`
+ );
+});
+
+const getNumberRegex = memoize(function getNumberRegex(locale: Locale) {
+ const decimalSeparator = escapeRegExp(locale.decimalSeparator);
+ const thousandsSeparator = escapeRegExp(locale.thousandsSeparator || "");
+
+ const pIntegerAndDecimals = `(?:\\d+(?:${thousandsSeparator}\\d{3,})*(?:${decimalSeparator}\\d*)?)`;
+ const pOnlyDecimals = `(?:${decimalSeparator}\\d+)`;
+ const pScientificFormat = "(?:e(?:\\+|-)?\\d+)?";
+ const pPercentFormat = "(?:\\s*%)?";
+ const pNumber =
+ "(?:\\s*" +
+ pIntegerAndDecimals +
+ "|" +
+ pOnlyDecimals +
+ ")" +
+ pScientificFormat +
+ pPercentFormat;
+ const pMinus = "(?:\\s*-)?";
+ const pCurrencyFormat = "(?:\\s*[\\$€])?";
+
+ const p1 = pMinus + pCurrencyFormat + pNumber;
+ const p2 = pMinus + pNumber + pCurrencyFormat;
+ const p3 = pCurrencyFormat + pMinus + pNumber;
+
+ const pNumberExp = "^(?:(?:" + [p1, p2, p3].join(")|(?:") + "))$";
+
+ return new RegExp(pNumberExp, "i");
+});
+
+/**
+ * Return true if the argument is a "number string".
+ *
+ * Note that "" (empty string) does not count as a number string
+ */
+export function isNumber(value: string | undefined, locale: Locale): boolean {
+ if (!value) return false;
+ return getNumberRegex(locale).test(value.trim());
+}
+
+const getInvaluableSymbolsRegexp = memoize(function getInvaluableSymbolsRegexp(locale: Locale) {
+ return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator || "")}]`, "g");
+});
+/**
+ * Convert a string into a number. It assumes that the string actually represents
+ * a number (as determined by the isNumber function)
+ *
+ * Note that it accepts "" (empty string), even though it does not count as a
+ * number from the point of view of the isNumber function.
+ */
+export function parseNumber(str: string, locale: Locale): number {
+ str = str.replace(getInvaluableSymbolsRegexp(locale), "");
+
+ if (locale.decimalSeparator !== ".") {
+ str = str.replace(locale.decimalSeparator, ".");
+ }
+ let n = Number(str);
+ if (isNaN(n) && str.includes("%")) {
+ n = Number(str.split("%")[0]);
+ if (!isNaN(n)) {
+ return n / 100;
+ }
+ }
+ return n;
+}
+
+export function percentile(values: number[], percent: number, isInclusive: boolean) {
+ const sortedValues = [...values].sort((a, b) => a - b);
+
+ let percentIndex = (sortedValues.length + (isInclusive ? -1 : 1)) * percent;
+ if (!isInclusive) {
+ percentIndex--;
+ }
+ if (Number.isInteger(percentIndex)) {
+ return sortedValues[percentIndex];
+ }
+ const indexSup = Math.ceil(percentIndex);
+ const indexLow = Math.floor(percentIndex);
+ return (
+ sortedValues[indexSup] * (percentIndex - indexLow) +
+ sortedValues[indexLow] * (indexSup - percentIndex)
+ );
+}
diff --git a/src/helpers/recompute_zones.ts b/packages/o-spreadsheet-engine/src/helpers/recompute_zones.ts
similarity index 99%
rename from src/helpers/recompute_zones.ts
rename to packages/o-spreadsheet-engine/src/helpers/recompute_zones.ts
index 1760a2370e..5c2151f62b 100644
--- a/src/helpers/recompute_zones.ts
+++ b/packages/o-spreadsheet-engine/src/helpers/recompute_zones.ts
@@ -1,5 +1,5 @@
import { deepEqualsArray } from "../helpers/misc";
-import { UnboundedZone, Zone } from "../types";
+import { UnboundedZone, Zone } from "../index";
/**
* ####################################################
diff --git a/packages/o-spreadsheet-engine/src/helpers/references.ts b/packages/o-spreadsheet-engine/src/helpers/references.ts
new file mode 100644
index 0000000000..60e1c83c59
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/helpers/references.ts
@@ -0,0 +1,53 @@
+import { getCanonicalSymbolName, getUnquotedSheetName } from "./misc";
+
+export const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
+const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
+const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
+const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
+const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
+const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
+const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
+const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
+
+export const rangeReference = new RegExp(
+ /^\s*('.+'!|[^']+!)?/.source +
+ "(" +
+ [cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
+ ")" +
+ /$/.source,
+ "i"
+);
+
+export function isColReference(xc: string): boolean {
+ return colReference.test(xc);
+}
+
+export function isRowReference(xc: string): boolean {
+ return rowReference.test(xc);
+}
+
+export function isColHeader(str: string): boolean {
+ return colHeader.test(str);
+}
+
+export function isRowHeader(str: string): boolean {
+ return rowHeader.test(str);
+}
+
+export function isSingleCellReference(xc: string): boolean {
+ return singleCellReference.test(xc);
+}
+
+export function splitReference(ref: string): { sheetName?: string; xc: string } {
+ if (!ref.includes("!")) {
+ return { xc: ref };
+ }
+ const parts = ref.split("!");
+ const xc = parts.pop()!;
+ const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
+ return { sheetName, xc };
+}
+
+export function getFullReference(sheetName: string | undefined, xc: string): string {
+ return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
+}
diff --git a/packages/o-spreadsheet-engine/src/helpers/sort.ts b/packages/o-spreadsheet-engine/src/helpers/sort.ts
new file mode 100644
index 0000000000..f4f3ac9682
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/helpers/sort.ts
@@ -0,0 +1,52 @@
+import { CellValue, CellValueType, EvaluatedCell, SortDirection } from "../types";
+
+type CellWithIndex = { index: number; type: CellValueType; value: any };
+const SORT_TYPES: CellValueType[] = [
+ CellValueType.number,
+ CellValueType.error,
+ CellValueType.text,
+ CellValueType.boolean,
+];
+
+export function cellsSortingCriterion(sortingOrder: string) {
+ const inverse = sortingOrder === "asc" ? 1 : -1;
+ return (
+ left: { type: CellValueType; value: CellValue },
+ right: { type: CellValueType; value: CellValue }
+ ) => {
+ if (left.type === CellValueType.empty) {
+ return right.type === CellValueType.empty ? 0 : 1;
+ } else if (right.type === CellValueType.empty) {
+ return -1;
+ }
+ let typeOrder = SORT_TYPES.indexOf(left.type) - SORT_TYPES.indexOf(right.type);
+ if (typeOrder === 0) {
+ if (left.type === CellValueType.text || left.type === CellValueType.error) {
+ typeOrder = (left.value as string).localeCompare(right.value as string);
+ } else {
+ typeOrder = (left.value as number) - (right.value as number);
+ }
+ }
+ return inverse * typeOrder;
+ };
+}
+
+export function sort(
+ cells: EvaluatedCell[],
+ sortDirection: SortDirection,
+ emptyCellAsZero: boolean
+): CellWithIndex[] {
+ const cellsWithIndex: CellWithIndex[] = cells.map((cell, index) => ({
+ index,
+ type: cell.type,
+ value: cell.value,
+ }));
+
+ const cellsToSort = emptyCellAsZero
+ ? cellsWithIndex.map((cell) =>
+ cell.type === CellValueType.empty ? { ...cell, type: CellValueType.number, value: 0 } : cell
+ )
+ : cellsWithIndex;
+
+ return cellsToSort.sort(cellsSortingCriterion(sortDirection));
+}
diff --git a/src/helpers/state_manager_helpers.ts b/packages/o-spreadsheet-engine/src/helpers/state_manager_helpers.ts
similarity index 100%
rename from src/helpers/state_manager_helpers.ts
rename to packages/o-spreadsheet-engine/src/helpers/state_manager_helpers.ts
diff --git a/packages/o-spreadsheet-engine/src/helpers/uuid.ts b/packages/o-spreadsheet-engine/src/helpers/uuid.ts
new file mode 100644
index 0000000000..85b6cb9fb9
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/helpers/uuid.ts
@@ -0,0 +1,50 @@
+/*
+ * https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
+ * */
+
+export class UuidGenerator {
+ /**
+ * Generates a custom UUID using a simple 36^12 method (8-character alphanumeric string with lowercase letters)
+ * This has a higher chance of collision than a UUIDv4, but not only faster to generate than an UUIDV4,
+ * it also has a smaller size, which is preferable to alleviate the overall data size.
+ *
+ * This method is preferable when generating uuids for the core data (sheetId, figureId, etc)
+ * as they will appear several times in the revisions and local history.
+ *
+ */
+ smallUuid(): string {
+ if (window.crypto) {
+ return "10000000-1000".replace(/[01]/g, (c) => {
+ const n = Number(c);
+ return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
+ });
+ } else {
+ // mainly for jest and other browsers that do not have the crypto functionality
+ return "xxxxxxxx-xxxx".replace(/[xy]/g, function (c) {
+ const r = (Math.random() * 16) | 0,
+ v = c === "x" ? r : (r & 0x3) | 0x8;
+ return v.toString(16);
+ });
+ }
+ }
+
+ /**
+ * Generates an UUIDV4, has astronomically low chance of collision, but is larger in size than the smallUuid.
+ * This method should be used when you need to avoid collisions at all costs, like the id of a revision.
+ */
+ uuidv4(): string {
+ if (window.crypto) {
+ return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => {
+ const n = Number(c);
+ return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
+ });
+ } else {
+ // mainly for jest and other browsers that do not have the crypto functionality
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
+ const r = (Math.random() * 16) | 0,
+ v = c === "x" ? r : (r & 0x3) | 0x8;
+ return v.toString(16);
+ });
+ }
+ }
+}
diff --git a/src/helpers/zones.ts b/packages/o-spreadsheet-engine/src/helpers/zones.ts
similarity index 100%
rename from src/helpers/zones.ts
rename to packages/o-spreadsheet-engine/src/helpers/zones.ts
diff --git a/packages/o-spreadsheet-engine/src/index.ts b/packages/o-spreadsheet-engine/src/index.ts
new file mode 100644
index 0000000000..629854c360
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/index.ts
@@ -0,0 +1,117 @@
+export { FunctionCodeBuilder, Scope, type FunctionCode } from "./formulas/code_builder";
+export {
+ OPERATOR_MAP,
+ UNARY_OPERATOR_MAP,
+ compile,
+ compileTokens,
+ functionCache,
+ setArgTargetingImplementation,
+ setFunctionRegistryProvider,
+} from "./formulas/compiler";
+export { getFunctionsFromTokens, isExportableToExcel } from "./formulas/isExportableToExcel";
+export {
+ OP_PRIORITY,
+ convertAstNodes,
+ iterateAstNodes,
+ mapAst,
+ parse,
+ parseTokens,
+} from "./formulas/parser";
+export type {
+ AST,
+ ASTFuncall,
+ ASTOperation,
+ ASTString,
+ ASTSymbol,
+ ASTUnaryOperation,
+} from "./formulas/parser";
+export { rangeTokenize } from "./formulas/range_tokenizer";
+export { POSTFIX_UNARY_OPERATORS, tokenize } from "./formulas/tokenizer";
+export type { Token } from "./formulas/tokenizer";
+export { FunctionRegistry } from "./functions/function_registry";
+export {
+ Category,
+ categories,
+ functionRegistry,
+ handleError,
+ implementationErrorMessage,
+ type,
+} from "./functions/functionRegistry";
+export * from "./helpers";
+export { BasePlugin } from "./plugins/base_plugin";
+export { Registry } from "./registry";
+export { StateObserver, type StateObserverChange } from "./state_observer";
+export * from "./translation";
+export * from "./types/base";
+export * from "./types/errors";
+export {
+ ArgDefinition,
+ ArgProposal,
+ ArgType,
+ ComputeFunction,
+ EvalContext,
+ FunctionDescription,
+ Functions,
+ LookupCaches,
+} from "./types/functions";
+export * from "./types/history";
+export {
+ AdaptSheetName,
+ AdjacentEdge,
+ Alias,
+ Align,
+ AnchorZone,
+ ApplyRangeChange,
+ ApplyRangeChangeResult,
+ Arg,
+ Border,
+ BorderData,
+ BorderDescr,
+ BorderPosition,
+ BorderStyle,
+ CellPosition,
+ ChangeType,
+ ClipboardCell,
+ Color,
+ CompiledFormula,
+ ConsecutiveIndexes,
+ DIRECTION,
+ DataBarFill,
+ EnsureRange,
+ FilterId,
+ FormulaToExecute,
+ FunctionResultObject,
+ GetSymbolValue,
+ HeaderDimensions,
+ HeaderGroup,
+ HeaderIndex,
+ Highlight,
+ Matrix,
+ Maybe,
+ MenuMouseEvent,
+ Merge,
+ PaneDivision,
+ Pixel,
+ PixelPosition,
+ Position,
+ RangeAdapter,
+ RangeCompiledFormula,
+ RangeProvider,
+ ReferenceDenormalizer,
+ Row,
+ Selection,
+ Sheet,
+ Style,
+ TableId,
+ UID,
+ UnboundedZone,
+ UpdateCellData,
+ VerticalAlign,
+ Wrapping,
+ Zone,
+ ZoneDimension,
+ borderStyles,
+ isMatrix,
+} from "./types/isMatrix";
+export * from "./types/locale";
+export * from "./types/validator";
diff --git a/src/plugins/base_plugin.ts b/packages/o-spreadsheet-engine/src/plugins/base_plugin.ts
similarity index 52%
rename from src/plugins/base_plugin.ts
rename to packages/o-spreadsheet-engine/src/plugins/base_plugin.ts
index 6756fdbe62..cadd5c10fb 100644
--- a/src/plugins/base_plugin.ts
+++ b/packages/o-spreadsheet-engine/src/plugins/base_plugin.ts
@@ -1,12 +1,6 @@
-import { StateObserver } from "../state_observer";
-import {
- CommandHandler,
- CommandResult,
- ExcelWorkbookData,
- Validation,
- WorkbookHistory,
-} from "../types/index";
-import { Validator } from "../types/validator";
+import { StateObserver, type StateObserverChange } from "../state_observer";
+import type { WorkbookHistory } from "../types/history";
+import type { Validation, Validator } from "../types/validator";
/**
* BasePlugin
@@ -14,18 +8,26 @@ import { Validator } from "../types/validator";
* Since the spreadsheet internal state is quite complex, it is split into
* multiple parts, each managing a specific concern.
*
- * This file introduce the BasePlugin, which is the common class that defines
+ * This file introduces the BasePlugin, which is the common class that defines
* how each of these model sub parts should interact with each other.
- * There are two kind of plugins: core plugins handling persistent data
+ * There are two kinds of plugins: core plugins handling persistent data
* and UI plugins handling transient data.
*/
-
-export class BasePlugin implements CommandHandler, Validator {
+export class BasePlugin<
+ State = unknown,
+ Command = unknown,
+ Result = unknown,
+ Change extends StateObserverChange = StateObserverChange,
+ ExcelData = unknown
+> implements Validator
+{
static getters: readonly string[] = [];
protected history: WorkbookHistory;
+ protected readonly successResult: Result;
- constructor(stateObserver: StateObserver) {
+ constructor(stateObserver: StateObserver, successResult: Result) {
+ this.successResult = successResult;
this.history = Object.assign(Object.create(stateObserver), {
update: stateObserver.addChange.bind(stateObserver, this),
selectCell: () => {},
@@ -34,10 +36,10 @@ export class BasePlugin implements CommandHandler, Vali
/**
* Export for excel should be available for all plugins, even for the UI.
- * In some case, we need to export evaluated value, which is available from
+ * In some cases, we need to export evaluated value, which is available from
* UI plugin only.
*/
- exportForExcel(data: ExcelWorkbookData) {}
+ exportForExcel(_data: ExcelData) {}
// ---------------------------------------------------------------------------
// Command handling
@@ -45,42 +47,52 @@ export class BasePlugin implements CommandHandler, Vali
/**
* Before a command is accepted, the model will ask each plugin if the command
- * is allowed. If all of then return true, then we can proceed. Otherwise,
+ * is allowed. If all of them return true, then we can proceed. Otherwise,
* the command is cancelled.
*
* There should not be any side effects in this method.
*/
- allowDispatch(command: C): CommandResult | CommandResult[] {
- return CommandResult.Success;
+ allowDispatch(_command: Command): Result | Result[] {
+ return this.successResult;
}
/**
- * This method is useful when a plugin need to perform some action before a
+ * This method is useful when a plugin needs to perform some action before a
* command is handled in another plugin. This should only be used if it is not
* possible to do the work in the handle method.
*/
- beforeHandle(command: C): void {}
+ beforeHandle(_command: Command): void {}
/**
* This is the standard place to handle any command. Most of the plugin
* command handling work should take place here.
*/
- handle(command: C): void {}
+ handle(_command: Command): void {}
/**
* Sometimes, it is useful to perform some work after a command (and all its
- * subcommands) has been completely handled. For example, when we paste
+ * subcommands) has been completely handled. For example, when we paste
* multiple cells, we only want to reevaluate the cell values once at the end.
*/
finalize(): void {}
/**
* Combine multiple validation functions into a single function
- * returning the list of result of every validation.
+ * returning the list of results of every validation.
*/
- batchValidations(...validations: Validation[]): Validation {
- return (toValidate: T) =>
- validations.map((validation) => validation.call(this, toValidate)).flat();
+ batchValidations(...validations: Validation[]): Validation {
+ return (toValidate: T) => {
+ const outcomes: Result[] = [];
+ for (const validation of validations) {
+ const result = validation.call(this, toValidate);
+ if (Array.isArray(result)) {
+ outcomes.push(...result);
+ } else {
+ outcomes.push(result);
+ }
+ }
+ return outcomes;
+ };
}
/**
@@ -88,26 +100,26 @@ export class BasePlugin implements CommandHandler, Vali
* the other. As soon as one validation fails, it stops and the cancelled reason
* is returned.
*/
- chainValidations(...validations: Validation[]): Validation {
+ chainValidations(...validations: Validation[]): Validation {
return (toValidate: T) => {
for (const validation of validations) {
- let results: CommandResult | CommandResult[] = validation.call(this, toValidate);
+ let results = validation.call(this, toValidate);
if (!Array.isArray(results)) {
results = [results];
}
- const cancelledReasons = results.filter((result) => result !== CommandResult.Success);
+ const cancelledReasons = results.filter((result) => result !== this.successResult);
if (cancelledReasons.length) {
return cancelledReasons;
}
}
- return CommandResult.Success;
+ return this.successResult;
};
}
checkValidations(
command: T,
- ...validations: Validation>[]
- ): CommandResult | CommandResult[] {
+ ...validations: Validation, Result>[]
+ ): Result | Result[] {
return this.batchValidations(...validations)(command);
}
}
diff --git a/packages/o-spreadsheet-engine/src/registry.ts b/packages/o-spreadsheet-engine/src/registry.ts
new file mode 100644
index 0000000000..76e952a57b
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/registry.ts
@@ -0,0 +1,39 @@
+export class Registry {
+ content: Record = {};
+
+ add(key: string, value: T): this {
+ if (key in this.content) {
+ throw new Error(`${key} is already present in this registry!`);
+ }
+ return this.replace(key, value);
+ }
+
+ replace(key: string, value: T): this {
+ this.content[key] = value;
+ return this;
+ }
+
+ get(key: string): T {
+ const content = this.content[key];
+ if (!content && !(key in this.content)) {
+ throw new Error(`Cannot find ${key} in this registry!`);
+ }
+ return content;
+ }
+
+ contains(key: string): boolean {
+ return key in this.content;
+ }
+
+ getAll(): T[] {
+ return Object.values(this.content);
+ }
+
+ getKeys(): string[] {
+ return Object.keys(this.content);
+ }
+
+ remove(key: string): void {
+ delete this.content[key];
+ }
+}
diff --git a/src/state_observer.ts b/packages/o-spreadsheet-engine/src/state_observer.ts
similarity index 70%
rename from src/state_observer.ts
rename to packages/o-spreadsheet-engine/src/state_observer.ts
index 05217f9494..b290f03067 100644
--- a/src/state_observer.ts
+++ b/packages/o-spreadsheet-engine/src/state_observer.ts
@@ -1,24 +1,32 @@
import { createEmptyStructure } from "./helpers/state_manager_helpers";
-import { CoreCommand, HistoryChange } from "./types";
type HistoryPath = [any, ...(number | string)[]];
-export class StateObserver {
- private changes: HistoryChange[] | undefined;
- private commands: CoreCommand[] = [];
+export interface StateObserverChange {
+ key: PropertyKey;
+ target: unknown;
+ before: unknown;
+}
+
+export class StateObserver<
+ Command = unknown,
+ Change extends StateObserverChange = StateObserverChange
+> {
+ private changes: Change[] | undefined;
+ private commands: Command[] = [];
/**
* Record the changes which could happen in the given callback, save them in a
* new revision with the given id and userId.
*/
- recordChanges(callback: () => void): { changes: HistoryChange[]; commands: CoreCommand[] } {
+ recordChanges(callback: () => void): { changes: Change[]; commands: Command[] } {
this.changes = [];
this.commands = [];
callback();
return { changes: this.changes, commands: this.commands };
}
- addCommand(command: CoreCommand) {
+ addCommand(command: Command) {
this.commands.push(command);
}
@@ -26,7 +34,7 @@ export class StateObserver {
const val: any = args.pop();
const root = args[0];
let value = root as any;
- const key = args.at(-1);
+ const key = args.at(-1) as Change["key"];
const pathLength = args.length - 2;
for (let pathIndex = 1; pathIndex <= pathLength; pathIndex++) {
const p = args[pathIndex];
@@ -43,7 +51,7 @@ export class StateObserver {
key,
target: value,
before: value[key],
- });
+ } as Change);
if (val === undefined) {
delete value[key];
} else {
diff --git a/packages/o-spreadsheet-engine/src/translation.ts b/packages/o-spreadsheet-engine/src/translation.ts
new file mode 100644
index 0000000000..f8cfeffefe
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/translation.ts
@@ -0,0 +1,64 @@
+type SprintfValues = (string | String | number)[] | [{ [key: string]: string | number }];
+
+export type TranslationFunction = (string: string, ...values: SprintfValues) => string;
+
+const defaultTranslate: TranslationFunction = (s: string) => s;
+const defaultLoaded: () => boolean = () => false;
+
+let _translate = defaultTranslate;
+let _loaded = defaultLoaded;
+
+function sprintf(s: string, ...values: SprintfValues): string {
+ if (values.length === 1 && typeof values[0] === "object" && !(values[0] instanceof String)) {
+ const valuesDict = values[0] as { [key: string]: string };
+ s = s.replace(/\%\(([^\)]+)\)s/g, (match, value) => valuesDict[value]);
+ } else if (values.length > 0) {
+ s = s.replace(/\%s/g, () => values.shift() as string);
+ }
+ return s;
+}
+
+/***
+ * Allow to inject a translation function from outside o-spreadsheet. This should be called before instantiating
+ * a model.
+ * @param tfn the function that will do the translation
+ * @param loaded a function that returns true when the translation is loaded
+ */
+export function setTranslationMethod(tfn: TranslationFunction, loaded: () => boolean = () => true) {
+ _translate = tfn;
+ _loaded = loaded;
+}
+
+/**
+ * If no translation function has been set, this will mark the translation are loaded.
+ *
+ * By default, the translations should not be set as loaded, otherwise top-level translated constants will never be
+ * translated. But if by the time the model is instantiated no custom translation function has been set, we can set
+ * the default translation function as loaded so o-spreadsheet can be run in standalone with no translations.
+ */
+export function setDefaultTranslationMethod() {
+ if (_translate === defaultTranslate && _loaded === defaultLoaded) {
+ _loaded = () => true;
+ }
+}
+
+export const _t: TranslationFunction = function (s: string, ...values: SprintfValues) {
+ if (!_loaded()) {
+ return new LazyTranslatedString(s, values) as unknown as string;
+ }
+ return sprintf(_translate(s), ...values);
+};
+
+class LazyTranslatedString extends String {
+ constructor(str: string, private values: SprintfValues) {
+ super(str);
+ }
+
+ valueOf() {
+ const str = super.valueOf();
+ return _loaded() ? sprintf(_translate(str), ...this.values) : sprintf(str, ...this.values);
+ }
+ toString() {
+ return this.valueOf();
+ }
+}
diff --git a/packages/o-spreadsheet-engine/src/types/base.ts b/packages/o-spreadsheet-engine/src/types/base.ts
new file mode 100644
index 0000000000..ba2d87e558
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/types/base.ts
@@ -0,0 +1,9 @@
+import { Alias } from "./isMatrix";
+
+export type Range = unknown;
+
+export type Format = string & Alias;
+
+export type Dimension = "COL" | "ROW";
+
+export type SortDirection = "asc" | "desc";
diff --git a/src/types/cells.ts b/packages/o-spreadsheet-engine/src/types/cells.ts
similarity index 94%
rename from src/types/cells.ts
rename to packages/o-spreadsheet-engine/src/types/cells.ts
index fccb10d8c6..30dc6753ae 100644
--- a/src/types/cells.ts
+++ b/packages/o-spreadsheet-engine/src/types/cells.ts
@@ -1,5 +1,6 @@
+import { FunctionResultObject, RangeCompiledFormula, Style, UID } from "../index";
import { Format, FormattedValue } from "./format";
-import { FunctionResultObject, Link, RangeCompiledFormula, Style, UID } from "./misc";
+import { Link } from "./misc";
interface CellAttributes {
readonly id: UID;
diff --git a/packages/o-spreadsheet-engine/src/types/errors.ts b/packages/o-spreadsheet-engine/src/types/errors.ts
new file mode 100644
index 0000000000..c1f1ca0674
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/types/errors.ts
@@ -0,0 +1,67 @@
+import { _t } from "../translation";
+
+export const CellErrorType = {
+ NotAvailable: "#N/A",
+ InvalidReference: "#REF",
+ BadExpression: "#BAD_EXPR",
+ CircularDependency: "#CYCLE",
+ UnknownFunction: "#NAME?",
+ DivisionByZero: "#DIV/0!",
+ SpilledBlocked: "#SPILL!",
+ GenericError: "#ERROR",
+ NullError: "#NULL!",
+} as const;
+
+export type ErrorValue = (typeof CellErrorType)[keyof typeof CellErrorType];
+
+export const errorTypes: Set = new Set(Object.values(CellErrorType));
+
+export class EvaluationError {
+ constructor(
+ readonly message: string = _t("Error"),
+ readonly value: string = CellErrorType.GenericError
+ ) {
+ this.message = message.toString();
+ }
+}
+
+export class BadExpressionError extends EvaluationError {
+ constructor(message = _t("Invalid expression")) {
+ super(message, CellErrorType.BadExpression);
+ }
+}
+export class CircularDependencyError extends EvaluationError {
+ constructor(message = _t("Circular reference")) {
+ super(message, CellErrorType.CircularDependency);
+ }
+}
+
+export class InvalidReferenceError extends EvaluationError {
+ constructor(message = _t("Invalid reference")) {
+ super(message, CellErrorType.InvalidReference);
+ }
+}
+
+export class NotAvailableError extends EvaluationError {
+ constructor(message = _t("Data not available")) {
+ super(message, CellErrorType.NotAvailable);
+ }
+}
+
+export class UnknownFunctionError extends EvaluationError {
+ constructor(message = _t("Unknown function")) {
+ super(message, CellErrorType.UnknownFunction);
+ }
+}
+
+export class SplillBlockedError extends EvaluationError {
+ constructor(message = _t("Spill range is not empty")) {
+ super(message, CellErrorType.SpilledBlocked);
+ }
+}
+
+export class DivisionByZeroError extends EvaluationError {
+ constructor(message = _t("Division by zero")) {
+ super(message, CellErrorType.DivisionByZero);
+ }
+}
diff --git a/src/types/format.ts b/packages/o-spreadsheet-engine/src/types/format.ts
similarity index 84%
rename from src/types/format.ts
rename to packages/o-spreadsheet-engine/src/types/format.ts
index 7d196528bd..812fbd488f 100644
--- a/src/types/format.ts
+++ b/packages/o-spreadsheet-engine/src/types/format.ts
@@ -1,5 +1,6 @@
import { Locale } from "./locale";
-import { Alias } from "./misc";
+
+import { Alias } from "../index";
export type Format = string & Alias;
diff --git a/src/types/functions.ts b/packages/o-spreadsheet-engine/src/types/functions.ts
similarity index 84%
rename from src/types/functions.ts
rename to packages/o-spreadsheet-engine/src/types/functions.ts
index 9f2aafd0cd..0356538de7 100644
--- a/src/types/functions.ts
+++ b/packages/o-spreadsheet-engine/src/types/functions.ts
@@ -1,8 +1,5 @@
-import { CellValue } from "./cells";
-import { Getters } from "./getters";
+import { Arg, CellPosition, CellValue, FunctionResultObject, Matrix, UID } from "./index";
import { Locale } from "./locale";
-import { Arg, CellPosition, FunctionResultObject, Matrix, UID } from "./misc";
-import { Range } from "./range";
export type ArgType =
| "ANY"
@@ -34,10 +31,9 @@ export interface ArgDefinition {
}
export type ArgProposal = { value: CellValue; label?: string };
-
export type ComputeFunction = (this: EvalContext, ...args: Arg[]) => R;
-export interface AddFunctionDescription {
+export interface Functions {
compute: ComputeFunction<
FunctionResultObject | Matrix | CellValue | Matrix
>;
@@ -48,14 +44,13 @@ export interface AddFunctionDescription {
hidden?: boolean;
}
-export type FunctionDescription = AddFunctionDescription & {
+export type FunctionDescription = Functions & {
name: string;
minArgRequired: number;
maxArgPossible: number;
nbrArgRepeating: number;
nbrArgOptional: number;
};
-
export type EvalContext = {
__originSheetId: UID;
__originCellPosition?: CellPosition;
@@ -67,7 +62,6 @@ export type EvalContext = {
debug?: boolean;
lookupCaches?: LookupCaches;
};
-
/**
* used to cache lookup values for linear search
**/
diff --git a/packages/o-spreadsheet-engine/src/types/history.ts b/packages/o-spreadsheet-engine/src/types/history.ts
new file mode 100644
index 0000000000..47603e9984
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/types/history.ts
@@ -0,0 +1,62 @@
+export interface WorkbookHistory {
+ update(key: T, val: Plugin[T]): void;
+ update>(
+ key1: T,
+ key2: U,
+ val: NonNullable[U]
+ ): void;
+ update<
+ T extends keyof Plugin,
+ U extends keyof NonNullable,
+ K extends keyof NonNullable[U]>
+ >(
+ key1: T,
+ key2: U,
+ key3: K,
+ val: NonNullable[U]>[K]
+ ): void;
+ update<
+ T extends keyof Plugin,
+ U extends keyof NonNullable,
+ K extends keyof NonNullable[U]>,
+ V extends keyof NonNullable[U]>[K]>
+ >(
+ key1: T,
+ key2: U,
+ key3: K,
+ key4: V,
+ val: NonNullable[U]>[K]>[V]
+ ): void;
+ update<
+ T extends keyof Plugin,
+ U extends keyof NonNullable,
+ K extends keyof NonNullable[U]>,
+ V extends keyof NonNullable[U]>[K]>,
+ W extends keyof NonNullable[U]>[K]>[V]>
+ >(
+ key1: T,
+ key2: U,
+ key3: K,
+ key4: V,
+ key5: W,
+ val: NonNullable[U]>[K]>[V]>[W]
+ ): void;
+ update<
+ T extends keyof Plugin,
+ U extends keyof NonNullable,
+ K extends keyof NonNullable[U]>,
+ V extends keyof NonNullable[U]>[K]>,
+ W extends keyof NonNullable[U]>[K]>[V]>,
+ Y extends keyof NonNullable<
+ NonNullable[U]>[K]>[V]>[W]
+ >
+ >(
+ key1: T,
+ key2: U,
+ key3: K,
+ key4: V,
+ key5: W,
+ key6: Y,
+ val: NonNullable[U]>[K]>[V]>[W]>[Y]
+ ): void;
+}
diff --git a/packages/o-spreadsheet-engine/src/types/index.ts b/packages/o-spreadsheet-engine/src/types/index.ts
new file mode 100644
index 0000000000..b3808f22ce
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/types/index.ts
@@ -0,0 +1,28 @@
+export * from "./base";
+export * from "./cells";
+export * from "./errors";
+export * from "./functions";
+export * from "./history";
+export * from "./isMatrix";
+export * from "./locale";
+export {
+ Cloneable,
+ DebouncedFunction,
+ Dimension,
+ Direction,
+ FunctionResultNumber,
+ HSLA,
+ Immutable,
+ Increment,
+ Lazy,
+ Link,
+ Offset,
+ RGBA,
+ Ref,
+ SelectionStep,
+ SetDecimalStep,
+ SortDirection,
+ SortOptions,
+ ValueAndLabel,
+} from "./misc";
+export * from "./validator";
diff --git a/packages/o-spreadsheet-engine/src/types/isMatrix.ts b/packages/o-spreadsheet-engine/src/types/isMatrix.ts
new file mode 100644
index 0000000000..4f70005793
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/types/isMatrix.ts
@@ -0,0 +1,274 @@
+import { Token } from "../formulas/tokenizer";
+import { CellValue, EvaluatedCell, Format } from "./index";
+
+/**
+ * The following type is meant to be used in union with other aliases to prevent
+ * Intellisense from resolving it.
+ * See https://github.com/microsoft/TypeScript/issues/31940#issuecomment-841712377
+ */
+export type Alias = {} & {};
+// Col/row Index
+export type HeaderIndex = number & Alias;
+// any DOM pixel value
+export type Pixel = number & Alias;
+// Unique identifier
+export type UID = string & Alias;
+export type FilterId = UID & Alias;
+export type TableId = UID & Alias;
+/**
+ * CSS style color string
+ * e.g. "#ABC", "#AAAFFF", "rgb(30, 80, 16)"
+ */
+export type Color = string & Alias;
+
+export interface Zone {
+ left: HeaderIndex;
+ right: HeaderIndex;
+ top: HeaderIndex;
+ bottom: HeaderIndex;
+}
+
+export interface AnchorZone {
+ zone: Zone;
+ cell: Position;
+}
+
+export interface Selection {
+ anchor: AnchorZone;
+ zones: Zone[];
+}
+
+export type AdjacentEdge = {
+ position: "left" | "top" | "bottom" | "right";
+ start: HeaderIndex;
+ stop: HeaderIndex;
+};
+
+export interface UnboundedZone {
+ top: HeaderIndex;
+ bottom: HeaderIndex | undefined;
+ left: HeaderIndex;
+ right: HeaderIndex | undefined;
+ /**
+ * The hasHeader flag is used to determine if the zone has a header (eg. A2:A or C3:3).
+ *
+ * The main issue is that the zone A1:A and A:A have different behavior. The "correct" way to handle this would be to
+ * allow the top/left to be undefined, but this make typing and using unbounded zones VERY annoying. So we use this
+ * boolean instead.
+ */
+ hasHeader?: boolean;
+}
+
+export interface ZoneDimension {
+ numberOfRows: HeaderIndex;
+ numberOfCols: HeaderIndex;
+}
+
+export type Align = "left" | "right" | "center" | undefined;
+export type VerticalAlign = "top" | "middle" | "bottom" | undefined;
+export type Wrapping = "overflow" | "wrap" | "clip" | undefined;
+
+export interface Style {
+ bold?: boolean;
+ italic?: boolean;
+ strikethrough?: boolean;
+ underline?: boolean;
+ align?: Align;
+ wrapping?: Wrapping;
+ verticalAlign?: VerticalAlign;
+ fillColor?: Color;
+ textColor?: Color;
+ fontSize?: number; // in pt, not in px!
+}
+
+export interface DataBarFill {
+ color: Color;
+ percentage: number;
+}
+
+export interface UpdateCellData {
+ content?: string;
+ formula?: string;
+ style?: Style | null;
+ format?: Format;
+}
+
+export interface Sheet {
+ id: UID;
+ name: string;
+ numberOfCols: number;
+ rows: Row[];
+ areGridLinesVisible: boolean;
+ isVisible: boolean;
+ panes: PaneDivision;
+ color?: Color;
+}
+
+export interface CellPosition {
+ col: HeaderIndex;
+ row: HeaderIndex;
+ sheetId: UID;
+}
+
+export const borderStyles = ["thin", "medium", "thick", "dashed", "dotted"] as const;
+export type BorderStyle = (typeof borderStyles)[number];
+// A complete border description is a pair [style, color]
+export type BorderDescr = { style: BorderStyle; color: Color };
+/**
+ * A complete border(s) data is a set of position-color-style information
+ */
+export type BorderData = {
+ position: BorderPosition;
+ color?: Color;
+ style?: BorderStyle;
+};
+
+export interface Border {
+ top?: BorderDescr;
+ left?: BorderDescr;
+ bottom?: BorderDescr;
+ right?: BorderDescr;
+}
+
+export type ReferenceDenormalizer = (
+ range: Range,
+ isMeta: boolean,
+ functionName: string,
+ paramNumber: number
+) => FunctionResultObject;
+export type EnsureRange = (range: Range, isMeta: boolean) => Matrix;
+export type GetSymbolValue = (symbolName: string) => Arg;
+export type FormulaToExecute = (
+ deps: Range[],
+ refFn: ReferenceDenormalizer,
+ range: EnsureRange,
+ getSymbolValue: GetSymbolValue,
+ ctx: object
+) => Matrix | FunctionResultObject;
+
+export interface CompiledFormula {
+ execute: FormulaToExecute;
+ tokens: Token[];
+ dependencies: string[];
+ isBadExpression: boolean;
+ normalizedFormula: string;
+}
+
+export interface RangeCompiledFormula extends Omit {
+ dependencies: Range[];
+}
+
+export type Matrix = T[][];
+export type FunctionResultObject = {
+ value: CellValue;
+ format?: Format;
+ errorOriginPosition?: CellPosition;
+ message?: string;
+ origin?: CellPosition;
+};
+// FORMULA FUNCTION VALUE AND FORMAT INPUT
+export type Arg = Maybe | Matrix; // undefined corresponds to the lack of argument, e.g. =SUM(1,2,,4)
+export function isMatrix(x: any): x is Matrix {
+ return Array.isArray(x) && Array.isArray(x[0]);
+}
+
+export interface ClipboardCell {
+ evaluatedCell: EvaluatedCell;
+ position: CellPosition;
+ content: string;
+ style?: Style | undefined;
+ format?: Format | undefined;
+ tokens?: Token[];
+ border?: Border;
+}
+
+export interface HeaderDimensions {
+ start: Pixel;
+ size: Pixel;
+ end: Pixel;
+}
+
+export interface Row {
+ cells: Record; // number is a column index
+}
+
+export interface Position {
+ col: HeaderIndex;
+ row: HeaderIndex;
+}
+
+export interface PixelPosition {
+ x: Pixel;
+ y: Pixel;
+}
+
+export interface Merge extends Zone {
+ id: number;
+}
+
+export interface Highlight {
+ range: Range;
+ color: Color;
+ interactive?: boolean;
+ thinLine?: boolean;
+ noFill?: boolean;
+ /** transparency of the fill color (0-1) */
+ fillAlpha?: number;
+ noBorder?: boolean;
+ dashed?: boolean;
+}
+
+export interface PaneDivision {
+ /** Represents the number of frozen columns */
+ xSplit: number;
+ /** Represents the number of frozen rows */
+ ySplit: number;
+}
+
+export type BorderPosition =
+ | "all"
+ | "hv"
+ | "h"
+ | "v"
+ | "external"
+ | "left"
+ | "top"
+ | "right"
+ | "bottom"
+ | "clear";
+
+export const enum DIRECTION {
+ UP = "up",
+ DOWN = "down",
+ LEFT = "left",
+ RIGHT = "right",
+}
+
+export type ChangeType = "REMOVE" | "RESIZE" | "MOVE" | "CHANGE" | "NONE";
+export type ApplyRangeChangeResult =
+ | { changeType: Exclude; range: Range }
+ | { changeType: "NONE" };
+export type ApplyRangeChange = (range: Range) => ApplyRangeChangeResult;
+export type AdaptSheetName = { old: string; current: string };
+export type RangeAdapter = {
+ sheetId: UID;
+ sheetName: AdaptSheetName;
+ applyChange: ApplyRangeChange;
+};
+export type ConsecutiveIndexes = HeaderIndex[];
+
+export interface RangeProvider {
+ adaptRanges: (applyChange: ApplyRangeChange, sheetId: UID, sheetName: AdaptSheetName) => void;
+}
+
+export type Maybe = T | undefined;
+
+export interface MenuMouseEvent extends MouseEvent {
+ closedMenuId?: UID;
+}
+
+export interface HeaderGroup {
+ start: HeaderIndex;
+ end: HeaderIndex;
+ isFolded?: boolean;
+}
diff --git a/packages/o-spreadsheet-engine/src/types/locale.ts b/packages/o-spreadsheet-engine/src/types/locale.ts
new file mode 100644
index 0000000000..e2cdb9cf78
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/types/locale.ts
@@ -0,0 +1,38 @@
+type Alias = {} & {};
+
+export type LocaleCode = string & Alias;
+
+export interface Locale {
+ name: string;
+ code: LocaleCode;
+ thousandsSeparator?: string;
+ decimalSeparator: string;
+ weekStart: number; //1 = Monday, 7 = Sunday
+ dateFormat: string;
+ timeFormat: string;
+ formulaArgSeparator: string;
+}
+
+export const DEFAULT_LOCALES: Locale[] = [
+ {
+ name: "English (US)",
+ code: "en_US" as LocaleCode,
+ thousandsSeparator: ",",
+ decimalSeparator: ".",
+ weekStart: 7, // Sunday
+ dateFormat: "m/d/yyyy",
+ timeFormat: "hh:mm:ss a",
+ formulaArgSeparator: ",",
+ },
+ {
+ name: "French",
+ code: "fr_FR" as LocaleCode,
+ thousandsSeparator: " ",
+ decimalSeparator: ",",
+ weekStart: 1, // Monday
+ dateFormat: "dd/mm/yyyy",
+ timeFormat: "hh:mm:ss",
+ formulaArgSeparator: ";",
+ },
+];
+export const DEFAULT_LOCALE: Locale = DEFAULT_LOCALES[0];
diff --git a/packages/o-spreadsheet-engine/src/types/misc.ts b/packages/o-spreadsheet-engine/src/types/misc.ts
new file mode 100644
index 0000000000..76ab971422
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/types/misc.ts
@@ -0,0 +1,100 @@
+export type FunctionResultNumber = { value: number; format?: string };
+export type SetDecimalStep = 1 | -1;
+
+export interface RGBA {
+ a: number;
+ r: number;
+ g: number;
+ b: number;
+}
+
+export interface HSLA {
+ a: number;
+ h: number;
+ s: number;
+ l: number;
+}
+
+export interface Link {
+ readonly label: string;
+ readonly url: string;
+ readonly isExternal: boolean;
+ /**
+ * Specifies if the URL is editable by the end user.
+ * Special links might not allow it.
+ */
+ readonly isUrlEditable: boolean;
+}
+
+export type Dimension = "COL" | "ROW";
+export type Increment = 1 | -1 | 0;
+
+export interface Ref {
+ el: T | null;
+}
+
+/**
+ * Container for a lazy computed value
+ */
+export interface Lazy {
+ /**
+ * Return the computed value.
+ * The value is computed only once and memoized.
+ */
+ (): T;
+ /**
+ * Map a lazy value to another lazy value.
+ *
+ * ```ts
+ * // neither function is called here
+ * const lazyValue = lazy(() => veryExpensive(...)).map((result) => alsoVeryExpensive(result));
+ *
+ * // both values are computed now
+ * const value = lazyValue()
+ * ```
+ */
+ map: (callback: (value: T) => U) => Lazy;
+}
+
+export interface Cloneable {
+ clone: (args?: Partial) => T;
+}
+
+export interface SortOptions {
+ /** If true sort the headers of the range along with the rest */
+ sortHeaders?: boolean;
+ /** If true treat empty cells as "0" instead of undefined */
+ emptyCellAsZero?: boolean;
+}
+
+// https://github.com/Microsoft/TypeScript/issues/13923#issuecomment-557509399
+// prettier-ignore
+export type Immutable =
+ T extends ImmutablePrimitive ? T :
+ T extends Array ? ImmutableArray :
+ T extends Map ? ImmutableMap :
+ T extends Set ? ImmutableSet :
+ ImmutableObject;
+type ImmutablePrimitive = undefined | null | boolean | string | number | Function;
+type ImmutableArray = ReadonlyArray>;
+type ImmutableMap = ReadonlyMap, Immutable>;
+type ImmutableSet = ReadonlySet>;
+type ImmutableObject = { readonly [K in keyof T]: Immutable };
+export type Direction = "up" | "down" | "left" | "right";
+export type SelectionStep = number | "end";
+
+export interface Offset {
+ col: number;
+ row: number;
+}
+
+export type DebouncedFunction = T & {
+ stopDebounce: () => void;
+ isDebouncePending: () => boolean;
+};
+export type SortDirection = "asc" | "desc";
+
+export interface ValueAndLabel {
+ value: T;
+ label: string;
+}
diff --git a/src/types/range.ts b/packages/o-spreadsheet-engine/src/types/range.ts
similarity index 89%
rename from src/types/range.ts
rename to packages/o-spreadsheet-engine/src/types/range.ts
index 4819f1f7a1..7236369d54 100644
--- a/src/types/range.ts
+++ b/packages/o-spreadsheet-engine/src/types/range.ts
@@ -1,4 +1,5 @@
-import { UID, UnboundedZone, Zone } from "./misc";
+import { UID, Zone } from "./base";
+import { UnboundedZone } from "./isMatrix";
export interface RangePart {
readonly colFixed: boolean;
diff --git a/packages/o-spreadsheet-engine/src/types/validator.ts b/packages/o-spreadsheet-engine/src/types/validator.ts
new file mode 100644
index 0000000000..f007bb4a9a
--- /dev/null
+++ b/packages/o-spreadsheet-engine/src/types/validator.ts
@@ -0,0 +1,21 @@
+export type Validation = (toValidate: T) => Result | Result[];
+
+export interface Validator {
+ /**
+ * Combine multiple validation functions into a single function
+ * returning the list of results of every validation.
+ */
+ batchValidations(...validations: Validation[]): Validation;
+
+ /**
+ * Combine multiple validation functions. Every validation is executed one after
+ * the other. As soon as one validation fails, it stops and the cancelled reason
+ * is returned.
+ */
+ chainValidations(...validations: Validation[]): Validation;
+
+ checkValidations(
+ command: T,
+ ...validations: Validation, Result>[]
+ ): Result | Result[];
+}
diff --git a/packages/o-spreadsheet-engine/tests/index.test.ts b/packages/o-spreadsheet-engine/tests/index.test.ts
new file mode 100644
index 0000000000..3d2f415fe2
--- /dev/null
+++ b/packages/o-spreadsheet-engine/tests/index.test.ts
@@ -0,0 +1,5 @@
+describe("dummy", () => {
+ test("dummy", () => {
+ expect(true).toBe(true);
+ });
+});
diff --git a/packages/o-spreadsheet-engine/tsconfig.jest.json b/packages/o-spreadsheet-engine/tsconfig.jest.json
new file mode 100644
index 0000000000..8bbe1edf31
--- /dev/null
+++ b/packages/o-spreadsheet-engine/tsconfig.jest.json
@@ -0,0 +1,7 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "dist"
+ },
+ "include": ["src", "tests"]
+}
diff --git a/packages/o-spreadsheet-engine/tsconfig.json b/packages/o-spreadsheet-engine/tsconfig.json
new file mode 100644
index 0000000000..7111e9b4e9
--- /dev/null
+++ b/packages/o-spreadsheet-engine/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "outDir": "build/js/o-spreadsheet-engine/src",
+ "preserveWatchOutput": true
+ },
+ "include": ["src"]
+}
diff --git a/rollup.config.js b/rollup.config.js
index 3585d20966..fc30518e10 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -1,7 +1,10 @@
+import alias from "@rollup/plugin-alias";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import terser from "@rollup/plugin-terser";
+import path from "path";
import dts from "rollup-plugin-dts";
import typescript from "rollup-plugin-typescript2";
+import { fileURLToPath } from "url";
import { bundle } from "./tools/bundle.cjs";
const outro = bundle.outro();
@@ -14,7 +17,7 @@ const outro = bundle.outro();
*/
function getConfigForFormat(format, minified = false) {
return {
- file: minified ? `dist/o-spreadsheet.${format}.min.js` : `dist/o-spreadsheet.${format}.js`,
+ file: minified ? `dist/o_spreadsheet.${format}.min.js` : `dist/o_spreadsheet.${format}.js`,
format,
name: "o_spreadsheet",
extend: true,
@@ -24,17 +27,38 @@ function getConfigForFormat(format, minified = false) {
plugins: minified ? [terser()] : [],
};
}
+const __dirname = fileURLToPath(new URL(".", import.meta.url));
export default (commandLineArgs) => {
let output = [];
let input = "";
- let plugins = [nodeResolve()];
+ let plugins = [
+ alias({
+ entries: [
+ {
+ find: "@odoo/o-spreadsheet-engine",
+ replacement: path.resolve(
+ __dirname,
+ "./packages/o-spreadsheet-engine/build/js/o-spreadsheet-engine/src"
+ ),
+ },
+ {
+ find: "@odoo/o-spreadsheet-engine/*",
+ replacement: path.resolve(
+ __dirname,
+ "./packages/o-spreadsheet-engine/build/js/o-spreadsheet-engine/src/*"
+ ),
+ },
+ ],
+ }),
+ nodeResolve(),
+ ];
let config = {};
if (commandLineArgs.format) {
// Only build one version to improve speed
config = {
- input: "build/js/index.js",
+ input: "build/js/src/index.js",
external: ["@odoo/owl"],
output: [
{
@@ -48,6 +72,9 @@ export default (commandLineArgs) => {
},
],
plugins,
+ watch: {
+ include: ["src/**", "./packages/o-spreadsheet-engine/src/**"],
+ },
};
} else {
input = "src/index.ts";
@@ -66,9 +93,27 @@ export default (commandLineArgs) => {
plugins,
},
{
- input: "dist/types/index.d.ts",
+ input: "dist/types/src/index.d.ts",
output: [{ file: "dist/o-spreadsheet.d.ts", format: "es" }],
- plugins: [dts(), nodeResolve()],
+ plugins: [
+ dts(),
+ nodeResolve(),
+ alias({
+ entries: [
+ {
+ find: "@odoo/o-spreadsheet-engine",
+ replacement: path.resolve(__dirname, "./dist/types/packages/o-spreadsheet-engine"),
+ },
+ {
+ find: "@odoo/o-spreadsheet-engine/*",
+ replacement: path.resolve(
+ __dirname,
+ "./dist/types/packages/o-spreadsheet-engine/*"
+ ),
+ },
+ ],
+ }),
+ ],
},
];
}
diff --git a/src/actions/action.ts b/src/actions/action.ts
index 84d36a443f..0f595bde4e 100644
--- a/src/actions/action.ts
+++ b/src/actions/action.ts
@@ -1,4 +1,5 @@
-import { Color, SpreadsheetChildEnv } from "../types";
+import { Color } from "@odoo/o-spreadsheet-engine";
+import { SpreadsheetChildEnv } from "../types";
/*
* An Action represent a menu item for the menus of the top bar
diff --git a/src/actions/figure_menu_actions.ts b/src/actions/figure_menu_actions.ts
index ff5ddafe0d..83e65d005e 100644
--- a/src/actions/figure_menu_actions.ts
+++ b/src/actions/figure_menu_actions.ts
@@ -1,8 +1,7 @@
-import { UID } from "..";
+import { deepEquals, UID } from "@odoo/o-spreadsheet-engine";
import { downloadFile } from "../components/helpers/dom_helpers";
import { chartToImageFile, chartToImageUrl } from "../helpers/figures/charts";
import { getMaxFigureSize } from "../helpers/figures/figure/figure";
-import { deepEquals } from "../helpers/misc";
import { _t } from "../translation";
import { SpreadsheetChildEnv } from "../types";
import { xmlEscape } from "../xlsx/helpers/xml_helpers";
diff --git a/src/actions/format_actions.ts b/src/actions/format_actions.ts
index 40619433a8..608e9c0061 100644
--- a/src/actions/format_actions.ts
+++ b/src/actions/format_actions.ts
@@ -1,3 +1,4 @@
+import { Align, VerticalAlign, Wrapping } from "@odoo/o-spreadsheet-engine";
import {
DEFAULT_CURRENCY,
DEFAULT_FONT_SIZE,
@@ -9,19 +10,9 @@ import { createAccountingFormat, createCurrencyFormat, formatValue, roundFormat
import { parseLiteral } from "../helpers/cells";
import { getDateTimeFormat } from "../helpers/locale";
import { _t } from "../translation";
-import {
- Align,
- CellValue,
- DEFAULT_LOCALE,
- Format,
- SpreadsheetChildEnv,
- VerticalAlign,
- Wrapping,
-} from "../types";
+import { CellValue, DEFAULT_LOCALE, Format, SpreadsheetChildEnv } from "../types";
import { ActionSpec } from "./action";
import * as ACTIONS from "./menu_items_actions";
-import { setFormatter, setStyle } from "./menu_items_actions";
-
export interface NumberFormatActionSpec extends ActionSpec {
format?: Format | ((env: SpreadsheetChildEnv) => Format);
}
diff --git a/src/actions/insert_actions.ts b/src/actions/insert_actions.ts
index 60506541a2..f66be97fb5 100644
--- a/src/actions/insert_actions.ts
+++ b/src/actions/insert_actions.ts
@@ -1,6 +1,3 @@
-import { functionRegistry } from "../functions";
-import { isDefined } from "../helpers";
-import { localizeDataValidationRule } from "../helpers/locale";
import { handlePasteResult } from "../helpers/ui/paste_interactive";
import { _t } from "../translation";
import { ActionBuilder, ActionSpec } from "./action";
diff --git a/src/actions/menu_items_actions.ts b/src/actions/menu_items_actions.ts
index 0ae7349984..ddee2b198f 100644
--- a/src/actions/menu_items_actions.ts
+++ b/src/actions/menu_items_actions.ts
@@ -8,22 +8,14 @@ import {
import { parseOSClipboardContent } from "../helpers/clipboard/clipboard_helpers";
import { getSmartChartDefinition } from "../helpers/figures/charts/smart_chart_engine";
import { centerFigurePosition, getMaxFigureSize } from "../helpers/figures/figure/figure";
-import {
- areZonesContinuous,
- getZoneArea,
- isConsecutive,
- isEqual,
- largeMax,
- largeMin,
- numberToLetters,
-} from "../helpers/index";
+import { areZonesContinuous, getZoneArea, isEqual, numberToLetters } from "../helpers/index";
import { DEFAULT_TABLE_CONFIG } from "../helpers/table_presets";
import { interactivePaste, interactivePasteFromOS } from "../helpers/ui/paste_interactive";
import { interactiveCreateTable } from "../helpers/ui/table_interactive";
import { _t } from "../translation";
import { ClipboardMIMEType, ClipboardPasteOptions } from "../types/clipboard";
import { Image } from "../types/image";
-import { Dimension, Format, SpreadsheetChildEnv, Style } from "../types/index";
+import { Format, SpreadsheetChildEnv } from "../types/index";
import { ActionSpec } from "./action";
//------------------------------------------------------------------------------
diff --git a/src/actions/sheet_actions.ts b/src/actions/sheet_actions.ts
index a941ef50f0..cf52275fb7 100644
--- a/src/actions/sheet_actions.ts
+++ b/src/actions/sheet_actions.ts
@@ -1,4 +1,5 @@
-import { buildSheetLink, markdownLink } from "../helpers";
+import { buildSheetLink } from "@odoo/o-spreadsheet-engine";
+import { markdownLink } from "../helpers";
import { _t } from "../translation";
import { ActionSpec } from "./action";
diff --git a/src/actions/view_actions.ts b/src/actions/view_actions.ts
index ab42be2582..d74848c130 100644
--- a/src/actions/view_actions.ts
+++ b/src/actions/view_actions.ts
@@ -1,9 +1,9 @@
+import { Dimension } from "@odoo/o-spreadsheet-engine/types";
import { numberToLetters } from "../helpers";
import { interactiveFreezeColumnsRows } from "../helpers/ui/freeze_interactive";
import { FormulaFingerprintStore } from "../stores/formula_fingerprints_store";
import { _t } from "../translation";
import { SpreadsheetChildEnv } from "../types";
-import { Dimension } from "./../types/misc";
import { ActionSpec } from "./action";
import * as ACTIONS from "./menu_items_actions";
diff --git a/src/clipboard_handlers/abstract_cell_clipboard_handler.ts b/src/clipboard_handlers/abstract_cell_clipboard_handler.ts
index cacaaf3a73..a72be2861e 100644
--- a/src/clipboard_handlers/abstract_cell_clipboard_handler.ts
+++ b/src/clipboard_handlers/abstract_cell_clipboard_handler.ts
@@ -1,13 +1,7 @@
+import { HeaderIndex, UID, Zone } from "@odoo/o-spreadsheet-engine";
import { recomputeZones } from "../helpers";
import { getPasteZones } from "../helpers/clipboard/clipboard_helpers";
-import {
- ClipboardCellData,
- ClipboardCopyOptions,
- ClipboardOptions,
- HeaderIndex,
- UID,
- Zone,
-} from "../types";
+import { ClipboardCellData, ClipboardCopyOptions, ClipboardOptions } from "../types";
import { ClipboardHandler } from "./abstract_clipboard_handler";
export class AbstractCellClipboardHandler extends ClipboardHandler {
diff --git a/src/clipboard_handlers/abstract_clipboard_handler.ts b/src/clipboard_handlers/abstract_clipboard_handler.ts
index 9d22510e7b..9ca3f95743 100644
--- a/src/clipboard_handlers/abstract_clipboard_handler.ts
+++ b/src/clipboard_handlers/abstract_clipboard_handler.ts
@@ -1,3 +1,4 @@
+import { UID, Zone } from "@odoo/o-spreadsheet-engine";
import {
ClipboardCopyOptions,
ClipboardData,
@@ -6,8 +7,6 @@ import {
CommandDispatcher,
CommandResult,
Getters,
- UID,
- Zone,
} from "../types";
export class ClipboardHandler {
diff --git a/src/clipboard_handlers/borders_clipboard.ts b/src/clipboard_handlers/borders_clipboard.ts
index 5a14c9e0fd..35529d07a9 100644
--- a/src/clipboard_handlers/borders_clipboard.ts
+++ b/src/clipboard_handlers/borders_clipboard.ts
@@ -1,15 +1,14 @@
-import { splitZoneForPaste } from "../helpers/clipboard/clipboard_helpers";
-import { deepEquals, groupConsecutive } from "../helpers/misc";
-import { ZoneBorder, ZoneBorderData } from "../plugins/core";
import {
BorderDescr,
BorderPosition,
- ClipboardCellData,
- ClipboardOptions,
- ClipboardPasteTarget,
+ deepEquals,
HeaderIndex,
UID,
-} from "../types";
+} from "@odoo/o-spreadsheet-engine";
+import { splitZoneForPaste } from "../helpers/clipboard/clipboard_helpers";
+import { groupConsecutive } from "../helpers/misc";
+import { ZoneBorder, ZoneBorderData } from "../plugins/core";
+import { ClipboardCellData, ClipboardOptions, ClipboardPasteTarget } from "../types";
import { AbstractCellClipboardHandler } from "./abstract_cell_clipboard_handler";
type ClipboardContent = {
diff --git a/src/clipboard_handlers/carousel_clipboard.ts b/src/clipboard_handlers/carousel_clipboard.ts
index 5bbafdfe9c..368a8203d0 100644
--- a/src/clipboard_handlers/carousel_clipboard.ts
+++ b/src/clipboard_handlers/carousel_clipboard.ts
@@ -1,3 +1,4 @@
+import { UID, Zone } from "@odoo/o-spreadsheet-engine";
import { deepCopy, UuidGenerator } from "../helpers";
import { AbstractChart } from "../helpers/figures/charts";
import {
@@ -7,8 +8,6 @@ import {
ClipboardPasteTarget,
CommandResult,
Figure,
- UID,
- Zone,
} from "../types";
import { AbstractFigureClipboardHandler } from "./abstract_figure_clipboard_handler";
diff --git a/src/clipboard_handlers/cell_clipboard.ts b/src/clipboard_handlers/cell_clipboard.ts
index 64651153c3..4ebac22783 100644
--- a/src/clipboard_handlers/cell_clipboard.ts
+++ b/src/clipboard_handlers/cell_clipboard.ts
@@ -1,18 +1,21 @@
-import { deepEquals, formatValue, isZoneInside } from "../helpers";
+import {
+ CellPosition,
+ ClipboardCell,
+ deepEquals,
+ HeaderIndex,
+ UID,
+ Zone,
+} from "@odoo/o-spreadsheet-engine";
+import { formatValue, isZoneInside } from "../helpers";
import { getPasteZones } from "../helpers/clipboard/clipboard_helpers";
import { canonicalizeNumberValue } from "../helpers/locale";
import { createPivotFormula } from "../helpers/pivot/pivot_helpers";
import {
- CellPosition,
- ClipboardCell,
ClipboardCellData,
ClipboardCopyOptions,
ClipboardOptions,
ClipboardPasteTarget,
CommandResult,
- HeaderIndex,
- UID,
- Zone,
} from "../types";
import { AbstractCellClipboardHandler } from "./abstract_cell_clipboard_handler";
diff --git a/src/clipboard_handlers/chart_clipboard.ts b/src/clipboard_handlers/chart_clipboard.ts
index 9d8519d795..e5e367c701 100644
--- a/src/clipboard_handlers/chart_clipboard.ts
+++ b/src/clipboard_handlers/chart_clipboard.ts
@@ -1,3 +1,4 @@
+import { UID, Zone } from "@odoo/o-spreadsheet-engine";
import { UuidGenerator } from "../helpers";
import { AbstractChart } from "../helpers/figures/charts";
import {
@@ -6,8 +7,6 @@ import {
ClipboardPasteTarget,
CommandResult,
Figure,
- UID,
- Zone,
} from "../types";
import { AbstractFigureClipboardHandler } from "./abstract_figure_clipboard_handler";
diff --git a/src/clipboard_handlers/conditional_format_clipboard.ts b/src/clipboard_handlers/conditional_format_clipboard.ts
index a406109ac3..a7816384da 100644
--- a/src/clipboard_handlers/conditional_format_clipboard.ts
+++ b/src/clipboard_handlers/conditional_format_clipboard.ts
@@ -1,14 +1,17 @@
-import { UuidGenerator, deepEquals, positionToZone } from "../helpers";
import {
CellPosition,
- ClipboardCellData,
- ClipboardOptions,
- ClipboardPasteTarget,
- ConditionalFormat,
+ deepEquals,
HeaderIndex,
Maybe,
UID,
Zone,
+} from "@odoo/o-spreadsheet-engine";
+import { positionToZone, UuidGenerator } from "../helpers";
+import {
+ ClipboardCellData,
+ ClipboardOptions,
+ ClipboardPasteTarget,
+ ConditionalFormat,
} from "../types";
import { AbstractCellClipboardHandler } from "./abstract_cell_clipboard_handler";
diff --git a/src/clipboard_handlers/data_validation_clipboard.ts b/src/clipboard_handlers/data_validation_clipboard.ts
index e6014a31a5..1ed52fdb4f 100644
--- a/src/clipboard_handlers/data_validation_clipboard.ts
+++ b/src/clipboard_handlers/data_validation_clipboard.ts
@@ -1,14 +1,17 @@
-import { UuidGenerator, deepEquals, positionToZone, recomputeZones } from "../helpers";
import {
CellPosition,
- ClipboardCellData,
- ClipboardOptions,
- ClipboardPasteTarget,
- DataValidationRule,
+ deepEquals,
HeaderIndex,
Maybe,
UID,
Zone,
+} from "@odoo/o-spreadsheet-engine";
+import { positionToZone, recomputeZones, UuidGenerator } from "../helpers";
+import {
+ ClipboardCellData,
+ ClipboardOptions,
+ ClipboardPasteTarget,
+ DataValidationRule,
} from "../types";
import { AbstractCellClipboardHandler } from "./abstract_cell_clipboard_handler";
diff --git a/src/clipboard_handlers/image_clipboard.ts b/src/clipboard_handlers/image_clipboard.ts
index 8485cdad44..3ff31a9c3a 100644
--- a/src/clipboard_handlers/image_clipboard.ts
+++ b/src/clipboard_handlers/image_clipboard.ts
@@ -1,3 +1,4 @@
+import { UID, Zone } from "@odoo/o-spreadsheet-engine";
import { UuidGenerator, deepCopy } from "../helpers";
import {
ClipboardFigureData,
@@ -5,8 +6,6 @@ import {
ClipboardPasteTarget,
CommandResult,
Figure,
- UID,
- Zone,
} from "../types";
import { Image } from "../types/image";
import { AbstractFigureClipboardHandler } from "./abstract_figure_clipboard_handler";
diff --git a/src/clipboard_handlers/merge_clipboard.ts b/src/clipboard_handlers/merge_clipboard.ts
index faaf6ecf3d..9cd5bf44c1 100644
--- a/src/clipboard_handlers/merge_clipboard.ts
+++ b/src/clipboard_handlers/merge_clipboard.ts
@@ -1,14 +1,3 @@
-import { isDefined } from "../helpers";
-import {
- CellPosition,
- ClipboardCellData,
- ClipboardOptions,
- ClipboardPasteTarget,
- HeaderIndex,
- Maybe,
- Merge,
- UID,
-} from "../types";
import { AbstractCellClipboardHandler } from "./abstract_cell_clipboard_handler";
interface ClipboardContent {
diff --git a/src/clipboard_handlers/references_clipboard.ts b/src/clipboard_handlers/references_clipboard.ts
index e6b6b1b81d..7d7f4153b9 100644
--- a/src/clipboard_handlers/references_clipboard.ts
+++ b/src/clipboard_handlers/references_clipboard.ts
@@ -1,6 +1,5 @@
-import { ClipboardCellData, ClipboardOptions, ClipboardPasteTarget, UID, Zone } from "../types";
-import { AbstractCellClipboardHandler } from "./abstract_cell_clipboard_handler";
-
+import { UID, Zone } from "@odoo/o-spreadsheet-engine";
+import { ClipboardCellData, ClipboardOptions, ClipboardPasteTarget } from "../types";
interface ClipboardContent {
zones: Zone[];
sheetId: UID;
diff --git a/src/clipboard_handlers/sheet_clipboard.ts b/src/clipboard_handlers/sheet_clipboard.ts
index fd96d82b9d..1ae430c2c7 100644
--- a/src/clipboard_handlers/sheet_clipboard.ts
+++ b/src/clipboard_handlers/sheet_clipboard.ts
@@ -1,8 +1,7 @@
+import { UID, Zone } from "@odoo/o-spreadsheet-engine";
import { doesAnyZoneCrossFrozenPane } from "../helpers";
import { getPasteZones } from "../helpers/clipboard/clipboard_helpers";
-import { ClipboardOptions, CommandResult, UID, Zone } from "../types";
-import { AbstractCellClipboardHandler } from "./abstract_cell_clipboard_handler";
-
+import { ClipboardOptions, CommandResult } from "../types";
type ClipboardContent = {
cells: any[][];
zones: Zone[];
diff --git a/src/clipboard_handlers/tables_clipboard.ts b/src/clipboard_handlers/tables_clipboard.ts
index 23c49c9a33..82ae9f6191 100644
--- a/src/clipboard_handlers/tables_clipboard.ts
+++ b/src/clipboard_handlers/tables_clipboard.ts
@@ -1,18 +1,11 @@
-import { isZoneInside, removeFalsyAttributes, zoneToDimension } from "../helpers";
import {
- Border,
- CellPosition,
ClipboardCellData,
ClipboardCopyOptions,
ClipboardOptions,
ClipboardPasteTarget,
CoreTableType,
- HeaderIndex,
RangeData,
- Style,
TableConfig,
- UID,
- Zone,
} from "../types";
import { AbstractCellClipboardHandler } from "./abstract_cell_clipboard_handler";
diff --git a/src/collaborative/local_transport_service.ts b/src/collaborative/local_transport_service.ts
index 45c47313c1..9390f14629 100644
--- a/src/collaborative/local_transport_service.ts
+++ b/src/collaborative/local_transport_service.ts
@@ -1,4 +1,4 @@
-import { UID } from "../types";
+import { UID } from "@odoo/o-spreadsheet-engine";
import {
CollaborationMessage,
NewMessageCallback,
diff --git a/src/collaborative/ot/ot.ts b/src/collaborative/ot/ot.ts
index 65cd99284a..ca13a1ac77 100644
--- a/src/collaborative/ot/ot.ts
+++ b/src/collaborative/ot/ot.ts
@@ -1,24 +1,13 @@
-import {
- getAddHeaderStartIndex,
- getRangeAdapter,
- isDefined,
- isInside,
- moveHeaderIndexesOnHeaderAddition,
- moveHeaderIndexesOnHeaderDeletion,
- rangeAdapterRegistry,
-} from "../../helpers/index";
import { otRegistry } from "../../registries/ot_registry";
import { specificRangeTransformRegistry } from "../../registries/srt_registry";
import {
AddColumnsRowsCommand,
AddMergeCommand,
CoreCommand,
- HeaderIndex,
PositionDependentCommand,
RemoveColumnsRowsCommand,
SheetDependentCommand,
TargetDependentCommand,
- Zone,
isPositionDependent,
isSheetDependent,
isTargetDependent,
diff --git a/src/collaborative/ot/ot_helpers.ts b/src/collaborative/ot/ot_helpers.ts
index 3acd42230c..8fe3c04e51 100644
--- a/src/collaborative/ot/ot_helpers.ts
+++ b/src/collaborative/ot/ot_helpers.ts
@@ -1,5 +1,6 @@
+import { UnboundedZone, Zone } from "@odoo/o-spreadsheet-engine";
import { expandZoneOnInsertion, reduceZoneOnDeletion } from "../../helpers";
-import { CoreCommand, RangeData, UnboundedZone, Zone } from "../../types";
+import { CoreCommand } from "../../types";
export function transformZone(
zone: Z,
diff --git a/src/collaborative/ot/ot_specific.ts b/src/collaborative/ot/ot_specific.ts
index 2160717fdf..93aa2a7206 100644
--- a/src/collaborative/ot/ot_specific.ts
+++ b/src/collaborative/ot/ot_specific.ts
@@ -1,3 +1,4 @@
+import { HeaderIndex, Zone } from "@odoo/o-spreadsheet-engine";
import {
getAddHeaderStartIndex,
moveHeaderIndexesOnHeaderAddition,
@@ -22,7 +23,6 @@ import {
FreezeColumnsCommand,
FreezeRowsCommand,
GroupHeadersCommand,
- HeaderIndex,
InsertPivotCommand,
MoveRangeCommand,
RemoveColumnsRowsCommand,
@@ -37,7 +37,6 @@ import {
UpdateFigureCommand,
UpdatePivotCommand,
UpdateTableCommand,
- Zone,
} from "../../types";
import { transformRangeData, transformZone } from "./ot_helpers";
diff --git a/src/collaborative/ot/srt_specific.ts b/src/collaborative/ot/srt_specific.ts
index 02d4b8b2b0..2544a2c724 100644
--- a/src/collaborative/ot/srt_specific.ts
+++ b/src/collaborative/ot/srt_specific.ts
@@ -11,7 +11,8 @@ import {
UpdateChartCommand,
UpdatePivotCommand,
} from "../../types/commands";
-import { RangeAdapter } from "../../types/misc";
+
+import { RangeAdapter } from "@odoo/o-spreadsheet-engine";
function updateCellCommandAdaptRange(
cmd: UpdateCellCommand,
diff --git a/src/collaborative/readonly_transport_filter.ts b/src/collaborative/readonly_transport_filter.ts
index 0cb4fd37e5..17f1a47e88 100644
--- a/src/collaborative/readonly_transport_filter.ts
+++ b/src/collaborative/readonly_transport_filter.ts
@@ -1,4 +1,4 @@
-import { UID } from "../types";
+import { UID } from "@odoo/o-spreadsheet-engine";
import {
CollaborationMessage,
NewMessageCallback,
diff --git a/src/collaborative/revisions.ts b/src/collaborative/revisions.ts
index 6ceba2f022..1a7e272b2c 100644
--- a/src/collaborative/revisions.ts
+++ b/src/collaborative/revisions.ts
@@ -1,4 +1,5 @@
-import { ClientId, Command, CoreCommand, HistoryChange, RevisionData, UID } from "../types";
+import { UID } from "@odoo/o-spreadsheet-engine";
+import { ClientId, Command, CoreCommand, HistoryChange, RevisionData } from "../types";
export class Revision implements RevisionData {
public readonly id: UID;
diff --git a/src/collaborative/session.ts b/src/collaborative/session.ts
index bcbc977a02..1490cf65b1 100644
--- a/src/collaborative/session.ts
+++ b/src/collaborative/session.ts
@@ -1,9 +1,9 @@
-import { DEBOUNCE_TIME, DEFAULT_REVISION_ID, MESSAGE_VERSION } from "../constants";
+import { debounce } from "@odoo/o-spreadsheet-engine";
+import { Lazy } from "@odoo/o-spreadsheet-engine/types";
import { EventBus } from "../helpers/event_bus";
-import { debounce, isDefined } from "../helpers/misc";
import { UuidGenerator } from "../helpers/uuid";
import { SelectiveHistory as RevisionLog } from "../history/selective_history";
-import { CoreCommand, HistoryChange, Lazy, UID, WorkbookData } from "../types";
+import { CoreCommand, HistoryChange, WorkbookData } from "../types";
import {
Client,
ClientId,
diff --git a/src/components/autofill/autofill.ts b/src/components/autofill/autofill.ts
index ebe4679988..cd942faf46 100644
--- a/src/components/autofill/autofill.ts
+++ b/src/components/autofill/autofill.ts
@@ -1,6 +1,7 @@
+import { HeaderIndex } from "@odoo/o-spreadsheet-engine";
import { Component, useState, xml } from "@odoo/owl";
import { clip } from "../../helpers";
-import { HeaderIndex, SpreadsheetChildEnv } from "../../types";
+import { SpreadsheetChildEnv } from "../../types";
import { cssPropertiesToCss } from "../helpers/css";
import { useDragAndDropBeyondTheViewport } from "../helpers/drag_and_drop_grid_hook";
diff --git a/src/components/border_editor/border_editor.ts b/src/components/border_editor/border_editor.ts
index 7ad89d6a28..5750ea686b 100644
--- a/src/components/border_editor/border_editor.ts
+++ b/src/components/border_editor/border_editor.ts
@@ -1,13 +1,12 @@
-import { Component, useRef, useState } from "@odoo/owl";
import {
BorderPosition,
BorderStyle,
+ borderStyles,
Color,
Pixel,
- Rect,
- SpreadsheetChildEnv,
- borderStyles,
-} from "../../types/index";
+} from "@odoo/o-spreadsheet-engine";
+import { Component, useRef, useState } from "@odoo/owl";
+import { Rect, SpreadsheetChildEnv } from "../../types/index";
import { ColorPickerWidget } from "../color_picker/color_picker_widget";
import { Popover, PopoverProps } from "../popover/popover";
diff --git a/src/components/border_editor/border_editor_widget.ts b/src/components/border_editor/border_editor_widget.ts
index a0aa96134b..e0b8d4715d 100644
--- a/src/components/border_editor/border_editor_widget.ts
+++ b/src/components/border_editor/border_editor_widget.ts
@@ -1,9 +1,7 @@
+import { BorderPosition, BorderStyle, Color, Pixel } from "@odoo/o-spreadsheet-engine";
import { Component, onWillUpdateProps, useRef, useState } from "@odoo/owl";
import { DEFAULT_BORDER_DESC } from "../../constants";
-import { BorderPosition, BorderStyle, Color, Pixel, Rect, SpreadsheetChildEnv } from "../../types";
-import { ToolBarDropdownStore, useToolBarDropdownStore } from "../helpers/top_bar_tool_hook";
-import { BorderEditor } from "./border_editor";
-
+import { Rect, SpreadsheetChildEnv } from "../../types";
interface Props {
disabled?: boolean;
dropdownMaxHeight?: Pixel;
diff --git a/src/components/bottom_bar/bottom_bar.ts b/src/components/bottom_bar/bottom_bar.ts
index 790984e9b7..25d1af5a94 100644
--- a/src/components/bottom_bar/bottom_bar.ts
+++ b/src/components/bottom_bar/bottom_bar.ts
@@ -1,8 +1,8 @@
+import { deepEquals, MenuMouseEvent, Pixel, UID } from "@odoo/o-spreadsheet-engine";
import { Component, onWillUpdateProps, useRef, useState } from "@odoo/owl";
-import { deepEquals } from "../../helpers";
import { MenuItemRegistry } from "../../registries/menu_items_registry";
import { _t } from "../../translation";
-import { MenuMouseEvent, Pixel, Rect, SpreadsheetChildEnv, UID } from "../../types";
+import { Rect, SpreadsheetChildEnv } from "../../types";
import { Ripple } from "../animation/ripple";
import { useDragAndDropListItems } from "../helpers/drag_and_drop_dom_items_hook";
import { MenuPopover, MenuState } from "../menu_popover/menu_popover";
diff --git a/src/components/bottom_bar/bottom_bar_statistic/aggregate_statistics_store.ts b/src/components/bottom_bar/bottom_bar_statistic/aggregate_statistics_store.ts
index 5b28758806..c647bba50f 100644
--- a/src/components/bottom_bar/bottom_bar_statistic/aggregate_statistics_store.ts
+++ b/src/components/bottom_bar/bottom_bar_statistic/aggregate_statistics_store.ts
@@ -1,6 +1,8 @@
+import { lazy } from "@odoo/o-spreadsheet-engine";
+import { Lazy } from "@odoo/o-spreadsheet-engine/types";
import { sum } from "../../../functions/helper_math";
import { average, countAny, countNumbers, max, min } from "../../../functions/helper_statistical";
-import { lazy, memoize, recomputeZones } from "../../../helpers";
+import { memoize, recomputeZones } from "../../../helpers";
import { Get } from "../../../store_engine";
import { SpreadsheetStore } from "../../../stores";
import { _t } from "../../../translation";
@@ -8,7 +10,6 @@ import {
CellValueType,
Command,
EvaluatedCell,
- Lazy,
Locale,
invalidateEvaluationCommands,
} from "../../../types";
diff --git a/src/components/collaborative_client_tag/collaborative_client_tag.ts b/src/components/collaborative_client_tag/collaborative_client_tag.ts
index 21b30d69b7..651565a148 100644
--- a/src/components/collaborative_client_tag/collaborative_client_tag.ts
+++ b/src/components/collaborative_client_tag/collaborative_client_tag.ts
@@ -1,7 +1,5 @@
+import { Color, HeaderIndex } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
-import { Color, HeaderIndex, SpreadsheetChildEnv } from "../../types";
-import { cssPropertiesToCss } from "../helpers/css";
-
interface ClientTagProps {
active: boolean;
name: string;
diff --git a/src/components/color_picker/color_picker.ts b/src/components/color_picker/color_picker.ts
index 11ca424e88..20445130ec 100644
--- a/src/components/color_picker/color_picker.ts
+++ b/src/components/color_picker/color_picker.ts
@@ -1,3 +1,5 @@
+import { Color, Pixel, PixelPosition } from "@odoo/o-spreadsheet-engine";
+import { HSLA } from "@odoo/o-spreadsheet-engine/types";
import { Component, useState } from "@odoo/owl";
import { COLOR_PICKER_DEFAULTS, ICON_EDGE_LENGTH } from "../../constants";
import {
@@ -10,12 +12,10 @@ import {
toHex,
} from "../../helpers";
import { chartFontColor } from "../../helpers/figures/charts";
-import { Color, HSLA, Pixel, PixelPosition, Rect } from "../../types";
+import { Rect } from "../../types";
import { SpreadsheetChildEnv } from "../../types/env";
import { cssPropertiesToCss } from "../helpers/css";
import { startDnd } from "../helpers/drag_and_drop";
-import { Popover, PopoverProps } from "../popover/popover";
-
const ITEM_BORDER_WIDTH = 1;
const ITEM_EDGE_LENGTH = 18;
const ITEMS_PER_LINE = 10;
diff --git a/src/components/color_picker/color_picker_widget.ts b/src/components/color_picker/color_picker_widget.ts
index 61cc5b8291..af6c96de48 100644
--- a/src/components/color_picker/color_picker_widget.ts
+++ b/src/components/color_picker/color_picker_widget.ts
@@ -1,5 +1,6 @@
+import { Pixel } from "@odoo/o-spreadsheet-engine";
import { Component, useRef } from "@odoo/owl";
-import { Pixel, Rect, SpreadsheetChildEnv } from "../../types";
+import { Rect, SpreadsheetChildEnv } from "../../types";
import { ColorPicker } from "./color_picker";
interface Props {
diff --git a/src/components/composer/composer/abstract_composer_store.ts b/src/components/composer/composer/abstract_composer_store.ts
index 306db5308c..f8fb1571e7 100644
--- a/src/components/composer/composer/abstract_composer_store.ts
+++ b/src/components/composer/composer/abstract_composer_store.ts
@@ -2,18 +2,15 @@ import { DEFAULT_TOKEN_COLOR, tokenColors } from "../../../constants";
import { composerTokenize, EnrichedToken } from "../../../formulas/composer_tokenizer";
import { AST, iterateAstNodes, parseTokens } from "../../../formulas/parser";
import { POSTFIX_UNARY_OPERATORS } from "../../../formulas/tokenizer";
-import { functionRegistry } from "../../../functions";
import { isEvaluationError, transposeMatrix } from "../../../functions/helpers";
import { KeepLast } from "../../../helpers/concurrency";
import {
clip,
colors,
- concat,
formatValue,
fuzzyLookup,
getZoneArea,
isEqual,
- isFormula,
isNumber,
isSheetNameEqual,
positionToZone,
@@ -32,23 +29,7 @@ import { SpreadsheetStore } from "../../../stores";
import { HighlightStore } from "../../../stores/highlight_store";
import { NotificationStore } from "../../../stores/notification_store";
import { _t } from "../../../translation";
-import {
- CellPosition,
- Color,
- Command,
- Direction,
- EditionMode,
- FunctionResultObject,
- HeaderIndex,
- Highlight,
- isMatrix,
- Matrix,
- Range,
- RangePart,
- UID,
- UnboundedZone,
- Zone,
-} from "../../../types";
+import { Command, EditionMode, Range, RangePart } from "../../../types";
import { EvaluationError } from "../../../types/errors";
import { SelectionEvent } from "../../../types/event_stream";
import { AutoCompleteStore } from "../autocomplete_dropdown/autocomplete_dropdown_store";
diff --git a/src/components/composer/composer/cell_composer_store.ts b/src/components/composer/composer/cell_composer_store.ts
index 6d3d30dac6..f4df85ce52 100644
--- a/src/components/composer/composer/cell_composer_store.ts
+++ b/src/components/composer/composer/cell_composer_store.ts
@@ -5,7 +5,6 @@ import { parseLiteral } from "../../../helpers/cells";
import {
formatValue,
isDateTimeFormat,
- isFormula,
markdownLink,
numberToString,
parseDateTime,
@@ -19,18 +18,14 @@ import { criterionEvaluatorRegistry } from "../../../registries/criterion_regist
import { _t } from "../../../translation";
import {
AddColumnsRowsCommand,
- CellPosition,
CellValueType,
Command,
- Direction,
Format,
FormulaCell,
Locale,
RemoveColumnsRowsCommand,
- isMatrix,
} from "../../../types";
import { AbstractComposerStore } from "./abstract_composer_store";
-
const CELL_DELETED_MESSAGE = _t("The cell you are trying to edit has been deleted.");
export class CellComposerStore extends AbstractComposerStore {
diff --git a/src/components/composer/composer/composer.ts b/src/components/composer/composer/composer.ts
index 2b1aacb29b..c6943dc4b1 100644
--- a/src/components/composer/composer/composer.ts
+++ b/src/components/composer/composer/composer.ts
@@ -1,20 +1,15 @@
import { Component, onMounted, onWillUnmount, useEffect, useRef, useState } from "@odoo/owl";
import { NEWLINE, SCROLLBAR_WIDTH } from "../../../constants";
-import { functionRegistry } from "../../../functions/index";
-import { debounce, deepEquals, isFormula, setColorAlpha } from "../../../helpers/index";
+import { setColorAlpha } from "../../../helpers/index";
-import { DEFAULT_TOKEN_COLOR } from "../../../constants";
import { EnrichedToken } from "../../../formulas/composer_tokenizer";
import { argTargeting } from "../../../functions/arguments";
import { Store, useStore } from "../../../store_engine";
import { DOMFocusableElementStore } from "../../../stores/DOM_focus_store";
import {
- CSSProperties,
- Color,
ComposerFocusType,
+ CSSProperties,
DOMDimension,
- Direction,
- FunctionDescription,
Rect,
SpreadsheetChildEnv,
} from "../../../types/index";
@@ -25,9 +20,6 @@ import { updateSelectionWithArrowKeys } from "../../helpers/selection_helpers";
import { TextValueProvider } from "../autocomplete_dropdown/autocomplete_dropdown";
import { ContentEditableHelper } from "../content_editable_helper";
import { FunctionDescriptionProvider } from "../formula_assistant/formula_assistant";
-import { SpeechBubble } from "../speech_bubble/speech_bubble";
-import { CellComposerStore } from "./cell_composer_store";
-
const functions = functionRegistry.content;
const ASSISTANT_WIDTH = 300;
diff --git a/src/components/composer/content_editable_helper.ts b/src/components/composer/content_editable_helper.ts
index 14ca648b88..b82628971e 100644
--- a/src/components/composer/content_editable_helper.ts
+++ b/src/components/composer/content_editable_helper.ts
@@ -1,4 +1,5 @@
-import { deepEquals, toHex } from "../../helpers";
+import { deepEquals } from "@odoo/o-spreadsheet-engine";
+import { toHex } from "../../helpers";
import {
getBoundingRectAsPOJO,
getCurrentSelection,
diff --git a/src/components/composer/formula_assistant/formula_assistant.ts b/src/components/composer/formula_assistant/formula_assistant.ts
index 5bb6d6244e..16ee21316d 100644
--- a/src/components/composer/formula_assistant/formula_assistant.ts
+++ b/src/components/composer/formula_assistant/formula_assistant.ts
@@ -1,5 +1,6 @@
+import { FunctionDescription } from "@odoo/o-spreadsheet-engine";
import { Component, useState } from "@odoo/owl";
-import { FunctionDescription, SpreadsheetChildEnv } from "../../../types";
+import { SpreadsheetChildEnv } from "../../../types";
import { Collapse } from "../../side_panel/components/collapse/collapse";
interface Props {
diff --git a/src/components/composer/grid_composer/grid_composer.ts b/src/components/composer/grid_composer/grid_composer.ts
index b767decbe9..b9fd50ff0a 100644
--- a/src/components/composer/grid_composer/grid_composer.ts
+++ b/src/components/composer/grid_composer/grid_composer.ts
@@ -1,21 +1,7 @@
-import { Component, onWillUpdateProps } from "@odoo/owl";
import { SELECTION_BORDER_COLOR } from "../../../constants";
-import {
- deepEquals,
- fontSizeInPixels,
- getFullReference,
- isFormula,
- positionToZone,
- toXC,
-} from "../../../helpers";
+import { fontSizeInPixels, getFullReference, positionToZone, toXC } from "../../../helpers";
import { Store, useStore } from "../../../store_engine";
-import {
- CellPosition,
- ComposerFocusType,
- DOMDimension,
- Rect,
- SpreadsheetChildEnv,
-} from "../../../types/index";
+import { ComposerFocusType, DOMDimension, Rect, SpreadsheetChildEnv } from "../../../types/index";
import { getTextDecoration } from "../../helpers";
import { cssPropertiesToCss } from "../../helpers/css";
import { CellComposerStore } from "../composer/cell_composer_store";
diff --git a/src/components/composer/standalone_composer/standalone_composer.ts b/src/components/composer/standalone_composer/standalone_composer.ts
index cbad065224..2f2956dcaa 100644
--- a/src/components/composer/standalone_composer/standalone_composer.ts
+++ b/src/components/composer/standalone_composer/standalone_composer.ts
@@ -1,15 +1,14 @@
+import { Color, UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { Token } from "../../../formulas";
import { AutoCompleteProviderDefinition } from "../../../registries/auto_completes";
import { Store, useLocalStore, useStore } from "../../../store_engine";
-import { Color, ComposerFocusType, SpreadsheetChildEnv, UID } from "../../../types/index";
+import { ComposerFocusType, SpreadsheetChildEnv } from "../../../types/index";
import { cssPropertiesToCss } from "../../helpers/css";
import { useSpreadsheetRect } from "../../helpers/position_hook";
import { ComposerSelection } from "../composer/abstract_composer_store";
import { Composer } from "../composer/composer";
import { ComposerFocusStore, ComposerInterface } from "../composer_focus_store";
-import { StandaloneComposerStore } from "./standalone_composer_store";
-
interface Props {
onConfirm: (content: string) => void;
composerContent: string;
diff --git a/src/components/composer/standalone_composer/standalone_composer_store.ts b/src/components/composer/standalone_composer/standalone_composer_store.ts
index 58f838f299..438aa32c92 100644
--- a/src/components/composer/standalone_composer/standalone_composer_store.ts
+++ b/src/components/composer/standalone_composer/standalone_composer_store.ts
@@ -1,12 +1,10 @@
+import { Color, UID, UnboundedZone, Zone } from "@odoo/o-spreadsheet-engine";
import { Token, rangeTokenize } from "../../../formulas";
import { EnrichedToken } from "../../../formulas/composer_tokenizer";
import { localizeContent } from "../../../helpers/locale";
import { setXcToFixedReferenceType } from "../../../helpers/reference_type";
import { AutoCompleteProviderDefinition } from "../../../registries/auto_completes";
import { Get } from "../../../store_engine";
-import { Color, UID, UnboundedZone, Zone } from "../../../types";
-import { AbstractComposerStore } from "../composer/abstract_composer_store";
-
export interface StandaloneComposerArgs {
onConfirm: (content: string) => void;
content: string;
diff --git a/src/components/dashboard/clickable_cell_sort_icon/clickable_cell_sort_icon.ts b/src/components/dashboard/clickable_cell_sort_icon/clickable_cell_sort_icon.ts
index 333dd63be2..46eb5da121 100644
--- a/src/components/dashboard/clickable_cell_sort_icon/clickable_cell_sort_icon.ts
+++ b/src/components/dashboard/clickable_cell_sort_icon/clickable_cell_sort_icon.ts
@@ -1,11 +1,11 @@
+import { CellPosition, Color, Style } from "@odoo/o-spreadsheet-engine";
+import { SortDirection } from "@odoo/o-spreadsheet-engine/types";
import { Component } from "@odoo/owl";
import { TEXT_BODY_MUTED } from "../../../constants";
import { blendColors } from "../../../helpers";
import { Store, useStore } from "../../../store_engine";
-import { CellPosition, Color, SortDirection, SpreadsheetChildEnv, Style } from "../../../types";
+import { SpreadsheetChildEnv } from "../../../types";
import { cssPropertiesToCss } from "../../helpers";
-import { HoveredTableStore } from "../../tables/hovered_table_store";
-
interface Props {
position: CellPosition;
sortDirection: SortDirection | "none";
diff --git a/src/components/dashboard/clickable_cell_store.ts b/src/components/dashboard/clickable_cell_store.ts
index 53cdf35234..98b25a8993 100644
--- a/src/components/dashboard/clickable_cell_store.ts
+++ b/src/components/dashboard/clickable_cell_store.ts
@@ -1,15 +1,9 @@
+import { CellPosition, UID } from "@odoo/o-spreadsheet-engine";
import { ComponentConstructor, markRaw } from "@odoo/owl";
import { positionToZone, toXC } from "../../helpers";
import { CellClickableItem, clickableCellRegistry } from "../../registries/cell_clickable_registry";
import { SpreadsheetStore } from "../../stores/spreadsheet_store";
-import {
- CellPosition,
- Command,
- Rect,
- SpreadsheetChildEnv,
- UID,
- invalidateEvaluationCommands,
-} from "../../types";
+import { Rect, SpreadsheetChildEnv } from "../../types";
export interface ClickableCell {
coordinates: Rect;
diff --git a/src/components/dashboard/dashboard.ts b/src/components/dashboard/dashboard.ts
index a727090d61..310eb564c6 100644
--- a/src/components/dashboard/dashboard.ts
+++ b/src/components/dashboard/dashboard.ts
@@ -1,13 +1,8 @@
+import { Pixel } from "@odoo/o-spreadsheet-engine";
+import { Ref } from "@odoo/o-spreadsheet-engine/types";
import { Component, toRaw, useChildSubEnv, useRef } from "@odoo/owl";
import { Store, useStore } from "../../store_engine";
-import {
- DOMCoordinates,
- DOMDimension,
- Pixel,
- Rect,
- Ref,
- SpreadsheetChildEnv,
-} from "../../types/index";
+import { DOMCoordinates, DOMDimension, Rect, SpreadsheetChildEnv } from "../../types/index";
import { DelayedHoveredCellStore } from "../grid/delayed_hovered_cell_store";
import { GridOverlay } from "../grid_overlay/grid_overlay";
import { GridPopover } from "../grid_popover/grid_popover";
diff --git a/src/components/error_tooltip/error_tooltip.ts b/src/components/error_tooltip/error_tooltip.ts
index 1ce653ce22..d6a5b71217 100644
--- a/src/components/error_tooltip/error_tooltip.ts
+++ b/src/components/error_tooltip/error_tooltip.ts
@@ -1,6 +1,7 @@
+import { CellPosition, deepEquals } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
-import { deepEquals, positionToZone } from "../../helpers";
-import { CellPosition, CellValueType, SpreadsheetChildEnv } from "../../types";
+import { positionToZone } from "../../helpers";
+import { CellValueType, SpreadsheetChildEnv } from "../../types";
import { CellPopoverComponent, PopoverBuilders } from "../../types/cell_popovers";
const ERROR_TOOLTIP_MAX_HEIGHT = 80;
diff --git a/src/components/figures/chart/chartJs/chartjs.ts b/src/components/figures/chart/chartJs/chartjs.ts
index 487efcce52..85954b76a8 100644
--- a/src/components/figures/chart/chartJs/chartjs.ts
+++ b/src/components/figures/chart/chartJs/chartjs.ts
@@ -1,8 +1,9 @@
+import { deepEquals, UID } from "@odoo/o-spreadsheet-engine";
import { Component, onMounted, onWillUnmount, useEffect, useRef } from "@odoo/owl";
import { Chart, ChartConfiguration } from "chart.js/auto";
-import { deepCopy, deepEquals } from "../../../../helpers";
+import { deepCopy } from "../../../../helpers";
import { Store, useStore } from "../../../../store_engine";
-import { SpreadsheetChildEnv, UID } from "../../../../types";
+import { SpreadsheetChildEnv } from "../../../../types";
import { ChartJSRuntime } from "../../../../types/chart/chart";
import { chartJsExtensionRegistry, registerChartJSExtensions } from "./chart_js_extension";
import { ChartAnimationStore } from "./chartjs_animation_store";
diff --git a/src/components/figures/chart/chartJs/chartjs_animation_store.ts b/src/components/figures/chart/chartJs/chartjs_animation_store.ts
index 543a9a5d88..6be126e684 100644
--- a/src/components/figures/chart/chartJs/chartjs_animation_store.ts
+++ b/src/components/figures/chart/chartJs/chartjs_animation_store.ts
@@ -1,5 +1,6 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { SpreadsheetStore } from "../../../../stores/spreadsheet_store";
-import { ChartType, UID } from "../../../../types";
+import { ChartType } from "../../../../types";
export class ChartAnimationStore extends SpreadsheetStore {
mutators = ["disableAnimationForChart", "enableAnimationForChart"] as const;
diff --git a/src/components/figures/chart/chartJs/chartjs_show_values_plugin.ts b/src/components/figures/chart/chartJs/chartjs_show_values_plugin.ts
index f4aa7039be..bc846d0380 100644
--- a/src/components/figures/chart/chartJs/chartjs_show_values_plugin.ts
+++ b/src/components/figures/chart/chartJs/chartjs_show_values_plugin.ts
@@ -1,7 +1,8 @@
import { ChartMeta, ChartType, Plugin } from "chart.js";
import { computeTextWidth } from "../../../../helpers";
import { chartFontColor, isTrendLineAxis } from "../../../../helpers/figures/charts/chart_common";
-import { Color } from "../../../../types";
+
+import { Color } from "@odoo/o-spreadsheet-engine";
export interface ChartShowValuesPluginOptions {
showValues: boolean;
diff --git a/src/components/figures/chart/chartJs/chartjs_sunburst_labels_plugin.ts b/src/components/figures/chart/chartJs/chartjs_sunburst_labels_plugin.ts
index 59c76eb89a..d4d66cecdb 100644
--- a/src/components/figures/chart/chartJs/chartjs_sunburst_labels_plugin.ts
+++ b/src/components/figures/chart/chartJs/chartjs_sunburst_labels_plugin.ts
@@ -1,12 +1,5 @@
-import { ChartType, Plugin } from "chart.js";
-import {
- getDefaultContextFont,
- isDefined,
- relativeLuminance,
- sliceTextToFitWidth,
-} from "../../../../helpers";
+import { getDefaultContextFont, relativeLuminance, sliceTextToFitWidth } from "../../../../helpers";
import { GHOST_SUNBURST_VALUE } from "../../../../helpers/figures/charts/runtime/chartjs_dataset";
-import { Style } from "../../../../types";
import { SunburstChartRawData } from "../../../../types/chart";
export interface ChartSunburstLabelsPluginOptions {
diff --git a/src/components/figures/chart/chartJs/zoomable_chart/zoomable_chart_store.ts b/src/components/figures/chart/chartJs/zoomable_chart/zoomable_chart_store.ts
index ae2e92d3cd..8b7caeee43 100644
--- a/src/components/figures/chart/chartJs/zoomable_chart/zoomable_chart_store.ts
+++ b/src/components/figures/chart/chartJs/zoomable_chart/zoomable_chart_store.ts
@@ -1,4 +1,5 @@
-import { Command, UID } from "../../../../..";
+import { UID } from "@odoo/o-spreadsheet-engine";
+import { Command } from "../../../../..";
import {
MOVING_AVERAGE_TREND_LINE_XAXIS_ID,
TREND_LINE_XAXIS_ID,
diff --git a/src/components/figures/chart/chart_dashboard_menu/chart_dashboard_menu.ts b/src/components/figures/chart/chart_dashboard_menu/chart_dashboard_menu.ts
index 5585bdd878..7ab5d67791 100644
--- a/src/components/figures/chart/chart_dashboard_menu/chart_dashboard_menu.ts
+++ b/src/components/figures/chart/chart_dashboard_menu/chart_dashboard_menu.ts
@@ -1,10 +1,8 @@
-import { Component, useState } from "@odoo/owl";
import { getChartMenuActions } from "../../../../actions/figure_menu_actions";
import { BACKGROUND_CHART_COLOR } from "../../../../constants";
-import { isDefined } from "../../../../helpers";
import { Store, useStore } from "../../../../store_engine";
import { _t } from "../../../../translation";
-import { SpreadsheetChildEnv, UID } from "../../../../types";
+import { SpreadsheetChildEnv } from "../../../../types";
import { FullScreenChartStore } from "../../../full_screen_chart/full_screen_chart_store";
import { MenuPopover, MenuState } from "../../../menu_popover/menu_popover";
diff --git a/src/components/figures/chart/gauge/gauge_chart_component.ts b/src/components/figures/chart/gauge/gauge_chart_component.ts
index 931f9138ac..78d36ebcc3 100644
--- a/src/components/figures/chart/gauge/gauge_chart_component.ts
+++ b/src/components/figures/chart/gauge/gauge_chart_component.ts
@@ -1,9 +1,9 @@
+import { deepEquals, UID } from "@odoo/o-spreadsheet-engine";
import { Component, useEffect, useRef } from "@odoo/owl";
-import { deepEquals } from "../../../../helpers";
import { drawGaugeChart } from "../../../../helpers/figures/charts/gauge_chart_rendering";
import { EASING_FN } from "../../../../registries/cell_animation_registry";
import { Store, useStore } from "../../../../store_engine";
-import { SpreadsheetChildEnv, UID } from "../../../../types";
+import { SpreadsheetChildEnv } from "../../../../types";
import { GaugeChartRuntime } from "../../../../types/chart";
import { ChartAnimationStore } from "../chartJs/chartjs_animation_store";
diff --git a/src/components/figures/chart/scorecard/chart_scorecard.ts b/src/components/figures/chart/scorecard/chart_scorecard.ts
index a6670ee8b5..4f43e0cc58 100644
--- a/src/components/figures/chart/scorecard/chart_scorecard.ts
+++ b/src/components/figures/chart/scorecard/chart_scorecard.ts
@@ -1,7 +1,8 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component, useEffect, useRef } from "@odoo/owl";
import { drawScoreChart } from "../../../../helpers/figures/charts/scorecard_chart";
import { getScorecardConfiguration } from "../../../../helpers/figures/charts/scorecard_chart_config_builder";
-import { SpreadsheetChildEnv, UID } from "../../../../types";
+import { SpreadsheetChildEnv } from "../../../../types";
import { ScorecardChartRuntime } from "../../../../types/chart/scorecard_chart";
interface Props {
diff --git a/src/components/figures/figure/figure.ts b/src/components/figures/figure/figure.ts
index f858729651..bac51d7790 100644
--- a/src/components/figures/figure/figure.ts
+++ b/src/components/figures/figure/figure.ts
@@ -1,3 +1,4 @@
+import { Pixel, UID } from "@odoo/o-spreadsheet-engine";
import { Component, onWillUnmount, useEffect, useRef, useState } from "@odoo/owl";
import { FIGURE_BORDER_COLOR, SELECTION_BORDER_COLOR } from "../../../constants";
import { figureRegistry } from "../../../registries/figures_registry";
@@ -5,16 +6,12 @@ import {
AnchorOffset,
CSSProperties,
FigureUI,
- Pixel,
Rect,
ResizeDirection,
SpreadsheetChildEnv,
- UID,
} from "../../../types/index";
import { cssPropertiesToCss } from "../../helpers/css";
import { getRefBoundingRect, keyboardEventToShortcutString } from "../../helpers/dom_helpers";
-import { MenuPopover, MenuState } from "../../menu_popover/menu_popover";
-
type ResizeAnchor =
| "top left"
| "top"
diff --git a/src/components/figures/figure_carousel/figure_carousel.ts b/src/components/figures/figure_carousel/figure_carousel.ts
index 8e53bde51b..794d78e059 100644
--- a/src/components/figures/figure_carousel/figure_carousel.ts
+++ b/src/components/figures/figure_carousel/figure_carousel.ts
@@ -1,7 +1,8 @@
+import { deepEquals, MenuMouseEvent } from "@odoo/o-spreadsheet-engine";
import { Component, useEffect, useRef, useState } from "@odoo/owl";
import { ActionSpec, createActions } from "../../../actions/action";
import { DEFAULT_CAROUSEL_TITLE_STYLE } from "../../../constants";
-import { chartStyleToCellStyle, deepEquals } from "../../../helpers";
+import { chartStyleToCellStyle } from "../../../helpers";
import { getCarouselItemTitle } from "../../../helpers/carousel_helpers";
import { chartComponentRegistry } from "../../../registries/chart_types";
import { Store, useStore } from "../../../store_engine";
@@ -10,7 +11,6 @@ import {
CarouselItem,
CSSProperties,
FigureUI,
- MenuMouseEvent,
SpreadsheetChildEnv,
} from "../../../types";
import { cellTextStyleToCss, cssPropertiesToCss } from "../../helpers";
diff --git a/src/components/figures/figure_chart/figure_chart.ts b/src/components/figures/figure_chart/figure_chart.ts
index 1436fb7fad..aba29a4425 100644
--- a/src/components/figures/figure_chart/figure_chart.ts
+++ b/src/components/figures/figure_chart/figure_chart.ts
@@ -1,6 +1,7 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { chartComponentRegistry } from "../../../registries/chart_types";
-import { ChartType, CSSProperties, FigureUI, SpreadsheetChildEnv, UID } from "../../../types";
+import { ChartType, CSSProperties, FigureUI, SpreadsheetChildEnv } from "../../../types";
import { ChartDashboardMenu } from "../chart/chart_dashboard_menu/chart_dashboard_menu";
interface Props {
diff --git a/src/components/figures/figure_container/figure_container.ts b/src/components/figures/figure_container/figure_container.ts
index 5549a56128..8ccdf79a5b 100644
--- a/src/components/figures/figure_container/figure_container.ts
+++ b/src/components/figures/figure_container/figure_container.ts
@@ -1,6 +1,4 @@
-import { Component, onMounted, onWillUpdateProps, useState } from "@odoo/owl";
import { DRAG_THRESHOLD, MIN_FIG_SIZE } from "../../../constants";
-import { isDefined } from "../../../helpers";
import { rectUnion } from "../../../helpers/rectangle";
import { figureRegistry } from "../../../registries/figures_registry";
import {
@@ -10,17 +8,16 @@ import {
Rect,
ResizeDirection,
SpreadsheetChildEnv,
- UID,
} from "../../../types/index";
import { cssPropertiesToCss } from "../../helpers";
import { startDnd } from "../../helpers/drag_and_drop";
import { dragFigureForMove, dragFigureForResize } from "../../helpers/figure_drag_helper";
import {
HFigureAxisType,
- SnapLine,
- VFigureAxisType,
snapForMove,
snapForResize,
+ SnapLine,
+ VFigureAxisType,
} from "../../helpers/figure_snap_helper";
import { FigureComponent } from "../figure/figure";
diff --git a/src/components/figures/figure_image/figure_image.ts b/src/components/figures/figure_image/figure_image.ts
index 2e603f1f6f..f3be325daa 100644
--- a/src/components/figures/figure_image/figure_image.ts
+++ b/src/components/figures/figure_image/figure_image.ts
@@ -1,5 +1,6 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
-import { CSSProperties, FigureUI, SpreadsheetChildEnv, UID } from "../../../types";
+import { CSSProperties, FigureUI, SpreadsheetChildEnv } from "../../../types";
interface Props {
figureUI: FigureUI;
diff --git a/src/components/filters/filter_menu/filter_menu.ts b/src/components/filters/filter_menu/filter_menu.ts
index 8f15d477a2..43495f82b2 100644
--- a/src/components/filters/filter_menu/filter_menu.ts
+++ b/src/components/filters/filter_menu/filter_menu.ts
@@ -1,16 +1,16 @@
+import { deepEquals, Position } from "@odoo/o-spreadsheet-engine";
+import { SortDirection } from "@odoo/o-spreadsheet-engine/types";
import { Component, onWillUpdateProps } from "@odoo/owl";
-import { deepEquals, isDateTimeFormat } from "../../../helpers";
+import { isDateTimeFormat } from "../../../helpers";
import { interactiveSort } from "../../../helpers/sort";
import {
CellValueType,
CriterionFilter,
DataFilterValue,
- Position,
- SortDirection,
- SpreadsheetChildEnv,
filterDateCriterionOperators,
filterNumberCriterionOperators,
filterTextCriterionOperators,
+ SpreadsheetChildEnv,
} from "../../../types";
import { CellPopoverComponent, PopoverBuilders } from "../../../types/cell_popovers";
import { SidePanelCollapsible } from "../../side_panel/components/collapsible/side_panel_collapsible";
diff --git a/src/components/filters/filter_menu_criterion/filter_menu_criterion.ts b/src/components/filters/filter_menu_criterion/filter_menu_criterion.ts
index 1d5ae0fe05..1148f6d370 100644
--- a/src/components/filters/filter_menu_criterion/filter_menu_criterion.ts
+++ b/src/components/filters/filter_menu_criterion/filter_menu_criterion.ts
@@ -1,18 +1,14 @@
+import { deepEquals, Position } from "@odoo/o-spreadsheet-engine";
import { Component, ComponentConstructor, onWillUpdateProps, useState } from "@odoo/owl";
import { Action, createAction } from "../../../actions/action";
-import { deepCopy, deepEquals } from "../../../helpers";
+import { deepCopy } from "../../../helpers";
import {
criterionComponentRegistry,
getCriterionMenuItems,
} from "../../../registries/criterion_component_registry";
import { criterionEvaluatorRegistry } from "../../../registries/criterion_registry";
import { _t } from "../../../translation";
-import {
- CriterionFilter,
- GenericCriterionType,
- Position,
- SpreadsheetChildEnv,
-} from "../../../types";
+import { CriterionFilter, GenericCriterionType, SpreadsheetChildEnv } from "../../../types";
import { SelectMenu } from "../../side_panel/select_menu/select_menu";
interface Props {
diff --git a/src/components/filters/filter_menu_value_list/filter_menu_value_list.ts b/src/components/filters/filter_menu_value_list/filter_menu_value_list.ts
index 38dd48571a..2c6eb9517c 100644
--- a/src/components/filters/filter_menu_value_list/filter_menu_value_list.ts
+++ b/src/components/filters/filter_menu_value_list/filter_menu_value_list.ts
@@ -1,7 +1,8 @@
+import { deepEquals, Position } from "@odoo/o-spreadsheet-engine";
import { Component, onWillUpdateProps, useRef, useState } from "@odoo/owl";
-import { deepEquals, positions, toLowerCase } from "../../../helpers";
+import { positions, toLowerCase } from "../../../helpers";
import { fuzzyLookup } from "../../../helpers/search";
-import { Position, SpreadsheetChildEnv } from "../../../types";
+import { SpreadsheetChildEnv } from "../../../types";
import { FilterMenuValueItem } from "../filter_menu_item/filter_menu_value_item";
interface Props {
diff --git a/src/components/full_screen_chart/full_screen_chart_store.ts b/src/components/full_screen_chart/full_screen_chart_store.ts
index a6bdc73064..7c723f8cbc 100644
--- a/src/components/full_screen_chart/full_screen_chart_store.ts
+++ b/src/components/full_screen_chart/full_screen_chart_store.ts
@@ -1,5 +1,6 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { SpreadsheetStore } from "../../stores";
-import { FigureUI, UID } from "../../types";
+import { FigureUI } from "../../types";
export class FullScreenChartStore extends SpreadsheetStore {
mutators = ["toggleFullScreenChart"] as const;
diff --git a/src/components/grid/delayed_hovered_cell_store.ts b/src/components/grid/delayed_hovered_cell_store.ts
index ea330c79e5..11f242ef42 100644
--- a/src/components/grid/delayed_hovered_cell_store.ts
+++ b/src/components/grid/delayed_hovered_cell_store.ts
@@ -1,5 +1,6 @@
+import { Position } from "@odoo/o-spreadsheet-engine";
import { SpreadsheetStore } from "../../stores";
-import { Command, Position } from "../../types";
+import { Command } from "../../types";
export class DelayedHoveredCellStore extends SpreadsheetStore {
mutators = ["clear", "hover"] as const;
diff --git a/src/components/grid/grid.ts b/src/components/grid/grid.ts
index daaac21860..d9ba8abb1c 100644
--- a/src/components/grid/grid.ts
+++ b/src/components/grid/grid.ts
@@ -1,3 +1,5 @@
+import { Align, HeaderIndex, Pixel } from "@odoo/o-spreadsheet-engine";
+import { Dimension, Direction, Ref } from "@odoo/o-spreadsheet-engine/types";
import {
Component,
onMounted,
@@ -41,19 +43,13 @@ import { ClientFocusStore } from "../../stores/client_focus_store";
import { HighlightStore } from "../../stores/highlight_store";
import { AllowedImageMimeTypes } from "../../types/image";
import {
- Align,
CellValueType,
Client,
ClipboardMIMEType,
DOMCoordinates,
DOMDimension,
- Dimension,
- Direction,
GridClickModifiers,
- HeaderIndex,
- Pixel,
Rect,
- Ref,
SpreadsheetChildEnv,
Table,
} from "../../types/index";
diff --git a/src/components/grid_overlay/grid_overlay.ts b/src/components/grid_overlay/grid_overlay.ts
index bdf673e739..0fa6c867dc 100644
--- a/src/components/grid_overlay/grid_overlay.ts
+++ b/src/components/grid_overlay/grid_overlay.ts
@@ -1,17 +1,10 @@
+import { deepEquals, HeaderIndex, Pixel, Position } from "@odoo/o-spreadsheet-engine";
+import { Ref } from "@odoo/o-spreadsheet-engine/types";
import { Component, onMounted, onWillUnmount, useExternalListener, useRef } from "@odoo/owl";
-import { deepEquals, positionToZone } from "../../helpers";
+import { positionToZone } from "../../helpers";
import { isPointInsideRect } from "../../helpers/rectangle";
import { Store, useStore } from "../../store_engine";
-import {
- DOMCoordinates,
- GridClickModifiers,
- HeaderIndex,
- Pixel,
- Position,
- Rect,
- Ref,
- SpreadsheetChildEnv,
-} from "../../types";
+import { DOMCoordinates, GridClickModifiers, Rect, SpreadsheetChildEnv } from "../../types";
import { FiguresContainer } from "../figures/figure_container/figure_container";
import { DelayedHoveredCellStore } from "../grid/delayed_hovered_cell_store";
import { GridAddRowsFooter } from "../grid_add_rows_footer/grid_add_rows_footer";
@@ -27,8 +20,6 @@ import { useInterval } from "../helpers/time_hooks";
import { PaintFormatStore } from "../paint_format_button/paint_format_store";
import { CellPopoverStore } from "../popover";
import { HoveredTableStore } from "../tables/hovered_table_store";
-import { HoveredIconStore } from "./hovered_icon_store";
-
function useCellHovered(env: SpreadsheetChildEnv, gridRef: Ref): Partial {
const delayedHoveredCell = useStore(DelayedHoveredCellStore);
const hoveredTable = useStore(HoveredTableStore);
diff --git a/src/components/grid_overlay/hovered_icon_store.ts b/src/components/grid_overlay/hovered_icon_store.ts
index 710b21adc5..f765603295 100644
--- a/src/components/grid_overlay/hovered_icon_store.ts
+++ b/src/components/grid_overlay/hovered_icon_store.ts
@@ -1,5 +1,6 @@
import { SpreadsheetStore } from "../../stores";
-import { CellPosition } from "../../types";
+
+import { CellPosition } from "@odoo/o-spreadsheet-engine";
interface HoveredIcon {
id: string;
diff --git a/src/components/header_group/header_group.ts b/src/components/header_group/header_group.ts
index a81e1806a3..19d10308da 100644
--- a/src/components/header_group/header_group.ts
+++ b/src/components/header_group/header_group.ts
@@ -1,3 +1,5 @@
+import { HeaderGroup } from "@odoo/o-spreadsheet-engine";
+import { Dimension } from "@odoo/o-spreadsheet-engine/types";
import { Component } from "@odoo/owl";
import { Action } from "../../actions/action";
import {
@@ -8,7 +10,7 @@ import {
} from "../../constants";
import { interactiveToggleGroup } from "../../helpers/ui/toggle_group_interactive";
import { getHeaderGroupContextMenu } from "../../registries/menus/header_group_registry";
-import { DOMCoordinates, Dimension, HeaderGroup, Rect } from "../../types";
+import { DOMCoordinates, Rect } from "../../types";
import { SpreadsheetChildEnv } from "../../types/env";
import { cssPropertiesToCss } from "../helpers";
diff --git a/src/components/header_group/header_group_container.ts b/src/components/header_group/header_group_container.ts
index a4ad343e3d..33be52f75d 100644
--- a/src/components/header_group/header_group_container.ts
+++ b/src/components/header_group/header_group_container.ts
@@ -1,14 +1,14 @@
+import { HeaderGroup, Pixel } from "@odoo/o-spreadsheet-engine";
+import { Dimension } from "@odoo/o-spreadsheet-engine/types";
import { Component, useState } from "@odoo/owl";
import { Action } from "../../actions/action";
import { GROUP_LAYER_WIDTH } from "../../constants";
import { createHeaderGroupContainerContextMenu } from "../../registries/menus/header_group_registry";
import { DOMCoordinates, SpreadsheetChildEnv } from "../../types";
-import { CSSProperties, Dimension, HeaderGroup, Pixel } from "../../types/misc";
+import { CSSProperties } from "../../types/misc";
import { cssPropertiesToCss } from "../helpers";
import { MenuPopover, MenuState } from "../menu_popover/menu_popover";
import { HEADER_HEIGHT, HEADER_WIDTH } from "./../../constants";
-import { ColGroup, RowGroup } from "./header_group";
-
interface Props {
dimension: Dimension;
layers: HeaderGroup[][];
diff --git a/src/components/headers_overlay/headers_overlay.ts b/src/components/headers_overlay/headers_overlay.ts
index ccd1b5fcfe..960d03711f 100644
--- a/src/components/headers_overlay/headers_overlay.ts
+++ b/src/components/headers_overlay/headers_overlay.ts
@@ -1,15 +1,9 @@
+import { HeaderDimensions, HeaderIndex, Pixel } from "@odoo/o-spreadsheet-engine";
+import { Ref } from "@odoo/o-spreadsheet-engine/types";
import { Component, useRef, useState } from "@odoo/owl";
import { MIN_COL_WIDTH, MIN_ROW_HEIGHT } from "../../constants";
import { Store, useStore } from "../../store_engine";
-import {
- CommandResult,
- EdgeScrollInfo,
- HeaderDimensions,
- HeaderIndex,
- Pixel,
- Ref,
- SpreadsheetChildEnv,
-} from "../../types/index";
+import { CommandResult, EdgeScrollInfo, SpreadsheetChildEnv } from "../../types/index";
import { ContextMenuType } from "../grid/grid";
import { cssPropertiesToCss } from "../helpers/css";
import { isCtrlKey } from "../helpers/dom_helpers";
diff --git a/src/components/headers_overlay/unhide_headers.ts b/src/components/headers_overlay/unhide_headers.ts
index e4915493d1..49c92df5c1 100644
--- a/src/components/headers_overlay/unhide_headers.ts
+++ b/src/components/headers_overlay/unhide_headers.ts
@@ -1,9 +1,7 @@
+import { ConsecutiveIndexes, HeaderIndex } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { HEADER_HEIGHT, HEADER_WIDTH } from "../../constants";
import { positionToZone } from "../../helpers";
-import { ConsecutiveIndexes, HeaderIndex, SpreadsheetChildEnv } from "../../types";
-import { cssPropertiesToCss } from "../helpers";
-
interface Props {
headersGroups: ConsecutiveIndexes[];
offset: number;
diff --git a/src/components/helpers/css.ts b/src/components/helpers/css.ts
index 86a39a68ef..21d704ae01 100644
--- a/src/components/helpers/css.ts
+++ b/src/components/helpers/css.ts
@@ -7,7 +7,8 @@
* created for the first time.
*/
-import { CSSProperties, Style } from "../../types";
+import { Style } from "@odoo/o-spreadsheet-engine";
+import { CSSProperties } from "../../types";
export function getTextDecoration({
strikethrough,
diff --git a/src/components/helpers/dom_helpers.ts b/src/components/helpers/dom_helpers.ts
index 0ef84785a2..57605feab9 100644
--- a/src/components/helpers/dom_helpers.ts
+++ b/src/components/helpers/dom_helpers.ts
@@ -1,4 +1,4 @@
-import { Ref } from "../../types/misc";
+import { Ref } from "@odoo/o-spreadsheet-engine/types";
import { Rect } from "./../../types/rendering";
const macRegex = /Mac/i;
diff --git a/src/components/helpers/drag_and_drop_dom_items_hook.ts b/src/components/helpers/drag_and_drop_dom_items_hook.ts
index 3d426453a4..af12618361 100644
--- a/src/components/helpers/drag_and_drop_dom_items_hook.ts
+++ b/src/components/helpers/drag_and_drop_dom_items_hook.ts
@@ -1,8 +1,6 @@
+import { Pixel, UID } from "@odoo/o-spreadsheet-engine";
import { onWillUnmount, useState } from "@odoo/owl";
-import { CSSProperties, Pixel, UID } from "../../types";
-import { cssPropertiesToCss } from "./css";
-import { startDnd } from "./drag_and_drop";
-
+import { CSSProperties } from "../../types";
type Direction = "horizontal" | "vertical";
interface DragAndDropItemsPartial {
diff --git a/src/components/helpers/drag_and_drop_grid_hook.ts b/src/components/helpers/drag_and_drop_grid_hook.ts
index 530ccda327..22b95fbaa8 100644
--- a/src/components/helpers/drag_and_drop_grid_hook.ts
+++ b/src/components/helpers/drag_and_drop_grid_hook.ts
@@ -1,10 +1,8 @@
+import { HeaderIndex, Pixel } from "@odoo/o-spreadsheet-engine";
import { onWillUnmount, useEffect } from "@odoo/owl";
import { MAX_DELAY } from "../../helpers";
import { SpreadsheetChildEnv } from "../../types/env";
-import { HeaderIndex, Pixel } from "../../types/misc";
import { gridOverlayPosition } from "./dom_helpers";
-import { startDnd } from "./drag_and_drop";
-
export type DnDDirection = "all" | "vertical" | "horizontal";
/**
diff --git a/src/components/helpers/figure_drag_helper.ts b/src/components/helpers/figure_drag_helper.ts
index ed0e10aa80..ff62c72909 100644
--- a/src/components/helpers/figure_drag_helper.ts
+++ b/src/components/helpers/figure_drag_helper.ts
@@ -1,5 +1,6 @@
+import { PixelPosition } from "@odoo/o-spreadsheet-engine";
import { clip } from "../../helpers";
-import { FigureUI, PixelPosition, SheetDOMScrollInfo } from "../../types";
+import { FigureUI, SheetDOMScrollInfo } from "../../types";
export function dragFigureForMove(
{ x: mouseX, y: mouseY }: PixelPosition,
diff --git a/src/components/helpers/figure_snap_helper.ts b/src/components/helpers/figure_snap_helper.ts
index 82fdcdba4d..4727df1bcf 100644
--- a/src/components/helpers/figure_snap_helper.ts
+++ b/src/components/helpers/figure_snap_helper.ts
@@ -1,6 +1,4 @@
-import { FigureUI, Getters, Pixel, PixelPosition, UID } from "../../types";
-import { FIGURE_BORDER_WIDTH } from "./../../constants";
-
+import { Pixel, PixelPosition, UID } from "@odoo/o-spreadsheet-engine";
const SNAP_MARGIN: Pixel = 5;
export type HFigureAxisType = "top" | "bottom" | "vCenter";
diff --git a/src/components/helpers/highlight_hook.ts b/src/components/helpers/highlight_hook.ts
index 2d628a6d13..fe95736105 100644
--- a/src/components/helpers/highlight_hook.ts
+++ b/src/components/helpers/highlight_hook.ts
@@ -1,8 +1,8 @@
+import { deepEquals } from "@odoo/o-spreadsheet-engine";
+import { Ref } from "@odoo/o-spreadsheet-engine/types";
import { onMounted, useEffect } from "@odoo/owl";
-import { deepEquals } from "../../helpers";
import { useLocalStore, useStoreProvider } from "../../store_engine";
import { HighlightProvider, HighlightStore } from "../../stores/highlight_store";
-import { Ref } from "../../types";
import { useHoveredElement } from "./listener_hook";
export function useHighlightsOnHover(ref: Ref, highlightProvider: HighlightProvider) {
diff --git a/src/components/helpers/listener_hook.ts b/src/components/helpers/listener_hook.ts
index a871ecca75..3738ab407f 100644
--- a/src/components/helpers/listener_hook.ts
+++ b/src/components/helpers/listener_hook.ts
@@ -1,5 +1,6 @@
import { useEffect, useState } from "@odoo/owl";
-import { Ref } from "../../types";
+
+import { Ref } from "@odoo/o-spreadsheet-engine/types";
/**
* Manages an event listener on a ref. Useful for hooks that want to manage
diff --git a/src/components/helpers/touch_scroll_hook.ts b/src/components/helpers/touch_scroll_hook.ts
index 7598f8df51..80d7cbcc6f 100644
--- a/src/components/helpers/touch_scroll_hook.ts
+++ b/src/components/helpers/touch_scroll_hook.ts
@@ -1,4 +1,4 @@
-import { Ref } from "../../types";
+import { Ref } from "@odoo/o-spreadsheet-engine/types";
import { useRefListener } from "./listener_hook";
const friction = 0.95;
diff --git a/src/components/highlight/border/border.ts b/src/components/highlight/border/border.ts
index a5c92b6f4d..0a365244eb 100644
--- a/src/components/highlight/border/border.ts
+++ b/src/components/highlight/border/border.ts
@@ -1,5 +1,6 @@
+import { Zone } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
-import { SpreadsheetChildEnv, Zone } from "../../../types";
+import { SpreadsheetChildEnv } from "../../../types";
import { cssPropertiesToCss } from "../../helpers/css";
type Orientation = "n" | "s" | "w" | "e";
diff --git a/src/components/highlight/corner/corner.ts b/src/components/highlight/corner/corner.ts
index 3ac4df8d6f..7bd41a5f4d 100644
--- a/src/components/highlight/corner/corner.ts
+++ b/src/components/highlight/corner/corner.ts
@@ -1,8 +1,7 @@
+import { Color, Zone } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { AUTOFILL_EDGE_LENGTH } from "../../../constants";
-import { Color, ResizeDirection, SpreadsheetChildEnv, Zone } from "../../../types";
-import { cssPropertiesToCss } from "../../helpers/css";
-
+import { ResizeDirection, SpreadsheetChildEnv } from "../../../types";
const MOBILE_HANDLER_WIDTH = 40;
type Orientation = "nw" | "ne" | "sw" | "se" | "n" | "s" | "e" | "w";
diff --git a/src/components/highlight/highlight/highlight.ts b/src/components/highlight/highlight/highlight.ts
index 1adc15226b..451b70d586 100644
--- a/src/components/highlight/highlight/highlight.ts
+++ b/src/components/highlight/highlight/highlight.ts
@@ -1,21 +1,13 @@
+import { Color, HeaderIndex, Zone } from "@odoo/o-spreadsheet-engine";
import { Component, useState } from "@odoo/owl";
import { clip, isEqual } from "../../../helpers";
-import {
- Color,
- HeaderIndex,
- Range,
- ResizeDirection,
- SpreadsheetChildEnv,
- Zone,
-} from "../../../types";
+import { Range, ResizeDirection, SpreadsheetChildEnv } from "../../../types";
import { gridOverlayPosition } from "../../helpers/dom_helpers";
import {
DnDDirection,
useDragAndDropBeyondTheViewport,
} from "../../helpers/drag_and_drop_grid_hook";
import { Border } from "../border/border";
-import { Corner } from "../corner/corner";
-
export interface HighlightProps {
range: Range;
color: Color;
diff --git a/src/components/icons/icons.ts b/src/components/icons/icons.ts
index cff2ecd56d..bf18cefd7f 100644
--- a/src/components/icons/icons.ts
+++ b/src/components/icons/icons.ts
@@ -1,13 +1,3 @@
-import {
- ACTION_COLOR,
- FILTERS_COLOR,
- GRAY_200,
- GRAY_300,
- GRAY_900,
- TEXT_BODY_MUTED,
-} from "../../constants";
-import { isDefined } from "../../helpers";
-import { Style } from "../../types";
import { ImageSVG } from "../../types/image";
export type IconSetType = keyof typeof ICON_SETS;
diff --git a/src/components/link/link_display/link_display.ts b/src/components/link/link_display/link_display.ts
index dbab483287..2dd5cc01b0 100644
--- a/src/components/link/link_display/link_display.ts
+++ b/src/components/link/link_display/link_display.ts
@@ -1,9 +1,11 @@
+import { Position } from "@odoo/o-spreadsheet-engine";
+import { Link } from "@odoo/o-spreadsheet-engine/types";
import { Component } from "@odoo/owl";
import { LINK_COLOR } from "../../../constants";
import { toXC } from "../../../helpers";
import { openLink, urlRepresentation } from "../../../helpers/links";
import { Store, useStore } from "../../../store_engine";
-import { EvaluatedCell, Link, Position, SpreadsheetChildEnv } from "../../../types";
+import { EvaluatedCell, SpreadsheetChildEnv } from "../../../types";
import { CellPopoverComponent, PopoverBuilders } from "../../../types/cell_popovers";
import { isMiddleClickOrCtrlClick } from "../../helpers/dom_helpers";
import { CellPopoverStore } from "../../popover/cell_popover_store";
diff --git a/src/components/link/link_editor/link_editor.ts b/src/components/link/link_editor/link_editor.ts
index f9dcbeba5f..662ce30a9f 100644
--- a/src/components/link/link_editor/link_editor.ts
+++ b/src/components/link/link_editor/link_editor.ts
@@ -1,9 +1,11 @@
+import { Position } from "@odoo/o-spreadsheet-engine";
+import { Link } from "@odoo/o-spreadsheet-engine/types";
import { Component, onMounted, useRef, useState } from "@odoo/owl";
import { markdownLink } from "../../../helpers";
import { detectLink, urlRepresentation } from "../../../helpers/links";
import { canonicalizeNumberContent } from "../../../helpers/locale";
import { linkMenuRegistry } from "../../../registries/menus/link_menu_registry";
-import { Link, Position, Rect, SpreadsheetChildEnv } from "../../../types";
+import { Rect, SpreadsheetChildEnv } from "../../../types";
import { CellPopoverComponent, PopoverBuilders } from "../../../types/cell_popovers";
import { getRefBoundingRect } from "../../helpers/dom_helpers";
import { MenuPopover } from "../../menu_popover/menu_popover";
diff --git a/src/components/menu/menu.ts b/src/components/menu/menu.ts
index 584d73912e..f7b8f32def 100644
--- a/src/components/menu/menu.ts
+++ b/src/components/menu/menu.ts
@@ -1,6 +1,7 @@
+import { Pixel } from "@odoo/o-spreadsheet-engine";
import { Component, onWillUnmount } from "@odoo/owl";
import { Action } from "../../actions/action";
-import { Pixel, SpreadsheetChildEnv } from "../../types";
+import { SpreadsheetChildEnv } from "../../types";
import { cssPropertiesToCss } from "../helpers/css";
//------------------------------------------------------------------------------
diff --git a/src/components/menu_popover/menu_popover.ts b/src/components/menu_popover/menu_popover.ts
index f2257c9f1e..b345b48437 100644
--- a/src/components/menu_popover/menu_popover.ts
+++ b/src/components/menu_popover/menu_popover.ts
@@ -1,3 +1,4 @@
+import { MenuMouseEvent, Pixel, UID } from "@odoo/o-spreadsheet-engine";
import {
Component,
onWillUnmount,
@@ -8,7 +9,7 @@ import {
} from "@odoo/owl";
import { Action } from "../../actions/action";
import { DESKTOP_MENU_ITEM_HEIGHT, MENU_VERTICAL_PADDING, MENU_WIDTH } from "../../constants";
-import { MenuMouseEvent, Pixel, Rect, SpreadsheetChildEnv, UID } from "../../types";
+import { Rect, SpreadsheetChildEnv } from "../../types";
import { PopoverPropsPosition } from "../../types/cell_popovers";
import { cssPropertiesToCss } from "../helpers/css";
import {
diff --git a/src/components/paint_format_button/paint_format_store.ts b/src/components/paint_format_button/paint_format_store.ts
index 664269cf05..53ad6fef9d 100644
--- a/src/components/paint_format_button/paint_format_store.ts
+++ b/src/components/paint_format_button/paint_format_store.ts
@@ -1,3 +1,4 @@
+import { ClipboardCell, Highlight, UID, Zone } from "@odoo/o-spreadsheet-engine";
import { clipboardHandlersRegistries } from "../../clipboard_handlers";
import { ClipboardHandler } from "../../clipboard_handlers/abstract_clipboard_handler";
import { SELECTION_BORDER_COLOR } from "../../constants";
@@ -9,9 +10,6 @@ import {
} from "../../helpers/clipboard/clipboard_helpers";
import { Get } from "../../store_engine";
import { SpreadsheetStore } from "../../stores";
-import { HighlightStore } from "../../stores/highlight_store";
-import { ClipboardCell, ClipboardOptions, Command, Highlight, UID, Zone } from "../../types";
-
interface ClipboardContent {
cells: ClipboardCell[][];
zones: Zone[];
diff --git a/src/components/pivot_html_renderer/pivot_html_renderer.ts b/src/components/pivot_html_renderer/pivot_html_renderer.ts
index 35c1149bc4..0ee768bd4d 100644
--- a/src/components/pivot_html_renderer/pivot_html_renderer.ts
+++ b/src/components/pivot_html_renderer/pivot_html_renderer.ts
@@ -1,11 +1,6 @@
+import { FunctionResultObject, Maybe, UID } from "@odoo/o-spreadsheet-engine";
import { Component, useState } from "@odoo/owl";
-import {
- FunctionResultObject,
- Maybe,
- SpreadsheetChildEnv,
- SpreadsheetPivotTable,
- UID,
-} from "../..";
+import { SpreadsheetChildEnv, SpreadsheetPivotTable } from "../..";
import { toString } from "../../functions/helpers";
import { formatValue } from "../../helpers";
import { generatePivotArgs } from "../../helpers/pivot/pivot_helpers";
diff --git a/src/components/popover/cell_popover_store.ts b/src/components/popover/cell_popover_store.ts
index 7d8e2aa49f..667a65c0bb 100644
--- a/src/components/popover/cell_popover_store.ts
+++ b/src/components/popover/cell_popover_store.ts
@@ -1,7 +1,8 @@
+import { CellPosition, Position } from "@odoo/o-spreadsheet-engine";
import { positionToZone } from "../../helpers";
import { cellPopoverRegistry } from "../../registries/cell_popovers_registry";
import { SpreadsheetStore } from "../../stores";
-import { CellPosition, Command, Position, Rect } from "../../types";
+import { Command, Rect } from "../../types";
import {
CellPopoverType,
ClosedCellPopover,
diff --git a/src/components/popover/popover.ts b/src/components/popover/popover.ts
index d2afae76d8..722bd24245 100644
--- a/src/components/popover/popover.ts
+++ b/src/components/popover/popover.ts
@@ -1,6 +1,7 @@
+import { Pixel } from "@odoo/o-spreadsheet-engine";
import { Component, onMounted, onWillUnmount, useEffect, useRef } from "@odoo/owl";
import { rectIntersection } from "../../helpers/rectangle";
-import { DOMCoordinates, DOMDimension, Pixel, Rect, SpreadsheetChildEnv } from "../../types";
+import { DOMCoordinates, DOMDimension, Rect, SpreadsheetChildEnv } from "../../types";
import { PopoverPropsPosition } from "../../types/cell_popovers";
import { usePopoverContainer, useSpreadsheetRect } from "../helpers/position_hook";
import { CSSProperties } from "./../../types/misc";
diff --git a/src/components/scrollbar.ts b/src/components/scrollbar.ts
index 15f7948dfe..e1b3232546 100644
--- a/src/components/scrollbar.ts
+++ b/src/components/scrollbar.ts
@@ -1,4 +1,4 @@
-import { Pixel } from "../types";
+import { Pixel } from "@odoo/o-spreadsheet-engine";
export type ScrollDirection = "horizontal" | "vertical";
diff --git a/src/components/scrollbar/scrollbar.ts b/src/components/scrollbar/scrollbar.ts
index 07ff7f1875..54df61c556 100644
--- a/src/components/scrollbar/scrollbar.ts
+++ b/src/components/scrollbar/scrollbar.ts
@@ -1,5 +1,7 @@
+import { Pixel } from "@odoo/o-spreadsheet-engine";
+import { Ref } from "@odoo/o-spreadsheet-engine/types";
import { Component, onMounted, useEffect, useRef, xml } from "@odoo/owl";
-import { CSSProperties, Pixel, Ref } from "../../types";
+import { CSSProperties } from "../../types";
import { cssPropertiesToCss } from "../helpers";
import { ScrollBar as ScrollBarElement, ScrollDirection } from "../scrollbar";
diff --git a/src/components/selection_input/selection_input.ts b/src/components/selection_input/selection_input.ts
index 22045cc1f8..7e3589fb3d 100644
--- a/src/components/selection_input/selection_input.ts
+++ b/src/components/selection_input/selection_input.ts
@@ -1,7 +1,8 @@
+import { Color, deepEquals } from "@odoo/o-spreadsheet-engine";
import { Component, onWillUpdateProps, useEffect, useRef, useState } from "@odoo/owl";
-import { deepEquals, range } from "../../helpers";
+import { range } from "../../helpers";
import { Store, useLocalStore } from "../../store_engine";
-import { Color, SpreadsheetChildEnv } from "../../types";
+import { SpreadsheetChildEnv } from "../../types";
import { cssPropertiesToCss } from "../helpers/css";
import { useDragAndDropListItems } from "../helpers/drag_and_drop_dom_items_hook";
import { updateSelectionWithArrowKeys } from "../helpers/selection_helpers";
diff --git a/src/components/selection_input/selection_input_store.ts b/src/components/selection_input/selection_input_store.ts
index 5975c93c19..0495d9db45 100644
--- a/src/components/selection_input/selection_input_store.ts
+++ b/src/components/selection_input/selection_input_store.ts
@@ -1,11 +1,9 @@
+import { Color, Highlight, UID } from "@odoo/o-spreadsheet-engine";
import { ColorGenerator, isEqual, positionToZone, splitReference } from "../../helpers/index";
import { Get } from "../../store_engine";
import { SpreadsheetStore } from "../../stores";
import { HighlightStore } from "../../stores/highlight_store";
import { SelectionEvent } from "../../types/event_stream";
-import { Color, Command, Highlight, UID } from "../../types/index";
-import { FocusStore } from "../focus_store";
-
export interface RangeInputValue {
id: number;
xc: string;
diff --git a/src/components/side_panel/carousel_panel/carousel_panel.ts b/src/components/side_panel/carousel_panel/carousel_panel.ts
index 546c12965e..baaa762834 100644
--- a/src/components/side_panel/carousel_panel/carousel_panel.ts
+++ b/src/components/side_panel/carousel_panel/carousel_panel.ts
@@ -1,10 +1,10 @@
+import { deepEquals, UID } from "@odoo/o-spreadsheet-engine";
import { Component, onWillUpdateProps, useRef } from "@odoo/owl";
import { ActionSpec } from "../../../actions/action";
import { DEFAULT_CAROUSEL_TITLE_STYLE } from "../../../constants";
-import { deepEquals } from "../../../helpers";
import { getCarouselItemPreview, getCarouselItemTitle } from "../../../helpers/carousel_helpers";
import { _t } from "../../../translation";
-import { CarouselItem, SpreadsheetChildEnv, TitleDesign, UID } from "../../../types";
+import { CarouselItem, SpreadsheetChildEnv, TitleDesign } from "../../../types";
import { getBoundingRectAsPOJO } from "../../helpers/dom_helpers";
import { useDragAndDropListItems } from "../../helpers/drag_and_drop_dom_items_hook";
import { TextInput } from "../../text_input/text_input";
diff --git a/src/components/side_panel/chart/building_blocks/axis_design/axis_design_editor.ts b/src/components/side_panel/chart/building_blocks/axis_design/axis_design_editor.ts
index b327739766..7b9a55b4be 100644
--- a/src/components/side_panel/chart/building_blocks/axis_design/axis_design_editor.ts
+++ b/src/components/side_panel/chart/building_blocks/axis_design/axis_design_editor.ts
@@ -1,3 +1,4 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component, useState } from "@odoo/owl";
import { CHART_AXIS_TITLE_FONT_SIZE } from "../../../../../constants";
import { deepCopy } from "../../../../../helpers";
@@ -6,7 +7,6 @@ import {
DispatchResult,
SpreadsheetChildEnv,
TitleDesign,
- UID,
} from "../../../../../types";
import { BadgeSelection } from "../../../components/badge_selection/badge_selection";
import { Section } from "../../../components/section/section";
diff --git a/src/components/side_panel/chart/building_blocks/data_series/data_series.ts b/src/components/side_panel/chart/building_blocks/data_series/data_series.ts
index c4ee7c6b67..5ccf8047bf 100644
--- a/src/components/side_panel/chart/building_blocks/data_series/data_series.ts
+++ b/src/components/side_panel/chart/building_blocks/data_series/data_series.ts
@@ -1,8 +1,8 @@
+import { Color } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { _t } from "../../../../../translation";
import {
ChartDatasetOrientation,
- Color,
CustomizedDataSet,
SpreadsheetChildEnv,
} from "../../../../../types";
diff --git a/src/components/side_panel/chart/building_blocks/general_design/general_design_editor.ts b/src/components/side_panel/chart/building_blocks/general_design/general_design_editor.ts
index b520757fa8..029cec1c63 100644
--- a/src/components/side_panel/chart/building_blocks/general_design/general_design_editor.ts
+++ b/src/components/side_panel/chart/building_blocks/general_design/general_design_editor.ts
@@ -1,12 +1,11 @@
+import { Color, UID } from "@odoo/o-spreadsheet-engine";
import { Component, useState } from "@odoo/owl";
import { CHART_TITLE_FONT_SIZE } from "../../../../../constants";
import {
ChartDefinition,
- Color,
DispatchResult,
SpreadsheetChildEnv,
TitleDesign,
- UID,
} from "../../../../../types";
import { SidePanelCollapsible } from "../../../components/collapsible/side_panel_collapsible";
import { RadioSelection } from "../../../components/radio_selection/radio_selection";
diff --git a/src/components/side_panel/chart/building_blocks/generic_side_panel/config_panel.ts b/src/components/side_panel/chart/building_blocks/generic_side_panel/config_panel.ts
index d621dcad8b..e65e774cfb 100644
--- a/src/components/side_panel/chart/building_blocks/generic_side_panel/config_panel.ts
+++ b/src/components/side_panel/chart/building_blocks/generic_side_panel/config_panel.ts
@@ -1,7 +1,5 @@
-import { Component, useState } from "@odoo/owl";
import {
createValidRange,
- isDefined,
isXcRepresentation,
mergeContiguousZones,
numberToLetters,
@@ -21,8 +19,6 @@ import {
CustomizedDataSet,
DispatchResult,
SpreadsheetChildEnv,
- UID,
- Zone,
} from "../../../../../types";
import { ChartTerms } from "../../../../translations_terms";
import { Checkbox } from "../../../components/checkbox/checkbox";
diff --git a/src/components/side_panel/chart/building_blocks/humanize_numbers/humanize_numbers.ts b/src/components/side_panel/chart/building_blocks/humanize_numbers/humanize_numbers.ts
index 0767e90096..9d1c422dbe 100644
--- a/src/components/side_panel/chart/building_blocks/humanize_numbers/humanize_numbers.ts
+++ b/src/components/side_panel/chart/building_blocks/humanize_numbers/humanize_numbers.ts
@@ -1,9 +1,9 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import {
ChartWithDataSetDefinition,
DispatchResult,
SpreadsheetChildEnv,
- UID,
} from "../../../../../types";
import { Checkbox } from "../../../components/checkbox/checkbox";
diff --git a/src/components/side_panel/chart/building_blocks/legend/legend.ts b/src/components/side_panel/chart/building_blocks/legend/legend.ts
index c772137bfc..357b11850a 100644
--- a/src/components/side_panel/chart/building_blocks/legend/legend.ts
+++ b/src/components/side_panel/chart/building_blocks/legend/legend.ts
@@ -1,9 +1,9 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import {
ChartWithDataSetDefinition,
DispatchResult,
SpreadsheetChildEnv,
- UID,
} from "../../../../../types";
import { Section } from "../../../components/section/section";
diff --git a/src/components/side_panel/chart/building_blocks/pie_hole_size/pie_hole_size.ts b/src/components/side_panel/chart/building_blocks/pie_hole_size/pie_hole_size.ts
index 4b7b8236de..fdd170b46c 100644
--- a/src/components/side_panel/chart/building_blocks/pie_hole_size/pie_hole_size.ts
+++ b/src/components/side_panel/chart/building_blocks/pie_hole_size/pie_hole_size.ts
@@ -1,5 +1,6 @@
+import { debounce } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
-import { clip, debounce } from "../../../../../helpers";
+import { clip } from "../../../../../helpers";
import { SpreadsheetChildEnv } from "../../../../../types";
import { Section } from "../../../components/section/section";
diff --git a/src/components/side_panel/chart/building_blocks/series_design/series_design_editor.ts b/src/components/side_panel/chart/building_blocks/series_design/series_design_editor.ts
index c890c4dc75..03d7b32339 100644
--- a/src/components/side_panel/chart/building_blocks/series_design/series_design_editor.ts
+++ b/src/components/side_panel/chart/building_blocks/series_design/series_design_editor.ts
@@ -1,3 +1,4 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component, useState } from "@odoo/owl";
import { getColorsPalette, getNthColor, toHex } from "../../../../../helpers";
import { isTrendLineAxis } from "../../../../../helpers/figures/charts";
@@ -5,7 +6,6 @@ import {
ChartWithDataSetDefinition,
DispatchResult,
SpreadsheetChildEnv,
- UID,
} from "../../../../../types";
import { SidePanelCollapsible } from "../../../components/collapsible/side_panel_collapsible";
import { RoundColorPicker } from "../../../components/round_color_picker/round_color_picker";
diff --git a/src/components/side_panel/chart/building_blocks/series_design/series_with_axis_design_editor.ts b/src/components/side_panel/chart/building_blocks/series_design/series_with_axis_design_editor.ts
index 9c9ea25f8b..1ef0fba34c 100644
--- a/src/components/side_panel/chart/building_blocks/series_design/series_with_axis_design_editor.ts
+++ b/src/components/side_panel/chart/building_blocks/series_design/series_with_axis_design_editor.ts
@@ -1,3 +1,4 @@
+import { Color, UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { DEFAULT_WINDOW_SIZE } from "../../../../../constants";
import { getColorsPalette, getNthColor, range, setColorAlpha, toHex } from "../../../../../helpers";
@@ -5,11 +6,9 @@ import { CHART_AXIS_CHOICES } from "../../../../../helpers/figures/charts";
import {
ChartJSRuntime,
ChartWithDataSetDefinition,
- Color,
DispatchResult,
SpreadsheetChildEnv,
TrendConfiguration,
- UID,
} from "../../../../../types";
import { Checkbox } from "../../../components/checkbox/checkbox";
import { RadioSelection } from "../../../components/radio_selection/radio_selection";
diff --git a/src/components/side_panel/chart/building_blocks/show_data_markers/show_data_markers.ts b/src/components/side_panel/chart/building_blocks/show_data_markers/show_data_markers.ts
index fd62c840a2..490aa5524b 100644
--- a/src/components/side_panel/chart/building_blocks/show_data_markers/show_data_markers.ts
+++ b/src/components/side_panel/chart/building_blocks/show_data_markers/show_data_markers.ts
@@ -1,9 +1,9 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import {
ChartWithDataSetDefinition,
DispatchResult,
SpreadsheetChildEnv,
- UID,
} from "../../../../../types";
import { Checkbox } from "../../../components/checkbox/checkbox";
diff --git a/src/components/side_panel/chart/building_blocks/show_values/show_values.ts b/src/components/side_panel/chart/building_blocks/show_values/show_values.ts
index 8a438925db..f7f8b15101 100644
--- a/src/components/side_panel/chart/building_blocks/show_values/show_values.ts
+++ b/src/components/side_panel/chart/building_blocks/show_values/show_values.ts
@@ -1,9 +1,9 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import {
ChartWithDataSetDefinition,
DispatchResult,
SpreadsheetChildEnv,
- UID,
} from "../../../../../types";
import { Checkbox } from "../../../components/checkbox/checkbox";
diff --git a/src/components/side_panel/chart/building_blocks/text_styler/text_styler.ts b/src/components/side_panel/chart/building_blocks/text_styler/text_styler.ts
index 50aa930432..c13375115b 100644
--- a/src/components/side_panel/chart/building_blocks/text_styler/text_styler.ts
+++ b/src/components/side_panel/chart/building_blocks/text_styler/text_styler.ts
@@ -1,12 +1,11 @@
+import { Align, Color, VerticalAlign } from "@odoo/o-spreadsheet-engine";
import { Component, useExternalListener, useState } from "@odoo/owl";
import { ActionSpec } from "../../../../../actions/action";
import { DEFAULT_STYLE } from "../../../../../constants";
import { _t } from "../../../../../translation";
-import { Align, ChartStyle, Color, SpreadsheetChildEnv, VerticalAlign } from "../../../../../types";
+import { ChartStyle, SpreadsheetChildEnv } from "../../../../../types";
import { ActionButton } from "../../../../action_button/action_button";
import { ColorPickerWidget } from "../../../../color_picker/color_picker_widget";
-import { FontSizeEditor } from "../../../../font_size_editor/font_size_editor";
-
interface Props {
class?: string;
style: ChartStyle;
diff --git a/src/components/side_panel/chart/chart_type_picker/chart_type_picker.ts b/src/components/side_panel/chart/chart_type_picker/chart_type_picker.ts
index 113f6de559..1fee5266a3 100644
--- a/src/components/side_panel/chart/chart_type_picker/chart_type_picker.ts
+++ b/src/components/side_panel/chart/chart_type_picker/chart_type_picker.ts
@@ -1,10 +1,11 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component, useExternalListener, useRef, useState } from "@odoo/owl";
import {
ChartSubtypeProperties,
chartCategories,
chartSubtypeRegistry,
} from "../../../../registries/chart_types";
-import { ChartDefinition, ChartType, SpreadsheetChildEnv, UID } from "../../../../types/index";
+import { ChartDefinition, ChartType, SpreadsheetChildEnv } from "../../../../types/index";
import { cssPropertiesToCss } from "../../../helpers/css";
import { isChildEvent } from "../../../helpers/dom_helpers";
import { Popover, PopoverProps } from "../../../popover";
diff --git a/src/components/side_panel/chart/chart_with_axis/design_panel.ts b/src/components/side_panel/chart/chart_with_axis/design_panel.ts
index e8377f1c2a..dd7d447d43 100644
--- a/src/components/side_panel/chart/chart_with_axis/design_panel.ts
+++ b/src/components/side_panel/chart/chart_with_axis/design_panel.ts
@@ -1,3 +1,4 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { getDefinedAxis } from "../../../../helpers/figures/charts";
import { _t } from "../../../../translation";
@@ -6,7 +7,6 @@ import {
DispatchResult,
GenericDefinition,
SpreadsheetChildEnv,
- UID,
} from "../../../../types/index";
import { SidePanelCollapsible } from "../../components/collapsible/side_panel_collapsible";
import { Section } from "../../components/section/section";
diff --git a/src/components/side_panel/chart/combo_chart/combo_chart_design_panel.ts b/src/components/side_panel/chart/combo_chart/combo_chart_design_panel.ts
index 914014e352..15eadab117 100644
--- a/src/components/side_panel/chart/combo_chart/combo_chart_design_panel.ts
+++ b/src/components/side_panel/chart/combo_chart/combo_chart_design_panel.ts
@@ -1,6 +1,7 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { _t } from "../../../../translation";
import { ComboChartDefinition } from "../../../../types/chart/combo_chart";
-import { DispatchResult, GenericDefinition, UID } from "../../../../types/index";
+import { DispatchResult, GenericDefinition } from "../../../../types/index";
import { RadioSelection } from "../../components/radio_selection/radio_selection";
import { ChartShowDataMarkers } from "../building_blocks/show_data_markers/show_data_markers";
import { GenericZoomableChartDesignPanel } from "../zoomable_chart/design_panel";
diff --git a/src/components/side_panel/chart/funnel_chart_panel/funnel_chart_design_panel.ts b/src/components/side_panel/chart/funnel_chart_panel/funnel_chart_design_panel.ts
index 3892f71c75..eedcc81605 100644
--- a/src/components/side_panel/chart/funnel_chart_panel/funnel_chart_design_panel.ts
+++ b/src/components/side_panel/chart/funnel_chart_panel/funnel_chart_design_panel.ts
@@ -1,9 +1,7 @@
-import { Component } from "@odoo/owl";
-import { replaceItemAtIndex } from "../../../../helpers";
import { getFunnelLabelColors } from "../../../../helpers/figures/charts/runtime";
import { _t } from "../../../../translation";
import { FunnelChartDefinition, FunnelChartRuntime } from "../../../../types/chart";
-import { DispatchResult, SpreadsheetChildEnv, UID } from "../../../../types/index";
+import { DispatchResult, SpreadsheetChildEnv } from "../../../../types/index";
import { SidePanelCollapsible } from "../../components/collapsible/side_panel_collapsible";
import { RoundColorPicker } from "../../components/round_color_picker/round_color_picker";
import { Section } from "../../components/section/section";
diff --git a/src/components/side_panel/chart/gauge_chart_panel/gauge_chart_config_panel.ts b/src/components/side_panel/chart/gauge_chart_panel/gauge_chart_config_panel.ts
index 28e2aa77ae..e9c123f2e4 100644
--- a/src/components/side_panel/chart/gauge_chart_panel/gauge_chart_config_panel.ts
+++ b/src/components/side_panel/chart/gauge_chart_panel/gauge_chart_config_panel.ts
@@ -1,3 +1,4 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component, useState } from "@odoo/owl";
import { GaugeChartDefinition } from "../../../../types/chart/gauge_chart";
import {
@@ -5,7 +6,6 @@ import {
CustomizedDataSet,
DispatchResult,
SpreadsheetChildEnv,
- UID,
} from "../../../../types/index";
import { ChartTerms } from "../../../translations_terms";
import { ChartDataSeries } from "../building_blocks/data_series/data_series";
diff --git a/src/components/side_panel/chart/gauge_chart_panel/gauge_chart_design_panel.ts b/src/components/side_panel/chart/gauge_chart_panel/gauge_chart_design_panel.ts
index e6f43ba60c..489e9a50a8 100644
--- a/src/components/side_panel/chart/gauge_chart_panel/gauge_chart_design_panel.ts
+++ b/src/components/side_panel/chart/gauge_chart_panel/gauge_chart_design_panel.ts
@@ -1,16 +1,11 @@
+import { Color, UID } from "@odoo/o-spreadsheet-engine";
import { Component, useState } from "@odoo/owl";
import { isMultipleElementMatrix, toScalar } from "../../../../functions/helper_matrices";
import { tryToNumber } from "../../../../functions/helpers";
import { deepCopy } from "../../../../helpers/index";
import { _t } from "../../../../translation";
import { GaugeChartDefinition, SectionRule } from "../../../../types/chart/gauge_chart";
-import {
- Color,
- CommandResult,
- DispatchResult,
- SpreadsheetChildEnv,
- UID,
-} from "../../../../types/index";
+import { CommandResult, DispatchResult, SpreadsheetChildEnv } from "../../../../types/index";
import { StandaloneComposer } from "../../../composer/standalone_composer/standalone_composer";
import { ChartTerms } from "../../../translations_terms";
import { SidePanelCollapsible } from "../../components/collapsible/side_panel_collapsible";
diff --git a/src/components/side_panel/chart/geo_chart_panel/geo_chart_design_panel.ts b/src/components/side_panel/chart/geo_chart_panel/geo_chart_design_panel.ts
index 8679c226b3..e76e9b4e40 100644
--- a/src/components/side_panel/chart/geo_chart_panel/geo_chart_design_panel.ts
+++ b/src/components/side_panel/chart/geo_chart_panel/geo_chart_design_panel.ts
@@ -1,14 +1,13 @@
+import { Color, UID } from "@odoo/o-spreadsheet-engine";
import { LegendPosition } from "../../../../types/chart";
import {
GeoChartColorScale,
GeoChartCustomColorScale,
GeoChartDefinition,
} from "../../../../types/chart/geo_chart";
-import { Color, DispatchResult, UID } from "../../../../types/index";
+import { DispatchResult } from "../../../../types/index";
import { ChartTerms } from "../../../translations_terms";
import { RoundColorPicker } from "../../components/round_color_picker/round_color_picker";
-import { ChartWithAxisDesignPanel } from "../chart_with_axis/design_panel";
-
interface Props {
chartId: UID;
definition: GeoChartDefinition;
diff --git a/src/components/side_panel/chart/geo_chart_panel/geo_chart_region_select_section.ts b/src/components/side_panel/chart/geo_chart_panel/geo_chart_region_select_section.ts
index 8a92cae9b1..d9327e089b 100644
--- a/src/components/side_panel/chart/geo_chart_panel/geo_chart_region_select_section.ts
+++ b/src/components/side_panel/chart/geo_chart_panel/geo_chart_region_select_section.ts
@@ -1,6 +1,7 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { GeoChartDefinition } from "../../../../types/chart/geo_chart";
-import { DispatchResult, SpreadsheetChildEnv, UID } from "../../../../types/index";
+import { DispatchResult, SpreadsheetChildEnv } from "../../../../types/index";
import { Section } from "../../components/section/section";
interface Props {
diff --git a/src/components/side_panel/chart/line_chart/line_chart_design_panel.ts b/src/components/side_panel/chart/line_chart/line_chart_design_panel.ts
index 2cdc1a305f..4d059bbde0 100644
--- a/src/components/side_panel/chart/line_chart/line_chart_design_panel.ts
+++ b/src/components/side_panel/chart/line_chart/line_chart_design_panel.ts
@@ -1,5 +1,6 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { LineChartDefinition } from "../../../../types/chart";
-import { DispatchResult, UID } from "../../../../types/index";
+import { DispatchResult } from "../../../../types/index";
import { ChartShowDataMarkers } from "../building_blocks/show_data_markers/show_data_markers";
import { GenericZoomableChartDesignPanel } from "../zoomable_chart/design_panel";
diff --git a/src/components/side_panel/chart/main_chart_panel/main_chart_panel.ts b/src/components/side_panel/chart/main_chart_panel/main_chart_panel.ts
index 7169ac46c9..80f16af04a 100644
--- a/src/components/side_panel/chart/main_chart_panel/main_chart_panel.ts
+++ b/src/components/side_panel/chart/main_chart_panel/main_chart_panel.ts
@@ -1,18 +1,11 @@
+import { Pixel, UID } from "@odoo/o-spreadsheet-engine";
+import { Ref } from "@odoo/o-spreadsheet-engine/types";
import { Component, useEffect, useRef } from "@odoo/owl";
import { ChartSidePanel, chartSidePanelComponentRegistry } from "..";
import { Store, useLocalStore } from "../../../../store_engine";
-import {
- ChartDefinition,
- ChartType,
- Pixel,
- Ref,
- SpreadsheetChildEnv,
- UID,
-} from "../../../../types/index";
+import { ChartDefinition, ChartType, SpreadsheetChildEnv } from "../../../../types/index";
import { Section } from "../../components/section/section";
import { ChartTypePicker } from "../chart_type_picker/chart_type_picker";
-import { MainChartPanelStore } from "./main_chart_panel_store";
-
interface Props {
onCloseSidePanel: () => void;
chartId: UID;
diff --git a/src/components/side_panel/chart/main_chart_panel/main_chart_panel_store.ts b/src/components/side_panel/chart/main_chart_panel/main_chart_panel_store.ts
index a2ed5b79b2..e380daaf66 100644
--- a/src/components/side_panel/chart/main_chart_panel/main_chart_panel_store.ts
+++ b/src/components/side_panel/chart/main_chart_panel/main_chart_panel_store.ts
@@ -1,7 +1,7 @@
-import { deepEquals } from "../../../../helpers";
+import { deepEquals, UID } from "@odoo/o-spreadsheet-engine";
import { chartRegistry, chartSubtypeRegistry } from "../../../../registries/chart_types";
import { SpreadsheetStore } from "../../../../stores";
-import { ChartCreationContext, ChartDefinition, UID } from "../../../../types";
+import { ChartCreationContext, ChartDefinition } from "../../../../types";
export class MainChartPanelStore extends SpreadsheetStore {
mutators = ["activatePanel", "changeChartType"] as const;
diff --git a/src/components/side_panel/chart/pie_chart/pie_chart_design_panel.ts b/src/components/side_panel/chart/pie_chart/pie_chart_design_panel.ts
index 51300e921a..ec999850c5 100644
--- a/src/components/side_panel/chart/pie_chart/pie_chart_design_panel.ts
+++ b/src/components/side_panel/chart/pie_chart/pie_chart_design_panel.ts
@@ -1,5 +1,6 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
-import { DispatchResult, SpreadsheetChildEnv, UID } from "../../../../types";
+import { DispatchResult, SpreadsheetChildEnv } from "../../../../types";
import { GenericDefinition, PieChartDefinition } from "../../../../types/chart";
import { DEFAULT_DOUGHNUT_CHART_HOLE_SIZE } from "../../../../xlsx/constants";
import { Checkbox } from "../../components/checkbox/checkbox";
diff --git a/src/components/side_panel/chart/radar_chart/radar_chart_design_panel.ts b/src/components/side_panel/chart/radar_chart/radar_chart_design_panel.ts
index 5fd4617341..91aa4987d4 100644
--- a/src/components/side_panel/chart/radar_chart/radar_chart_design_panel.ts
+++ b/src/components/side_panel/chart/radar_chart/radar_chart_design_panel.ts
@@ -1,11 +1,7 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { RadarChartDefinition } from "../../../../types/chart/radar_chart";
-import {
- DispatchResult,
- GenericDefinition,
- SpreadsheetChildEnv,
- UID,
-} from "../../../../types/index";
+import { DispatchResult, GenericDefinition, SpreadsheetChildEnv } from "../../../../types/index";
import { Checkbox } from "../../components/checkbox/checkbox";
import { Section } from "../../components/section/section";
import { GeneralDesignEditor } from "../building_blocks/general_design/general_design_editor";
diff --git a/src/components/side_panel/chart/scorecard_chart_panel/scorecard_chart_config_panel.ts b/src/components/side_panel/chart/scorecard_chart_panel/scorecard_chart_config_panel.ts
index b1e162d692..1862025644 100644
--- a/src/components/side_panel/chart/scorecard_chart_panel/scorecard_chart_config_panel.ts
+++ b/src/components/side_panel/chart/scorecard_chart_panel/scorecard_chart_config_panel.ts
@@ -1,6 +1,7 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component, useState } from "@odoo/owl";
import { ScorecardChartDefinition } from "../../../../types/chart/scorecard_chart";
-import { CommandResult, DispatchResult, SpreadsheetChildEnv, UID } from "../../../../types/index";
+import { CommandResult, DispatchResult, SpreadsheetChildEnv } from "../../../../types/index";
import { SelectionInput } from "../../../selection_input/selection_input";
import { ChartTerms } from "../../../translations_terms";
import { Section } from "../../components/section/section";
diff --git a/src/components/side_panel/chart/scorecard_chart_panel/scorecard_chart_design_panel.ts b/src/components/side_panel/chart/scorecard_chart_panel/scorecard_chart_design_panel.ts
index 0c0b4c6abf..21d6c0af97 100644
--- a/src/components/side_panel/chart/scorecard_chart_panel/scorecard_chart_design_panel.ts
+++ b/src/components/side_panel/chart/scorecard_chart_panel/scorecard_chart_design_panel.ts
@@ -1,3 +1,4 @@
+import { Color, UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import {
DEFAULT_SCORECARD_BASELINE_FONT_SIZE,
@@ -6,13 +7,7 @@ import {
} from "../../../../constants";
import { _t } from "../../../../translation";
import { ScorecardChartDefinition } from "../../../../types/chart/scorecard_chart";
-import {
- Color,
- DispatchResult,
- SpreadsheetChildEnv,
- TitleDesign,
- UID,
-} from "../../../../types/index";
+import { DispatchResult, SpreadsheetChildEnv, TitleDesign } from "../../../../types/index";
import { Checkbox } from "../../components/checkbox/checkbox";
import { SidePanelCollapsible } from "../../components/collapsible/side_panel_collapsible";
import { RoundColorPicker } from "../../components/round_color_picker/round_color_picker";
diff --git a/src/components/side_panel/chart/sunburst_chart/sunburst_chart_design_panel.ts b/src/components/side_panel/chart/sunburst_chart/sunburst_chart_design_panel.ts
index 0bd2df0f03..0b168d9704 100644
--- a/src/components/side_panel/chart/sunburst_chart/sunburst_chart_design_panel.ts
+++ b/src/components/side_panel/chart/sunburst_chart/sunburst_chart_design_panel.ts
@@ -1,3 +1,4 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { deepCopy } from "../../../../helpers";
import {
@@ -6,7 +7,7 @@ import {
SunburstChartJSDataset,
SunburstChartRuntime,
} from "../../../../types/chart";
-import { DispatchResult, SpreadsheetChildEnv, UID } from "../../../../types/index";
+import { DispatchResult, SpreadsheetChildEnv } from "../../../../types/index";
import { Checkbox } from "../../components/checkbox/checkbox";
import { SidePanelCollapsible } from "../../components/collapsible/side_panel_collapsible";
import { RoundColorPicker } from "../../components/round_color_picker/round_color_picker";
diff --git a/src/components/side_panel/chart/treemap_chart/treemap_category_color/treemap_category_color.ts b/src/components/side_panel/chart/treemap_chart/treemap_category_color/treemap_category_color.ts
index fc67f2fc95..4aa63c0a8f 100644
--- a/src/components/side_panel/chart/treemap_chart/treemap_category_color/treemap_category_color.ts
+++ b/src/components/side_panel/chart/treemap_chart/treemap_category_color/treemap_category_color.ts
@@ -1,6 +1,7 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { ChartConfiguration } from "chart.js";
-import { DispatchResult, UID } from "../../../../..";
+import { DispatchResult } from "../../../../..";
import { deepCopy } from "../../../../../helpers";
import { SpreadsheetChildEnv } from "../../../../../types";
import {
diff --git a/src/components/side_panel/chart/treemap_chart/treemap_chart_design_panel.ts b/src/components/side_panel/chart/treemap_chart/treemap_chart_design_panel.ts
index 502669accb..58ee95fc1c 100644
--- a/src/components/side_panel/chart/treemap_chart/treemap_chart_design_panel.ts
+++ b/src/components/side_panel/chart/treemap_chart/treemap_chart_design_panel.ts
@@ -1,3 +1,4 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { _t } from "../../../../translation";
import {
@@ -6,7 +7,7 @@ import {
TreeMapChartDefinition,
TreeMapColorScaleOptions,
} from "../../../../types/chart/tree_map_chart";
-import { DispatchResult, SpreadsheetChildEnv, UID } from "../../../../types/index";
+import { DispatchResult, SpreadsheetChildEnv } from "../../../../types/index";
import { BadgeSelection } from "../../components/badge_selection/badge_selection";
import { Checkbox } from "../../components/checkbox/checkbox";
import { SidePanelCollapsible } from "../../components/collapsible/side_panel_collapsible";
diff --git a/src/components/side_panel/chart/treemap_chart/treemap_color_scale/treemap_color_scale.ts b/src/components/side_panel/chart/treemap_chart/treemap_color_scale/treemap_color_scale.ts
index fd7df7b588..e984049b3b 100644
--- a/src/components/side_panel/chart/treemap_chart/treemap_color_scale/treemap_color_scale.ts
+++ b/src/components/side_panel/chart/treemap_chart/treemap_color_scale/treemap_color_scale.ts
@@ -1,5 +1,6 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
-import { DispatchResult, UID } from "../../../../..";
+import { DispatchResult } from "../../../../..";
import { SpreadsheetChildEnv } from "../../../../../types";
import {
TreeMapChartDefaults,
diff --git a/src/components/side_panel/chart/waterfall_chart/waterfall_chart_design_panel.ts b/src/components/side_panel/chart/waterfall_chart/waterfall_chart_design_panel.ts
index 0ff0dfb4fe..77a38ec963 100644
--- a/src/components/side_panel/chart/waterfall_chart/waterfall_chart_design_panel.ts
+++ b/src/components/side_panel/chart/waterfall_chart/waterfall_chart_design_panel.ts
@@ -1,3 +1,4 @@
+import { Color, UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import {
CHART_WATERFALL_NEGATIVE_COLOR,
@@ -6,13 +7,7 @@ import {
} from "../../../../constants";
import { CHART_AXIS_CHOICES } from "../../../../helpers/figures/charts";
import { _t } from "../../../../translation";
-import {
- Color,
- DispatchResult,
- GenericDefinition,
- SpreadsheetChildEnv,
- UID,
-} from "../../../../types";
+import { DispatchResult, GenericDefinition, SpreadsheetChildEnv } from "../../../../types";
import { WaterfallChartDefinition } from "../../../../types/chart/waterfall_chart";
import { SidePanelCollapsible } from "../../components/collapsible/side_panel_collapsible";
import { RadioSelection } from "../../components/radio_selection/radio_selection";
diff --git a/src/components/side_panel/chart/zoomable_chart/design_panel.ts b/src/components/side_panel/chart/zoomable_chart/design_panel.ts
index 0e9e8389ff..e544a856fc 100644
--- a/src/components/side_panel/chart/zoomable_chart/design_panel.ts
+++ b/src/components/side_panel/chart/zoomable_chart/design_panel.ts
@@ -1,7 +1,7 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import {
DispatchResult,
GenericDefinition,
- UID,
ZoomableChartDefinition,
} from "../../../../types/index";
import { Checkbox } from "../../components/checkbox/checkbox";
diff --git a/src/components/side_panel/components/cog_wheel_menu/cog_wheel_menu.ts b/src/components/side_panel/components/cog_wheel_menu/cog_wheel_menu.ts
index 467eb9d34d..db5c0a3f0e 100644
--- a/src/components/side_panel/components/cog_wheel_menu/cog_wheel_menu.ts
+++ b/src/components/side_panel/components/cog_wheel_menu/cog_wheel_menu.ts
@@ -1,6 +1,6 @@
+import { MenuMouseEvent } from "@odoo/o-spreadsheet-engine";
import { Component, useRef, useState } from "@odoo/owl";
import { ActionSpec, createActions } from "../../../../actions/action";
-import { MenuMouseEvent } from "../../../../types";
import { SpreadsheetChildEnv } from "../../../../types/env";
import { getBoundingRectAsPOJO } from "../../../helpers/dom_helpers";
import { MenuPopover, MenuState } from "../../../menu_popover/menu_popover";
diff --git a/src/components/side_panel/conditional_formatting/cf_editor/cf_editor.ts b/src/components/side_panel/conditional_formatting/cf_editor/cf_editor.ts
index 34ba3ca501..8732c52a83 100644
--- a/src/components/side_panel/conditional_formatting/cf_editor/cf_editor.ts
+++ b/src/components/side_panel/conditional_formatting/cf_editor/cf_editor.ts
@@ -1,3 +1,4 @@
+import { Color } from "@odoo/o-spreadsheet-engine";
import { Component, ComponentConstructor, useExternalListener, useState } from "@odoo/owl";
import { Action } from "../../../../actions/action";
import { DEFAULT_COLOR_SCALE_MIDPOINT_COLOR } from "../../../../constants";
@@ -13,7 +14,6 @@ import { _t } from "../../../../translation";
import {
CancelledReason,
CellIsRule,
- Color,
ColorScaleRule,
ColorScaleThreshold,
CommandResult,
diff --git a/src/components/side_panel/conditional_formatting/cf_preview/cf_preview.ts b/src/components/side_panel/conditional_formatting/cf_preview/cf_preview.ts
index 402375ed1e..573fccb075 100644
--- a/src/components/side_panel/conditional_formatting/cf_preview/cf_preview.ts
+++ b/src/components/side_panel/conditional_formatting/cf_preview/cf_preview.ts
@@ -1,8 +1,9 @@
+import { Highlight } from "@odoo/o-spreadsheet-engine";
import { Component, useRef } from "@odoo/owl";
import { HIGHLIGHT_COLOR } from "../../../../constants";
import { colorNumberToHex } from "../../../../helpers";
import { criterionEvaluatorRegistry } from "../../../../registries/criterion_registry";
-import { ConditionalFormat, Highlight, SpreadsheetChildEnv } from "../../../../types";
+import { ConditionalFormat, SpreadsheetChildEnv } from "../../../../types";
import { cellStyleToCss, cssPropertiesToCss } from "../../../helpers";
import { useHighlightsOnHover } from "../../../helpers/highlight_hook";
import { ICONS } from "../../../icons/icons";
diff --git a/src/components/side_panel/conditional_formatting/cf_preview_list/cf_preview_list.ts b/src/components/side_panel/conditional_formatting/cf_preview_list/cf_preview_list.ts
index 2092a11524..1615ba4be0 100644
--- a/src/components/side_panel/conditional_formatting/cf_preview_list/cf_preview_list.ts
+++ b/src/components/side_panel/conditional_formatting/cf_preview_list/cf_preview_list.ts
@@ -1,6 +1,6 @@
+import { deepEquals, UID } from "@odoo/o-spreadsheet-engine";
import { Component, onWillUpdateProps, useRef } from "@odoo/owl";
-import { deepEquals } from "../../../../helpers";
-import { ConditionalFormat, SpreadsheetChildEnv, UID } from "../../../../types";
+import { ConditionalFormat, SpreadsheetChildEnv } from "../../../../types";
import { getBoundingRectAsPOJO } from "../../../helpers/dom_helpers";
import { useDragAndDropListItems } from "../../../helpers/drag_and_drop_dom_items_hook";
import { ICONS } from "../../../icons/icons";
diff --git a/src/components/side_panel/conditional_formatting/conditional_formatting.ts b/src/components/side_panel/conditional_formatting/conditional_formatting.ts
index 144e954e07..5fd36b40ce 100644
--- a/src/components/side_panel/conditional_formatting/conditional_formatting.ts
+++ b/src/components/side_panel/conditional_formatting/conditional_formatting.ts
@@ -1,10 +1,9 @@
+import { UID, Zone } from "@odoo/o-spreadsheet-engine";
import { Component, onWillUpdateProps, useState } from "@odoo/owl";
import { localizeCFRule } from "../../../helpers/locale";
-import { ConditionalFormat, SpreadsheetChildEnv, UID, Zone } from "../../../types";
+import { ConditionalFormat, SpreadsheetChildEnv } from "../../../types";
import { Section } from "../components/section/section";
import { ConditionalFormattingEditor } from "./cf_editor/cf_editor";
-import { ConditionalFormatPreviewList } from "./cf_preview_list/cf_preview_list";
-
interface Props {
selection?: Zone[];
onCloseSidePanel: () => void;
diff --git a/src/components/side_panel/criterion_form/value_in_list_criterion/value_in_list_criterion.ts b/src/components/side_panel/criterion_form/value_in_list_criterion/value_in_list_criterion.ts
index 0fe891f20e..8999c33874 100644
--- a/src/components/side_panel/criterion_form/value_in_list_criterion/value_in_list_criterion.ts
+++ b/src/components/side_panel/criterion_form/value_in_list_criterion/value_in_list_criterion.ts
@@ -1,5 +1,6 @@
+import { Color } from "@odoo/o-spreadsheet-engine";
import { onWillStart, onWillUpdateProps, useState } from "@odoo/owl";
-import { Color, IsValueInListCriterion } from "../../../../types";
+import { IsValueInListCriterion } from "../../../../types";
import { RoundColorPicker } from "../../components/round_color_picker/round_color_picker";
import { CriterionForm } from "../criterion_form";
import { CriterionInput } from "../criterion_input/criterion_input";
diff --git a/src/components/side_panel/criterion_form/value_in_range_criterion/value_in_range_criterion.ts b/src/components/side_panel/criterion_form/value_in_range_criterion/value_in_range_criterion.ts
index bbf8350dae..f9dedf5e38 100644
--- a/src/components/side_panel/criterion_form/value_in_range_criterion/value_in_range_criterion.ts
+++ b/src/components/side_panel/criterion_form/value_in_range_criterion/value_in_range_criterion.ts
@@ -1,5 +1,6 @@
+import { Color } from "@odoo/o-spreadsheet-engine";
import { onWillStart, onWillUpdateProps } from "@odoo/owl";
-import { Color, IsValueInRangeCriterion } from "../../../../types";
+import { IsValueInRangeCriterion } from "../../../../types";
import { SelectionInput } from "../../../selection_input/selection_input";
import { RoundColorPicker } from "../../components/round_color_picker/round_color_picker";
import { CriterionForm } from "../criterion_form";
diff --git a/src/components/side_panel/custom_currency/custom_currency.ts b/src/components/side_panel/custom_currency/custom_currency.ts
index 9474a72ddf..e15a1b97db 100644
--- a/src/components/side_panel/custom_currency/custom_currency.ts
+++ b/src/components/side_panel/custom_currency/custom_currency.ts
@@ -1,10 +1,6 @@
+import { isDefined } from "@odoo/o-spreadsheet-engine";
import { Component, onWillStart, useState } from "@odoo/owl";
-import {
- createAccountingFormat,
- createCurrencyFormat,
- formatValue,
- isDefined,
-} from "../../../helpers";
+import { createAccountingFormat, createCurrencyFormat, formatValue } from "../../../helpers";
import { currenciesRegistry } from "../../../registries/currencies_registry";
import { _t } from "../../../translation";
import { Currency, Format, SpreadsheetChildEnv } from "../../../types";
diff --git a/src/components/side_panel/data_validation/data_validation_panel.ts b/src/components/side_panel/data_validation/data_validation_panel.ts
index fdaf487535..522d611de6 100644
--- a/src/components/side_panel/data_validation/data_validation_panel.ts
+++ b/src/components/side_panel/data_validation/data_validation_panel.ts
@@ -1,6 +1,7 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component, useState } from "@odoo/owl";
import { localizeDataValidationRule } from "../../../helpers/locale";
-import { DataValidationRule, SpreadsheetChildEnv, UID } from "../../../types";
+import { DataValidationRule, SpreadsheetChildEnv } from "../../../types";
import { DataValidationEditor } from "./dv_editor/dv_editor";
import { DataValidationPreview } from "./dv_preview/dv_preview";
diff --git a/src/components/side_panel/data_validation/dv_preview/dv_preview.ts b/src/components/side_panel/data_validation/dv_preview/dv_preview.ts
index ffb998dd1d..a663b098d1 100644
--- a/src/components/side_panel/data_validation/dv_preview/dv_preview.ts
+++ b/src/components/side_panel/data_validation/dv_preview/dv_preview.ts
@@ -1,7 +1,8 @@
+import { Highlight } from "@odoo/o-spreadsheet-engine";
import { Component, useRef } from "@odoo/owl";
import { HIGHLIGHT_COLOR } from "../../../../constants";
import { criterionEvaluatorRegistry } from "../../../../registries/criterion_registry";
-import { DataValidationRule, Highlight, SpreadsheetChildEnv } from "../../../../types";
+import { DataValidationRule, SpreadsheetChildEnv } from "../../../../types";
import { useHighlightsOnHover } from "../../../helpers/highlight_hook";
interface Props {
diff --git a/src/components/side_panel/find_and_replace/find_and_replace.ts b/src/components/side_panel/find_and_replace/find_and_replace.ts
index 857bbcd391..7f27c4c553 100644
--- a/src/components/side_panel/find_and_replace/find_and_replace.ts
+++ b/src/components/side_panel/find_and_replace/find_and_replace.ts
@@ -1,3 +1,5 @@
+import { debounce } from "@odoo/o-spreadsheet-engine";
+import { DebouncedFunction } from "@odoo/o-spreadsheet-engine/types";
import {
Component,
onMounted,
@@ -6,10 +8,10 @@ import {
useRef,
useState,
} from "@odoo/owl";
-import { debounce, zoneToXc } from "../../../helpers";
+import { zoneToXc } from "../../../helpers";
import { Store, useLocalStore } from "../../../store_engine";
import { _t } from "../../../translation";
-import { DebouncedFunction, SpreadsheetChildEnv } from "../../../types/index";
+import { SpreadsheetChildEnv } from "../../../types/index";
import { keyboardEventToShortcutString } from "../../helpers/dom_helpers";
import { SelectionInput } from "../../selection_input/selection_input";
import { ValidationMessages } from "../../validation_messages/validation_messages";
diff --git a/src/components/side_panel/find_and_replace/find_and_replace_store.ts b/src/components/side_panel/find_and_replace/find_and_replace_store.ts
index b6f3b9e127..aad3080be4 100644
--- a/src/components/side_panel/find_and_replace/find_and_replace_store.ts
+++ b/src/components/side_panel/find_and_replace/find_and_replace_store.ts
@@ -1,14 +1,11 @@
-import { getSearchRegex, isInside, positionToZone } from "../../../helpers";
+import { isInside, positionToZone } from "../../../helpers";
import { HighlightProvider, HighlightStore } from "../../../stores/highlight_store";
-import { CellPosition, Color, Command, Highlight } from "../../../types";
+import { Command } from "../../../types";
-import { canonicalizeNumberContent } from "../../../helpers/locale";
import { Get } from "../../../store_engine";
import { SpreadsheetStore } from "../../../stores";
import { NotificationStore } from "../../../stores/notification_store";
import { _t } from "../../../translation";
-import { SearchOptions } from "../../../types/find_and_replace";
-
const FIND_AND_REPLACE_HIGHLIGHT_COLOR: Color = "#8B008B";
enum Direction {
diff --git a/src/components/side_panel/pivot/pivot_custom_groups_collapsible/pivot_custom_groups_collapsible.ts b/src/components/side_panel/pivot/pivot_custom_groups_collapsible/pivot_custom_groups_collapsible.ts
index 43dbe0cf28..b89df95aaf 100644
--- a/src/components/side_panel/pivot/pivot_custom_groups_collapsible/pivot_custom_groups_collapsible.ts
+++ b/src/components/side_panel/pivot/pivot_custom_groups_collapsible/pivot_custom_groups_collapsible.ts
@@ -1,3 +1,4 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { deepCopy } from "../../../../helpers";
import { getUniquePivotGroupName } from "../../../../helpers/pivot/pivot_helpers";
@@ -7,7 +8,6 @@ import {
PivotCustomGroup,
PivotCustomGroupedField,
SpreadsheetChildEnv,
- UID,
} from "../../../../types";
import { TextInput } from "../../../text_input/text_input";
import { Checkbox } from "../../components/checkbox/checkbox";
diff --git a/src/components/side_panel/pivot/pivot_layout_configurator/pivot_layout_configurator.ts b/src/components/side_panel/pivot/pivot_layout_configurator/pivot_layout_configurator.ts
index 8411189694..4e75d5b748 100644
--- a/src/components/side_panel/pivot/pivot_layout_configurator/pivot_layout_configurator.ts
+++ b/src/components/side_panel/pivot/pivot_layout_configurator/pivot_layout_configurator.ts
@@ -1,5 +1,4 @@
-import { Component, useRef } from "@odoo/owl";
-import { isDefined } from "../../../../helpers";
+import { SortDirection } from "@odoo/o-spreadsheet-engine/types";
import {
AGGREGATORS,
getFieldDisplayName,
@@ -8,7 +7,7 @@ import {
import { PivotRuntimeDefinition } from "../../../../helpers/pivot/pivot_runtime_definition";
import { Store, useStore } from "../../../../store_engine";
import { _t } from "../../../../translation";
-import { SortDirection, SpreadsheetChildEnv, UID } from "../../../../types";
+import { SpreadsheetChildEnv } from "../../../../types";
import {
Aggregator,
Granularity,
diff --git a/src/components/side_panel/pivot/pivot_layout_configurator/pivot_measure/pivot_measure.ts b/src/components/side_panel/pivot/pivot_layout_configurator/pivot_measure/pivot_measure.ts
index 25e88f4fe7..b446514ccc 100644
--- a/src/components/side_panel/pivot/pivot_layout_configurator/pivot_measure/pivot_measure.ts
+++ b/src/components/side_panel/pivot/pivot_layout_configurator/pivot_measure/pivot_measure.ts
@@ -1,10 +1,11 @@
+import { Color } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { PIVOT_TOKEN_COLOR } from "../../../../../constants";
import { Token, compile } from "../../../../../formulas";
import { unquote } from "../../../../../helpers";
import { PivotRuntimeDefinition } from "../../../../../helpers/pivot/pivot_runtime_definition";
import { createMeasureAutoComplete } from "../../../../../registries/auto_completes/pivot_dimension_auto_complete";
-import { Color, PivotMeasure } from "../../../../../types";
+import { PivotMeasure } from "../../../../../types";
import { StandaloneComposer } from "../../../../composer/standalone_composer/standalone_composer";
import { PivotDimension } from "../pivot_dimension/pivot_dimension";
diff --git a/src/components/side_panel/pivot/pivot_layout_configurator/pivot_sort_section/pivot_sort_section.ts b/src/components/side_panel/pivot/pivot_layout_configurator/pivot_sort_section/pivot_sort_section.ts
index 0aa5ae47b8..55d3c00118 100644
--- a/src/components/side_panel/pivot/pivot_layout_configurator/pivot_sort_section/pivot_sort_section.ts
+++ b/src/components/side_panel/pivot/pivot_layout_configurator/pivot_sort_section/pivot_sort_section.ts
@@ -1,3 +1,4 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { SpreadsheetChildEnv } from "../../../../..";
import { formatValue } from "../../../../../helpers";
@@ -7,7 +8,7 @@ import {
} from "../../../../../helpers/pivot/pivot_helpers";
import { PivotRuntimeDefinition } from "../../../../../helpers/pivot/pivot_runtime_definition";
import { _t } from "../../../../../translation";
-import { PivotDomain, UID } from "../../../../../types";
+import { PivotDomain } from "../../../../../types";
import { Section } from "../../../components/section/section";
interface Props {
diff --git a/src/components/side_panel/pivot/pivot_measure_display_panel/pivot_measure_display_panel.ts b/src/components/side_panel/pivot/pivot_measure_display_panel/pivot_measure_display_panel.ts
index 8a707e1c37..38e76a54c1 100644
--- a/src/components/side_panel/pivot/pivot_measure_display_panel/pivot_measure_display_panel.ts
+++ b/src/components/side_panel/pivot/pivot_measure_display_panel/pivot_measure_display_panel.ts
@@ -1,5 +1,6 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
-import { PivotCoreMeasure, SpreadsheetChildEnv, UID } from "../../../..";
+import { PivotCoreMeasure, SpreadsheetChildEnv } from "../../../..";
import { Store, useLocalStore } from "../../../../store_engine";
import { measureDisplayTerms } from "../../../translations_terms";
import { Checkbox } from "../../components/checkbox/checkbox";
diff --git a/src/components/side_panel/pivot/pivot_measure_display_panel/pivot_measure_display_panel_store.ts b/src/components/side_panel/pivot/pivot_measure_display_panel/pivot_measure_display_panel_store.ts
index ea76205c41..628c89bd65 100644
--- a/src/components/side_panel/pivot/pivot_measure_display_panel/pivot_measure_display_panel_store.ts
+++ b/src/components/side_panel/pivot/pivot_measure_display_panel/pivot_measure_display_panel_store.ts
@@ -1,3 +1,4 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { deepCopy } from "../../../../helpers";
import { NEXT_VALUE, PREVIOUS_VALUE } from "../../../../helpers/pivot/pivot_domain_helpers";
import { getFieldDisplayName } from "../../../../helpers/pivot/pivot_helpers";
@@ -9,7 +10,6 @@ import {
PivotCoreMeasure,
PivotMeasureDisplay,
PivotMeasureDisplayType,
- UID,
} from "../../../../types";
export class PivotMeasureDisplayPanelStore extends SpreadsheetStore {
diff --git a/src/components/side_panel/pivot/pivot_side_panel/pivot_side_panel.ts b/src/components/side_panel/pivot/pivot_side_panel/pivot_side_panel.ts
index 51bad42fac..2cf66b8c22 100644
--- a/src/components/side_panel/pivot/pivot_side_panel/pivot_side_panel.ts
+++ b/src/components/side_panel/pivot/pivot_side_panel/pivot_side_panel.ts
@@ -1,7 +1,8 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { getPivotHighlights } from "../../../../helpers/pivot/pivot_highlight";
import { pivotSidePanelRegistry } from "../../../../helpers/pivot/pivot_side_panel_registry";
-import { SpreadsheetChildEnv, UID } from "../../../../types";
+import { SpreadsheetChildEnv } from "../../../../types";
import { useHighlights } from "../../../helpers/highlight_hook";
import { Section } from "../../components/section/section";
import { PivotLayoutConfigurator } from "../pivot_layout_configurator/pivot_layout_configurator";
diff --git a/src/components/side_panel/pivot/pivot_side_panel/pivot_side_panel_store.ts b/src/components/side_panel/pivot/pivot_side_panel/pivot_side_panel_store.ts
index 3b970b5dfa..216b7ad82f 100644
--- a/src/components/side_panel/pivot/pivot_side_panel/pivot_side_panel_store.ts
+++ b/src/components/side_panel/pivot/pivot_side_panel/pivot_side_panel_store.ts
@@ -1,5 +1,6 @@
+import { deepEquals, UID } from "@odoo/o-spreadsheet-engine";
import { PIVOT_MAX_NUMBER_OF_CELLS } from "../../../../constants";
-import { deepCopy, deepEquals } from "../../../../helpers";
+import { deepCopy } from "../../../../helpers";
import { getFirstPivotFunction } from "../../../../helpers/pivot/pivot_composer_helpers";
import { isDateOrDatetimeField } from "../../../../helpers/pivot/pivot_helpers";
import { pivotRegistry } from "../../../../helpers/pivot/pivot_registry";
@@ -7,7 +8,7 @@ import { Get } from "../../../../store_engine";
import { NotificationStore } from "../../../../stores/notification_store";
import { SpreadsheetStore } from "../../../../stores/spreadsheet_store";
import { _t } from "../../../../translation";
-import { Command, UID } from "../../../../types";
+import { Command } from "../../../../types";
import {
PivotCoreDefinition,
PivotCoreDimension,
diff --git a/src/components/side_panel/pivot/pivot_side_panel/pivot_spreadsheet_side_panel/pivot_spreadsheet_side_panel.ts b/src/components/side_panel/pivot/pivot_side_panel/pivot_spreadsheet_side_panel/pivot_spreadsheet_side_panel.ts
index 305d2da612..eee0cf0df4 100644
--- a/src/components/side_panel/pivot/pivot_side_panel/pivot_spreadsheet_side_panel/pivot_spreadsheet_side_panel.ts
+++ b/src/components/side_panel/pivot/pivot_side_panel/pivot_spreadsheet_side_panel/pivot_spreadsheet_side_panel.ts
@@ -1,8 +1,10 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
+import { Ref } from "@odoo/o-spreadsheet-engine/types";
import { Component, useRef, useState } from "@odoo/owl";
import { SpreadsheetPivotRuntimeDefinition } from "../../../../../helpers/pivot/spreadsheet_pivot/runtime_definition_spreadsheet_pivot";
import { SpreadsheetPivot } from "../../../../../helpers/pivot/spreadsheet_pivot/spreadsheet_pivot";
import { Store, useLocalStore } from "../../../../../store_engine";
-import { Ref, SpreadsheetChildEnv, UID } from "../../../../../types";
+import { SpreadsheetChildEnv } from "../../../../../types";
import { SpreadsheetPivotCoreDefinition } from "../../../../../types/pivot";
import { SelectionInput } from "../../../../selection_input/selection_input";
import { Checkbox } from "../../../components/checkbox/checkbox";
diff --git a/src/components/side_panel/pivot/pivot_title_section/pivot_title_section.ts b/src/components/side_panel/pivot/pivot_title_section/pivot_title_section.ts
index 94ac21e186..05dbdb451b 100644
--- a/src/components/side_panel/pivot/pivot_title_section/pivot_title_section.ts
+++ b/src/components/side_panel/pivot/pivot_title_section/pivot_title_section.ts
@@ -1,7 +1,8 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { Component } from "@odoo/owl";
import { ActionSpec } from "../../../../actions/action";
import { _t } from "../../../../translation";
-import { CommandResult, SpreadsheetChildEnv, UID } from "../../../../types";
+import { CommandResult, SpreadsheetChildEnv } from "../../../../types";
import { TextInput } from "../../../text_input/text_input";
import { CogWheelMenu } from "../../components/cog_wheel_menu/cog_wheel_menu";
import { Section } from "../../components/section/section";
diff --git a/src/components/side_panel/remove_duplicates/remove_duplicates.ts b/src/components/side_panel/remove_duplicates/remove_duplicates.ts
index a127bcd937..3038793ef8 100644
--- a/src/components/side_panel/remove_duplicates/remove_duplicates.ts
+++ b/src/components/side_panel/remove_duplicates/remove_duplicates.ts
@@ -1,7 +1,8 @@
+import { HeaderIndex } from "@odoo/o-spreadsheet-engine";
import { Component, onWillUpdateProps, useState } from "@odoo/owl";
import { numberToLetters, zoneToDimension } from "../../../helpers";
import { _t } from "../../../translation";
-import { HeaderIndex, SpreadsheetChildEnv } from "../../../types/index";
+import { SpreadsheetChildEnv } from "../../../types/index";
import { RemoveDuplicateTerms } from "../../translations_terms";
import { ValidationMessages } from "../../validation_messages/validation_messages";
import { Checkbox } from "../components/checkbox/checkbox";
diff --git a/src/components/side_panel/select_menu/select_menu.ts b/src/components/side_panel/select_menu/select_menu.ts
index 2c6f9a3224..bee55afe11 100644
--- a/src/components/side_panel/select_menu/select_menu.ts
+++ b/src/components/side_panel/select_menu/select_menu.ts
@@ -1,7 +1,8 @@
+import { MenuMouseEvent } from "@odoo/o-spreadsheet-engine";
import { Component, useRef, useState } from "@odoo/owl";
import { Action } from "../../../actions/action";
import { UuidGenerator } from "../../../helpers";
-import { MenuMouseEvent, Rect, SpreadsheetChildEnv } from "../../../types";
+import { Rect, SpreadsheetChildEnv } from "../../../types";
import { getRefBoundingRect } from "../../helpers/dom_helpers";
import { MenuPopover } from "../../menu_popover/menu_popover";
diff --git a/src/components/side_panel/settings/settings_panel.ts b/src/components/side_panel/settings/settings_panel.ts
index bbda1469dd..9e5297f4a1 100644
--- a/src/components/side_panel/settings/settings_panel.ts
+++ b/src/components/side_panel/settings/settings_panel.ts
@@ -1,5 +1,6 @@
+import { deepEquals } from "@odoo/o-spreadsheet-engine";
import { Component, onWillStart } from "@odoo/owl";
-import { DAYS, deepEquals, formatValue } from "../../../helpers";
+import { DAYS, formatValue } from "../../../helpers";
import { getDateTimeFormat, isValidLocale } from "../../../helpers/locale";
import { Locale, LocaleCode, SpreadsheetChildEnv } from "../../../types";
import { ValidationMessages } from "../../validation_messages/validation_messages";
diff --git a/src/components/side_panel/table_panel/table_panel.ts b/src/components/side_panel/table_panel/table_panel.ts
index d460f3efe5..4679238176 100644
--- a/src/components/side_panel/table_panel/table_panel.ts
+++ b/src/components/side_panel/table_panel/table_panel.ts
@@ -7,9 +7,9 @@ import {
Range,
SpreadsheetChildEnv,
TableConfig,
- Zone,
} from "../../../types";
+import { Zone } from "@odoo/o-spreadsheet-engine";
import { getTableTopLeft } from "../../../helpers/table_helpers";
import { SelectionInput } from "../../selection_input/selection_input";
import { TableStylePicker } from "../../tables/table_style_picker/table_style_picker";
diff --git a/src/components/side_panel/table_style_editor_panel/table_style_editor_panel.ts b/src/components/side_panel/table_style_editor_panel/table_style_editor_panel.ts
index 2f1cf8af8a..62837b46f9 100644
--- a/src/components/side_panel/table_style_editor_panel/table_style_editor_panel.ts
+++ b/src/components/side_panel/table_style_editor_panel/table_style_editor_panel.ts
@@ -1,8 +1,8 @@
+import { Color } from "@odoo/o-spreadsheet-engine";
import { Component, useExternalListener, useState } from "@odoo/owl";
import { isColorValid } from "../../../helpers";
import { TABLE_STYLES_TEMPLATES, buildTableStyle } from "../../../helpers/table_presets";
import {
- Color,
SpreadsheetChildEnv,
TableConfig,
TableStyle,
diff --git a/src/components/spreadsheet/spreadsheet.ts b/src/components/spreadsheet/spreadsheet.ts
index f86f5704b5..f5ebf3b721 100644
--- a/src/components/spreadsheet/spreadsheet.ts
+++ b/src/components/spreadsheet/spreadsheet.ts
@@ -1,16 +1,4 @@
-import {
- Component,
- onMounted,
- onPatched,
- onWillUnmount,
- onWillUpdateProps,
- useEffect,
- useExternalListener,
- useRef,
- useSubEnv,
-} from "@odoo/owl";
import { GROUP_LAYER_WIDTH, MAXIMAL_FREEZABLE_RATIO, SCROLLBAR_WIDTH } from "../../constants";
-import { batched } from "../../helpers";
import { ImageProvider } from "../../helpers/figures/images/image_provider";
import { Model } from "../../model";
import { Store, useStore, useStoreProvider } from "../../store_engine";
@@ -18,13 +6,7 @@ import { ModelStore } from "../../stores";
import { NotificationStore, NotificationStoreMethods } from "../../stores/notification_store";
import { ScreenWidthStore } from "../../stores/screen_width_store";
import { _t } from "../../translation";
-import {
- CSSProperties,
- HeaderGroup,
- InformationNotification,
- Pixel,
- SpreadsheetChildEnv,
-} from "../../types";
+import { CSSProperties, InformationNotification, SpreadsheetChildEnv } from "../../types";
import { BottomBar } from "../bottom_bar/bottom_bar";
import { ComposerFocusStore } from "../composer/composer_focus_store";
import { SpreadsheetDashboard } from "../dashboard/dashboard";
diff --git a/src/components/tables/hovered_table_store.ts b/src/components/tables/hovered_table_store.ts
index f65ae6bb84..74be583d5e 100644
--- a/src/components/tables/hovered_table_store.ts
+++ b/src/components/tables/hovered_table_store.ts
@@ -1,8 +1,9 @@
+import { Color, Position } from "@odoo/o-spreadsheet-engine";
import { TABLE_HOVER_BACKGROUND_COLOR } from "../../constants";
import { range } from "../../helpers";
import { PositionMap } from "../../helpers/cells/position_map";
import { SpreadsheetStore } from "../../stores";
-import { Color, Command, Position } from "../../types";
+import { Command } from "../../types";
export class HoveredTableStore extends SpreadsheetStore {
mutators = ["clear", "hover"] as const;
diff --git a/src/components/tables/table_resizer/table_resizer.ts b/src/components/tables/table_resizer/table_resizer.ts
index 3803d9212e..61d0c8fa91 100644
--- a/src/components/tables/table_resizer/table_resizer.ts
+++ b/src/components/tables/table_resizer/table_resizer.ts
@@ -1,9 +1,8 @@
+import { HeaderIndex, Highlight, Zone } from "@odoo/o-spreadsheet-engine";
import { Component, useState } from "@odoo/owl";
-import { HeaderIndex, Highlight, SpreadsheetChildEnv, Table, Zone } from "../../../types";
+import { SpreadsheetChildEnv, Table } from "../../../types";
import { cssPropertiesToCss } from "../../helpers";
import { useDragAndDropBeyondTheViewport } from "../../helpers/drag_and_drop_grid_hook";
-import { useHighlights } from "../../helpers/highlight_hook";
-
const SIZE = 3;
const COLOR = "#777";
diff --git a/src/components/tables/table_style_preview/table_style_preview.ts b/src/components/tables/table_style_preview/table_style_preview.ts
index d329833452..dfedbea9a4 100644
--- a/src/components/tables/table_style_preview/table_style_preview.ts
+++ b/src/components/tables/table_style_preview/table_style_preview.ts
@@ -1,5 +1,5 @@
+import { deepEquals } from "@odoo/o-spreadsheet-engine";
import { Component, onMounted, onWillUpdateProps, useRef, useState } from "@odoo/owl";
-import { deepEquals } from "../../../helpers";
import { getComputedTableStyle } from "../../../helpers/table_helpers";
import { createTableStyleContextMenuActions } from "../../../registries/menus/table_style_menu_registry";
import { SpreadsheetChildEnv } from "../../../types";
diff --git a/src/components/text_input/text_input.ts b/src/components/text_input/text_input.ts
index 86b41340af..c579c05c14 100644
--- a/src/components/text_input/text_input.ts
+++ b/src/components/text_input/text_input.ts
@@ -1,7 +1,7 @@
+import { isDefined } from "@odoo/o-spreadsheet-engine";
+import { Ref } from "@odoo/o-spreadsheet-engine/types";
import { Component, useExternalListener, useRef } from "@odoo/owl";
import { SpreadsheetChildEnv } from "../..";
-import { isDefined } from "../../helpers";
-import { Ref } from "../../types";
import { useAutofocus } from "../helpers/autofocus_hook";
interface Props {
diff --git a/src/components/top_bar/top_bar.ts b/src/components/top_bar/top_bar.ts
index 506f0b1e7e..91acd00497 100644
--- a/src/components/top_bar/top_bar.ts
+++ b/src/components/top_bar/top_bar.ts
@@ -1,3 +1,4 @@
+import { Color, Pixel } from "@odoo/o-spreadsheet-engine";
import {
Component,
onWillStart,
@@ -15,7 +16,7 @@ import { topbarMenuRegistry } from "../../registries/menus/topbar_menu_registry"
import { topbarComponentRegistry } from "../../registries/topbar_component_registry";
import { Store, useStore } from "../../store_engine";
import { FormulaFingerprintStore } from "../../stores/formula_fingerprints_store";
-import { Color, Pixel, SpreadsheetChildEnv } from "../../types/index";
+import { SpreadsheetChildEnv } from "../../types/index";
import { ComposerFocusStore } from "../composer/composer_focus_store";
import { TopBarComposer } from "../composer/top_bar_composer/top_bar_composer";
import { getBoundingRectAsPOJO } from "../helpers/dom_helpers";
@@ -23,8 +24,6 @@ import { useSpreadsheetRect } from "../helpers/position_hook";
import { MenuPopover, MenuState } from "../menu_popover/menu_popover";
import { Popover, PopoverProps } from "../popover";
import { TopBarToolStore } from "./top_bar_tool_store";
-import { topBarToolBarRegistry } from "./top_bar_tools_registry";
-
interface State {
menuState: MenuState;
invisibleToolsCategories: string[];
diff --git a/src/constants.ts b/src/constants.ts
index a408ba8941..74be050a4b 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -1,5 +1,3 @@
-import { BorderDescr, ChartStyle, Color, Currency, Style } from "./types";
-
export const CANVAS_SHIFT = 0.5;
// Colors
diff --git a/src/formulas/compiler.ts b/src/formulas/compiler.ts
index b42b5ae2dc..7ddc09fd9f 100644
--- a/src/formulas/compiler.ts
+++ b/src/formulas/compiler.ts
@@ -1,362 +1,29 @@
-import { Token } from ".";
+import { CompiledFormula, FormulaToExecute, functionRegistry } from "@odoo/o-spreadsheet-engine";
+import {
+ OPERATOR_MAP,
+ UNARY_OPERATOR_MAP,
+ compile as engineCompile,
+ compileTokens as engineCompileTokens,
+ functionCache as engineFunctionCache,
+ setArgTargetingImplementation,
+ setFunctionRegistryProvider,
+} from "@odoo/o-spreadsheet-engine/formulas/compiler";
import { argTargeting } from "../functions/arguments";
-import { functionRegistry } from "../functions/index";
-import { parseNumber, unquote } from "../helpers";
-import { _t } from "../translation";
-import { CompiledFormula, DEFAULT_LOCALE, FormulaToExecute } from "../types";
-import { BadExpressionError, UnknownFunctionError } from "../types/errors";
-import { FunctionCode, FunctionCodeBuilder, Scope } from "./code_builder";
-import { AST, ASTFuncall, parseTokens } from "./parser";
-import { rangeTokenize } from "./range_tokenizer";
+import type { Token } from "./tokenizer";
-const functions = functionRegistry.content;
+//TODO When the getters will be moved to o-spreadsheet-engine, we will be able
+// to remove this file and directly use the one from o-spreadsheet-engine
+setFunctionRegistryProvider(() => functionRegistry);
+setArgTargetingImplementation(argTargeting);
-export const OPERATOR_MAP = {
- // export for test
- "=": "EQ",
- "+": "ADD",
- "-": "MINUS",
- "*": "MULTIPLY",
- "/": "DIVIDE",
- ">=": "GTE",
- "<>": "NE",
- ">": "GT",
- "<=": "LTE",
- "<": "LT",
- "^": "POWER",
- "&": "CONCATENATE",
-};
-
-export const UNARY_OPERATOR_MAP = {
- // export for test
- "-": "UMINUS",
- "+": "UPLUS",
- "%": "UNARY.PERCENT",
-};
-
-interface LiteralValues {
- numbers: { value: number }[];
- strings: { value: string }[];
-}
-
-type InternalCompiledFormula = CompiledFormula & {
- literalValues: LiteralValues;
- symbols: string[];
-};
-
-// this cache contains all compiled function code, grouped by "structure". For
-// example, "=2*sum(A1:A4)" and "=2*sum(B1:B4)" are compiled into the same
-// structural function.
-// It is only exported for testing purposes
-export const functionCache: { [key: string]: FormulaToExecute } = {};
-
-// -----------------------------------------------------------------------------
-// COMPILER
-// -----------------------------------------------------------------------------
+export { OPERATOR_MAP, UNARY_OPERATOR_MAP };
export function compile(formula: string): CompiledFormula {
- const tokens = rangeTokenize(formula);
- return compileTokens(tokens);
+ return engineCompile(formula) as unknown as CompiledFormula;
}
export function compileTokens(tokens: Token[]): CompiledFormula {
- try {
- return compileTokensOrThrow(tokens);
- } catch (error) {
- return {
- tokens,
- dependencies: [],
- execute: function () {
- return error;
- },
- isBadExpression: true,
- normalizedFormula: tokens.map((t) => t.value).join(""),
- };
- }
-}
-
-function compileTokensOrThrow(tokens: Token[]): CompiledFormula {
- const { dependencies, literalValues, symbols } = formulaArguments(tokens);
- const cacheKey = compilationCacheKey(tokens);
- if (!functionCache[cacheKey]) {
- const ast = parseTokens([...tokens]);
- const scope = new Scope();
-
- let stringCount = 0;
- let numberCount = 0;
- let dependencyCount = 0;
-
- if (ast.type === "BIN_OPERATION" && ast.value === ":") {
- throw new BadExpressionError(_t("Invalid formula"));
- }
- if (ast.type === "EMPTY") {
- throw new BadExpressionError(_t("Invalid formula"));
- }
- const compiledAST = compileAST(ast);
- const code = new FunctionCodeBuilder();
- code.append(`// ${cacheKey}`);
- code.append(compiledAST);
- code.append(`return ${compiledAST.returnExpression};`);
- const baseFunction = new Function(
- "deps", // the dependencies in the current formula
- "ref", // a function to access a certain dependency at a given index
- "range", // same as above, but guarantee that the result is in the form of a range
- "getSymbolValue",
- "ctx",
- code.toString()
- );
-
- // @ts-ignore
- functionCache[cacheKey] = baseFunction;
-
- /**
- * This function compile the function arguments. It is mostly straightforward,
- * except that there is a non trivial transformation in one situation:
- *
- * If a function argument is asking for a range, and get a cell, we transform
- * the cell value into a range. This allow the grid model to differentiate
- * between a cell value and a non cell value.
- */
- function compileFunctionArgs(ast: ASTFuncall): FunctionCode[] {
- const { args } = ast;
- const functionName = ast.value.toUpperCase();
- const functionDefinition = functions[functionName];
-
- if (!functionDefinition) {
- throw new UnknownFunctionError(_t('Unknown function: "%s"', ast.value));
- }
-
- assertEnoughArgs(ast);
-
- const compiledArgs: FunctionCode[] = [];
-
- const argToFocus = argTargeting(functionDefinition, args.length);
-
- for (let i = 0; i < args.length; i++) {
- const argDefinition = functionDefinition.args[argToFocus(i) ?? -1];
- const currentArg = args[i];
- const argTypes = argDefinition.type || [];
-
- // detect when an argument need to be evaluated as a meta argument
- const isMeta = argTypes.includes("META") || argTypes.includes("RANGE");
- const hasRange = argTypes.some((t) => isRangeType(t));
-
- compiledArgs.push(compileAST(currentArg, isMeta, hasRange));
- }
-
- return compiledArgs;
- }
-
- /**
- * This function compiles all the information extracted by the parser into an
- * executable code for the evaluation of the cells content. It uses a cache to
- * not reevaluate identical code structures.
- *
- * The function is sensitive to parameter “isMeta”. This
- * parameter may vary when compiling function arguments:
- * isMeta: In some cases the function arguments expects information on the
- * cell/range other than the associated value(s). For example the COLUMN
- * function needs to receive as argument the coordinates of a cell rather
- * than its value. For this we have meta arguments.
- */
- function compileAST(ast: AST, isMeta = false, hasRange = false): FunctionCode {
- const code = new FunctionCodeBuilder(scope);
- if (ast.type !== "REFERENCE" && !(ast.type === "BIN_OPERATION" && ast.value === ":")) {
- if (isMeta) {
- throw new BadExpressionError(_t("Argument must be a reference to a cell or range."));
- }
- }
- if (ast.debug) {
- code.append("debugger;");
- code.append(`ctx["debug"] = true;`);
- }
- switch (ast.type) {
- case "BOOLEAN":
- return code.return(`{ value: ${ast.value} }`);
- case "NUMBER":
- return code.return(`this.literalValues.numbers[${numberCount++}]`);
- case "STRING":
- return code.return(`this.literalValues.strings[${stringCount++}]`);
- case "REFERENCE":
- return code.return(
- `${ast.value.includes(":") || hasRange ? `range` : `ref`}(deps[${dependencyCount++}], ${
- isMeta ? "true" : "false"
- })`
- );
- case "FUNCALL":
- const args = compileFunctionArgs(ast).map((arg) => arg.assignResultToVariable());
- code.append(...args);
- const fnName = ast.value.toUpperCase();
- return code.return(`ctx['${fnName}'](${args.map((arg) => arg.returnExpression)})`);
- case "UNARY_OPERATION": {
- const fnName = UNARY_OPERATOR_MAP[ast.value];
- const operand = compileAST(ast.operand, false, false).assignResultToVariable();
- code.append(operand);
- return code.return(`ctx['${fnName}'](${operand.returnExpression})`);
- }
- case "BIN_OPERATION": {
- const fnName = OPERATOR_MAP[ast.value];
- const left = compileAST(ast.left, false, false).assignResultToVariable();
- const right = compileAST(ast.right, false, false).assignResultToVariable();
- code.append(left);
- code.append(right);
- return code.return(
- `ctx['${fnName}'](${left.returnExpression}, ${right.returnExpression})`
- );
- }
- case "SYMBOL":
- const symbolIndex = symbols.indexOf(ast.value);
- return code.return(`getSymbolValue(this.symbols[${symbolIndex}])`);
- case "EMPTY":
- return code.return("undefined");
- }
- }
- }
- const compiledFormula: InternalCompiledFormula = {
- execute: functionCache[cacheKey],
- dependencies,
- literalValues,
- symbols,
- tokens,
- isBadExpression: false,
- normalizedFormula: cacheKey,
- };
- return compiledFormula;
-}
-
-/**
- * Compute a cache key for the formula.
- * References, numbers and strings are replaced with placeholders because
- * the compiled formula does not depend on their actual value.
- * Both `=A1+1+"2"` and `=A2+2+"3"` are compiled to the exact same function.
- * Spaces are also ignored to compute the cache key.
- *
- * A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|C|+|C|+SUM(|N|,|N|,|S|)`
- */
-function compilationCacheKey(tokens: Token[]): string {
- let cacheKey = "";
- for (const token of tokens) {
- switch (token.type) {
- case "STRING":
- cacheKey += "|S|";
- break;
- case "NUMBER":
- cacheKey += "|N|";
- break;
- case "REFERENCE":
- case "INVALID_REFERENCE":
- if (token.value.includes(":")) {
- cacheKey += "|R|";
- } else {
- cacheKey += "|C|";
- }
- break;
- case "SPACE":
- // ignore spaces
- break;
- default:
- cacheKey += token.value;
- break;
- }
- }
- return cacheKey;
-}
-
-/**
- * Return formula arguments which are references, strings and numbers.
- */
-function formulaArguments(tokens: Token[]) {
- const literalValues: LiteralValues = {
- numbers: [],
- strings: [],
- };
- const dependencies: string[] = [];
- const symbols: string[] = [];
- for (const token of tokens) {
- switch (token.type) {
- case "INVALID_REFERENCE":
- case "REFERENCE":
- dependencies.push(token.value);
- break;
- case "STRING":
- const value = unquote(token.value);
- literalValues.strings.push({ value });
- break;
- case "NUMBER": {
- const value = parseNumber(token.value, DEFAULT_LOCALE);
- literalValues.numbers.push({ value });
- break;
- }
- case "SYMBOL": {
- // function name symbols are also included here
- symbols.push(unquote(token.value, "'"));
- }
- }
- }
- return {
- dependencies,
- literalValues,
- symbols,
- };
-}
-
-/**
- * Check if arguments are supplied in the correct quantities
- */
-function assertEnoughArgs(ast: ASTFuncall) {
- const nbrArgSupplied = ast.args.length;
- const functionName = ast.value.toUpperCase();
- const functionDefinition = functions[functionName];
- const { nbrArgRepeating, minArgRequired } = functionDefinition;
-
- if (nbrArgSupplied < minArgRequired) {
- throw new BadExpressionError(
- _t(
- "Invalid number of arguments for the %(functionName)s function. Expected %(minArgRequired)s minimum, but got %(nbrArgSupplied)s instead.",
- {
- functionName,
- minArgRequired,
- nbrArgSupplied,
- }
- )
- );
- }
-
- if (nbrArgSupplied > functionDefinition.maxArgPossible) {
- throw new BadExpressionError(
- _t(
- "Invalid number of arguments for the %(functionName)s function. Expected %(maxArgPossible)s maximum, but got %(nbrArgSupplied)s instead.",
- {
- functionName,
- maxArgPossible: functionDefinition.maxArgPossible,
- nbrArgSupplied,
- }
- )
- );
- }
-
- if (nbrArgRepeating > 1) {
- const nbrValueRepeating =
- nbrArgRepeating * Math.floor((nbrArgSupplied - minArgRequired) / nbrArgRepeating);
- const nbrValueRemaining =
- nbrArgSupplied - minArgRequired - nbrValueRepeating - functionDefinition.nbrArgOptional;
-
- if (nbrValueRemaining > 0) {
- throw new BadExpressionError(
- _t(
- "Invalid number of arguments for the %(functionName)s function. Repeatable arguments should be supplied in groups of %(nbrArgRepeating)s, with up to %(nbrArgOptional)s optional. Got %(nbrValueRemaining)s too many.",
- {
- functionName,
- nbrArgRepeating,
- nbrArgOptional: functionDefinition.nbrArgOptional,
- nbrValueRemaining,
- }
- )
- );
- }
- }
+ return engineCompileTokens(tokens) as unknown as CompiledFormula;
}
-function isRangeType(type: string) {
- return type.startsWith("RANGE");
-}
+export const functionCache = engineFunctionCache as Record;
diff --git a/src/formulas/composer_tokenizer.ts b/src/formulas/composer_tokenizer.ts
index e17df8bdbf..4cc0910c9b 100644
--- a/src/formulas/composer_tokenizer.ts
+++ b/src/formulas/composer_tokenizer.ts
@@ -1,4 +1,5 @@
-import { Color, Locale } from "../types";
+import { Color } from "@odoo/o-spreadsheet-engine";
+import { Locale } from "../types";
import { Token } from "./index";
import { AST, parseTokens } from "./parser";
import { rangeTokenize } from "./range_tokenizer";
diff --git a/src/formulas/index.ts b/src/formulas/index.ts
index 7fce7c353b..24aad6b1fa 100644
--- a/src/formulas/index.ts
+++ b/src/formulas/index.ts
@@ -8,7 +8,6 @@
*/
export { compile } from "./compiler";
-export * from "./helpers";
export { parse } from "./parser";
export { rangeTokenize } from "./range_tokenizer";
export { Token, tokenize } from "./tokenizer";
diff --git a/src/formulas/parser.ts b/src/formulas/parser.ts
index 059b649c9d..c2bb30803c 100644
--- a/src/formulas/parser.ts
+++ b/src/formulas/parser.ts
@@ -1,414 +1,16 @@
-import { parseNumber, unquote } from "../helpers/index";
-import { _t } from "../translation";
-import { DEFAULT_LOCALE } from "../types";
-import { BadExpressionError, CellErrorType } from "../types/errors";
-import { rangeTokenize } from "./range_tokenizer";
-import { Token } from "./tokenizer";
-
-const functionRegex = /[a-zA-Z0-9\_]+(\.[a-zA-Z0-9\_]+)*/;
-
-const UNARY_OPERATORS_PREFIX = ["-", "+"];
-const UNARY_OPERATORS_POSTFIX = ["%"];
-
-interface RichToken extends Token {
- tokenIndex: number;
-}
-
-export class TokenList {
- private tokens: RichToken[];
- currentIndex: number = 0;
- current: RichToken | undefined;
- length: number;
-
- constructor(tokens: RichToken[]) {
- this.tokens = tokens;
- this.current = tokens[0];
- this.length = tokens.length;
- }
-
- shift() {
- const current = this.tokens[this.currentIndex];
- this.current = this.tokens[++this.currentIndex];
- return current;
- }
-
- get next(): RichToken | undefined {
- return this.tokens[this.currentIndex + 1];
- }
-}
-
-// -----------------------------------------------------------------------------
-// PARSER
-// -----------------------------------------------------------------------------
-interface ASTBase {
- debug?: boolean;
- tokenStartIndex: number;
- tokenEndIndex: number;
-}
-
-interface ASTNumber extends ASTBase {
- type: "NUMBER";
- value: number;
-}
-
-interface ASTReference extends ASTBase {
- type: "REFERENCE";
- value: string;
-}
-
-export interface ASTString extends ASTBase {
- type: "STRING";
- value: string;
-}
-
-interface ASTBoolean extends ASTBase {
- type: "BOOLEAN";
- value: boolean;
-}
-
-export interface ASTUnaryOperation extends ASTBase {
- type: "UNARY_OPERATION";
- value: any;
- operand: AST;
- postfix?: boolean; // needed to rebuild string from ast
-}
-
-export interface ASTOperation extends ASTBase {
- type: "BIN_OPERATION";
- value: any;
- left: AST;
- right: AST;
-}
-
-export interface ASTFuncall extends ASTBase {
- type: "FUNCALL";
- value: string;
- args: AST[];
-}
-
-export interface ASTSymbol extends ASTBase {
- type: "SYMBOL";
- value: string;
-}
-
-interface ASTEmpty extends ASTBase {
- type: "EMPTY";
- value: "";
-}
-
-export type AST =
- | ASTOperation
- | ASTUnaryOperation
- | ASTFuncall
- | ASTSymbol
- | ASTNumber
- | ASTBoolean
- | ASTString
- | ASTReference
- | ASTEmpty;
-
-export const OP_PRIORITY = {
- "%": 40,
- "^": 30,
- "*": 20,
- "/": 20,
- "+": 15,
- "-": 15,
- "&": 13,
- ">": 10,
- "<>": 10,
- ">=": 10,
- "<": 10,
- "<=": 10,
- "=": 10,
-};
-
-/**
- * Parse the next operand in an arithmetic expression.
- * e.g.
- * for 1+2*3, the next operand is 1
- * for (1+2)*3, the next operand is (1+2)
- * for SUM(1,2)+3, the next operand is SUM(1,2)
- */
-function parseOperand(tokens: TokenList): AST {
- const current = tokens.shift();
- if (!current) {
- throw new BadExpressionError();
- }
- switch (current.type) {
- case "DEBUGGER":
- const next = parseExpression(tokens, 1000);
- next.debug = true;
- return next;
- case "NUMBER":
- return {
- type: "NUMBER",
- value: parseNumber(current.value, DEFAULT_LOCALE),
- tokenStartIndex: current.tokenIndex,
- tokenEndIndex: current.tokenIndex,
- };
- case "STRING":
- return {
- type: "STRING",
- value: unquote(current.value),
- tokenStartIndex: current.tokenIndex,
- tokenEndIndex: current.tokenIndex,
- };
- case "INVALID_REFERENCE":
- return {
- type: "REFERENCE",
- value: CellErrorType.InvalidReference,
- tokenStartIndex: current.tokenIndex,
- tokenEndIndex: current.tokenIndex,
- };
-
- case "REFERENCE":
- if (tokens.current?.value === ":" && tokens.next?.type === "REFERENCE") {
- tokens.shift();
- const rightReference = tokens.shift();
- return {
- type: "REFERENCE",
- value: `${current.value}:${rightReference?.value}`,
- tokenStartIndex: current.tokenIndex,
- tokenEndIndex: rightReference.tokenIndex,
- };
- }
- return {
- type: "REFERENCE",
- value: current.value,
- tokenStartIndex: current.tokenIndex,
- tokenEndIndex: current.tokenIndex,
- };
- case "SYMBOL":
- const value = current.value;
- const nextToken = tokens.current;
- if (
- nextToken?.type === "LEFT_PAREN" &&
- functionRegex.test(current.value) &&
- value === unquote(value, "'")
- ) {
- const { args, rightParen } = parseFunctionArgs(tokens);
- return {
- type: "FUNCALL",
- value: value,
- args,
- tokenStartIndex: current.tokenIndex,
- tokenEndIndex: rightParen.tokenIndex,
- };
- }
- const upperCaseValue = value.toUpperCase();
- if (upperCaseValue === "TRUE" || upperCaseValue === "FALSE") {
- return {
- type: "BOOLEAN",
- value: upperCaseValue === "TRUE",
- tokenStartIndex: current.tokenIndex,
- tokenEndIndex: current.tokenIndex,
- };
- }
- return {
- type: "SYMBOL",
- value: unquote(current.value, "'"),
- tokenStartIndex: current.tokenIndex,
- tokenEndIndex: current.tokenIndex,
- };
- case "LEFT_PAREN":
- const result = parseExpression(tokens);
- const rightParen = consumeOrThrow(tokens, "RIGHT_PAREN", _t("Missing closing parenthesis"));
- return {
- ...result,
- tokenStartIndex: current.tokenIndex,
- tokenEndIndex: rightParen.tokenIndex,
- };
- case "OPERATOR":
- const operator = current.value;
- if (UNARY_OPERATORS_PREFIX.includes(operator)) {
- const operand = parseExpression(tokens, OP_PRIORITY[operator]);
- return {
- type: "UNARY_OPERATION",
- value: operator,
- operand,
- tokenStartIndex: current.tokenIndex,
- tokenEndIndex: operand.tokenEndIndex,
- };
- }
- throw new BadExpressionError(_t("Unexpected token: %s", current.value));
- default:
- throw new BadExpressionError(_t("Unexpected token: %s", current.value));
- }
-}
-
-function parseFunctionArgs(tokens: TokenList) {
- consumeOrThrow(tokens, "LEFT_PAREN", _t("Missing opening parenthesis"));
- const nextToken = tokens.current;
- if (nextToken?.type === "RIGHT_PAREN") {
- const rightParen = consumeOrThrow(tokens, "RIGHT_PAREN");
- return { args: [], rightParen };
- }
- const args: AST[] = [];
- args.push(parseOneFunctionArg(tokens));
- while (tokens.current?.type !== "RIGHT_PAREN") {
- consumeOrThrow(tokens, "ARG_SEPARATOR", _t("Wrong function call"));
- args.push(parseOneFunctionArg(tokens));
- }
- const rightParen = consumeOrThrow(tokens, "RIGHT_PAREN");
- return { args, rightParen };
-}
-
-function parseOneFunctionArg(tokens: TokenList): AST {
- const nextToken = tokens.current;
- if (nextToken?.type === "ARG_SEPARATOR" || nextToken?.type === "RIGHT_PAREN") {
- // arg is empty: "sum(1,,2)" "sum(,1)" "sum(1,)"
- return {
- type: "EMPTY",
- value: "",
- tokenStartIndex: nextToken.tokenIndex,
- tokenEndIndex: nextToken.tokenIndex,
- };
- }
- return parseExpression(tokens);
-}
-
-function consumeOrThrow(tokens: TokenList, type, message?: string) {
- const token = tokens.shift();
- if (!token || token.type !== type) {
- throw new BadExpressionError(message);
- }
- return token;
-}
-
-function parseExpression(tokens: TokenList, parent_priority: number = 0): AST {
- if (tokens.length === 0) {
- throw new BadExpressionError();
- }
- let left = parseOperand(tokens);
- // as long as we have operators with higher priority than the parent one,
- // continue parsing the expression because it is a child sub-expression
- while (
- tokens.current?.type === "OPERATOR" &&
- OP_PRIORITY[tokens.current.value] > parent_priority
- ) {
- const operatorToken = tokens.shift();
- const operator = operatorToken.value;
- if (UNARY_OPERATORS_POSTFIX.includes(operator)) {
- left = {
- type: "UNARY_OPERATION",
- value: operator,
- operand: left,
- postfix: true,
- tokenStartIndex: left.tokenStartIndex,
- tokenEndIndex: operatorToken.tokenIndex,
- };
- } else {
- const right = parseExpression(tokens, OP_PRIORITY[operator]);
- left = {
- type: "BIN_OPERATION",
- value: operator,
- left,
- right,
- tokenStartIndex: left.tokenStartIndex,
- tokenEndIndex: right.tokenEndIndex,
- };
- }
- }
- return left;
-}
-
-/**
- * Parse an expression (as a string) into an AST.
- */
-export function parse(str: string): AST {
- return parseTokens(rangeTokenize(str));
-}
-
-export function parseTokens(tokens: Token[]): AST {
- const richTokens = tokens.map((token, index) => ({
- type: token.type,
- value: token.value,
- tokenIndex: index,
- }));
- const tokensToParse = richTokens.filter((x) => x.type !== "SPACE");
- const tokenList = new TokenList(tokensToParse);
- if (tokenList.current?.value === "=") {
- tokenList.shift();
- }
- const result = parseExpression(tokenList);
- if (tokenList.current) {
- throw new BadExpressionError();
- }
- return result;
-}
-
-/**
- * Allows to visit all nodes of an AST and apply a mapping function
- * to nodes of a specific type.
- * Useful if you want to convert some part of a formula.
- *
- * @example
- * convertAstNodes(ast, "FUNCALL", convertFormulaToExcel)
- *
- * function convertFormulaToExcel(ast: ASTFuncall) {
- * // ...
- * return modifiedAst
- * }
- */
-export function convertAstNodes(
- ast: AST,
- type: T,
- fn: (ast: Extract) => AST
-): AST {
- return mapAst(ast, (ast) => {
- if (ast.type === type) {
- return fn(ast as Extract);
- }
- return ast;
- });
-}
-
-export function iterateAstNodes(ast: AST): AST[] {
- return Array.from(astIterator(ast));
-}
-
-function* astIterator(ast: AST): Iterable {
- yield ast;
- switch (ast.type) {
- case "FUNCALL":
- for (const arg of ast.args) {
- yield* astIterator(arg);
- }
- break;
- case "UNARY_OPERATION":
- yield* astIterator(ast.operand);
- break;
- case "BIN_OPERATION":
- yield* astIterator(ast.left);
- yield* astIterator(ast.right);
- break;
- }
-}
-
-export function mapAst(
- ast: AST,
- fn: (ast: Extract) => AST
-): AST {
- ast = fn(ast as Extract);
- switch (ast.type) {
- case "FUNCALL":
- return {
- ...ast,
- args: ast.args.map((child) => mapAst(child, fn)),
- };
- case "UNARY_OPERATION":
- return {
- ...ast,
- operand: mapAst(ast.operand, fn),
- };
- case "BIN_OPERATION":
- return {
- ...ast,
- right: mapAst(ast.right, fn),
- left: mapAst(ast.left, fn),
- };
- default:
- return ast;
- }
-}
+export {
+ OP_PRIORITY,
+ convertAstNodes,
+ iterateAstNodes,
+ mapAst,
+ parse,
+ parseTokens,
+} from "@odoo/o-spreadsheet-engine/formulas/parser";
+export type {
+ AST,
+ ASTFuncall,
+ ASTOperation,
+ ASTString,
+ ASTSymbol,
+ ASTUnaryOperation,
+} from "@odoo/o-spreadsheet-engine/formulas/parser";
diff --git a/src/formulas/range_tokenizer.ts b/src/formulas/range_tokenizer.ts
index 37c99bf642..31c9a487cc 100644
--- a/src/formulas/range_tokenizer.ts
+++ b/src/formulas/range_tokenizer.ts
@@ -1,162 +1 @@
-import {
- isColHeader,
- isColReference,
- isRowHeader,
- isRowReference,
- isSingleCellReference,
-} from "../helpers";
-import { DEFAULT_LOCALE } from "./../types/locale";
-import { Token, tokenize } from "./tokenizer";
-
-enum State {
- /**
- * Initial state.
- * Expecting any reference for the left part of a range
- * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
- */
- LeftRef,
- /**
- * Expecting any reference for the right part of a range
- * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
- */
- RightRef,
- /**
- * Expecting the separator without any constraint on the right part
- */
- Separator,
- /**
- * Expecting the separator for a full column range
- */
- FullColumnSeparator,
- /**
- * Expecting the separator for a full row range
- */
- FullRowSeparator,
- /**
- * Expecting the right part of a full column range
- * e.g. "1", "A1"
- */
- RightColumnRef,
- /**
- * Expecting the right part of a full row range
- * e.g. "A", "A1"
- */
- RightRowRef,
- /**
- * Final state. A range has been matched
- */
- Found,
-}
-
-const goTo = (state: State, guard: (token: Token) => boolean = () => true) => [
- {
- goTo: state,
- guard,
- },
-];
-
-const goToMulti = (state: State, guard: (token: Token) => boolean = () => true) => ({
- goTo: state,
- guard,
-});
-
-interface Transition {
- goTo: State;
- guard: (token: Token) => boolean;
-}
-
-type Machine = {
- [s in State]: Record;
-};
-
-const machine: Machine = {
- [State.LeftRef]: {
- REFERENCE: goTo(State.Separator),
- NUMBER: goTo(State.FullRowSeparator),
- SYMBOL: [
- goToMulti(State.FullColumnSeparator, (token) => isColReference(token.value)),
- goToMulti(State.FullRowSeparator, (token) => isRowReference(token.value)),
- ],
- },
- [State.FullColumnSeparator]: {
- SPACE: goTo(State.FullColumnSeparator),
- OPERATOR: goTo(State.RightColumnRef, (token) => token.value === ":"),
- },
- [State.FullRowSeparator]: {
- SPACE: goTo(State.FullRowSeparator),
- OPERATOR: goTo(State.RightRowRef, (token) => token.value === ":"),
- },
- [State.Separator]: {
- SPACE: goTo(State.Separator),
- OPERATOR: goTo(State.RightRef, (token) => token.value === ":"),
- },
- [State.RightRef]: {
- SPACE: goTo(State.RightRef),
- NUMBER: goTo(State.Found),
- REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
- SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
- },
- [State.RightColumnRef]: {
- SPACE: goTo(State.RightColumnRef),
- SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
- REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
- },
- [State.RightRowRef]: {
- SPACE: goTo(State.RightRowRef),
- NUMBER: goTo(State.Found),
- REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
- SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
- },
- [State.Found]: {},
-};
-
-/**
- * Check if the list of tokens starts with a sequence of tokens representing
- * a range.
- * If a range is found, the sequence is removed from the list and is returned
- * as a single token.
- */
-function matchReference(tokens: Token[]): Token | null {
- let head = 0;
- let transitions = machine[State.LeftRef];
- let matchedTokens: string = "";
- while (transitions !== undefined) {
- const token = tokens[head++];
- if (!token) {
- return null;
- }
- const transition = transitions[token.type]?.find((transition) => transition.guard(token));
- const nextState = transition ? transition.goTo : undefined;
- switch (nextState) {
- case undefined:
- return null;
- case State.Found:
- matchedTokens += token.value;
- tokens.splice(0, head);
- return {
- type: "REFERENCE",
- value: matchedTokens,
- };
- default:
- transitions = machine[nextState];
- matchedTokens += token.value;
- break;
- }
- }
- return null;
-}
-
-/**
- * Take the result of the tokenizer and transform it to be usable in the
- * manipulations of range
- *
- * @param formula
- */
-export function rangeTokenize(formula: string, locale = DEFAULT_LOCALE): Token[] {
- const tokens = tokenize(formula, locale);
- const result: Token[] = [];
- while (tokens.length) {
- result.push(matchReference(tokens) || tokens.shift()!);
- }
- return result;
-}
+export { rangeTokenize } from "@odoo/o-spreadsheet-engine/formulas/range_tokenizer";
diff --git a/src/formulas/tokenizer.ts b/src/formulas/tokenizer.ts
index 4c0dc5b975..1231933a13 100644
--- a/src/formulas/tokenizer.ts
+++ b/src/formulas/tokenizer.ts
@@ -1,263 +1,2 @@
-import { NEWLINE } from "../constants";
-import {
- TokenizingChars,
- getFormulaNumberRegex,
- rangeReference,
- replaceNewLines,
- specialWhiteSpaceRegexp,
-} from "../helpers/index";
-import { DEFAULT_LOCALE, Locale } from "../types";
-import { CellErrorType } from "../types/errors";
-
-/**
- * Tokenizer
- *
- * A tokenizer is a piece of code whose job is to transform a string into a list
- * of "tokens". For example, "(12+" is converted into:
- * [{type: "LEFT_PAREN", value: "("},
- * {type: "NUMBER", value: "12"},
- * {type: "OPERATOR", value: "+"}]
- *
- * As the example shows, a tokenizer does not care about the meaning behind those
- * tokens. It only cares about the structure.
- *
- * The tokenizer is usually the first step in a compilation pipeline. Also, it
- * is useful for the composer, which needs to be able to work with incomplete
- * formulas.
- */
-
-export const POSTFIX_UNARY_OPERATORS = ["%"];
-const OPERATORS = "+,-,*,/,:,=,<>,>=,>,<=,<,^,&".split(",").concat(POSTFIX_UNARY_OPERATORS);
-
-type TokenType =
- | "OPERATOR"
- | "NUMBER"
- | "STRING"
- | "SYMBOL"
- | "SPACE"
- | "DEBUGGER"
- | "ARG_SEPARATOR"
- | "LEFT_PAREN"
- | "RIGHT_PAREN"
- | "REFERENCE"
- | "INVALID_REFERENCE"
- | "UNKNOWN";
-
-export interface Token {
- readonly type: TokenType;
- readonly value: string;
-}
-
-export function tokenize(str: string, locale = DEFAULT_LOCALE): Token[] {
- str = replaceNewLines(str);
- const chars = new TokenizingChars(str);
- const result: Token[] = [];
- const tokenizeSpace = specialWhiteSpaceRegexp.test(str)
- ? tokenizeSpecialCharacterSpace
- : tokenizeSimpleSpace;
-
- while (!chars.isOver()) {
- let token =
- tokenizeNewLine(chars) ||
- tokenizeSpace(chars) ||
- tokenizeArgsSeparator(chars, locale) ||
- tokenizeParenthesis(chars) ||
- tokenizeOperator(chars) ||
- tokenizeString(chars) ||
- tokenizeDebugger(chars) ||
- tokenizeInvalidRange(chars) ||
- tokenizeNumber(chars, locale) ||
- tokenizeSymbol(chars);
-
- if (!token) {
- token = { type: "UNKNOWN", value: chars.shift() };
- }
-
- result.push(token);
- }
- return result;
-}
-
-function tokenizeDebugger(chars: TokenizingChars): Token | null {
- if (chars.current === "?") {
- chars.shift();
- return { type: "DEBUGGER", value: "?" };
- }
- return null;
-}
-
-const parenthesis = {
- "(": { type: "LEFT_PAREN", value: "(" },
- ")": { type: "RIGHT_PAREN", value: ")" },
-} as const;
-
-function tokenizeParenthesis(chars: TokenizingChars): Token | null {
- if (chars.current === "(" || chars.current === ")") {
- const value = chars.shift();
- return parenthesis[value];
- }
- return null;
-}
-
-function tokenizeArgsSeparator(chars: TokenizingChars, locale: Locale): Token | null {
- if (chars.current === locale.formulaArgSeparator) {
- const value = chars.shift();
- const type = "ARG_SEPARATOR";
- return { type, value };
- }
-
- return null;
-}
-
-function tokenizeOperator(chars: TokenizingChars): Token | null {
- for (const op of OPERATORS) {
- if (chars.currentStartsWith(op)) {
- chars.advanceBy(op.length);
- return { type: "OPERATOR", value: op };
- }
- }
- return null;
-}
-
-const FIRST_POSSIBLE_NUMBER_CHARS = new Set("0123456789");
-
-function tokenizeNumber(chars: TokenizingChars, locale: Locale): Token | null {
- if (
- !FIRST_POSSIBLE_NUMBER_CHARS.has(chars.current) &&
- chars.current !== locale.decimalSeparator
- ) {
- return null;
- }
- const match = chars.remaining().match(getFormulaNumberRegex(locale.decimalSeparator));
- if (match) {
- chars.advanceBy(match[0].length);
- return { type: "NUMBER", value: match[0] };
- }
- return null;
-}
-
-function tokenizeString(chars: TokenizingChars): Token | null {
- if (chars.current === '"') {
- const startChar = chars.shift();
- let letters: string = startChar;
- while (chars.current && (chars.current !== startChar || letters[letters.length - 1] === "\\")) {
- letters += chars.shift();
- }
- if (chars.current === '"') {
- letters += chars.shift();
- }
- return {
- type: "STRING",
- value: letters,
- };
- }
- return null;
-}
-
-/**
- - \p{L} is for any letter (from any language)
- - \p{N} is for any number
- - the u flag at the end is for unicode, which enables the `\p{...}` syntax
- */
-const unicodeSymbolCharRegexp = /\p{L}|\p{N}|_|\.|!|\$/u;
-const SYMBOL_CHARS = new Set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!$");
-
-/**
- * A "Symbol" is just basically any word-like element that can appear in a
- * formula, which is not a string. So:
- * A1
- * SUM
- * CEILING.MATH
- * A$1
- * Sheet2!A2
- * 'Sheet 2'!A2
- *
- * are examples of symbols
- */
-function tokenizeSymbol(chars: TokenizingChars): Token | null {
- let result: string = "";
- // there are two main cases to manage: either something which starts with
- // a ', like 'Sheet 2'A2, or a word-like element.
- if (chars.current === "'") {
- let lastChar = chars.shift();
- result += lastChar;
- while (chars.current) {
- lastChar = chars.shift();
- result += lastChar;
- if (lastChar === "'") {
- if (chars.current && chars.current === "'") {
- lastChar = chars.shift();
- result += lastChar;
- } else {
- break;
- }
- }
- }
-
- if (lastChar !== "'") {
- return {
- type: "UNKNOWN",
- value: result,
- };
- }
- }
- while (
- chars.current &&
- (SYMBOL_CHARS.has(chars.current) || chars.current.match(unicodeSymbolCharRegexp))
- ) {
- result += chars.shift();
- }
- if (result.length) {
- const value = result;
- const isReference = rangeReference.test(value);
- if (isReference) {
- return { type: "REFERENCE", value };
- }
- return { type: "SYMBOL", value };
- }
- return null;
-}
-
-function tokenizeSpecialCharacterSpace(chars: TokenizingChars): Token | null {
- let spaces = "";
- while (chars.current === " " || (chars.current && chars.current.match(specialWhiteSpaceRegexp))) {
- spaces += chars.shift();
- }
-
- if (spaces) {
- return { type: "SPACE", value: spaces };
- }
- return null;
-}
-
-function tokenizeSimpleSpace(chars: TokenizingChars): Token | null {
- let spaces = "";
- while (chars.current === " ") {
- spaces += chars.shift();
- }
-
- if (spaces) {
- return { type: "SPACE", value: spaces };
- }
- return null;
-}
-
-function tokenizeNewLine(chars: TokenizingChars): Token | null {
- let length = 0;
- while (chars.current === NEWLINE) {
- length++;
- chars.shift();
- }
- if (length) {
- return { type: "SPACE", value: NEWLINE.repeat(length) };
- }
- return null;
-}
-
-function tokenizeInvalidRange(chars: TokenizingChars): Token | null {
- if (chars.currentStartsWith(CellErrorType.InvalidReference)) {
- chars.advanceBy(CellErrorType.InvalidReference.length);
- return { type: "INVALID_REFERENCE", value: CellErrorType.InvalidReference };
- }
- return null;
-}
+export { POSTFIX_UNARY_OPERATORS, tokenize } from "@odoo/o-spreadsheet-engine/formulas/tokenizer";
+export type { Token } from "@odoo/o-spreadsheet-engine/formulas/tokenizer";
diff --git a/src/functions/createAutocompleteArgumentsProvider.ts b/src/functions/createAutocompleteArgumentsProvider.ts
new file mode 100644
index 0000000000..971d66bf66
--- /dev/null
+++ b/src/functions/createAutocompleteArgumentsProvider.ts
@@ -0,0 +1,85 @@
+import { ArgDefinition } from "@odoo/o-spreadsheet-engine";
+import { CellComposerStore } from "../components/composer/composer/cell_composer_store";
+import { tokenColors } from "../constants";
+import { EnrichedToken } from "../formulas/composer_tokenizer";
+import { AutoCompleteProposal, autoCompleteProviders } from "../registries/auto_completes";
+
+export function createAutocompleteArgumentsProvider(formulaName: string, args: ArgDefinition[]) {
+ for (let i = 0; i < args.length; i++) {
+ const proposalValues = args[i].proposalValues;
+ if (proposalValues === undefined || proposalValues.length === 0) {
+ continue;
+ }
+
+ const getProposals = (tokenAtCursor: EnrichedToken) => {
+ const functionContext = tokenAtCursor.functionContext;
+ if (
+ !functionContext ||
+ functionContext.parent.toUpperCase() !== formulaName.toUpperCase() ||
+ functionContext.argPosition !== i
+ ) {
+ return;
+ }
+
+ const proposals: AutoCompleteProposal[] = [];
+ let text = "";
+ for (const { value, label } of proposalValues) {
+ switch (typeof value) {
+ case "string":
+ text = `"${value}"`;
+ break;
+ case "number":
+ text = value.toString();
+ break;
+ case "boolean":
+ text = value ? "TRUE" : "FALSE";
+ break;
+ default:
+ }
+
+ proposals.push({
+ text,
+ description: label,
+ htmlContent: [
+ {
+ value: text,
+ color: typeof value === "string" ? tokenColors.STRING : tokenColors.NUMBER,
+ },
+ ],
+ fuzzySearchKey: text,
+ alwaysExpanded: true,
+ });
+ }
+
+ return proposals;
+ };
+
+ autoCompleteProviders.add(`${formulaName}_function_${args[i].name}_argument_proposals`, {
+ sequence: 50,
+ autoSelectFirstProposal: true,
+ selectProposal: insertTokenAtArgStartingPosition,
+ getProposals,
+ });
+ }
+}
+
+/**
+ * Perform the autocomplete of the composer by inserting the value
+ * at the cursor position, replacing the current token if necessary.
+ * Must be bound to the autocomplete provider.
+ */
+export function insertTokenAtArgStartingPosition(
+ this: { composer: CellComposerStore },
+ tokenAtCursor: EnrichedToken,
+ value: string
+) {
+ let start = tokenAtCursor.end;
+ const end = tokenAtCursor.end;
+ if (!["LEFT_PAREN", "ARG_SEPARATOR"].includes(tokenAtCursor.type)) {
+ // replace the whole token
+ start = tokenAtCursor.start;
+ }
+ this.composer.stopComposerRangeSelection();
+ this.composer.changeComposerCursorSelection(start, end);
+ this.composer.replaceComposerCursorSelection(value);
+}
diff --git a/src/functions/get_moving_average_values.ts b/src/functions/get_moving_average_values.ts
new file mode 100644
index 0000000000..103d25982f
--- /dev/null
+++ b/src/functions/get_moving_average_values.ts
@@ -0,0 +1,22 @@
+import { Point } from "chart.js";
+import { DEFAULT_WINDOW_SIZE } from "../constants";
+
+export function getMovingAverageValues(
+ dataset: number[],
+ labels: number[],
+ windowSize = DEFAULT_WINDOW_SIZE
+): Point[] {
+ const values: Point[] = [];
+ // Fill the starting values with null until we have a full window
+ for (let i = 0; i < windowSize - 1; i++) {
+ values.push({ x: labels[i], y: NaN });
+ }
+ for (let i = 0; i <= dataset.length - windowSize; i++) {
+ let sum = 0;
+ for (let j = i; j < i + windowSize; j++) {
+ sum += dataset[j];
+ }
+ values.push({ x: labels[i + windowSize - 1], y: sum / windowSize });
+ }
+ return values;
+}
diff --git a/src/functions/helper_lookup.ts b/src/functions/helper_lookup.ts
index 825d5e697e..02fc257170 100644
--- a/src/functions/helper_lookup.ts
+++ b/src/functions/helper_lookup.ts
@@ -1,9 +1,8 @@
+import { EvalContext, FunctionResultObject, Maybe, UID } from "@odoo/o-spreadsheet-engine";
import { isZoneInside, positionToZone, zoneToXc } from "../helpers";
import { _t } from "../translation";
-import { EvalContext, FunctionResultObject, Getters, Maybe, Range, UID } from "../types";
+import { Getters, Range } from "../types";
import { CircularDependencyError, EvaluationError, InvalidReferenceError } from "../types/errors";
-import { PivotCoreDefinition, PivotCoreMeasure } from "../types/pivot";
-
/**
* Get the pivot ID from the formula pivot ID.
*/
diff --git a/src/functions/index.ts b/src/functions/index.ts
index 59ae1b120c..593a8d25e7 100644
--- a/src/functions/index.ts
+++ b/src/functions/index.ts
@@ -1,106 +1,12 @@
-import { CellComposerStore } from "../components/composer/composer/cell_composer_store";
-import { tokenColors } from "../constants";
-import { EnrichedToken } from "../formulas/composer_tokenizer";
-import {
- AutoCompleteProposal,
- autoCompleteProviders,
-} from "../registries/auto_completes/auto_complete_registry";
-import { Registry } from "../registries/registry";
-import { _t } from "../translation";
-import {
- AddFunctionDescription,
- Arg,
- ArgDefinition,
- CellValue,
- ComputeFunction,
- EvalContext,
- FunctionDescription,
- FunctionResultObject,
- Matrix,
- isMatrix,
-} from "../types";
-import { BadExpressionError, EvaluationError } from "../types/errors";
-import { addMetaInfoFromArg, argTargeting, validateArguments } from "./arguments";
-import { applyVectorization, isEvaluationError, matrixForEach, matrixMap } from "./helpers";
-import * as array from "./module_array";
-import * as misc from "./module_custom";
-import * as database from "./module_database";
-import * as date from "./module_date";
-import * as engineering from "./module_engineering";
-import * as filter from "./module_filter";
-import * as financial from "./module_financial";
-import * as info from "./module_info";
-import * as logical from "./module_logical";
-import * as lookup from "./module_lookup";
-import * as math from "./module_math";
-import * as operators from "./module_operators";
-import * as parser from "./module_parser";
-import * as statistical from "./module_statistical";
-import * as text from "./module_text";
-import * as web from "./module_web";
+import { functionRegistry } from "@odoo/o-spreadsheet-engine";
+import { createAutocompleteArgumentsProvider } from "./createAutocompleteArgumentsProvider";
-export { arg } from "./arguments";
-
-type Functions = { [functionName: string]: AddFunctionDescription };
-type Category = { name: string; functions: Functions };
-const categories: Category[] = [
- { name: _t("Array"), functions: array },
- { name: _t("Database"), functions: database },
- { name: _t("Date"), functions: date },
- { name: _t("Filter"), functions: filter },
- { name: _t("Financial"), functions: financial },
- { name: _t("Info"), functions: info },
- { name: _t("Lookup"), functions: lookup },
- { name: _t("Logical"), functions: logical },
- { name: _t("Math"), functions: math },
- { name: _t("Misc"), functions: misc },
- { name: _t("Operator"), functions: operators },
- { name: _t("Statistical"), functions: statistical },
- { name: _t("Text"), functions: text },
- { name: _t("Engineering"), functions: engineering },
- { name: _t("Web"), functions: web },
- { name: _t("Parser"), functions: parser },
-];
-
-const functionNameRegex = /^[A-Z0-9\_\.]+$/;
+import { categories } from "@odoo/o-spreadsheet-engine";
//------------------------------------------------------------------------------
// Function registry
//------------------------------------------------------------------------------
-export class FunctionRegistry extends Registry {
- mapping: {
- [key: string]: ComputeFunction | FunctionResultObject>;
- } = {};
-
- add(name: string, addDescr: AddFunctionDescription) {
- name = name.toUpperCase();
- if (name in this.content) {
- throw new Error(`${name} is already present in this registry!`);
- }
- return this.replace(name, addDescr);
- }
-
- replace(name: string, addDescr: AddFunctionDescription) {
- name = name.toUpperCase();
- if (!functionNameRegex.test(name)) {
- throw new Error(
- _t(
- "Invalid function name %s. Function names can exclusively contain alphanumerical values separated by dots (.) or underscore (_)",
- name
- )
- );
- }
- const descr = addMetaInfoFromArg(name, addDescr);
- validateArguments(descr);
- this.mapping[name] = createComputeFunction(descr);
- super.replace(name, descr);
- return this;
- }
-}
-
-export const functionRegistry: FunctionRegistry = new FunctionRegistry();
-
for (const category of categories) {
const fns = category.functions;
for (let name in fns) {
@@ -112,216 +18,3 @@ for (const category of categories) {
createAutocompleteArgumentsProvider(name, addDescr.args);
}
}
-
-//------------------------------------------------------------------------------
-// CREATE COMPUTE FUNCTION
-//------------------------------------------------------------------------------
-
-function createComputeFunction(
- descr: FunctionDescription
-): ComputeFunction | FunctionResultObject> {
- function vectorizedCompute(
- this: EvalContext,
- ...args: Arg[]
- ): FunctionResultObject | Matrix {
- const acceptToVectorize: boolean[] = [];
-
- const getArgToFocus = argTargeting(descr, args.length);
- //#region Compute vectorisation limits
- for (let i = 0; i < args.length; i++) {
- const argIndex = getArgToFocus(i) ?? -1;
- const argDefinition = descr.args[argIndex];
- const arg = args[i];
- if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
- throw new BadExpressionError(
- _t(
- "Function %s expects the parameter '%s' to be reference to a cell or range.",
- descr.name,
- (i + 1).toString()
- )
- );
- }
- acceptToVectorize.push(!argDefinition.acceptMatrix);
- }
-
- return applyVectorization(errorHandlingCompute.bind(this), args, acceptToVectorize);
- }
-
- function errorHandlingCompute(
- this: EvalContext,
- ...args: Arg[]
- ): Matrix | FunctionResultObject {
- for (let i = 0; i < args.length; i++) {
- const arg = args[i];
- const getArgToFocus = argTargeting(descr, args.length);
- const argDefinition = descr.args[getArgToFocus(i) || i];
-
- // Early exit if the argument is an error and the function does not accept errors
- // We only check scalar arguments, not matrix arguments for performance reasons.
- // Casting helpers are responsible for handling errors in matrix arguments.
- if (!argDefinition.acceptErrors && !isMatrix(arg) && isEvaluationError(arg?.value)) {
- return arg;
- }
- }
- try {
- return computeFunctionToObject.apply(this, args);
- } catch (e) {
- return handleError(e, descr.name);
- }
- }
-
- function computeFunctionToObject(
- this: EvalContext,
- ...args: Arg[]
- ): FunctionResultObject | Matrix {
- if (this.debug) {
- // eslint-disable-next-line no-debugger
- debugger;
- }
- const result = descr.compute.apply(this, args);
-
- if (!isMatrix(result)) {
- if (typeof result === "object" && result !== null && "value" in result) {
- replaceFunctionNamePlaceholder(result, descr.name);
- return result;
- }
- return { value: result };
- }
-
- if (typeof result[0][0] === "object" && result[0][0] !== null && "value" in result[0][0]) {
- matrixForEach(result as Matrix, (result) =>
- replaceFunctionNamePlaceholder(result, descr.name)
- );
- return result as Matrix;
- }
-
- return matrixMap(result as Matrix, (row) => ({ value: row }));
- }
-
- return vectorizedCompute;
-}
-
-export function handleError(e: unknown, functionName: string): FunctionResultObject {
- // the error could be an user error (instance of EvaluationError)
- // or a javascript error (instance of Error)
- // we don't want block the user with an implementation error
- // so we fallback to a generic error
- if (hasStringValue(e) && isEvaluationError(e.value)) {
- if (hasStringMessage(e)) {
- replaceFunctionNamePlaceholder(e, functionName);
- }
- return e;
- }
- console.error(e);
- return new EvaluationError(
- implementationErrorMessage + (hasStringMessage(e) ? " " + e.message : "")
- );
-}
-
-function hasStringValue(obj: unknown): obj is { value: string } {
- return (
- (obj as { value: string })?.value !== undefined &&
- typeof (obj as { value: string }).value === "string"
- );
-}
-
-function replaceFunctionNamePlaceholder(
- functionResult: FunctionResultObject,
- functionName: string
-) {
- // for performance reasons: change in place and only if needed
- if (functionResult.message?.includes("[[FUNCTION_NAME]]")) {
- functionResult.message = functionResult.message.replace("[[FUNCTION_NAME]]", functionName);
- }
-}
-
-export const implementationErrorMessage = _t(
- "An unexpected error occurred. Submit a support ticket at odoo.com/help."
-);
-
-function hasStringMessage(obj: unknown): obj is { message: string } {
- return (
- (obj as { message: string })?.message !== undefined &&
- typeof (obj as { message: string }).message === "string"
- );
-}
-
-function createAutocompleteArgumentsProvider(formulaName: string, args: ArgDefinition[]) {
- for (let i = 0; i < args.length; i++) {
- const proposalValues = args[i].proposalValues;
- if (proposalValues === undefined || proposalValues.length === 0) {
- continue;
- }
-
- const getProposals = (tokenAtCursor: EnrichedToken) => {
- const functionContext = tokenAtCursor.functionContext;
- if (
- !functionContext ||
- functionContext.parent.toUpperCase() !== formulaName.toUpperCase() ||
- functionContext.argPosition !== i
- ) {
- return;
- }
-
- const proposals: AutoCompleteProposal[] = [];
- let text = "";
- for (const { value, label } of proposalValues) {
- switch (typeof value) {
- case "string":
- text = `"${value}"`;
- break;
- case "number":
- text = value.toString();
- break;
- case "boolean":
- text = value ? "TRUE" : "FALSE";
- break;
- default:
- }
-
- proposals.push({
- text,
- description: label,
- htmlContent: [
- {
- value: text,
- color: typeof value === "string" ? tokenColors.STRING : tokenColors.NUMBER,
- },
- ],
- fuzzySearchKey: text,
- alwaysExpanded: true,
- });
- }
-
- return proposals;
- };
-
- autoCompleteProviders.add(`${formulaName}_function_${args[i].name}_argument_proposals`, {
- sequence: 50,
- autoSelectFirstProposal: true,
- selectProposal: insertTokenAtArgStartingPosition,
- getProposals,
- });
- }
-}
-
-/**
- * Perform the autocomplete of the composer by inserting the value
- * at the cursor position, replacing the current token if necessary.
- * Must be bound to the autocomplete provider.
- */
-export function insertTokenAtArgStartingPosition(
- this: { composer: CellComposerStore },
- tokenAtCursor: EnrichedToken,
- value: string
-) {
- let start = tokenAtCursor.end;
- const end = tokenAtCursor.end;
- if (!["LEFT_PAREN", "ARG_SEPARATOR"].includes(tokenAtCursor.type)) {
- // replace the whole token
- start = tokenAtCursor.start;
- }
- this.composer.stopComposerRangeSelection();
- this.composer.changeComposerCursorSelection(start, end);
- this.composer.replaceComposerCursorSelection(value);
-}
diff --git a/src/functions/module_info.ts b/src/functions/module_info.ts
index 393d8ee29c..8ca86229b6 100644
--- a/src/functions/module_info.ts
+++ b/src/functions/module_info.ts
@@ -1,13 +1,8 @@
+import { FunctionResultObject, Functions, Matrix, Maybe } from "@odoo/o-spreadsheet-engine";
import { getFullReference, splitReference } from "../helpers";
import { setXcToFixedReferenceType } from "../helpers/reference_type";
import { _t } from "../translation";
-import {
- AddFunctionDescription,
- CellValueType,
- FunctionResultObject,
- Matrix,
- Maybe,
-} from "../types";
+import { CellValueType } from "../types";
import { CellErrorType, EvaluationError } from "../types/errors";
import { arg } from "./arguments";
import { isEvaluationError, toString } from "./helpers";
@@ -89,7 +84,7 @@ export const CELL = {
return "";
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISERR
@@ -102,7 +97,7 @@ export const ISERR = {
return isEvaluationError(value) && value !== CellErrorType.NotAvailable;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISERROR
@@ -115,7 +110,7 @@ export const ISERROR = {
return isEvaluationError(value);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISLOGICAL
@@ -127,7 +122,7 @@ export const ISLOGICAL = {
return typeof value?.value === "boolean";
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISNA
@@ -139,7 +134,7 @@ export const ISNA = {
return data?.value === CellErrorType.NotAvailable;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISNONTEXT
@@ -151,7 +146,7 @@ export const ISNONTEXT = {
return !ISTEXT.compute.bind(this)(value);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISNUMBER
@@ -164,7 +159,7 @@ export const ISNUMBER = {
return typeof value?.value === "number";
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISTEXT
@@ -176,7 +171,7 @@ export const ISTEXT = {
return typeof value?.value === "string" && isEvaluationError(value?.value) === false;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// ISBLANK
@@ -188,7 +183,7 @@ export const ISBLANK = {
return value?.value === null;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// NA
@@ -200,4 +195,4 @@ export const NA = {
return { value: CellErrorType.NotAvailable };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_logical.ts b/src/functions/module_logical.ts
index d94af564bd..23221f4ab3 100644
--- a/src/functions/module_logical.ts
+++ b/src/functions/module_logical.ts
@@ -1,5 +1,5 @@
+import { Arg, FunctionResultObject, Functions, Maybe } from "@odoo/o-spreadsheet-engine";
import { _t } from "../translation";
-import { AddFunctionDescription, Arg, FunctionResultObject, Maybe } from "../types";
import { CellErrorType, EvaluationError } from "../types/errors";
import { arg } from "./arguments";
import { boolAnd, boolOr } from "./helper_logical";
@@ -38,12 +38,12 @@ export const AND = {
return result;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// FALSE
// -----------------------------------------------------------------------------
-export const FALSE: AddFunctionDescription = {
+export const FALSE: Functions = {
description: _t("Logical value `false`."),
args: [],
compute: function (): boolean {
@@ -81,7 +81,7 @@ export const IF = {
return result ?? { value: 0 };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// IFERROR
@@ -103,7 +103,7 @@ export const IFERROR = {
return result ?? { value: 0 };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// IFNA
@@ -125,7 +125,7 @@ export const IFNA = {
return result ?? { value: 0 };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// IFS
@@ -168,7 +168,7 @@ export const IFS = {
return new EvaluationError(_t("No match."));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// NOT
@@ -187,7 +187,7 @@ export const NOT = {
return !toBoolean(logicalExpression);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// OR
@@ -214,7 +214,7 @@ export const OR = {
return result;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SWITCH
@@ -261,12 +261,12 @@ export const SWITCH = {
return defaultValue || { value: 0 };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TRUE
// -----------------------------------------------------------------------------
-export const TRUE: AddFunctionDescription = {
+export const TRUE: Functions = {
description: _t("Logical value `true`."),
args: [],
compute: function (): boolean {
@@ -306,4 +306,4 @@ export const XOR = {
return acc;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_parser.ts b/src/functions/module_parser.ts
index d33c1502cb..fd4e1ccfee 100644
--- a/src/functions/module_parser.ts
+++ b/src/functions/module_parser.ts
@@ -1,5 +1,5 @@
+import { FunctionResultObject, Functions, Maybe } from "@odoo/o-spreadsheet-engine";
import { _t } from "../translation";
-import { AddFunctionDescription, FunctionResultObject, Maybe } from "../types";
import { CellErrorType } from "../types/errors";
import { arg } from "./arguments";
import { getTransformation, getTranslatedCategory, UNIT_OPTIONS } from "./helper_parser";
@@ -60,4 +60,4 @@ export const CONVERT = {
};
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_pivot.ts b/src/functions/module_pivot.ts
new file mode 100644
index 0000000000..1cda17f3d7
--- /dev/null
+++ b/src/functions/module_pivot.ts
@@ -0,0 +1,221 @@
+import { FunctionResultObject, Functions, Matrix, Maybe } from "@odoo/o-spreadsheet-engine";
+import { getPivotTooBigErrorMessage } from "../components/translations_terms";
+import { PIVOT_MAX_NUMBER_OF_CELLS } from "../constants";
+import { range } from "../helpers/index";
+import { addAlignFormatToPivotHeader } from "../helpers/pivot/pivot_helpers";
+import { _t } from "../translation";
+import { PivotVisibilityOptions } from "../types";
+import { CellErrorType, EvaluationError } from "../types/errors";
+import { arg } from "./arguments";
+import {
+ addPivotDependencies,
+ assertDomainLength,
+ assertMeasureExist,
+ getPivotId,
+} from "./helper_lookup";
+import { toBoolean, toNumber, toString } from "./helpers";
+
+//--------------------------------------------------------------------------
+// Pivot functions
+//--------------------------------------------------------------------------
+
+// PIVOT.VALUE
+
+export const PIVOT_VALUE = {
+ description: _t("Get the value from a pivot."),
+ args: [
+ arg("pivot_id (number,string)", _t("ID of the pivot.")),
+ arg("measure_name (string)", _t("Name of the measure.")),
+ arg("domain_field_name (string,repeating)", _t("Field name.")),
+ arg("domain_value (number,string,boolean,repeating)", _t("Value.")),
+ ],
+ compute: function (
+ formulaId: Maybe,
+ measureName: Maybe,
+ ...domainArgs: Maybe[]
+ ) {
+ const _pivotFormulaId = toString(formulaId);
+ const _measure = toString(measureName);
+ const pivotId = getPivotId(_pivotFormulaId, this.getters);
+ assertMeasureExist(pivotId, _measure, this.getters);
+ assertDomainLength(domainArgs);
+ const pivot = this.getters.getPivot(pivotId);
+ const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
+
+ addPivotDependencies(
+ this,
+ coreDefinition,
+ coreDefinition.measures.filter((m) => m.id === _measure)
+ );
+ pivot.init({ reload: pivot.needsReevaluation });
+ const error = pivot.assertIsValid({ throwOnError: false });
+ if (error) {
+ return error;
+ }
+
+ if (!pivot.areDomainArgsFieldsValid(domainArgs)) {
+ const suggestion = _t(
+ "Consider using a dynamic pivot formula: %s. Or re-insert the static pivot from the Data menu.",
+ `=PIVOT(${_pivotFormulaId})`
+ );
+ return {
+ value: CellErrorType.GenericError,
+ message: _t("Dimensions don't match the pivot definition") + ". " + suggestion,
+ };
+ }
+ const domain = pivot.parseArgsToPivotDomain(domainArgs);
+ if (this.getters.getActiveSheetId() === this.__originSheetId) {
+ this.getters.getPivotPresenceTracker(pivotId)?.trackValue(_measure, domain);
+ }
+ return pivot.getPivotCellValueAndFormat(_measure, domain);
+ },
+} satisfies Functions;
+
+// PIVOT.HEADER
+
+export const PIVOT_HEADER = {
+ description: _t("Get the header of a pivot."),
+ args: [
+ arg("pivot_id (number,string)", _t("ID of the pivot.")),
+ arg("domain_field_name (string,repeating)", _t("Field name.")),
+ arg("domain_value (number,string,value,repeating)", _t("Value.")),
+ ],
+ compute: function (
+ pivotId: Maybe,
+ ...domainArgs: Maybe[]
+ ) {
+ const _pivotFormulaId = toString(pivotId);
+ const _pivotId = getPivotId(_pivotFormulaId, this.getters);
+ assertDomainLength(domainArgs);
+ const pivot = this.getters.getPivot(_pivotId);
+ const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
+ addPivotDependencies(this, coreDefinition, []);
+ pivot.init({ reload: pivot.needsReevaluation });
+ const error = pivot.assertIsValid({ throwOnError: false });
+ if (error) {
+ return error;
+ }
+ if (!pivot.areDomainArgsFieldsValid(domainArgs)) {
+ const suggestion = _t(
+ "Consider using a dynamic pivot formula: %s. Or re-insert the static pivot from the Data menu.",
+ `=PIVOT(${_pivotFormulaId})`
+ );
+ return {
+ value: CellErrorType.GenericError,
+ message: _t("Dimensions don't match the pivot definition") + ". " + suggestion,
+ };
+ }
+ const domain = pivot.parseArgsToPivotDomain(domainArgs);
+ if (this.getters.getActiveSheetId() === this.__originSheetId) {
+ this.getters.getPivotPresenceTracker(_pivotId)?.trackHeader(domain);
+ }
+ const lastNode = domain.at(-1);
+ if (lastNode?.field === "measure") {
+ return pivot.getPivotMeasureValue(toString(lastNode.value), domain);
+ }
+ const { value, format } = pivot.getPivotHeaderValueAndFormat(domain);
+ return {
+ value,
+ format:
+ !lastNode || lastNode.field === "measure" || lastNode.value === "false"
+ ? undefined
+ : format,
+ };
+ },
+} satisfies Functions;
+
+export const PIVOT = {
+ description: _t("Get a pivot table."),
+ args: [
+ arg("pivot_id (string)", _t("ID of the pivot.")),
+ arg("row_count (number, optional)", _t("number of rows")),
+ arg("include_total (boolean, default=TRUE)", _t("Whether to include total/sub-totals or not.")),
+ arg(
+ "include_column_titles (boolean, default=TRUE)",
+ _t("Whether to include the column titles or not.")
+ ),
+ arg("column_count (number, optional)", _t("number of columns")),
+ arg(
+ "include_measure_titles (boolean, default=TRUE)",
+ _t("Whether to include the measure titles row or not.")
+ ),
+ ],
+ compute: function (
+ pivotFormulaId: Maybe,
+ rowCount: Maybe = { value: 10000 },
+ includeTotal: Maybe = { value: true },
+ includeColumnHeaders: Maybe = { value: true },
+ columnCount: Maybe = { value: Number.MAX_VALUE },
+ includeMeasureTitles: Maybe = { value: true }
+ ) {
+ const _pivotFormulaId = toString(pivotFormulaId);
+ const _rowCount = toNumber(rowCount, this.locale);
+ if (_rowCount < 0) {
+ return new EvaluationError(_t("The number of rows must be positive."));
+ }
+ const _columnCount = toNumber(columnCount, this.locale);
+ if (_columnCount < 0) {
+ return new EvaluationError(_t("The number of columns must be positive."));
+ }
+ const visibilityOptions: PivotVisibilityOptions = {
+ displayColumnHeaders: toBoolean(includeColumnHeaders),
+ displayTotals: toBoolean(includeTotal),
+ displayMeasuresRow: toBoolean(includeMeasureTitles),
+ };
+
+ const pivotId = getPivotId(_pivotFormulaId, this.getters);
+ const pivot = this.getters.getPivot(pivotId);
+ const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
+ addPivotDependencies(this, coreDefinition, coreDefinition.measures);
+ pivot.init({ reload: pivot.needsReevaluation });
+ const error = pivot.assertIsValid({ throwOnError: false });
+ if (error) {
+ return error;
+ }
+ const table = pivot.getCollapsedTableStructure();
+ if (table.numberOfCells > PIVOT_MAX_NUMBER_OF_CELLS) {
+ return new EvaluationError(getPivotTooBigErrorMessage(table.numberOfCells, this.locale));
+ }
+ const cells = table.getPivotCells(visibilityOptions);
+
+ let headerRows = 0;
+ if (visibilityOptions.displayColumnHeaders) {
+ headerRows = table.columns.length - 1;
+ }
+ if (visibilityOptions.displayMeasuresRow) {
+ headerRows++;
+ }
+ const pivotTitle = this.getters.getPivotName(pivotId);
+ const tableHeight = Math.min(headerRows + _rowCount, cells[0].length);
+ if (tableHeight === 0) {
+ return [[{ value: pivotTitle }]];
+ }
+ const tableWidth = Math.min(1 + _columnCount, cells.length);
+ const result: Matrix = [];
+ for (const col of range(0, tableWidth)) {
+ result[col] = [];
+ for (const row of range(0, tableHeight)) {
+ const pivotCell = cells[col][row];
+ switch (pivotCell.type) {
+ case "EMPTY":
+ result[col].push({ value: "" });
+ break;
+ case "HEADER":
+ const valueAndFormat = pivot.getPivotHeaderValueAndFormat(pivotCell.domain);
+ result[col].push(addAlignFormatToPivotHeader(pivotCell.domain, valueAndFormat));
+ break;
+ case "MEASURE_HEADER":
+ result[col].push(pivot.getPivotMeasureValue(pivotCell.measure, pivotCell.domain));
+ break;
+ case "VALUE":
+ result[col].push(pivot.getPivotCellValueAndFormat(pivotCell.measure, pivotCell.domain));
+ break;
+ }
+ }
+ }
+ if (visibilityOptions.displayColumnHeaders || visibilityOptions.displayMeasuresRow) {
+ result[0][0] = { value: pivotTitle };
+ }
+ return result;
+ },
+} satisfies Functions;
diff --git a/src/functions/module_text.ts b/src/functions/module_text.ts
index 1ed156f524..f8bdd67d58 100644
--- a/src/functions/module_text.ts
+++ b/src/functions/module_text.ts
@@ -1,6 +1,4 @@
-import { escapeRegExp, formatValue, trimContent } from "../helpers";
import { _t } from "../translation";
-import { AddFunctionDescription, Arg, FunctionResultObject, Maybe } from "../types";
import { CellErrorType, EvaluationError, NotAvailableError } from "../types/errors";
import { arg } from "./arguments";
import { reduceAny, toBoolean, toMatrix, toNumber, toString, transposeMatrix } from "./helpers";
@@ -38,7 +36,7 @@ export const CHAR = {
return String.fromCharCode(_tableNumber);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// CLEAN
@@ -57,7 +55,7 @@ export const CLEAN = {
return cleanedStr;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// CONCATENATE
@@ -72,7 +70,7 @@ export const CONCATENATE = {
return reduceAny(datas, (acc, a) => acc + toString(a), "");
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// EXACT
@@ -90,7 +88,7 @@ export const EXACT = {
return toString(string1) === toString(string2);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// FIND
@@ -141,7 +139,7 @@ export const FIND = {
return result + 1;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// JOIN
@@ -166,7 +164,7 @@ export const JOIN = {
const _delimiter = toString(delimiter);
return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toString(a), "");
},
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// LEFT
@@ -191,7 +189,7 @@ export const LEFT = {
return toString(text).substring(0, _numberOfCharacters);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// LEN
@@ -203,7 +201,7 @@ export const LEN = {
return toString(text).length;
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// LOWER
@@ -215,7 +213,7 @@ export const LOWER = {
return toString(text).toLowerCase();
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// MID
@@ -258,7 +256,7 @@ export const MID = {
return _text.slice(_starting_at - 1, _starting_at + _extract_length - 1);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// PROPER
@@ -280,7 +278,7 @@ export const PROPER = {
});
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
const REGEXEXTRACT_DEFAULT_MODE = 0;
const REGEXEXTRACT_DEFAULT_CASE_SENSITIVITY = 0;
@@ -354,7 +352,7 @@ export const REGEXEXTRACT = {
}
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// REPLACE
@@ -389,7 +387,7 @@ export const REPLACE = {
return _text.substring(0, _position - 1) + _newText + _text.substring(_position - 1 + _length);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// RIGHT
@@ -415,7 +413,7 @@ export const RIGHT = {
return _text.substring(stringLength - _numberOfCharacters, stringLength);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SEARCH
@@ -468,7 +466,7 @@ export const SEARCH = {
return { value: result + 1 };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SPLIT
@@ -517,7 +515,7 @@ export const SPLIT = {
return transposeMatrix([result]);
},
isExported: false,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// SUBSTITUTE
@@ -565,7 +563,7 @@ export const SUBSTITUTE = {
return _textToSearch.replace(reg, (text) => (++n === _occurrenceNumber ? _replaceWith : text));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TEXTJOIN
@@ -614,7 +612,7 @@ export const TEXTJOIN = {
);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TEXTSPLIT
@@ -718,7 +716,7 @@ export const TEXTSPLIT = {
return transposeMatrix(cells);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TRIM
@@ -732,7 +730,7 @@ export const TRIM = {
return trimContent(toString(text));
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// UPPER
@@ -744,7 +742,7 @@ export const UPPER = {
return toString(text).toUpperCase();
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TEXT
@@ -768,7 +766,7 @@ export const TEXT = {
return formatValue(_number, { format: toString(format), locale: this.locale });
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// VALUE
@@ -780,7 +778,7 @@ export const VALUE = {
return toNumber(value, this.locale);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TEXTAFTER
@@ -862,7 +860,7 @@ export const TEXTAFTER = {
return targetIndex === undefined ? ifNotFound : { value: _text.substring(targetIndex) };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
// -----------------------------------------------------------------------------
// TEXTBEFORE
@@ -942,4 +940,4 @@ export const TEXTBEFORE = {
: { value: _text.substring(0, targetIndex - _delimiter.length) };
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/functions/module_web.ts b/src/functions/module_web.ts
index 182ca9b0bc..507ae3223a 100644
--- a/src/functions/module_web.ts
+++ b/src/functions/module_web.ts
@@ -1,6 +1,6 @@
+import { FunctionResultObject, Functions, Maybe } from "@odoo/o-spreadsheet-engine";
import { markdownLink } from "../helpers";
import { _t } from "../translation";
-import { AddFunctionDescription, FunctionResultObject, Maybe } from "../types";
import { arg } from "./arguments";
import { toString } from "./helpers";
@@ -26,4 +26,4 @@ export const HYPERLINK = {
return markdownLink(processedLabel, processedUrl);
},
isExported: true,
-} satisfies AddFunctionDescription;
+} satisfies Functions;
diff --git a/src/helpers/cells/cell_evaluation.ts b/src/helpers/cells/cell_evaluation.ts
index 3f4f3d5f0c..0686246461 100644
--- a/src/helpers/cells/cell_evaluation.ts
+++ b/src/helpers/cells/cell_evaluation.ts
@@ -1,15 +1,14 @@
+import { CellPosition, FunctionResultObject } from "@odoo/o-spreadsheet-engine";
import { isEvaluationError, toString } from "../../functions/helpers";
import {
BooleanCell,
Cell,
- CellPosition,
CellValue,
CellValueType,
DEFAULT_LOCALE,
EmptyCell,
ErrorCell,
EvaluatedCell,
- FunctionResultObject,
LiteralCell,
Locale,
LocaleFormat,
@@ -25,8 +24,6 @@ import {
} from "../format/format";
import { detectLink } from "../links";
import { isBoolean, memoize } from "../misc";
-import { isNumber, parseNumber } from "../numbers";
-
export function evaluateLiteral(
literalCell: LiteralCell,
localeFormat: LocaleFormat,
diff --git a/src/helpers/cells/position_map.ts b/src/helpers/cells/position_map.ts
index 190950f54a..a65753d121 100644
--- a/src/helpers/cells/position_map.ts
+++ b/src/helpers/cells/position_map.ts
@@ -1,4 +1,4 @@
-import { CellPosition, UID } from "../..";
+import { CellPosition, UID } from "@odoo/o-spreadsheet-engine";
export class PositionMap {
private map: Record>> = {};
diff --git a/src/helpers/chart_date.ts b/src/helpers/chart_date.ts
index a6cc36eb42..83f54230db 100644
--- a/src/helpers/chart_date.ts
+++ b/src/helpers/chart_date.ts
@@ -1,7 +1,6 @@
-import type { TimeScaleOptions } from "chart.js";
import { DeepPartial } from "chart.js/dist/types/utils";
-import { largeMax, largeMin, parseDateTime } from ".";
-import { Alias, Format, Locale } from "../types";
+import { parseDateTime } from ".";
+import { Format, Locale } from "../types";
// -----------------------------------------------------------------------------
// File for helpers needed to use time axis in ChartJS
diff --git a/src/helpers/clipboard/clipboard_helpers.ts b/src/helpers/clipboard/clipboard_helpers.ts
index 6d62158c48..a96ecabfb2 100644
--- a/src/helpers/clipboard/clipboard_helpers.ts
+++ b/src/helpers/clipboard/clipboard_helpers.ts
@@ -1,3 +1,4 @@
+import { UID, Zone } from "@odoo/o-spreadsheet-engine";
import { ClipboardHandler } from "../../clipboard_handlers/abstract_clipboard_handler";
import { SpreadsheetClipboardData } from "../../plugins/ui_stateful";
import { SelectionStreamProcessor } from "../../selection_stream/selection_stream_processor";
@@ -9,8 +10,6 @@ import {
MinimalClipboardData,
OSClipboardContent,
ParsedOSClipboardContent,
- UID,
- Zone,
} from "../../types";
import { AllowedImageMimeTypes } from "../../types/image";
import { mergeOverlappingZones, positions, union } from "../zones";
diff --git a/src/helpers/color.ts b/src/helpers/color.ts
index 9e0d43c08a..8bd8054198 100644
--- a/src/helpers/color.ts
+++ b/src/helpers/color.ts
@@ -1,7 +1,4 @@
-import { Color, HSLA, RGBA } from "../types";
-
-import { concat } from "./misc";
-
+import { Color } from "@odoo/o-spreadsheet-engine";
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
diff --git a/src/helpers/data_normalization.ts b/src/helpers/data_normalization.ts
index 182e283dc2..9d36e1dd9a 100644
--- a/src/helpers/data_normalization.ts
+++ b/src/helpers/data_normalization.ts
@@ -1,7 +1,6 @@
-import { Position, UID } from "../types";
-import { recomputeZones } from "./recompute_zones";
-import { positionToZone, toZone, zoneToXc } from "./zones";
-
+import { Position, UID } from "@odoo/o-spreadsheet-engine";
+import { recomputeZones } from "@odoo/o-spreadsheet-engine/helpers/recompute_zones";
+import { positionToZone, toZone, zoneToXc } from "@odoo/o-spreadsheet-engine/helpers/zones";
type ReverseLookup = Map;
type ItemsDic = { [id: number]: T };
diff --git a/src/helpers/figures/charts/abstract_chart.ts b/src/helpers/figures/charts/abstract_chart.ts
index 893a5bd7fa..14f4940ce1 100644
--- a/src/helpers/figures/charts/abstract_chart.ts
+++ b/src/helpers/figures/charts/abstract_chart.ts
@@ -1,13 +1,5 @@
-import {
- AdaptSheetName,
- ApplyRangeChange,
- CommandResult,
- CoreGetters,
- Getters,
- Range,
- RangeAdapter,
- UID,
-} from "../../../types";
+import { AdaptSheetName, ApplyRangeChange, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
+import { CommandResult, CoreGetters, Getters, Range } from "../../../types";
import {
ChartCreationContext,
ChartDefinition,
diff --git a/src/helpers/figures/charts/bar_chart.ts b/src/helpers/figures/charts/bar_chart.ts
index d757aa0163..27c9304411 100644
--- a/src/helpers/figures/charts/bar_chart.ts
+++ b/src/helpers/figures/charts/bar_chart.ts
@@ -1,15 +1,7 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import type { ChartConfiguration } from "chart.js";
import { BACKGROUND_CHART_COLOR } from "../../../constants";
-import {
- ApplyRangeChange,
- Color,
- CommandResult,
- CoreGetters,
- Getters,
- Range,
- RangeAdapter,
- UID,
-} from "../../../types";
+import { CommandResult, CoreGetters, Getters, Range } from "../../../types";
import { BarChartDefinition, BarChartRuntime } from "../../../types/chart/bar_chart";
import {
AxesDesign,
diff --git a/src/helpers/figures/charts/chart_common.ts b/src/helpers/figures/charts/chart_common.ts
index 5663f06c37..1b5a8f5944 100644
--- a/src/helpers/figures/charts/chart_common.ts
+++ b/src/helpers/figures/charts/chart_common.ts
@@ -1,8 +1,6 @@
-import { DEFAULT_WINDOW_SIZE, MAX_CHAR_LABEL } from "../../../constants";
+import { largeMax } from "@odoo/o-spreadsheet-engine";
import { _t } from "../../../translation";
import {
- ApplyRangeChange,
- Color,
CommandResult,
CoreGetters,
DOMCoordinates,
@@ -11,10 +9,6 @@ import {
Locale,
LocaleFormat,
Range,
- RangeAdapter,
- UID,
- UnboundedZone,
- Zone,
} from "../../../types";
import {
ChartAxisFormats,
@@ -31,7 +25,6 @@ import { MAX_XLSX_POLYNOMIAL_DEGREE } from "../../../xlsx/constants";
import { ColorGenerator, relativeLuminance } from "../../color";
import { formatValue, humanizeNumber } from "../../format/format";
import { adaptStringRange } from "../../formulas";
-import { isDefined, largeMax } from "../../misc";
import { createRange, duplicateRangeInDuplicatedSheet } from "../../range";
import { rangeReference } from "../../references";
import { getZoneArea, isFullRow, toUnboundedZone, zoneToDimension, zoneToXc } from "../../zones";
diff --git a/src/helpers/figures/charts/chart_factory.ts b/src/helpers/figures/charts/chart_factory.ts
index fcc71bdff7..7f8a3d33a3 100644
--- a/src/helpers/figures/charts/chart_factory.ts
+++ b/src/helpers/figures/charts/chart_factory.ts
@@ -1,6 +1,7 @@
+import { RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import { ChartConfiguration } from "chart.js";
import { chartRegistry } from "../../../registries/chart_types";
-import { CommandResult, RangeAdapter, UID } from "../../../types";
+import { CommandResult } from "../../../types";
import { ChartDefinition, ChartRuntime } from "../../../types/chart/chart";
import { CoreGetters, Getters } from "../../../types/getters";
import { Validator } from "../../../types/validator";
diff --git a/src/helpers/figures/charts/combo_chart.ts b/src/helpers/figures/charts/combo_chart.ts
index e7598f1688..ee8570a2a8 100644
--- a/src/helpers/figures/charts/combo_chart.ts
+++ b/src/helpers/figures/charts/combo_chart.ts
@@ -1,17 +1,14 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import { ChartConfiguration } from "chart.js";
import { BACKGROUND_CHART_COLOR } from "../../../constants";
import {
- ApplyRangeChange,
ChartCreationContext,
- Color,
CommandResult,
CoreGetters,
DataSet,
ExcelChartDefinition,
Getters,
Range,
- RangeAdapter,
- UID,
} from "../../../types";
import { AxesDesign, CustomizedDataSet, LegendPosition } from "../../../types/chart";
import {
diff --git a/src/helpers/figures/charts/funnel_chart.ts b/src/helpers/figures/charts/funnel_chart.ts
index 3e70a0f1a7..dc694df61c 100644
--- a/src/helpers/figures/charts/funnel_chart.ts
+++ b/src/helpers/figures/charts/funnel_chart.ts
@@ -1,15 +1,7 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import { ChartConfiguration } from "chart.js";
import { BACKGROUND_CHART_COLOR } from "../../../constants";
-import {
- ApplyRangeChange,
- Color,
- CommandResult,
- CoreGetters,
- Getters,
- Range,
- RangeAdapter,
- UID,
-} from "../../../types";
+import { CommandResult, CoreGetters, Getters, Range } from "../../../types";
import {
FunnelChartColors,
FunnelChartDefinition,
diff --git a/src/helpers/figures/charts/gauge_chart.ts b/src/helpers/figures/charts/gauge_chart.ts
index 104080b67e..5707366fb7 100644
--- a/src/helpers/figures/charts/gauge_chart.ts
+++ b/src/helpers/figures/charts/gauge_chart.ts
@@ -1,3 +1,4 @@
+import { Validation } from "@odoo/o-spreadsheet-engine/types";
import {
DEFAULT_GAUGE_LOWER_COLOR,
DEFAULT_GAUGE_MIDDLE_COLOR,
@@ -5,21 +6,7 @@ import {
} from "../../../constants";
import { isMultipleElementMatrix, toScalar } from "../../../functions/helper_matrices";
import { tryToNumber } from "../../../functions/helpers";
-import { BasePlugin } from "../../../plugins/base_plugin";
-import {
- AdaptSheetName,
- ApplyRangeChange,
- CellValueType,
- Color,
- CommandResult,
- CoreGetters,
- Format,
- Getters,
- Range,
- RangeAdapter,
- UID,
- Validation,
-} from "../../../types";
+import { CellValueType, CommandResult, CoreGetters, Format, Getters, Range } from "../../../types";
import { ChartCreationContext } from "../../../types/chart/chart";
import {
GaugeChartDefinition,
@@ -51,7 +38,7 @@ function isDataRangeValid(definition: GaugeChartDefinition): CommandResult {
function checkRangeLimits(
check: RangeLimitsValidation,
- batchValidations: BasePlugin["batchValidations"]
+ batchValidations: BasePlugin["batchValidations"]
): Validation {
return batchValidations(
(definition) => {
@@ -71,7 +58,7 @@ function checkRangeLimits(
function checkInflectionPointsValue(
check: InflectionPointValueValidation,
- batchValidations: BasePlugin["batchValidations"]
+ batchValidations: BasePlugin["batchValidations"]
): Validation {
return batchValidations(
(definition) => {
diff --git a/src/helpers/figures/charts/gauge_chart_rendering.ts b/src/helpers/figures/charts/gauge_chart_rendering.ts
index d71aa2d0a8..9b7310c1c7 100644
--- a/src/helpers/figures/charts/gauge_chart_rendering.ts
+++ b/src/helpers/figures/charts/gauge_chart_rendering.ts
@@ -1,10 +1,11 @@
+import { Color, PixelPosition } from "@odoo/o-spreadsheet-engine";
import {
CHART_PADDING,
CHART_PADDING_TOP,
CHART_TITLE_FONT_SIZE,
DEFAULT_FONT,
} from "../../../constants";
-import { Color, PixelPosition, Rect } from "../../../types";
+import { Rect } from "../../../types";
import { GaugeAnimatedRuntime } from "../../../types/chart";
import { clip } from "../../misc";
import {
@@ -13,8 +14,6 @@ import {
getDefaultContextFont,
getFontSizeMatchingWidth,
} from "../../text_helper";
-import { chartMutedFontColor } from "./chart_common";
-
export const GAUGE_PADDING_SIDE = 30;
export const GAUGE_PADDING_TOP = 10;
export const GAUGE_PADDING_BOTTOM = 20;
diff --git a/src/helpers/figures/charts/geo_chart.ts b/src/helpers/figures/charts/geo_chart.ts
index 7f988cb7e7..59c0e6b9e0 100644
--- a/src/helpers/figures/charts/geo_chart.ts
+++ b/src/helpers/figures/charts/geo_chart.ts
@@ -1,15 +1,7 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import { ChartConfiguration } from "chart.js";
import { BACKGROUND_CHART_COLOR } from "../../../constants";
-import {
- ApplyRangeChange,
- Color,
- CommandResult,
- CoreGetters,
- Getters,
- Range,
- RangeAdapter,
- UID,
-} from "../../../types";
+import { CommandResult, CoreGetters, Getters, Range } from "../../../types";
import { LegendPosition } from "../../../types/chart";
import {
ChartCreationContext,
diff --git a/src/helpers/figures/charts/line_chart.ts b/src/helpers/figures/charts/line_chart.ts
index cfda4a7ff9..7139027a18 100644
--- a/src/helpers/figures/charts/line_chart.ts
+++ b/src/helpers/figures/charts/line_chart.ts
@@ -1,15 +1,7 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import { ChartConfiguration } from "chart.js";
import { BACKGROUND_CHART_COLOR } from "../../../constants";
-import {
- ApplyRangeChange,
- Color,
- CommandResult,
- CoreGetters,
- Getters,
- Range,
- RangeAdapter,
- UID,
-} from "../../../types";
+import { CommandResult, CoreGetters, Getters, Range } from "../../../types";
import {
AxesDesign,
ChartCreationContext,
diff --git a/src/helpers/figures/charts/pie_chart.ts b/src/helpers/figures/charts/pie_chart.ts
index f3d5bd27c3..faf5ba432a 100644
--- a/src/helpers/figures/charts/pie_chart.ts
+++ b/src/helpers/figures/charts/pie_chart.ts
@@ -1,15 +1,7 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import type { ChartConfiguration } from "chart.js";
import { BACKGROUND_CHART_COLOR } from "../../../constants";
-import {
- ApplyRangeChange,
- Color,
- CommandResult,
- CoreGetters,
- Getters,
- Range,
- RangeAdapter,
- UID,
-} from "../../../types";
+import { CommandResult, CoreGetters, Getters, Range } from "../../../types";
import { ChartCreationContext, DataSet, ExcelChartDefinition } from "../../../types/chart/chart";
import { LegendPosition } from "../../../types/chart/common_chart";
import { PieChartDefinition, PieChartRuntime } from "../../../types/chart/pie_chart";
diff --git a/src/helpers/figures/charts/pyramid_chart.ts b/src/helpers/figures/charts/pyramid_chart.ts
index c4e7071b6f..f2e4d993af 100644
--- a/src/helpers/figures/charts/pyramid_chart.ts
+++ b/src/helpers/figures/charts/pyramid_chart.ts
@@ -1,15 +1,7 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import { ChartConfiguration } from "chart.js";
import { BACKGROUND_CHART_COLOR } from "../../../constants";
-import {
- ApplyRangeChange,
- Color,
- CommandResult,
- CoreGetters,
- Getters,
- Range,
- RangeAdapter,
- UID,
-} from "../../../types";
+import { CommandResult, CoreGetters, Getters, Range } from "../../../types";
import {
AxesDesign,
ChartCreationContext,
diff --git a/src/helpers/figures/charts/radar_chart.ts b/src/helpers/figures/charts/radar_chart.ts
index 380036689b..96893d3c15 100644
--- a/src/helpers/figures/charts/radar_chart.ts
+++ b/src/helpers/figures/charts/radar_chart.ts
@@ -1,16 +1,7 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import { ChartConfiguration } from "chart.js";
import { BACKGROUND_CHART_COLOR } from "../../../constants";
-import {
- ApplyRangeChange,
- Color,
- CommandResult,
- CoreGetters,
- DatasetDesign,
- Getters,
- Range,
- RangeAdapter,
- UID,
-} from "../../../types";
+import { CommandResult, CoreGetters, DatasetDesign, Getters, Range } from "../../../types";
import {
ChartCreationContext,
CustomizedDataSet,
diff --git a/src/helpers/figures/charts/runtime/chart_data_extractor.ts b/src/helpers/figures/charts/runtime/chart_data_extractor.ts
index 6ceacb27ef..0123c17400 100644
--- a/src/helpers/figures/charts/runtime/chart_data_extractor.ts
+++ b/src/helpers/figures/charts/runtime/chart_data_extractor.ts
@@ -1,9 +1,10 @@
+import { findNextDefinedValue } from "@odoo/o-spreadsheet-engine";
import { Point } from "chart.js";
import { ChartTerms } from "../../../../components/translations_terms";
+import { getMovingAverageValues } from "../../../../functions/get_moving_average_values";
import {
evaluatePolynomial,
expM,
- getMovingAverageValues,
logM,
polynomialRegression,
predictLinearValues,
@@ -40,7 +41,7 @@ import { RadarChartDefinition } from "../../../../types/chart/radar_chart";
import { TreeMapChartDefinition } from "../../../../types/chart/tree_map_chart";
import { timeFormatLuxonCompatible } from "../../../chart_date";
import { isDateTimeFormat } from "../../../format/format";
-import { deepCopy, findNextDefinedValue, range } from "../../../misc";
+import { deepCopy, range } from "../../../misc";
import { isNumber } from "../../../numbers";
import { recomputeZones } from "../../../recompute_zones";
import { positions } from "../../../zones";
diff --git a/src/helpers/figures/charts/runtime/chartjs_dataset.ts b/src/helpers/figures/charts/runtime/chartjs_dataset.ts
index 0090b54937..49a6da51c0 100644
--- a/src/helpers/figures/charts/runtime/chartjs_dataset.ts
+++ b/src/helpers/figures/charts/runtime/chartjs_dataset.ts
@@ -1,4 +1,3 @@
-import { ChartDataset, Point } from "chart.js";
import {
BACKGROUND_CHART_COLOR,
CHART_WATERFALL_NEGATIVE_COLOR,
@@ -9,7 +8,7 @@ import {
LINE_FILL_TRANSPARENCY,
} from "../../../../constants";
import { _t } from "../../../../translation";
-import { ChartRuntimeGenerationArgs, Color, GenericDefinition } from "../../../../types";
+import { ChartRuntimeGenerationArgs, GenericDefinition } from "../../../../types";
import {
BarChartDefinition,
ChartWithDataSetDefinition,
@@ -51,7 +50,7 @@ import {
setColorAlpha,
} from "../../../color";
import { formatValue } from "../../../format/format";
-import { isDefined, range } from "../../../misc";
+import { range } from "../../../misc";
import {
MOVING_AVERAGE_TREND_LINE_XAXIS_ID,
TREND_LINE_XAXIS_ID,
diff --git a/src/helpers/figures/charts/runtime/chartjs_scales.ts b/src/helpers/figures/charts/runtime/chartjs_scales.ts
index 71d32eb54b..9d7b219867 100644
--- a/src/helpers/figures/charts/runtime/chartjs_scales.ts
+++ b/src/helpers/figures/charts/runtime/chartjs_scales.ts
@@ -1,4 +1,3 @@
-import { LinearScaleOptions, ScaleChartOptions, Tick } from "chart.js";
import { DeepPartial } from "chart.js/dist/types/utils";
import {
CHART_AXIS_TITLE_FONT_SIZE,
@@ -30,7 +29,7 @@ import { RadarChartDefinition } from "../../../../types/chart/radar_chart";
import { getChartTimeOptions } from "../../../chart_date";
import { getColorScale } from "../../../color";
import { formatValue, humanizeNumber } from "../../../format/format";
-import { isDefined, range, removeFalsyAttributes } from "../../../misc";
+import { range } from "../../../misc";
import {
MOVING_AVERAGE_TREND_LINE_XAXIS_ID,
TREND_LINE_XAXIS_ID,
diff --git a/src/helpers/figures/charts/scatter_chart.ts b/src/helpers/figures/charts/scatter_chart.ts
index 964e9e3035..4188f6c84b 100644
--- a/src/helpers/figures/charts/scatter_chart.ts
+++ b/src/helpers/figures/charts/scatter_chart.ts
@@ -1,15 +1,7 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import { ChartConfiguration } from "chart.js";
import { BACKGROUND_CHART_COLOR } from "../../../constants";
-import {
- ApplyRangeChange,
- Color,
- CommandResult,
- CoreGetters,
- Getters,
- Range,
- RangeAdapter,
- UID,
-} from "../../../types";
+import { CommandResult, CoreGetters, Getters, Range } from "../../../types";
import {
AxesDesign,
ChartCreationContext,
diff --git a/src/helpers/figures/charts/scorecard_chart.ts b/src/helpers/figures/charts/scorecard_chart.ts
index ddce97f032..3a47e14889 100644
--- a/src/helpers/figures/charts/scorecard_chart.ts
+++ b/src/helpers/figures/charts/scorecard_chart.ts
@@ -1,3 +1,4 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import {
CHART_PADDING,
DEFAULT_SCORECARD_BASELINE_COLOR_DOWN,
@@ -6,17 +7,13 @@ import {
} from "../../../constants";
import { toNumber } from "../../../functions/helpers";
import {
- ApplyRangeChange,
CellValueType,
- Color,
CommandResult,
CoreGetters,
EvaluatedCell,
Getters,
Locale,
Range,
- RangeAdapter,
- UID,
} from "../../../types";
import { ChartCreationContext, TitleDesign } from "../../../types/chart/chart";
import {
diff --git a/src/helpers/figures/charts/scorecard_chart_config_builder.ts b/src/helpers/figures/charts/scorecard_chart_config_builder.ts
index 9e3906e796..5dafe6ab2c 100644
--- a/src/helpers/figures/charts/scorecard_chart_config_builder.ts
+++ b/src/helpers/figures/charts/scorecard_chart_config_builder.ts
@@ -1,3 +1,4 @@
+import { Pixel, PixelPosition } from "@odoo/o-spreadsheet-engine";
import { Color } from "chart.js";
import {
CHART_PADDING,
@@ -6,7 +7,7 @@ import {
DEFAULT_SCORECARD_KEY_VALUE_FONT_SIZE,
SCORECARD_CHART_TITLE_FONT_SIZE,
} from "../../../constants";
-import { DOMDimension, Pixel, PixelPosition } from "../../../types";
+import { DOMDimension } from "../../../types";
import { BaselineArrowDirection, ScorecardChartRuntime } from "../../../types/chart";
import { getDefaultContextFont } from "../../text_helper";
import { chartMutedFontColor } from "./chart_common";
diff --git a/src/helpers/figures/charts/smart_chart_engine.ts b/src/helpers/figures/charts/smart_chart_engine.ts
index 940afd114b..e9dbf44f84 100644
--- a/src/helpers/figures/charts/smart_chart_engine.ts
+++ b/src/helpers/figures/charts/smart_chart_engine.ts
@@ -1,9 +1,10 @@
+import { Zone } from "@odoo/o-spreadsheet-engine";
import {
DEFAULT_SCORECARD_BASELINE_COLOR_DOWN,
DEFAULT_SCORECARD_BASELINE_COLOR_UP,
DEFAULT_SCORECARD_BASELINE_MODE,
} from "../../../constants";
-import { CellValueType, ChartDefinition, EvaluatedCell, Getters, Zone } from "../../../types";
+import { CellValueType, ChartDefinition, EvaluatedCell, Getters } from "../../../types";
import { isDateTimeFormat } from "../../format/format";
import { recomputeZones } from "../../recompute_zones";
import { getZoneArea, getZonesByColumns, zoneToXc } from "../../zones";
diff --git a/src/helpers/figures/charts/sunburst_chart.ts b/src/helpers/figures/charts/sunburst_chart.ts
index b5f36636da..83594539cd 100644
--- a/src/helpers/figures/charts/sunburst_chart.ts
+++ b/src/helpers/figures/charts/sunburst_chart.ts
@@ -1,15 +1,7 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import type { ChartConfiguration, ChartOptions } from "chart.js";
import { BACKGROUND_CHART_COLOR } from "../../../constants";
-import {
- ApplyRangeChange,
- Color,
- CommandResult,
- CoreGetters,
- Getters,
- Range,
- RangeAdapter,
- UID,
-} from "../../../types";
+import { CommandResult, CoreGetters, Getters, Range } from "../../../types";
import { SunburstChartDefinition, SunburstChartRuntime } from "../../../types/chart";
import {
ChartCreationContext,
diff --git a/src/helpers/figures/charts/tree_map_chart.ts b/src/helpers/figures/charts/tree_map_chart.ts
index 0d6d57f78c..b2f6f54c8c 100644
--- a/src/helpers/figures/charts/tree_map_chart.ts
+++ b/src/helpers/figures/charts/tree_map_chart.ts
@@ -1,15 +1,7 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import { ChartConfiguration } from "chart.js";
import { BACKGROUND_CHART_COLOR } from "../../../constants";
-import {
- ApplyRangeChange,
- Color,
- CommandResult,
- CoreGetters,
- Getters,
- Range,
- RangeAdapter,
- UID,
-} from "../../../types";
+import { CommandResult, CoreGetters, Getters, Range } from "../../../types";
import {
ChartCreationContext,
CustomizedDataSet,
diff --git a/src/helpers/figures/charts/waterfall_chart.ts b/src/helpers/figures/charts/waterfall_chart.ts
index da567ad08c..526552e91a 100644
--- a/src/helpers/figures/charts/waterfall_chart.ts
+++ b/src/helpers/figures/charts/waterfall_chart.ts
@@ -1,15 +1,7 @@
+import { ApplyRangeChange, Color, RangeAdapter, UID } from "@odoo/o-spreadsheet-engine";
import type { ChartConfiguration } from "chart.js";
import { BACKGROUND_CHART_COLOR } from "../../../constants";
-import {
- ApplyRangeChange,
- Color,
- CommandResult,
- CoreGetters,
- Getters,
- Range,
- RangeAdapter,
- UID,
-} from "../../../types";
+import { CommandResult, CoreGetters, Getters, Range } from "../../../types";
import {
AxesDesign,
ChartCreationContext,
diff --git a/src/helpers/formulas.ts b/src/helpers/formulas.ts
index 6e67babbd2..df4338c1ed 100644
--- a/src/helpers/formulas.ts
+++ b/src/helpers/formulas.ts
@@ -1,10 +1,5 @@
-import { rangeTokenize } from "../formulas";
-import { Range, RangeAdapter, UID } from "../types";
-import { concat } from "./misc";
+import { Range } from "../types";
import { createInvalidRange, createRangeFromXc, getRangeString } from "./range";
-import { rangeReference, splitReference } from "./references";
-import { isSheetNameEqual } from "./sheet";
-
export function adaptFormulaStringRanges(
defaultSheetId: string,
formula: string,
diff --git a/src/helpers/internal_viewport.ts b/src/helpers/internal_viewport.ts
index f6b0455802..7fa94f7330 100644
--- a/src/helpers/internal_viewport.ts
+++ b/src/helpers/internal_viewport.ts
@@ -1,16 +1,7 @@
+import { HeaderIndex, Pixel, Position, UID, Zone } from "@odoo/o-spreadsheet-engine";
+import { Dimension } from "@odoo/o-spreadsheet-engine/types";
import { FOOTER_HEIGHT } from "../constants";
-import {
- DOMCoordinates,
- DOMDimension,
- Dimension,
- Getters,
- HeaderIndex,
- Pixel,
- Position,
- Rect,
- UID,
- Zone,
-} from "../types";
+import { DOMCoordinates, DOMDimension, Getters, Rect } from "../types";
import { intersection, isInside } from "./zones";
export class InternalViewport {
diff --git a/src/helpers/links.ts b/src/helpers/links.ts
index e501c138cb..424e664891 100644
--- a/src/helpers/links.ts
+++ b/src/helpers/links.ts
@@ -1,7 +1,9 @@
+import { parseSheetUrl } from "@odoo/o-spreadsheet-engine";
+import { Link } from "@odoo/o-spreadsheet-engine/types";
import { Registry } from "../registries/registry";
import { _t } from "../translation";
-import { CellValue, CommandResult, Getters, Link, SpreadsheetChildEnv } from "../types";
-import { isMarkdownLink, isSheetUrl, isWebLink, parseMarkdownLink, parseSheetUrl } from "./misc";
+import { CellValue, CommandResult, Getters, SpreadsheetChildEnv } from "../types";
+import { isMarkdownLink, isSheetUrl, isWebLink, parseMarkdownLink } from "./misc";
/**
* Add the `https` prefix to the url if it's missing
diff --git a/src/helpers/misc.ts b/src/helpers/misc.ts
index 67992f71a7..f635cde860 100644
--- a/src/helpers/misc.ts
+++ b/src/helpers/misc.ts
@@ -1,10 +1,19 @@
//------------------------------------------------------------------------------
// Miscellaneous
//------------------------------------------------------------------------------
-import { FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX, NEWLINE } from "../constants";
-import { ChartStyle, ConsecutiveIndexes, Lazy, UID } from "../types";
-import { SearchOptions } from "../types/find_and_replace";
-import { Cloneable, DebouncedFunction, Style } from "./../types/misc";
+import { ConsecutiveIndexes, Style } from "@odoo/o-spreadsheet-engine";
+import { Cloneable } from "@odoo/o-spreadsheet-engine/types";
+export {
+ escapeRegExp,
+ getCanonicalSymbolName,
+ getUnquotedSheetName,
+ memoize,
+ replaceNewLines,
+ specialWhiteSpaceRegexp,
+ TokenizingChars,
+ unquote,
+ whiteSpaceCharacters,
+} from "@odoo/o-spreadsheet-engine/helpers/misc";
const sanitizeSheetNameRegex = new RegExp(FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX, "g");
@@ -12,14 +21,6 @@ function isCloneable(obj: T | Cloneable): obj is Cloneable<
return "clone" in obj && obj.clone instanceof Function;
}
-/**
- * Escapes a string to use as a literal string in a RegExp.
- * @url https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping
- */
-export function escapeRegExp(str: string): string {
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
-}
-
/**
* Deep copy arrays, plain objects and primitive values.
* Throws an error for other types such as class instances.
@@ -72,43 +73,6 @@ function isPlainObject(obj: unknown): boolean {
);
}
-/**
- * Sanitize the name of a sheet, by eventually removing quotes
- * @param sheetName name of the sheet, potentially quoted with single quotes
- */
-export function getUnquotedSheetName(sheetName: string): string {
- return unquote(sheetName, "'");
-}
-
-/**
- * Remove quotes from a quoted string
- * ```js
- * unquote('"Hello"')
- * > 'Hello'
- * ```
- */
-export function unquote(string: string, quoteChar: "'" | '"' = '"'): string {
- if (string.startsWith(quoteChar)) {
- string = string.slice(1);
- }
- if (string.endsWith(quoteChar)) {
- string = string.slice(0, -1);
- }
- return string;
-}
-
-/**
- * Add quotes around the sheet name or any symbol name if it contains at least one non alphanumeric character
- * '\w' captures [0-9][a-z][A-Z] and _.
- * @param symbolName Name of the sheet or symbol
- */
-export function getCanonicalSymbolName(symbolName: string): string {
- if (symbolName.match(/\w/g)?.length !== symbolName.length) {
- symbolName = `'${symbolName}'`;
- }
- return symbolName;
-}
-
/** Replace the excel-excluded characters of a sheetName */
export function sanitizeSheetName(sheetName: string, replacementChar: string = " "): string {
return sheetName.replace(sanitizeSheetNameRegex, replacementChar);
@@ -223,446 +187,11 @@ export function parseMarkdownLink(str: string): { url: string; label: string } {
};
}
-const O_SPREADSHEET_LINK_PREFIX = "o-spreadsheet://";
-
-export function isSheetUrl(url: string) {
- return url.startsWith(O_SPREADSHEET_LINK_PREFIX);
-}
-
-export function buildSheetLink(sheetId: UID) {
- return `${O_SPREADSHEET_LINK_PREFIX}${sheetId}`;
-}
-
-/**
- * Parse a sheet link and return the sheet id
- */
-export function parseSheetUrl(sheetLink: string) {
- if (sheetLink.startsWith(O_SPREADSHEET_LINK_PREFIX)) {
- return sheetLink.slice(O_SPREADSHEET_LINK_PREFIX.length);
- }
- throw new Error(`${sheetLink} is not a valid sheet link`);
-}
-
-/**
- * This helper function can be used as a type guard when filtering arrays.
- * const foo: number[] = [1, 2, undefined, 4].filter(isDefined)
- */
-export function isDefined(argument: T | undefined): argument is T {
- return argument !== undefined;
-}
-
-export function isNotNull(argument: T | null): argument is T {
- return argument !== null;
-}
-
-/**
- * Check if all the values of an object, and all the values of the objects inside of it, are undefined.
- */
-export function isObjectEmptyRecursive(argument: T | undefined): boolean {
- if (argument === undefined) return true;
- return Object.values(argument).every((value) =>
- typeof value === "object" ? isObjectEmptyRecursive(value) : !value
- );
-}
-
-/**
- * Returns a function, that, as long as it continues to be invoked, will not
- * be triggered. The function will be called after it stops being called for
- * N milliseconds. If `immediate` is passed, trigger the function on the
- * leading edge, instead of the trailing.
- *
- * Also decorate the argument function with two methods: stopDebounce and isDebouncePending.
- *
- * Inspired by https://davidwalsh.name/javascript-debounce-function
- */
-export function debounce void>(
- func: T,
- wait: number,
- immediate?: boolean
-): DebouncedFunction {
- let timeout: any | undefined = undefined;
- const debounced = function (this: any): void {
- const context = this;
- const args = Array.from(arguments);
- function later() {
- timeout = undefined;
- if (!immediate) {
- func.apply(context, args);
- }
- }
- const callNow = immediate && !timeout;
- clearTimeout(timeout);
- timeout = setTimeout(later, wait);
- if (callNow) {
- func.apply(context, args);
- }
- };
- debounced.isDebouncePending = () => timeout !== undefined;
- debounced.stopDebounce = () => {
- clearTimeout(timeout);
- };
- return debounced as DebouncedFunction;
-}
-
-/**
- * Creates a batched version of a callback so that all calls to it in the same
- * microtick will only call the original callback once.
- *
- * @param callback the callback to batch
- * @returns a batched version of the original callback
- *
- * Copied from odoo/owl repo.
- */
-export function batched(callback: () => void): () => void {
- let scheduled = false;
- return async (...args) => {
- if (!scheduled) {
- scheduled = true;
- await Promise.resolve();
- scheduled = false;
- callback(...args);
- }
- };
-}
-
-/*
- * Concatenate an array of strings.
- */
-export function concat(chars: string[]): string {
- // ~40% faster than chars.join("")
- let output = "";
- for (let i = 0, len = chars.length; i < len; i++) {
- output += chars[i];
- }
- return output;
-}
-
-/**
- * Lazy value computed by the provided function.
- */
-export function lazy(fn: (() => T) | T): Lazy {
- let isMemoized = false;
- let memo: T | undefined;
- const lazyValue = () => {
- if (!isMemoized) {
- memo = fn instanceof Function ? fn() : fn;
- isMemoized = true;
- }
- return memo!;
- };
- lazyValue.map = (callback) => lazy(() => callback(lazyValue()));
- return lazyValue as Lazy;
-}
-
-/**
- * Find the next defined value after the given index in an array of strings. If there is no defined value
- * after the index, return the closest defined value before the index. Return an empty string if no
- * defined value was found.
- *
- */
-export function findNextDefinedValue(arr: string[], index: number): string {
- let value = arr.slice(index).find((val) => val);
- if (!value) {
- value = arr
- .slice(0, index)
- .reverse()
- .find((val) => val);
- }
- return value || "";
-}
-
/** Get index of first header added by an ADD_COLUMNS_ROWS command */
export function getAddHeaderStartIndex(position: "before" | "after", base: number): number {
return position === "after" ? base + 1 : base;
}
-/**
- * Compares n objects.
- */
-
-export function deepEquals(...o: any[]): boolean {
- if (o.length <= 1) return true;
- for (let index = 1; index < o.length; index++) {
- if (!_deepEquals(o[0], o[index])) return false;
- }
- return true;
-}
-
-function _deepEquals(o1: any, o2: any): boolean {
- if (o1 === o2) return true;
- if ((o1 && !o2) || (o2 && !o1)) return false;
- if (typeof o1 !== typeof o2) return false;
- if (typeof o1 !== "object") return false;
-
- // Objects can have different keys if the values are undefined
- for (const key in o2) {
- if (!(key in o1) && o2[key] !== undefined) {
- return false;
- }
- }
-
- for (const key in o1) {
- if (typeof o1[key] !== typeof o2[key]) return false;
- if (typeof o1[key] === "object") {
- if (!_deepEquals(o1[key], o2[key])) return false;
- } else {
- if (o1[key] !== o2[key]) return false;
- }
- }
-
- return true;
-}
-
-/**
- * Compares two arrays.
- * For performance reasons, this function is to be preferred
- * to 'deepEquals' in the case we know that the inputs are arrays.
- */
-export function deepEqualsArray(arr1: unknown[], arr2: unknown[]): boolean {
- if (arr1.length !== arr2.length) {
- return false;
- }
- for (let i = 0; i < arr1.length; i++) {
- if (!deepEquals(arr1[i], arr2[i])) {
- return false;
- }
- }
- return true;
-}
-
-/**
- * Check if the given array contains all the values of the other array.
- * It makes the assumption that both array do not contain duplicates.
- */
-export function includesAll(arr: T[], values: T[]): boolean {
- if (arr.length < values.length) {
- return false;
- }
-
- const set = new Set(arr);
- return values.every((value) => set.has(value));
-}
-
-/**
- * Return an object with all the keys in the object that have a falsy value removed.
- */
-export function removeFalsyAttributes(obj: T): T {
- if (!obj) return obj;
- const cleanObject = { ...obj };
- Object.keys(cleanObject).forEach((key) => !cleanObject[key] && delete cleanObject[key]);
- return cleanObject;
-}
-
-/**
- * Equivalent to "\s" in regexp, minus the new lines characters
- *
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
- */
-const specialWhiteSpaceSpecialCharacters = [
- "\t",
- "\f",
- "\v",
- String.fromCharCode(parseInt("00a0", 16)),
- String.fromCharCode(parseInt("1680", 16)),
- String.fromCharCode(parseInt("2000", 16)),
- String.fromCharCode(parseInt("200a", 16)),
- String.fromCharCode(parseInt("2028", 16)),
- String.fromCharCode(parseInt("2029", 16)),
- String.fromCharCode(parseInt("202f", 16)),
- String.fromCharCode(parseInt("205f", 16)),
- String.fromCharCode(parseInt("3000", 16)),
- String.fromCharCode(parseInt("feff", 16)),
-];
-export const specialWhiteSpaceRegexp = new RegExp(
- specialWhiteSpaceSpecialCharacters.join("|"),
- "g"
-);
-const newLineRegexp = /(\r\n|\r)/g;
-
-export const whiteSpaceCharacters = specialWhiteSpaceSpecialCharacters.concat([" "]);
-
-/**
- * Replace all different newlines characters by \n
- */
-export function replaceNewLines(text: string | undefined): string {
- if (!text) return "";
- return text.replace(newLineRegexp, NEWLINE);
-}
-
-/**
- * Determine if the numbers are consecutive.
- */
-export function isConsecutive(iterable: Iterable): boolean {
- const array = Array.from(iterable).sort((a, b) => a - b); // sort numerically rather than lexicographically
- for (let i = 1; i < array.length; i++) {
- if (array[i] - array[i - 1] !== 1) {
- return false;
- }
- }
- return true;
-}
-
-/**
- * Creates a version of the function that's memoized on the value of its first
- * argument, if any.
- */
-export function memoize(func: (...args: T) => U): (...args: T) => U {
- const cache = new Map();
- const funcName = func.name ? func.name + " (memoized)" : "memoized";
- return {
- [funcName](...args: T) {
- if (!cache.has(args[0])) {
- cache.set(args[0], func(...args));
- }
- return cache.get(args[0])!;
- },
- }[funcName];
-}
-
-/**
- * Removes the specified indexes from the array.
- * Sparse (empty) elements are transformed to undefined (unless their index is explicitly removed).
- */
-export function removeIndexesFromArray(array: readonly T[], indexes: number[]): T[] {
- const toRemove = new Set(indexes);
- const newArray: T[] = [];
- for (let i = 0; i < array.length; i++) {
- if (!toRemove.has(i)) {
- newArray.push(array[i]);
- }
- }
- return newArray;
-}
-
-export function insertItemsAtIndex(array: readonly T[], items: T[], index: number): T[] {
- const newArray = [...array];
- newArray.splice(index, 0, ...items);
- return newArray;
-}
-
-export function replaceItemAtIndex(array: readonly T[], newItem: T, index: number): T[] {
- const newArray = [...array];
- newArray[index] = newItem;
- return newArray;
-}
-
-export function trimContent(content: string): string {
- const contentLines = content.split("\n");
- return contentLines.map((line) => line.replace(/\s+/g, " ").trim()).join("\n");
-}
-
-export function isNumberBetween(value: number, min: number, max: number): boolean {
- if (min > max) {
- return isNumberBetween(value, max, min);
- }
- return value >= min && value <= max;
-}
-
-/**
- * Get a Regex for the find & replace that matches the given search string and options.
- */
-export function getSearchRegex(searchStr: string, searchOptions: SearchOptions): RegExp {
- let searchValue = escapeRegExp(searchStr);
- const flags = !searchOptions.matchCase ? "i" : "";
- if (searchOptions.exactMatch) {
- searchValue = `^${searchValue}$`;
- }
- return RegExp(searchValue, flags);
-}
-
-/**
- * Alternative to Math.max that works with large arrays.
- * Typically useful for arrays bigger than 100k elements.
- */
-export function largeMax(array: number[]) {
- let len = array.length;
-
- if (len < 100_000) return Math.max(...array);
-
- let max: number = -Infinity;
- while (len--) {
- max = array[len] > max ? array[len] : max;
- }
- return max;
-}
-
-/**
- * Alternative to Math.min that works with large arrays.
- * Typically useful for arrays bigger than 100k elements.
- */
-export function largeMin(array: number[]) {
- let len = array.length;
-
- if (len < 100_000) return Math.min(...array);
-
- let min: number = +Infinity;
- while (len--) {
- min = array[len] < min ? array[len] : min;
- }
- return min;
-}
-
-export class TokenizingChars {
- private text: string;
- private currentIndex: number = 0;
- current: string;
-
- constructor(text: string) {
- this.text = text;
- this.current = text[0];
- }
-
- shift() {
- const current = this.current;
- const next = this.text[++this.currentIndex];
- this.current = next;
- return current;
- }
-
- advanceBy(length: number) {
- this.currentIndex += length;
- this.current = this.text[this.currentIndex];
- }
-
- isOver() {
- return this.currentIndex >= this.text.length;
- }
-
- remaining() {
- return this.text.substring(this.currentIndex);
- }
-
- currentStartsWith(str: string) {
- if (this.current !== str[0]) {
- return false;
- }
- for (let j = 1; j < str.length; j++) {
- if (this.text[this.currentIndex + j] !== str[j]) {
- return false;
- }
- }
- return true;
- }
-}
-
-/**
- * Remove duplicates from an array.
- *
- * @param array The array to remove duplicates from.
- * @param cb A callback to get an element value.
- */
-export function removeDuplicates(array: T[], cb: (a: T) => any = (a) => a): T[] {
- const set = new Set();
- return array.filter((item) => {
- const key = cb(item);
- if (set.has(key)) {
- return false;
- }
- set.add(key);
- return true;
- });
-}
-
/**
* Similar to transposing and array, but with POJOs instead of arrays. Useful, for example, when manipulating
* a POJO grid[col][row] and you want to transpose it to grid[row][col].
diff --git a/src/helpers/numbers.ts b/src/helpers/numbers.ts
index 39a36d37d4..2970ea3d5e 100644
--- a/src/helpers/numbers.ts
+++ b/src/helpers/numbers.ts
@@ -1,103 +1,6 @@
-import { Locale } from "../types";
-import { escapeRegExp, memoize } from "./misc";
-
-/**
- * This function returns a regexp that is supposed to be as close as possible as the numberRegexp,
- * but its purpose is to be used by the tokenizer.
- *
- * - it tolerates extra characters at the end. This is useful because the tokenizer
- * only needs to find the number at the start of a string
- * - it does not support % symbol, in formulas % is an operator
- */
-export const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(
- decimalSeparator: string
-) {
- decimalSeparator = escapeRegExp(decimalSeparator);
- return new RegExp(
- `(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e(\\+|-)?\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`
- );
-});
-
-const getNumberRegex = memoize(function getNumberRegex(locale: Locale) {
- const decimalSeparator = escapeRegExp(locale.decimalSeparator);
- const thousandsSeparator = escapeRegExp(locale.thousandsSeparator || "");
-
- const pIntegerAndDecimals = `(?:\\d+(?:${thousandsSeparator}\\d{3,})*(?:${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
- const pOnlyDecimals = `(?:${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
- const pScientificFormat = "(?:e(?:\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
- const pPercentFormat = "(?:\\s*%)?"; // pattern that match percent symbol between zero and one time
- const pNumber =
- "(?:\\s*" +
- pIntegerAndDecimals +
- "|" +
- pOnlyDecimals +
- ")" +
- pScientificFormat +
- pPercentFormat;
- const pMinus = "(?:\\s*-)?"; // pattern that match negative symbol between zero and one time
- const pCurrencyFormat = "(?:\\s*[\\$€])?";
-
- const p1 = pMinus + pCurrencyFormat + pNumber;
- const p2 = pMinus + pNumber + pCurrencyFormat;
- const p3 = pCurrencyFormat + pMinus + pNumber;
-
- const pNumberExp = "^(?:(?:" + [p1, p2, p3].join(")|(?:") + "))$";
-
- return new RegExp(pNumberExp, "i");
-});
-
-/**
- * Return true if the argument is a "number string".
- *
- * Note that "" (empty string) does not count as a number string
- */
-export function isNumber(value: string | undefined, locale: Locale): boolean {
- if (!value) return false;
- // TO DO: add regexp for DATE string format (ex match: "28 02 2020")
- return getNumberRegex(locale).test(value.trim());
-}
-
-const getInvaluableSymbolsRegexp = memoize(function getInvaluableSymbolsRegexp(locale: Locale) {
- return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator || "")}]`, "g");
-});
-/**
- * Convert a string into a number. It assumes that the string actually represents
- * a number (as determined by the isNumber function)
- *
- * Note that it accepts "" (empty string), even though it does not count as a
- * number from the point of view of the isNumber function.
- */
-export function parseNumber(str: string, locale: Locale): number {
- // remove invaluable characters
- str = str.replace(getInvaluableSymbolsRegexp(locale), "");
-
- if (locale.decimalSeparator !== ".") {
- str = str.replace(locale.decimalSeparator, ".");
- }
- let n = Number(str);
- if (isNaN(n) && str.includes("%")) {
- n = Number(str.split("%")[0]);
- if (!isNaN(n)) {
- return n / 100;
- }
- }
- return n;
-}
-
-export function percentile(values: number[], percent: number, isInclusive: boolean) {
- const sortedValues = [...values].sort((a, b) => a - b);
-
- let percentIndex = (sortedValues.length + (isInclusive ? -1 : 1)) * percent;
- if (!isInclusive) {
- percentIndex--;
- }
- if (Number.isInteger(percentIndex)) {
- return sortedValues[percentIndex];
- }
- const indexSup = Math.ceil(percentIndex);
- const indexLow = Math.floor(percentIndex);
- return (
- sortedValues[indexSup] * (percentIndex - indexLow) +
- sortedValues[indexLow] * (indexSup - percentIndex)
- );
-}
+export {
+ getFormulaNumberRegex,
+ isNumber,
+ parseNumber,
+ percentile,
+} from "@odoo/o-spreadsheet-engine/helpers/numbers";
diff --git a/src/helpers/pivot/pivot_composer_helpers.ts b/src/helpers/pivot/pivot_composer_helpers.ts
index fc1e1a0107..6bf3032613 100644
--- a/src/helpers/pivot/pivot_composer_helpers.ts
+++ b/src/helpers/pivot/pivot_composer_helpers.ts
@@ -1,6 +1,7 @@
+import { getFunctionsFromTokens } from "@odoo/o-spreadsheet-engine";
import { CellComposerStore } from "../../components/composer/composer/cell_composer_store";
import { tokenColors } from "../../constants";
-import { Token, getFunctionsFromTokens } from "../../formulas";
+import { Token } from "../../formulas";
import { EnrichedToken } from "../../formulas/composer_tokenizer";
import { Granularity, PivotField, PivotMeasure } from "../../types";
diff --git a/src/helpers/pivot/pivot_domain_helpers.ts b/src/helpers/pivot/pivot_domain_helpers.ts
index 931a34a3ce..770de77b3a 100644
--- a/src/helpers/pivot/pivot_domain_helpers.ts
+++ b/src/helpers/pivot/pivot_domain_helpers.ts
@@ -1,3 +1,4 @@
+import { deepEquals } from "@odoo/o-spreadsheet-engine";
import {
CellValue,
DimensionTree,
@@ -6,7 +7,7 @@ import {
PivotDomain,
PivotNode,
} from "../../types";
-import { clip, deepCopy, deepEquals } from "../misc";
+import { clip, deepCopy } from "../misc";
export const PREVIOUS_VALUE = "(previous)";
export const NEXT_VALUE = "(next)";
diff --git a/src/helpers/pivot/pivot_helpers.ts b/src/helpers/pivot/pivot_helpers.ts
index 8a88e42b17..557199dc64 100644
--- a/src/helpers/pivot/pivot_helpers.ts
+++ b/src/helpers/pivot/pivot_helpers.ts
@@ -1,4 +1,4 @@
-import { boolAnd, boolOr } from "../../functions/helper_logical";
+import { getUniqueText } from "@odoo/o-spreadsheet-engine";
import { countUnique, sum } from "../../functions/helper_math";
import { average, countAny, max, min } from "../../functions/helper_statistical";
import {
@@ -11,15 +11,7 @@ import {
} from "../../functions/helpers";
import { Registry } from "../../registries/registry";
import { _t } from "../../translation";
-import {
- CellValue,
- DEFAULT_LOCALE,
- FunctionResultObject,
- Locale,
- Matrix,
- Maybe,
- Pivot,
-} from "../../types";
+import { CellValue, DEFAULT_LOCALE, Locale, Pivot } from "../../types";
import { EvaluationError } from "../../types/errors";
import {
Granularity,
@@ -33,10 +25,7 @@ import {
PivotSortedColumn,
PivotTableCell,
} from "../../types/pivot";
-import { getUniqueText, isDefined } from "../misc";
import { PivotRuntimeDefinition } from "./pivot_runtime_definition";
-import { pivotTimeAdapter } from "./pivot_time_adapter";
-
const AGGREGATOR_NAMES = {
count: _t("Count"),
count_distinct: _t("Count Distinct"),
diff --git a/src/helpers/pivot/pivot_highlight.ts b/src/helpers/pivot/pivot_highlight.ts
index f1990798eb..ea090a4634 100644
--- a/src/helpers/pivot/pivot_highlight.ts
+++ b/src/helpers/pivot/pivot_highlight.ts
@@ -1,5 +1,6 @@
+import { CellPosition, Highlight, UID } from "@odoo/o-spreadsheet-engine";
import { HIGHLIGHT_COLOR } from "../../constants";
-import { CellPosition, Getters, Highlight, UID } from "../../types";
+import { Getters } from "../../types";
import { mergeContiguousZones, positionToZone } from "../zones";
export function getPivotHighlights(getters: Getters, pivotId: UID): Highlight[] {
diff --git a/src/helpers/pivot/pivot_menu_items.ts b/src/helpers/pivot/pivot_menu_items.ts
index a257a76e4a..b2ae8bf192 100644
--- a/src/helpers/pivot/pivot_menu_items.ts
+++ b/src/helpers/pivot/pivot_menu_items.ts
@@ -1,5 +1,6 @@
+import { CellPosition } from "@odoo/o-spreadsheet-engine";
+import { SortDirection } from "@odoo/o-spreadsheet-engine/types";
import {
- CellPosition,
CellValue,
Getters,
PivotCoreDefinition,
@@ -8,7 +9,6 @@ import {
PivotField,
PivotFields,
PivotHeaderCell,
- SortDirection,
SpreadsheetChildEnv,
} from "../..";
import { ActionSpec } from "../../actions/action";
diff --git a/src/helpers/pivot/pivot_presentation.ts b/src/helpers/pivot/pivot_presentation.ts
index 0cdba373de..00be6c3ec4 100644
--- a/src/helpers/pivot/pivot_presentation.ts
+++ b/src/helpers/pivot/pivot_presentation.ts
@@ -1,24 +1,17 @@
-import { handleError } from "../../functions";
import { transposeMatrix } from "../../functions/helpers";
import { ModelConfig } from "../../model";
import { _t } from "../../translation";
import {
CellValue,
DimensionTree,
- FunctionResultObject,
Getters,
PivotDomain,
PivotMeasure,
PivotMeasureDisplay,
PivotValueCell,
- SortDirection,
- isMatrix,
} from "../../types";
import { CellErrorType, NotAvailableError } from "../../types/errors";
-import { deepEquals, removeDuplicates, transpose2dPOJO } from "../misc";
import {
- NEXT_VALUE,
- PREVIOUS_VALUE,
domainToColRowDomain,
domainToString,
getDimensionDomain,
@@ -31,12 +24,12 @@ import {
getRunningTotalDomainKey,
isDomainIsInPivot,
isFieldInDomain,
+ NEXT_VALUE,
+ PREVIOUS_VALUE,
replaceFieldValueInDomain,
} from "./pivot_domain_helpers";
import { AGGREGATORS_FN, isSortedColumnValid, toNormalizedPivotValue } from "./pivot_helpers";
import { PivotParams, PivotUIConstructor } from "./pivot_registry";
-import { SpreadsheetPivotTable } from "./table_spreadsheet_pivot";
-
const PERCENT_FORMAT = "0.00%";
type CacheForMeasureAndField = { [measureId: string]: { [field: string]: T } };
diff --git a/src/helpers/pivot/spreadsheet_pivot/spreadsheet_pivot.ts b/src/helpers/pivot/spreadsheet_pivot/spreadsheet_pivot.ts
index d2ae0e7eb6..79b05558df 100644
--- a/src/helpers/pivot/spreadsheet_pivot/spreadsheet_pivot.ts
+++ b/src/helpers/pivot/spreadsheet_pivot/spreadsheet_pivot.ts
@@ -1,18 +1,7 @@
-import { handleError } from "../../../functions";
-import { toString } from "../../../functions/helpers";
+import { ValueAndLabel } from "@odoo/o-spreadsheet-engine/types";
import { ModelConfig } from "../../../model";
import { _t } from "../../../translation";
-import {
- CellValueType,
- EvaluatedCell,
- FunctionResultObject,
- Getters,
- Maybe,
- Range,
- UID,
- ValueAndLabel,
- Zone,
-} from "../../../types";
+import { CellValueType, EvaluatedCell, Getters, Range } from "../../../types";
import { CellErrorType, EvaluationError } from "../../../types/errors";
import {
Granularity,
@@ -27,7 +16,6 @@ import {
import { InitPivotParams, Pivot } from "../../../types/pivot_runtime";
import { toXC } from "../../coordinates";
import { formatValue, isDateTimeFormat } from "../../format/format";
-import { deepEquals, isDefined } from "../../misc";
import {
AGGREGATORS_FN,
areDomainArgsFieldsValid,
diff --git a/src/helpers/pivot/table_spreadsheet_pivot.ts b/src/helpers/pivot/table_spreadsheet_pivot.ts
index 96b92b3251..e8f65ab38e 100644
--- a/src/helpers/pivot/table_spreadsheet_pivot.ts
+++ b/src/helpers/pivot/table_spreadsheet_pivot.ts
@@ -1,4 +1,3 @@
-import { FunctionResultObject, Lazy } from "../../types";
import {
DimensionTree,
DimensionTreeNode,
@@ -10,7 +9,6 @@ import {
PivotTableRow,
PivotVisibilityOptions,
} from "../../types/pivot";
-import { deepEquals, lazy } from "../misc";
import { isParentDomain, sortPivotTree } from "./pivot_domain_helpers";
import { parseDimension, toNormalizedPivotValue } from "./pivot_helpers";
diff --git a/src/helpers/range.ts b/src/helpers/range.ts
index 4d8d66750b..3e69ad16fa 100644
--- a/src/helpers/range.ts
+++ b/src/helpers/range.ts
@@ -1,27 +1,19 @@
-import { Registry } from "../registries/registry";
import {
AddColumnsRowsCommand,
- ApplyRangeChange,
- CellPosition,
- ChangeType,
CoreCommand,
CoreCommandTypes,
CoreGetters,
DeleteSheetCommand,
MoveRangeCommand,
Range,
- RangeAdapter,
RangePart,
RangeStringOptions,
RemoveColumnsRowsCommand,
RenameSheetCommand,
- UID,
- UnboundedZone,
- ZoneDimension,
} from "../types";
import { CellErrorType } from "../types/errors";
import { numberToLetters } from "./coordinates";
-import { getCanonicalSymbolName, groupConsecutive, largeMax, largeMin } from "./misc";
+import { getCanonicalSymbolName, groupConsecutive } from "./misc";
import { isRowReference, splitReference } from "./references";
import { isSheetNameEqual } from "./sheet";
import {
diff --git a/src/helpers/rectangle.ts b/src/helpers/rectangle.ts
index bdd241db25..dea39d09e9 100644
--- a/src/helpers/rectangle.ts
+++ b/src/helpers/rectangle.ts
@@ -1,4 +1,5 @@
-import { Rect, Zone } from "../types";
+import { Zone } from "@odoo/o-spreadsheet-engine";
+import { Rect } from "../types";
import { intersection, union } from "./zones";
/**
diff --git a/src/helpers/references.ts b/src/helpers/references.ts
index 05c7af4d1f..26d47c1c4b 100644
--- a/src/helpers/references.ts
+++ b/src/helpers/references.ts
@@ -1,80 +1,11 @@
-import { getCanonicalSymbolName, getUnquotedSheetName } from "./misc";
-
-/** Reference of a cell (eg. A1, $B$5) */
-export const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
-
-// Same as above, but matches the exact string (nothing before or after)
-const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
-
-/** Reference of a column header (eg. A, AB, $A) */
-const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
-
-/** Reference of a row header (eg. 1, $1) */
-const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
-
-/** Reference of a column (eg. A, $CA, Sheet1!B) */
-const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
-
-/** Reference of a row (eg. 1, 59, Sheet1!9) */
-const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
-
-/** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
-const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
-
-/** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
-const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
-
-/** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
-export const rangeReference = new RegExp(
- /^\s*('.+'!|[^']+!)?/.source +
- "(" +
- [cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
- ")" +
- /$/.source,
- "i"
-);
-
-/**
- * Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
- */
-export function isColReference(xc: string): boolean {
- return colReference.test(xc);
-}
-
-/**
- * Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
- */
-export function isRowReference(xc: string): boolean {
- return rowReference.test(xc);
-}
-
-export function isColHeader(str: string): boolean {
- return colHeader.test(str);
-}
-
-export function isRowHeader(str: string): boolean {
- return rowHeader.test(str);
-}
-
-/**
- * Return true if the given xc is the reference of a single cell,
- * without any specified sheet (e.g. A1)
- */
-export function isSingleCellReference(xc: string): boolean {
- return singleCellReference.test(xc);
-}
-
-export function splitReference(ref: string): { sheetName?: string; xc: string } {
- if (!ref.includes("!")) {
- return { xc: ref };
- }
- const parts = ref.split("!");
- const xc = parts.pop()!;
- const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
- return { sheetName, xc };
-}
-
-/** Return a reference SheetName!xc from the given arguments */
-export function getFullReference(sheetName: string | undefined, xc: string): string {
- return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
-}
+export {
+ cellReference,
+ getFullReference,
+ isColHeader,
+ isColReference,
+ isRowHeader,
+ isRowReference,
+ isSingleCellReference,
+ rangeReference,
+ splitReference,
+} from "@odoo/o-spreadsheet-engine/helpers/references";
diff --git a/src/helpers/rendering.ts b/src/helpers/rendering.ts
index 97f3804763..a0b970f78b 100644
--- a/src/helpers/rendering.ts
+++ b/src/helpers/rendering.ts
@@ -1,6 +1,7 @@
-import { GridRenderingContext, Highlight, Rect } from "../types";
+import { GridRenderingContext, Rect } from "../types";
import { toHex } from "./color";
+import { Highlight } from "@odoo/o-spreadsheet-engine";
import { HIGHLIGHT_COLOR } from "../constants";
import { setColorAlpha } from "./color";
diff --git a/src/helpers/sheet.ts b/src/helpers/sheet.ts
index 9e42da224d..2763897c3a 100644
--- a/src/helpers/sheet.ts
+++ b/src/helpers/sheet.ts
@@ -1,7 +1,5 @@
+import { HeaderIndex, Row } from "@odoo/o-spreadsheet-engine";
import { _t } from "../translation";
-import { HeaderIndex, Row } from "../types";
-import { getUnquotedSheetName, isDefined } from "./misc";
-
export function createDefaultRows(rowNumber: number): Row[] {
const rows: Row[] = [];
for (let i = 0; i < rowNumber; i++) {
diff --git a/src/helpers/sort.ts b/src/helpers/sort.ts
index b39cfe93e4..7bfaa127e9 100644
--- a/src/helpers/sort.ts
+++ b/src/helpers/sort.ts
@@ -1,70 +1,9 @@
+import { Position, UID, Zone } from "@odoo/o-spreadsheet-engine";
+import { SortDirection, SortOptions } from "@odoo/o-spreadsheet-engine/types";
import { _t } from "../translation";
-import {
- CellValue,
- CellValueType,
- CommandResult,
- EvaluatedCell,
- Position,
- SortDirection,
- SortOptions,
- SpreadsheetChildEnv,
- UID,
- Zone,
-} from "../types";
+import { SpreadsheetChildEnv } from "../types";
import { isEqual } from "./zones";
-type CellWithIndex = { index: number; type: CellValueType; value: any };
-
-const SORT_TYPES: CellValueType[] = [
- CellValueType.number,
- CellValueType.error,
- CellValueType.text,
- CellValueType.boolean,
-];
-
-export function cellsSortingCriterion(sortingOrder: string) {
- const inverse = sortingOrder === "asc" ? 1 : -1;
- return (
- left: { type: CellValueType; value: CellValue },
- right: { type: CellValueType; value: CellValue }
- ) => {
- if (left.type === CellValueType.empty) {
- return right.type === CellValueType.empty ? 0 : 1;
- } else if (right.type === CellValueType.empty) {
- return -1;
- }
- let typeOrder = SORT_TYPES.indexOf(left.type) - SORT_TYPES.indexOf(right.type);
- if (typeOrder === 0) {
- if (left.type === CellValueType.text || left.type === CellValueType.error) {
- typeOrder = (left.value as string).localeCompare(right.value as string);
- } else {
- typeOrder = (left.value as number) - (right.value as number);
- }
- }
- return inverse * typeOrder;
- };
-}
-
-export function sortCells(
- cells: EvaluatedCell[],
- sortDirection: SortDirection,
- emptyCellAsZero: boolean
-): CellWithIndex[] {
- const cellsWithIndex: CellWithIndex[] = cells.map((cell, index) => ({
- index,
- type: cell.type,
- value: cell.value,
- }));
-
- const cellsToSort = emptyCellAsZero
- ? cellsWithIndex.map((cell) =>
- cell.type === CellValueType.empty ? { ...cell, type: CellValueType.number, value: 0 } : cell
- )
- : cellsWithIndex;
-
- return cellsToSort.sort(cellsSortingCriterion(sortDirection));
-}
-
export function interactiveSortSelection(
env: SpreadsheetChildEnv,
sheetId: UID,
diff --git a/src/helpers/table_helpers.ts b/src/helpers/table_helpers.ts
index be16815dc2..a23463f546 100644
--- a/src/helpers/table_helpers.ts
+++ b/src/helpers/table_helpers.ts
@@ -1,9 +1,7 @@
-import { Border, BorderDescr, CellPosition, Range, Style, UID, Zone } from "../types";
+import { Range } from "../types";
import { CoreTable, Filter, StaticTable, Table, TableConfig, TableStyle } from "../types/table";
-import { generateMatrix } from "../functions/helpers";
-import { ComputedTableStyle } from "./../types/table";
-
+import { Border, BorderDescr, CellPosition, Style, UID, Zone } from "@odoo/o-spreadsheet-engine";
type TableElement = keyof Omit<
TableStyle,
"category" | "displayName" | "templateName" | "primaryColor"
diff --git a/src/helpers/table_presets.ts b/src/helpers/table_presets.ts
index 35702a841d..3454972ae1 100644
--- a/src/helpers/table_presets.ts
+++ b/src/helpers/table_presets.ts
@@ -1,6 +1,6 @@
+import { Color } from "@odoo/o-spreadsheet-engine";
import { darkenColor, lightenColor } from ".";
import { _t } from "../translation";
-import { Color } from "../types";
import { TableConfig, TableStyle, TableStyleTemplateName } from "../types/table";
export const TABLE_STYLE_CATEGORIES = {
diff --git a/src/helpers/text_helper.ts b/src/helpers/text_helper.ts
index cadc389e68..67981b0012 100644
--- a/src/helpers/text_helper.ts
+++ b/src/helpers/text_helper.ts
@@ -1,3 +1,4 @@
+import { Pixel, PixelPosition, Style } from "@odoo/o-spreadsheet-engine";
import {
DEFAULT_CELL_HEIGHT,
DEFAULT_FONT,
@@ -7,9 +8,7 @@ import {
NEWLINE,
PADDING_AUTORESIZE_VERTICAL,
} from "../constants";
-import { Cell, Pixel, PixelPosition, Style } from "../types";
-import { isMarkdownLink, parseMarkdownLink } from "./misc";
-
+import { Cell } from "../types";
export function computeTextLinesHeight(textLineHeight: number, numberOfLines: number = 1) {
return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
}
diff --git a/src/helpers/ui/freeze_interactive.ts b/src/helpers/ui/freeze_interactive.ts
index ef24463e24..b69f75a364 100644
--- a/src/helpers/ui/freeze_interactive.ts
+++ b/src/helpers/ui/freeze_interactive.ts
@@ -1,5 +1,7 @@
+import { HeaderIndex } from "@odoo/o-spreadsheet-engine";
+import { Dimension } from "@odoo/o-spreadsheet-engine/types";
import { MergeErrorMessage } from "../../components/translations_terms";
-import { CommandResult, Dimension, HeaderIndex, SpreadsheetChildEnv } from "../../types";
+import { CommandResult, SpreadsheetChildEnv } from "../../types";
export function interactiveFreezeColumnsRows(
env: SpreadsheetChildEnv,
diff --git a/src/helpers/ui/merge_interactive.ts b/src/helpers/ui/merge_interactive.ts
index 2e69e6ff86..a38a3585c8 100644
--- a/src/helpers/ui/merge_interactive.ts
+++ b/src/helpers/ui/merge_interactive.ts
@@ -1,6 +1,5 @@
+import { UID, Zone } from "@odoo/o-spreadsheet-engine";
import { _t } from "../../translation";
-import { CommandResult, SpreadsheetChildEnv, UID, Zone } from "../../types";
-
export const AddMergeInteractiveContent = {
MergeIsDestructive: _t(
"Merging these cells will only preserve the top-leftmost value. Merge anyway?"
diff --git a/src/helpers/ui/paste_interactive.ts b/src/helpers/ui/paste_interactive.ts
index ea2ad61991..cfb44dccfe 100644
--- a/src/helpers/ui/paste_interactive.ts
+++ b/src/helpers/ui/paste_interactive.ts
@@ -1,3 +1,4 @@
+import { Zone } from "@odoo/o-spreadsheet-engine";
import { RemoveDuplicateTerms } from "../../components/translations_terms";
import { getCurrentVersion } from "../../migrations/data";
import { _t } from "../../translation";
@@ -8,7 +9,6 @@ import {
ParsedOSClipboardContent,
ParsedOsClipboardContentWithImageData,
SpreadsheetChildEnv,
- Zone,
} from "../../types";
export const PasteInteractiveContent = {
diff --git a/src/helpers/ui/sheet_interactive.ts b/src/helpers/ui/sheet_interactive.ts
index b1e892844e..cd95846c5c 100644
--- a/src/helpers/ui/sheet_interactive.ts
+++ b/src/helpers/ui/sheet_interactive.ts
@@ -1,6 +1,7 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { FORBIDDEN_SHEETNAME_CHARS } from "../../constants";
import { _t } from "../../translation";
-import { CommandResult, SpreadsheetChildEnv, UID } from "../../types";
+import { CommandResult, SpreadsheetChildEnv } from "../../types";
export function interactiveRenameSheet(
env: SpreadsheetChildEnv,
diff --git a/src/helpers/ui/table_interactive.ts b/src/helpers/ui/table_interactive.ts
index 8da9ec1603..7251767aab 100644
--- a/src/helpers/ui/table_interactive.ts
+++ b/src/helpers/ui/table_interactive.ts
@@ -1,5 +1,6 @@
-import { CommandResult, DispatchResult, SpreadsheetChildEnv, UID } from "../../types";
+import { CommandResult, DispatchResult, SpreadsheetChildEnv } from "../../types";
+import { UID } from "@odoo/o-spreadsheet-engine";
import { TableTerms } from "../../components/translations_terms";
import { TableConfig } from "../../types/table";
import { DEFAULT_TABLE_CONFIG } from "../table_presets";
diff --git a/src/helpers/ui/toggle_group_interactive.ts b/src/helpers/ui/toggle_group_interactive.ts
index 7849fd7e22..525759cf3a 100644
--- a/src/helpers/ui/toggle_group_interactive.ts
+++ b/src/helpers/ui/toggle_group_interactive.ts
@@ -1,6 +1,5 @@
+import { HeaderIndex, UID } from "@odoo/o-spreadsheet-engine";
import { _t } from "../../translation";
-import { CommandResult, Dimension, HeaderIndex, SpreadsheetChildEnv, UID } from "../../types";
-
export const ToggleGroupInteractiveContent = {
CannotHideAllRows: _t("Cannot hide all the rows of a sheet."),
CannotHideAllColumns: _t("Cannot hide all the columns of a sheet."),
diff --git a/src/helpers/uuid.ts b/src/helpers/uuid.ts
index 85b6cb9fb9..eecad570ce 100644
--- a/src/helpers/uuid.ts
+++ b/src/helpers/uuid.ts
@@ -1,50 +1 @@
-/*
- * https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
- * */
-
-export class UuidGenerator {
- /**
- * Generates a custom UUID using a simple 36^12 method (8-character alphanumeric string with lowercase letters)
- * This has a higher chance of collision than a UUIDv4, but not only faster to generate than an UUIDV4,
- * it also has a smaller size, which is preferable to alleviate the overall data size.
- *
- * This method is preferable when generating uuids for the core data (sheetId, figureId, etc)
- * as they will appear several times in the revisions and local history.
- *
- */
- smallUuid(): string {
- if (window.crypto) {
- return "10000000-1000".replace(/[01]/g, (c) => {
- const n = Number(c);
- return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
- });
- } else {
- // mainly for jest and other browsers that do not have the crypto functionality
- return "xxxxxxxx-xxxx".replace(/[xy]/g, function (c) {
- const r = (Math.random() * 16) | 0,
- v = c === "x" ? r : (r & 0x3) | 0x8;
- return v.toString(16);
- });
- }
- }
-
- /**
- * Generates an UUIDV4, has astronomically low chance of collision, but is larger in size than the smallUuid.
- * This method should be used when you need to avoid collisions at all costs, like the id of a revision.
- */
- uuidv4(): string {
- if (window.crypto) {
- return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => {
- const n = Number(c);
- return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
- });
- } else {
- // mainly for jest and other browsers that do not have the crypto functionality
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
- const r = (Math.random() * 16) | 0,
- v = c === "x" ? r : (r & 0x3) | 0x8;
- return v.toString(16);
- });
- }
- }
-}
+export { UuidGenerator } from "@odoo/o-spreadsheet-engine";
diff --git a/src/history/branch.ts b/src/history/branch.ts
index 71c93b9211..224b25e547 100644
--- a/src/history/branch.ts
+++ b/src/history/branch.ts
@@ -1,4 +1,5 @@
-import { Transformation, TransformationFactory, UID } from "../types";
+import { UID } from "@odoo/o-spreadsheet-engine";
+import { Transformation, TransformationFactory } from "../types";
import { Operation } from "./operation";
/**
diff --git a/src/history/factory.ts b/src/history/factory.ts
index c8ff3e9c2c..c34147789d 100644
--- a/src/history/factory.ts
+++ b/src/history/factory.ts
@@ -1,13 +1,14 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
+import { StateObserver } from "@odoo/o-spreadsheet-engine/state_observer";
import { transformAll } from "../collaborative/ot/ot";
import { Revision } from "../collaborative/revisions";
import { inverseCommand } from "../helpers/inverse_commands";
-import { StateObserver } from "../state_observer";
-import { CoreCommand, HistoryChange, UID } from "../types";
+import { CoreCommand, HistoryChange } from "../types";
import { SelectiveHistory } from "./selective_history";
export function buildRevisionLog(args: {
initialRevisionId: UID;
- recordChanges: StateObserver["recordChanges"];
+ recordChanges: StateObserver["recordChanges"];
dispatch: (command: CoreCommand) => void;
}) {
return new SelectiveHistory({
diff --git a/src/history/operation.ts b/src/history/operation.ts
index 26c1ec0e71..3221bb9291 100644
--- a/src/history/operation.ts
+++ b/src/history/operation.ts
@@ -1,5 +1,4 @@
-import { lazy } from "../helpers";
-import { Lazy, Transformation, UID } from "../types";
+import { Transformation } from "../types";
/**
* An Operation can be executed to change a data structure from state A
diff --git a/src/history/operation_sequence.ts b/src/history/operation_sequence.ts
index 43392ad590..dbc950851f 100644
--- a/src/history/operation_sequence.ts
+++ b/src/history/operation_sequence.ts
@@ -1,4 +1,5 @@
-import { OperationSequenceNode, UID } from "../types";
+import { UID } from "@odoo/o-spreadsheet-engine";
+import { OperationSequenceNode } from "../types";
/**
* An execution object is a sequence of executionSteps (each execution step is an operation in a branch).
diff --git a/src/history/selective_history.ts b/src/history/selective_history.ts
index ff149484ea..1a15e599d4 100644
--- a/src/history/selective_history.ts
+++ b/src/history/selective_history.ts
@@ -1,4 +1,5 @@
-import { TransformationFactory, UID } from "../types";
+import { UID } from "@odoo/o-spreadsheet-engine";
+import { TransformationFactory } from "../types";
import { Branch } from "./branch";
import { Operation } from "./operation";
import { OperationSequence } from "./operation_sequence";
diff --git a/src/history/tree.ts b/src/history/tree.ts
index 8235bace3e..97bc216839 100644
--- a/src/history/tree.ts
+++ b/src/history/tree.ts
@@ -1,5 +1,6 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { linkNext } from "../helpers";
-import { OperationSequenceNode, Transformation, TransformationFactory, UID } from "../types";
+import { OperationSequenceNode, Transformation, TransformationFactory } from "../types";
import { Branch } from "./branch";
import { Operation } from "./operation";
import { OperationSequence } from "./operation_sequence";
diff --git a/src/index.ts b/src/index.ts
index dc4ec60d64..df20987efb 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -64,9 +64,8 @@ import {
PIVOT_TABLE_CONFIG,
SCROLLBAR_WIDTH,
} from "./constants";
-import { getFunctionsFromTokens } from "./formulas";
import { isEvaluationError, toBoolean, toJsDate, toNumber, toString } from "./functions/helpers";
-import { FunctionRegistry, arg, functionRegistry } from "./functions/index";
+import { FunctionRegistry, arg } from "./functions/index";
import {
ColorGenerator,
UuidGenerator,
@@ -74,16 +73,12 @@ import {
computeTextWidth,
createCurrencyFormat,
deepCopy,
- deepEquals,
expandZoneOnInsertion,
formatValue,
- getUniqueText,
isDateTime,
- isDefined,
isInside,
isMarkdownLink,
isNumber,
- lazy,
lettersToNumber,
markdownLink,
mergeContiguousZones,
@@ -112,11 +107,8 @@ import {
} from "./helpers/pivot/pivot_composer_helpers";
import { supportedPivotPositionalFormulaRegistry } from "./helpers/pivot/pivot_positional_formula_registry";
-import { CellComposerStore } from "./components/composer/composer/cell_composer_store";
-import { ClickableCellSortIcon } from "./components/dashboard/clickable_cell_sort_icon/clickable_cell_sort_icon";
-import { chartJsExtensionRegistry } from "./components/figures/chart/chartJs/chart_js_extension";
-import { ZoomableChartJsComponent } from "./components/figures/chart/chartJs/zoomable_chart/zoomable_chartjs";
-import { ChartDashboardMenu } from "./components/figures/chart/chart_dashboard_menu/chart_dashboard_menu";
+import { deepEquals, getUniqueText, isDefined, isMatrix, lazy } from "@odoo/o-spreadsheet-engine";
+
import { FullScreenChart } from "./components/full_screen_chart/full_screen_chart";
import { PivotHTMLRenderer } from "./components/pivot_html_renderer/pivot_html_renderer";
import { ComboChartDesignPanel } from "./components/side_panel/chart/combo_chart/combo_chart_design_panel";
@@ -204,7 +196,6 @@ import { HighlightStore } from "./stores/highlight_store";
import { ModelStore } from "./stores/model_store";
import { NotificationStore } from "./stores/notification_store";
import { RendererStore } from "./stores/renderer_store";
-import { AddFunctionDescription, isMatrix } from "./types";
import { errorTypes } from "./types/errors";
import { DEFAULT_LOCALE } from "./types/locale";
@@ -275,7 +266,7 @@ export const registries = {
colMenuRegistry,
errorTypes,
linkMenuRegistry,
- functionRegistry,
+ functionRegistry: typeof functionRegistry,
featurePluginRegistry,
iconsOnCellRegistry,
statefulUIPluginRegistry,
diff --git a/src/migrations/data.ts b/src/migrations/data.ts
index 8fea83ea14..99493efe90 100644
--- a/src/migrations/data.ts
+++ b/src/migrations/data.ts
@@ -1,3 +1,4 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { DEFAULT_REVISION_ID } from "../constants";
import { UuidGenerator, getDuplicateSheetName, getNextSheetName } from "../helpers/index";
import { isValidLocale } from "../helpers/locale";
@@ -8,7 +9,6 @@ import {
ExcelSheetData,
ExcelWorkbookData,
SheetData,
- UID,
WorkbookData,
} from "../types/index";
import { XlsxReader } from "../xlsx/xlsx_reader";
diff --git a/src/migrations/migration_steps.ts b/src/migrations/migration_steps.ts
index f692e59add..6c3dd48f48 100644
--- a/src/migrations/migration_steps.ts
+++ b/src/migrations/migration_steps.ts
@@ -1,11 +1,10 @@
-import { BACKGROUND_CHART_COLOR, FORMULA_REF_IDENTIFIER } from "../constants";
-import { getItemId, getUniqueText, sanitizeSheetName } from "../helpers";
+import { getItemId, sanitizeSheetName } from "../helpers";
import { toXC } from "../helpers/coordinates";
import { getMaxObjectId } from "../helpers/pivot/pivot_helpers";
import { DEFAULT_TABLE_CONFIG } from "../helpers/table_presets";
import { overlap, toZone, zoneToXc } from "../helpers/zones";
import { Registry } from "../registries/registry";
-import { CustomizedDataSet, DEFAULT_LOCALE, Format, WorkbookData, Zone } from "../types";
+import { CustomizedDataSet, DEFAULT_LOCALE, Format, WorkbookData } from "../types";
import { normalizeV9 } from "./legacy_tools";
import { WEEK_START } from "./locale";
diff --git a/src/model.ts b/src/model.ts
index d22a6268a5..599aec3ecb 100644
--- a/src/model.ts
+++ b/src/model.ts
@@ -1,10 +1,10 @@
-import { markRaw } from "@odoo/owl";
+import { lazy } from "@odoo/o-spreadsheet-engine";
import { LocalTransportService } from "./collaborative/local_transport_service";
import { ReadonlyTransportFilter } from "./collaborative/readonly_transport_filter";
import { Session } from "./collaborative/session";
import { DEFAULT_REVISION_ID } from "./constants";
import { EventBus } from "./helpers/event_bus";
-import { UuidGenerator, deepCopy, lazy } from "./helpers/index";
+import { UuidGenerator, deepCopy } from "./helpers/index";
import { buildRevisionLog } from "./history/factory";
import {
createEmptyExcelWorkbookData,
@@ -12,7 +12,6 @@ import {
load,
repairInitialMessages,
} from "./migrations/data";
-import { BasePlugin } from "./plugins/base_plugin";
import { RangeAdapter } from "./plugins/core/range";
import { CorePlugin, CorePluginConfig, CorePluginConstructor } from "./plugins/core_plugin";
import { CoreViewPluginConfig, CoreViewPluginConstructor } from "./plugins/core_view_plugin";
@@ -27,7 +26,6 @@ import {
SelectionStreamProcessor,
SelectionStreamProcessorImpl,
} from "./selection_stream/selection_stream_processor";
-import { StateObserver } from "./state_observer";
import { _t, setDefaultTranslationMethod } from "./translation";
import { GeoChartRegion } from "./types/chart/geo_chart";
import { StateUpdateMessage, TransportService } from "./types/collaborative/transport_service";
@@ -35,7 +33,6 @@ import { FileStore } from "./types/files";
import {
Client,
ClientPosition,
- Color,
Command,
CommandDispatcher,
CommandHandler,
@@ -48,11 +45,11 @@ import {
DispatchResult,
Getters,
GridRenderingContext,
+ HistoryChange,
InformationNotification,
LayerName,
LocalCommand,
Locale,
- UID,
canExecuteInReadonly,
isCoreCommand,
} from "./types/index";
@@ -168,7 +165,7 @@ export class Model extends EventBus implements CommandDispatcher {
private coreViewPluginConfig: CoreViewPluginConfig;
private uiPluginConfig: UIPluginConfig;
- private state: StateObserver;
+ private state: StateObserver;
readonly selection: SelectionStreamProcessor;
@@ -207,7 +204,7 @@ export class Model extends EventBus implements CommandDispatcher {
const workbookData = load(data, verboseImport);
- this.state = new StateObserver();
+ this.state = new StateObserver();
this.uuidGenerator = uuidGenerator;
diff --git a/src/plugins/core/borders.ts b/src/plugins/core/borders.ts
index d9e32a1710..48fb9448b6 100644
--- a/src/plugins/core/borders.ts
+++ b/src/plugins/core/borders.ts
@@ -1,32 +1,19 @@
-import { PositionMap } from "../../helpers/cells/position_map";
import {
deepCopy,
- deepEquals,
getItemId,
intersection,
positionToZone,
recomputeZones,
- removeFalsyAttributes,
toZone,
} from "../../helpers/index";
import { adjacent, overlap, splitIfAdjacent, zoneToXc } from "../../helpers/zones";
import {
- ApplyRangeChange,
- Border,
- BorderData,
- BorderDescr,
- CellPosition,
- Color,
CommandResult,
CoreCommand,
ExcelWorkbookData,
- HeaderIndex,
SetBorderCommand,
SetZoneBordersCommand,
- UID,
- UnboundedZone,
WorkbookData,
- Zone,
} from "../../types/index";
import { CorePlugin } from "../core_plugin";
diff --git a/src/plugins/core/carousel.ts b/src/plugins/core/carousel.ts
index 4acd4e7984..de1efe6f0d 100644
--- a/src/plugins/core/carousel.ts
+++ b/src/plugins/core/carousel.ts
@@ -1,10 +1,10 @@
+import { UID } from "@odoo/o-spreadsheet-engine";
import { FIGURE_ID_SPLITTER } from "../../constants";
import {
Carousel,
CarouselItem,
CommandResult,
CoreCommand,
- UID,
UpdateCarouselCommand,
WorkbookData,
} from "../../types/index";
diff --git a/src/plugins/core/cell.ts b/src/plugins/core/cell.ts
index 3554768026..10df1fef04 100644
--- a/src/plugins/core/cell.ts
+++ b/src/plugins/core/cell.ts
@@ -1,8 +1,7 @@
-import { DEFAULT_STYLE } from "../../constants";
-import { Token, compile } from "../../formulas";
+import { compile, Token } from "../../formulas";
import { compileTokens } from "../../formulas/compiler";
import { isEvaluationError, toString } from "../../functions/helpers";
-import { deepEquals, isExcelCompatible, isTextFormat, recomputeZones } from "../../helpers";
+import { isExcelCompatible, isTextFormat, recomputeZones } from "../../helpers";
import { parseLiteral } from "../../helpers/cells";
import { PositionMap } from "../../helpers/cells/position_map";
import {
@@ -11,7 +10,6 @@ import {
iterateItemIdsPositions,
} from "../../helpers/data_normalization";
import {
- concat,
detectDateFormat,
detectNumberFormat,
isInside,
@@ -21,30 +19,20 @@ import {
toXC,
} from "../../helpers/index";
import {
- AdaptSheetName,
AddColumnsRowsCommand,
- ApplyRangeChange,
Cell,
- CellPosition,
ClearCellCommand,
CommandResult,
- CompiledFormula,
CoreCommand,
ExcelWorkbookData,
Format,
FormulaCell,
- HeaderIndex,
LiteralCell,
PositionDependentCommand,
Range,
- RangeCompiledFormula,
RangePart,
- Style,
- UID,
UpdateCellCommand,
- UpdateCellData,
WorkbookData,
- Zone,
} from "../../types/index";
import { CorePlugin } from "../core_plugin";
diff --git a/src/plugins/core/chart.ts b/src/plugins/core/chart.ts
index 48cc8380af..1f5d7940f9 100644
--- a/src/plugins/core/chart.ts
+++ b/src/plugins/core/chart.ts
@@ -1,26 +1,15 @@
-import { DEFAULT_FIGURE_HEIGHT, DEFAULT_FIGURE_WIDTH, FIGURE_ID_SPLITTER } from "../../constants";
-import { deepEquals } from "../../helpers";
-import { AbstractChart } from "../../helpers/figures/charts/abstract_chart";
-import { chartFactory, validateChartDefinition } from "../../helpers/figures/charts/chart_factory";
-import { ChartCreationContext, ChartDefinition, ChartType } from "../../types/chart/chart";
import {
AdaptSheetName,
ApplyRangeChange,
- Command,
- CommandResult,
- CoreCommand,
- CreateChartCommand,
- DeleteChartCommand,
- DOMDimension,
- FigureData,
+ deepEquals,
HeaderIndex,
PixelPosition,
UID,
- UpdateChartCommand,
- WorkbookData,
-} from "../../types/index";
-import { CorePlugin } from "../core_plugin";
-
+} from "@odoo/o-spreadsheet-engine";
+import { DEFAULT_FIGURE_HEIGHT, DEFAULT_FIGURE_WIDTH, FIGURE_ID_SPLITTER } from "../../constants";
+import { AbstractChart } from "../../helpers/figures/charts/abstract_chart";
+import { chartFactory, validateChartDefinition } from "../../helpers/figures/charts/chart_factory";
+import { ChartCreationContext, ChartDefinition, ChartType } from "../../types/chart/chart";
interface FigureChart {
figureId: UID;
chart: AbstractChart;
diff --git a/src/plugins/core/conditional_format.ts b/src/plugins/core/conditional_format.ts
index 1b17925c17..18e9bd5e98 100644
--- a/src/plugins/core/conditional_format.ts
+++ b/src/plugins/core/conditional_format.ts
@@ -1,9 +1,10 @@
+import { ApplyRangeChange, deepEquals, UID, UnboundedZone, Zone } from "@odoo/o-spreadsheet-engine";
+import { Validation } from "@odoo/o-spreadsheet-engine/types";
import { compile } from "../../formulas/compiler";
-import { deepEquals, isInside, recomputeZones, toUnboundedZone } from "../../helpers/index";
+import { isInside, recomputeZones, toUnboundedZone } from "../../helpers/index";
import { criterionEvaluatorRegistry } from "../../registries/criterion_registry";
import {
AddConditionalFormatCommand,
- ApplyRangeChange,
CancelledReason,
CellIsRule,
ColorScaleMidPointThreshold,
@@ -18,11 +19,7 @@ import {
IconSetRule,
IconThreshold,
RangeData,
- UID,
- UnboundedZone,
- Validation,
WorkbookData,
- Zone,
} from "../../types";
import { CorePlugin } from "../core_plugin";
diff --git a/src/plugins/core/data_validation.ts b/src/plugins/core/data_validation.ts
index c00700b373..f4974afa69 100644
--- a/src/plugins/core/data_validation.ts
+++ b/src/plugins/core/data_validation.ts
@@ -1,3 +1,4 @@
+import { ApplyRangeChange, CellPosition, Style, UID } from "@odoo/o-spreadsheet-engine";
import { compile } from "../../formulas";
import {
deepCopy,
@@ -8,21 +9,7 @@ import {
toXC,
} from "../../helpers";
import { criterionEvaluatorRegistry } from "../../registries/criterion_registry";
-import {
- AddDataValidationCommand,
- ApplyRangeChange,
- CellPosition,
- Command,
- CommandResult,
- CoreCommand,
- DataValidationRule,
- ExcelWorkbookData,
- Range,
- Style,
- UID,
- WorkbookData,
-} from "../../types";
-import { CorePlugin } from "../core_plugin";
+import { DataValidationRule } from "../../types";
interface DataValidationState {
readonly rules: { [sheet: string]: DataValidationRule[] };
diff --git a/src/plugins/core/figures.ts b/src/plugins/core/figures.ts
index 9a2f4f3595..64d4704892 100644
--- a/src/plugins/core/figures.ts
+++ b/src/plugins/core/figures.ts
@@ -1,21 +1,8 @@
+import { ApplyRangeChange, HeaderIndex, PixelPosition, UID } from "@odoo/o-spreadsheet-engine";
import { DEFAULT_CELL_HEIGHT, FIGURE_ID_SPLITTER } from "../../constants";
import { clip } from "../../helpers/index";
import { AnchorOffset } from "../../types/figure";
-import {
- ApplyRangeChange,
- CommandResult,
- CoreCommand,
- CreateFigureCommand,
- DeleteFigureCommand,
- ExcelWorkbookData,
- Figure,
- HeaderIndex,
- PixelPosition,
- UID,
- UpdateFigureCommand,
- WorkbookData,
-} from "../../types/index";
-import { CorePlugin } from "../core_plugin";
+import { Figure } from "../../types/index";
interface FigureState {
readonly figures: { [sheet: string]: Record | undefined };
diff --git a/src/plugins/core/header_grouping.ts b/src/plugins/core/header_grouping.ts
index 6e6d79a862..d09cf3be0b 100644
--- a/src/plugins/core/header_grouping.ts
+++ b/src/plugins/core/header_grouping.ts
@@ -1,15 +1,7 @@
-import {
- deepCopy,
- getAddHeaderStartIndex,
- isConsecutive,
- moveHeaderIndexesOnHeaderAddition,
- moveHeaderIndexesOnHeaderDeletion,
- range,
-} from "../../helpers";
-import { CommandResult, CoreCommand, ExcelWorkbookData, UID, WorkbookData } from "../../types";
+import { CommandResult, CoreCommand, ExcelWorkbookData, WorkbookData } from "../../types";
import { getSheetDataHeader } from "../../xlsx/helpers/misc";
-import { Dimension, HeaderGroup, HeaderIndex, Zone } from "./../../types/misc";
-import { CorePlugin } from "./../core_plugin";
+
+import { Dimension } from "@odoo/o-spreadsheet-engine/types";
interface State {
groups: Record>;
diff --git a/src/plugins/core/header_size.ts b/src/plugins/core/header_size.ts
index 48e9aa4b3d..3f187602bf 100644
--- a/src/plugins/core/header_size.ts
+++ b/src/plugins/core/header_size.ts
@@ -1,8 +1,7 @@
-import { DEFAULT_CELL_HEIGHT, DEFAULT_CELL_WIDTH } from "../../constants";
-import { deepCopy, getAddHeaderStartIndex, range, removeIndexesFromArray } from "../../helpers";
+import { deepCopy, getAddHeaderStartIndex, range } from "../../helpers";
import { Command, ExcelWorkbookData, WorkbookData } from "../../types";
-import { Dimension, HeaderIndex, Pixel, UID } from "../../types/misc";
-import { CorePlugin } from "../core_plugin";
+
+import { Dimension } from "@odoo/o-spreadsheet-engine/types";
interface HeaderSizeState {
sizes: Record>>;
diff --git a/src/plugins/core/header_visibility.ts b/src/plugins/core/header_visibility.ts
index 967a6b29b4..7f852f3a24 100644
--- a/src/plugins/core/header_visibility.ts
+++ b/src/plugins/core/header_visibility.ts
@@ -1,13 +1,5 @@
-import {
- deepCopy,
- getAddHeaderStartIndex,
- includesAll,
- largeMax,
- largeMin,
- range,
-} from "../../helpers";
+import { deepCopy, getAddHeaderStartIndex, range } from "../../helpers";
import { Command, CommandResult, ExcelWorkbookData, WorkbookData } from "../../types";
-import { ConsecutiveIndexes, Dimension, HeaderIndex, UID } from "../../types/misc";
import { CorePlugin } from "../core_plugin";
export class HeaderVisibilityPlugin extends CorePlugin {
diff --git a/src/plugins/core/image.ts b/src/plugins/core/image.ts
index 76802ae1f0..a59d6724a1 100644
--- a/src/plugins/core/image.ts
+++ b/src/plugins/core/image.ts
@@ -1,5 +1,4 @@
-import { FIGURE_ID_SPLITTER } from "../../constants";
-import { deepCopy, isDefined } from "../../helpers";
+import { deepCopy } from "../../helpers";
import { FileStore } from "../../types/files";
import { Image } from "../../types/image";
import {
@@ -9,13 +8,8 @@ import {
ExcelWorkbookData,
FigureData,
FigureSize,
- HeaderIndex,
- PixelPosition,
- UID,
WorkbookData,
} from "../../types/index";
-import { CorePlugin, CorePluginConfig } from "../core_plugin";
-
interface ImageState {
readonly images: Record | undefined>;
}
diff --git a/src/plugins/core/merge.ts b/src/plugins/core/merge.ts
index 17b4381db1..ebb3edc562 100644
--- a/src/plugins/core/merge.ts
+++ b/src/plugins/core/merge.ts
@@ -1,37 +1,12 @@
-import {
- clip,
- createRange,
- deepEquals,
- doesAnyZoneCrossFrozenPane,
- getFullReference,
- isDefined,
- isEqual,
- isFullColRange,
- isFullRowRange,
- overlap,
- positions,
- splitReference,
- toXC,
- toZone,
- union,
- zoneToDimension,
- zoneToXc,
-} from "../../helpers/index";
import {
AddMergeCommand,
- ApplyRangeChange,
- CellPosition,
CommandResult,
CoreCommand,
ExcelWorkbookData,
- HeaderIndex,
- Merge,
Range,
TargetDependentCommand,
- UID,
UpdateCellCommand,
WorkbookData,
- Zone,
} from "../../types/index";
import { CorePlugin } from "../core_plugin";
diff --git a/src/plugins/core/pivot.ts b/src/plugins/core/pivot.ts
index fe7540f914..605aea2cc8 100644
--- a/src/plugins/core/pivot.ts
+++ b/src/plugins/core/pivot.ts
@@ -1,21 +1,17 @@
-import { compile } from "../../formulas";
-import { deepCopy, deepEquals } from "../../helpers";
-import { createPivotFormula, getMaxObjectId } from "../../helpers/pivot/pivot_helpers";
-import { SpreadsheetPivotTable } from "../../helpers/pivot/table_spreadsheet_pivot";
import {
ApplyRangeChange,
CellPosition,
- CellValue,
- CommandResult,
- CoreCommand,
+ deepEquals,
Position,
- Range,
RangeCompiledFormula,
UID,
- WorkbookData,
-} from "../../types";
-import { PivotCoreDefinition, PivotCoreMeasure } from "../../types/pivot";
-import { CorePlugin } from "../core_plugin";
+} from "@odoo/o-spreadsheet-engine";
+import { compile } from "../../formulas";
+import { deepCopy } from "../../helpers";
+import { createPivotFormula, getMaxObjectId } from "../../helpers/pivot/pivot_helpers";
+import { SpreadsheetPivotTable } from "../../helpers/pivot/table_spreadsheet_pivot";
+import { CellValue, CommandResult, CoreCommand, Range, WorkbookData } from "../../types";
+import { PivotCoreDefinition } from "../../types/pivot";
interface Pivot {
definition: PivotCoreDefinition;
diff --git a/src/plugins/core/range.ts b/src/plugins/core/range.ts
index ff99651910..d6a65bcf16 100644
--- a/src/plugins/core/range.ts
+++ b/src/plugins/core/range.ts
@@ -1,3 +1,13 @@
+import {
+ AdaptSheetName,
+ ApplyRangeChange,
+ ApplyRangeChangeResult,
+ RangeProvider,
+ UID,
+ UnboundedZone,
+ Zone,
+} from "@odoo/o-spreadsheet-engine";
+import { Dimension } from "@odoo/o-spreadsheet-engine/types";
import { compile } from "../../formulas";
import {
createInvalidRange,
@@ -17,22 +27,14 @@ import {
} from "../../helpers/index";
import { CellErrorType } from "../../types/errors";
import {
- AdaptSheetName,
- ApplyRangeChange,
- ApplyRangeChangeResult,
Command,
CommandHandler,
CommandResult,
CoreCommand,
CoreGetters,
- Dimension,
Range,
RangeData,
- RangeProvider,
RangeStringOptions,
- UID,
- UnboundedZone,
- Zone,
} from "../../types/index";
export class RangeAdapter implements CommandHandler {
diff --git a/src/plugins/core/sheet.ts b/src/plugins/core/sheet.ts
index f69110bb9b..8bcb4a2781 100644
--- a/src/plugins/core/sheet.ts
+++ b/src/plugins/core/sheet.ts
@@ -1,4 +1,5 @@
-import { FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX } from "../../constants";
+import { includesAll, largeMax, largeMin } from "@odoo/o-spreadsheet-engine";
+import { Dimension } from "@odoo/o-spreadsheet-engine/types";
import {
createDefaultRows,
deepCopy,
@@ -6,43 +7,27 @@ import {
getNextSheetName,
getUnquotedSheetName,
groupConsecutive,
- includesAll,
isColorValid,
- isDefined,
isZoneInside,
isZoneValid,
- largeMax,
- largeMin,
range,
toCartesian,
} from "../../helpers/index";
import { isSheetNameEqual } from "../../helpers/sheet";
import {
Cell,
- CellPosition,
Command,
CommandResult,
CoreCommand,
CreateSheetCommand,
- Dimension,
ExcelWorkbookData,
FreezeColumnsCommand,
FreezeRowsCommand,
- HeaderIndex,
- PaneDivision,
RenameSheetCommand,
- Row,
- Sheet,
SheetData,
- UID,
- UnboundedZone,
UpdateCellPositionCommand,
WorkbookData,
- Zone,
- ZoneDimension,
} from "../../types/index";
-import { CorePlugin } from "../core_plugin";
-
interface SheetState {
readonly sheets: Record;
readonly orderedSheetIds: UID[];
diff --git a/src/plugins/core/spreadsheet_pivot.ts b/src/plugins/core/spreadsheet_pivot.ts
index 3e10620375..0b1cf3ca1d 100644
--- a/src/plugins/core/spreadsheet_pivot.ts
+++ b/src/plugins/core/spreadsheet_pivot.ts
@@ -1,11 +1,6 @@
+import { ApplyRangeChange } from "@odoo/o-spreadsheet-engine";
import { isZoneValid } from "../../helpers";
-import {
- ApplyRangeChange,
- CommandResult,
- CoreCommand,
- PivotCoreDefinition,
- Range,
-} from "../../types";
+import { CommandResult, CoreCommand, PivotCoreDefinition, Range } from "../../types";
import { CorePlugin } from "../core_plugin";
function adaptPivotRange(
diff --git a/src/plugins/core/table_style.ts b/src/plugins/core/table_style.ts
index ff359dcb2d..47be39cabb 100644
--- a/src/plugins/core/table_style.ts
+++ b/src/plugins/core/table_style.ts
@@ -1,4 +1,5 @@
-import { getUniqueText, toHex } from "../../helpers";
+import { getUniqueText } from "@odoo/o-spreadsheet-engine";
+import { toHex } from "../../helpers";
import {
DEFAULT_TABLE_CONFIG,
TABLE_PRESETS,
diff --git a/src/plugins/core/tables.ts b/src/plugins/core/tables.ts
index 4d79d7b847..88207c3b1f 100644
--- a/src/plugins/core/tables.ts
+++ b/src/plugins/core/tables.ts
@@ -1,9 +1,7 @@
import {
areZonesContinuous,
deepCopy,
- deepEquals,
intersection,
- isDefined,
isInside,
isZoneInside,
overlap,
@@ -16,8 +14,6 @@ import {
import { createFilter } from "../../helpers/table_helpers";
import { DEFAULT_TABLE_CONFIG } from "../../helpers/table_presets";
import {
- ApplyRangeChange,
- CellPosition,
CommandResult,
CoreCommand,
CoreTable,
@@ -30,15 +26,12 @@ import {
Table,
TableConfig,
TableData,
- TableId,
- UID,
UpdateCellCommand,
UpdateTableCommand,
WorkbookData,
- Zone,
} from "../../types/index";
-import { CorePlugin } from "../core_plugin";
+import { TableId, UID } from "@odoo/o-spreadsheet-engine";
interface TableState {
tables: Record>;
diff --git a/src/plugins/core_plugin.ts b/src/plugins/core_plugin.ts
index 808ca85cf0..3950b21e70 100644
--- a/src/plugins/core_plugin.ts
+++ b/src/plugins/core_plugin.ts
@@ -1,21 +1,17 @@
-import { ModelConfig } from "../model";
-import { StateObserver } from "../state_observer";
import {
- AdaptSheetName,
- ApplyRangeChange,
+ CommandResult,
CoreCommand,
CoreCommandDispatcher,
- RangeProvider,
- UID,
+ ExcelWorkbookData,
+ HistoryChange,
WorkbookData,
} from "../types";
import { CoreGetters } from "../types/getters";
-import { BasePlugin } from "./base_plugin";
import { RangeAdapter } from "./core/range";
export interface CorePluginConfig {
readonly getters: CoreGetters;
- readonly stateObserver: StateObserver;
+ readonly stateObserver: StateObserver;
readonly range: RangeAdapter;
readonly dispatch: CoreCommandDispatcher["dispatch"];
readonly canDispatch: CoreCommandDispatcher["dispatch"];
@@ -35,7 +31,7 @@ export interface CorePluginConstructor {
* They should not be concerned about UI parts or transient state.
*/
export class CorePlugin
- extends BasePlugin
+ extends BasePlugin
implements RangeProvider
{
protected getters: CoreGetters;
@@ -43,7 +39,7 @@ export class CorePlugin