Browse Source

support css vars (fixes #1230)

master
Ulrich-Matthias Schäfer 8 months ago
parent
commit
70125d5644
5 changed files with 109 additions and 577 deletions
  1. 59
    566
      package-lock.json
  2. 1
    1
      package.json
  3. 23
    0
      spec/spec/modules/optional/css.js
  4. 11
    5
      src/modules/optional/css.js
  5. 15
    5
      svg.js.d.ts

+ 59
- 566
package-lock.json View File

@@ -37,7 +37,7 @@
"prettier": "^2.8.8",
"rollup": "^3.25.1",
"rollup-plugin-filesize": "^10.0.0",
"svgdom": "^0.1.14",
"svgdom": "^0.1.16",
"typescript": "^5.1.3",
"yargs": "^17.7.2"
},
@@ -2696,6 +2696,16 @@
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==",
"dev": true
},
"node_modules/@swc/helpers": {
"version": "0.4.36",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.36.tgz",
"integrity": "sha512-5lxnyLEYFskErRPenYItLRSge5DjrJngYKdVjRSrWfza9G6KkgHEXi0vUZiyUeMU5JfXH1YnvXZzSp8ul88o2Q==",
"dev": true,
"dependencies": {
"legacy-swc-helpers": "npm:@swc/helpers@=0.4.14",
"tslib": "^2.4.0"
}
},
"node_modules/@szmarczak/http-timer": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
@@ -3043,6 +3053,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
"dev": true,
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3059,26 +3070,6 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/acorn-node": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
"integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
"dev": true,
"dependencies": {
"acorn": "^7.0.0",
"acorn-walk": "^7.0.0",
"xtend": "^4.0.2"
}
},
"node_modules/acorn-walk": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -3134,16 +3125,6 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
"dev": true,
"optional": true,
"engines": {
"node": ">=0.4.2"
}
},
"node_modules/ansi-align": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
@@ -3370,12 +3351,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/array-from": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz",
"integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=",
"dev": true
},
"node_modules/array-includes": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
@@ -3452,91 +3427,6 @@
"node": ">=0.8"
}
},
"node_modules/ast-transform": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/ast-transform/-/ast-transform-0.0.0.tgz",
"integrity": "sha1-dJRAWIh9goPhidlUYAlHvJj+AGI=",
"dev": true,
"dependencies": {
"escodegen": "~1.2.0",
"esprima": "~1.0.4",
"through": "~2.3.4"
}
},
"node_modules/ast-transform/node_modules/escodegen": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.2.0.tgz",
"integrity": "sha1-Cd55Z3kcyVi3+Jot220jRRrzJ+E=",
"dev": true,
"dependencies": {
"esprima": "~1.0.4",
"estraverse": "~1.5.0",
"esutils": "~1.0.0"
},
"bin": {
"escodegen": "bin/escodegen.js",
"esgenerate": "bin/esgenerate.js"
},
"engines": {
"node": ">=0.4.0"
},
"optionalDependencies": {
"source-map": "~0.1.30"
}
},
"node_modules/ast-transform/node_modules/esprima": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz",
"integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=",
"dev": true,
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ast-transform/node_modules/estraverse": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz",
"integrity": "sha1-hno+jlip+EYYr7bC3bzZFrfLr3E=",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ast-transform/node_modules/esutils": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz",
"integrity": "sha1-gVHTWOIMisx/t0XnRywAJf5JZXA=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/ast-transform/node_modules/source-map": {
"version": "0.1.43",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
"integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
"dev": true,
"optional": true,
"dependencies": {
"amdefine": ">=0.0.4"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/ast-types": {
"version": "0.7.8",
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.7.8.tgz",
"integrity": "sha1-kC0uDWDQcb3NRtwRXhgJ7RHBOKk=",
"dev": true,
"engines": {
"node": ">= 0.6"
}
},
"node_modules/async": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
@@ -3640,30 +3530,6 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
"dev": true,
"dependencies": {
"core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0"
}
},
"node_modules/babel-runtime/node_modules/core-js": {
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
"deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
"dev": true,
"hasInstallScript": true
},
"node_modules/babel-runtime/node_modules/regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
"dev": true
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -4097,25 +3963,10 @@
"node": ">=8"
}
},
"node_modules/brfs": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brfs/-/brfs-2.0.2.tgz",
"integrity": "sha512-IrFjVtwu4eTJZyu8w/V2gxU7iLTtcHih67sgEdzrhjLBMHp2uYefUBfdM4k2UvcuWMgV7PQDZHSLeNWnLFKWVQ==",
"dev": true,
"dependencies": {
"quote-stream": "^1.0.1",
"resolve": "^1.1.5",
"static-module": "^3.0.2",
"through2": "^2.0.0"
},
"bin": {
"brfs": "bin/cmd.js"
}
},
"node_modules/brotli": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.2.tgz",
"integrity": "sha1-UlqcrU/LqWR119OI9q7LE+7VL0Y=",
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz",
"integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==",
"dev": true,
"dependencies": {
"base64-js": "^1.1.2"
@@ -4133,32 +3984,6 @@
"node": ">= 10.16.0"
}
},
"node_modules/browser-resolve": {
"version": "1.11.3",
"resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz",
"integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==",
"dev": true,
"dependencies": {
"resolve": "1.1.7"
}
},
"node_modules/browser-resolve/node_modules/resolve": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
"integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
"dev": true
},
"node_modules/browserify-optional": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/browserify-optional/-/browserify-optional-1.0.1.tgz",
"integrity": "sha1-HhNyLP3g2F8SFnbCpyztUzoBiGk=",
"dev": true,
"dependencies": {
"ast-transform": "0.0.0",
"ast-types": "^0.7.0",
"browser-resolve": "^1.8.1"
}
},
"node_modules/browserslist": {
"version": "4.21.7",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz",
@@ -4240,15 +4065,6 @@
"node": "*"
}
},
"node_modules/buffer-equal": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz",
"integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/buffer-fill": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
@@ -4642,9 +4458,9 @@
}
},
"node_modules/clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
"dev": true,
"engines": {
"node": ">=0.8"
@@ -4754,21 +4570,6 @@
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"node_modules/concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"dev": true,
"engines": [
"node >= 0.8"
],
"dependencies": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"node_modules/config-chain": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
@@ -5072,22 +4873,6 @@
"integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=",
"dev": true
},
"node_modules/d": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
"integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
"dev": true,
"dependencies": {
"es5-ext": "^0.10.50",
"type": "^1.0.1"
}
},
"node_modules/dash-ast": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-2.0.1.tgz",
"integrity": "sha512-5TXltWJGc+RdnabUGzhRae1TRq6m4gr+3K2wQX0is5/F2yS6MJXJvLyI3ErAnsAXuJoGqvfVD5icRgim07DrxQ==",
"dev": true
},
"node_modules/dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -5337,23 +5122,6 @@
"node": ">=0.10.0"
}
},
"node_modules/deep-equal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
"integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
"dev": true,
"dependencies": {
"is-arguments": "^1.0.4",
"is-date-object": "^1.0.1",
"is-regex": "^1.0.4",
"object-is": "^1.0.1",
"object-keys": "^1.1.1",
"regexp.prototype.flags": "^1.2.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -5748,15 +5516,6 @@
"integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
"dev": true
},
"node_modules/duplexer2": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
"integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
"dev": true,
"dependencies": {
"readable-stream": "^2.0.2"
}
},
"node_modules/duplexer3": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz",
@@ -6000,81 +5759,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/es5-ext": {
"version": "0.10.53",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz",
"integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==",
"dev": true,
"dependencies": {
"es6-iterator": "~2.0.3",
"es6-symbol": "~3.1.3",
"next-tick": "~1.0.0"
}
},
"node_modules/es6-error": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
"dev": true
},
"node_modules/es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
"dev": true,
"dependencies": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"node_modules/es6-map": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz",
"integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
"dev": true,
"dependencies": {
"d": "1",
"es5-ext": "~0.10.14",
"es6-iterator": "~2.0.1",
"es6-set": "~0.1.5",
"es6-symbol": "~3.1.1",
"event-emitter": "~0.3.5"
}
},
"node_modules/es6-set": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
"integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
"dev": true,
"dependencies": {
"d": "1",
"es5-ext": "~0.10.14",
"es6-iterator": "~2.0.1",
"es6-symbol": "3.1.1",
"event-emitter": "~0.3.5"
}
},
"node_modules/es6-set/node_modules/es6-symbol": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
"integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
"dev": true,
"dependencies": {
"d": "1",
"es5-ext": "~0.10.14"
}
},
"node_modules/es6-symbol": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
"integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
"dev": true,
"dependencies": {
"d": "^1.0.1",
"ext": "^1.1.2"
}
},
"node_modules/escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
@@ -6726,12 +6416,6 @@
"node": ">=4.0"
}
},
"node_modules/estree-is-function": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/estree-is-function/-/estree-is-function-1.0.0.tgz",
"integrity": "sha512-nSCWn1jkSq2QAtkaVLJZY2ezwcFO161HVc174zL1KPW3RJ+O6C3eJb8Nx7OXzvhoEv+nLgSR1g71oWUHUDTrJA==",
"dev": true
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
@@ -6747,16 +6431,6 @@
"node": ">=0.10.0"
}
},
"node_modules/event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
"integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
"dev": true,
"dependencies": {
"d": "1",
"es5-ext": "~0.10.14"
}
},
"node_modules/eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
@@ -6862,15 +6536,6 @@
"node": ">=0.10.0"
}
},
"node_modules/ext": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz",
"integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==",
"dev": true,
"dependencies": {
"type": "^2.5.0"
}
},
"node_modules/ext-list": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz",
@@ -6896,12 +6561,6 @@
"node": ">=4"
}
},
"node_modules/ext/node_modules/type": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz",
"integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==",
"dev": true
},
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -7154,22 +6813,20 @@
}
},
"node_modules/fontkit": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/fontkit/-/fontkit-1.8.1.tgz",
"integrity": "sha512-BsNCjDoYRxmNWFdAuK1y9bQt+igIxGtTC9u/jSFjR9MKhmI00rP1fwSvERt+5ddE82544l0XH5mzXozQVUy2Tw==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.2.tgz",
"integrity": "sha512-jc4k5Yr8iov8QfS6u8w2CnHWVmbOGtdBtOXMze5Y+QD966Rx6PEVWXSEGwXlsDlKtu1G12cJjcsybnqhSk/+LA==",
"dev": true,
"dependencies": {
"babel-runtime": "^6.26.0",
"brfs": "^2.0.0",
"brotli": "^1.2.0",
"browserify-optional": "^1.0.1",
"clone": "^1.0.4",
"deep-equal": "^1.0.0",
"@swc/helpers": "^0.4.2",
"brotli": "^1.3.2",
"clone": "^2.1.2",
"dfa": "^1.2.0",
"restructure": "^0.5.3",
"tiny-inflate": "^1.0.2",
"unicode-properties": "^1.2.2",
"unicode-trie": "^0.3.0"
"fast-deep-equal": "^3.1.3",
"restructure": "^3.0.0",
"tiny-inflate": "^1.0.3",
"unicode-properties": "^1.4.0",
"unicode-trie": "^2.0.0"
}
},
"node_modules/for-each": {
@@ -7325,6 +6982,7 @@
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
"dev": true,
"peer": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -7357,12 +7015,6 @@
"node": ">=6.9.0"
}
},
"node_modules/get-assigned-identifiers": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz",
"integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==",
"dev": true
},
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -7743,6 +7395,7 @@
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
"dev": true,
"peer": true,
"dependencies": {
"has-symbols": "^1.0.2"
},
@@ -8230,22 +7883,6 @@
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==",
"dev": true
},
"node_modules/is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-array-buffer": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
@@ -8354,6 +7991,7 @@
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
"dev": true,
"peer": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
@@ -8506,6 +8144,7 @@
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
"dev": true,
"peer": true,
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
@@ -9164,6 +8803,16 @@
"lcov-parse": "bin/cli.js"
}
},
"node_modules/legacy-swc-helpers": {
"name": "@swc/helpers",
"version": "0.4.14",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz",
"integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==",
"dev": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -9655,15 +9304,6 @@
"node": ">= 0.6"
}
},
"node_modules/merge-source-map": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz",
"integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=",
"dev": true,
"dependencies": {
"source-map": "^0.5.6"
}
},
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
@@ -9968,12 +9608,6 @@
"node": ">= 0.4.0"
}
},
"node_modules/next-tick": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
"dev": true
},
"node_modules/nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@@ -10396,22 +10030,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object-is": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
"integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
@@ -10747,7 +10365,7 @@
"node_modules/pako": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
"integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=",
"integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==",
"dev": true
},
"node_modules/param-case": {
@@ -11444,20 +11062,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/quote-stream": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz",
"integrity": "sha1-hJY/jJwmuULhU/7rU6rnRlK34LI=",
"dev": true,
"dependencies": {
"buffer-equal": "0.0.1",
"minimist": "^1.1.3",
"through2": "^2.0.0"
},
"bin": {
"quote-stream": "bin/cmd.js"
}
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -11660,6 +11264,7 @@
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz",
"integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==",
"dev": true,
"peer": true,
"dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.2.0",
@@ -11817,13 +11422,10 @@
"dev": true
},
"node_modules/restructure": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/restructure/-/restructure-0.5.4.tgz",
"integrity": "sha1-9U591WNZD7NP1r9Vh2EJrsyyjeg=",
"dev": true,
"dependencies": {
"browserify-optional": "^1.0.0"
}
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.0.tgz",
"integrity": "sha512-Xj8/MEIhhfj9X2rmD9iJ4Gga9EFqVlpMj3vfLnV2r/Mh5jRMryNV+6lWh9GdJtDBcBSPIqzRdfBQ3wDtNFv/uw==",
"dev": true
},
"node_modules/retry": {
"version": "0.12.0",
@@ -12035,21 +11637,6 @@
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true
},
"node_modules/scope-analyzer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/scope-analyzer/-/scope-analyzer-2.1.2.tgz",
"integrity": "sha512-5cfCmsTYV/wPaRIItNxatw02ua/MThdIUNnUOCYp+3LSEJvnG804ANw2VLaavNILIfWXF1D1G2KNANkBBvInwQ==",
"dev": true,
"dependencies": {
"array-from": "^2.1.1",
"dash-ast": "^2.0.1",
"es6-map": "^0.1.5",
"es6-set": "^0.1.5",
"es6-symbol": "^3.1.1",
"estree-is-function": "^1.0.0",
"get-assigned-identifiers": "^1.1.0"
}
},
"node_modules/secure-compare": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
@@ -12173,12 +11760,6 @@
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"dev": true
},
"node_modules/shallow-copy": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz",
"integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=",
"dev": true
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -12407,15 +11988,6 @@
"node": ">=0.10.0"
}
},
"node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.20",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz",
@@ -12435,13 +12007,6 @@
"node": ">=0.10.0"
}
},
"node_modules/sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
"deprecated": "Please use @jridgewell/sourcemap-codec instead",
"dev": true
},
"node_modules/spdx-correct": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
@@ -12517,46 +12082,6 @@
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
"node_modules/static-eval": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.0.tgz",
"integrity": "sha512-agtxZ/kWSsCkI5E4QifRwsaPs0P0JmZV6dkLz6ILYfFYQGn+5plctanRN+IC8dJRiFkyXHrwEE3W9Wmx67uDbw==",
"dev": true,
"dependencies": {
"escodegen": "^1.11.1"
}
},
"node_modules/static-module": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/static-module/-/static-module-3.0.4.tgz",
"integrity": "sha512-gb0v0rrgpBkifXCa3yZXxqVmXDVE+ETXj6YlC/jt5VzOnGXR2C15+++eXuMDUYsePnbhf+lwW0pE1UXyOLtGCw==",
"dev": true,
"dependencies": {
"acorn-node": "^1.3.0",
"concat-stream": "~1.6.0",
"convert-source-map": "^1.5.1",
"duplexer2": "~0.1.4",
"escodegen": "^1.11.1",
"has": "^1.0.1",
"magic-string": "0.25.1",
"merge-source-map": "1.0.4",
"object-inspect": "^1.6.0",
"readable-stream": "~2.3.3",
"scope-analyzer": "^2.0.1",
"shallow-copy": "~0.0.1",
"static-eval": "^2.0.5",
"through2": "~2.0.3"
}
},
"node_modules/static-module/node_modules/magic-string": {
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.1.tgz",
"integrity": "sha512-sCuTz6pYom8Rlt4ISPFn6wuFodbKMIHUMv4Qko9P17dpxb7s52KJTmRuZZqHdGmLCK9AOcDare039nRIcfdkEg==",
"dev": true,
"dependencies": {
"sourcemap-codec": "^1.4.1"
}
},
"node_modules/statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
@@ -12777,12 +12302,12 @@
}
},
"node_modules/svgdom": {
"version": "0.1.14",
"resolved": "https://registry.npmjs.org/svgdom/-/svgdom-0.1.14.tgz",
"integrity": "sha512-RsaFHupZ92NLkpuszq2t04XUI6biqh/Q+R7ntpC0FteTs6zK1lP7jHk++p2N9IBfpi5iU4J/tkKTjIzDmKdOZw==",
"version": "0.1.16",
"resolved": "https://registry.npmjs.org/svgdom/-/svgdom-0.1.16.tgz",
"integrity": "sha512-KtoW4wuJOCv9GJTnYGuuX0K60U6Ci5vavesK5AwjHzSZhcMUSKdZg5rf36V0ssmlpOd7txt4aZbCtZ1GotVePg==",
"dev": true,
"dependencies": {
"fontkit": "^1.8.1",
"fontkit": "^2.0.2",
"image-size": "^1.0.2",
"sax": "^1.2.4"
},
@@ -12966,16 +12491,6 @@
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
"dev": true
},
"node_modules/through2": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
"integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
"dev": true,
"dependencies": {
"readable-stream": "~2.3.6",
"xtend": "~4.0.1"
}
},
"node_modules/timed-out": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
@@ -13195,12 +12710,6 @@
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"dev": true
},
"node_modules/type": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
"integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
"dev": true
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -13253,12 +12762,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"node_modules/typescript": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz",
@@ -13349,25 +12852,15 @@
}
},
"node_modules/unicode-properties": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.3.1.tgz",
"integrity": "sha512-nIV3Tf3LcUEZttY/2g4ZJtGXhWwSkuLL+rCu0DIAMbjyVPj+8j5gNVz4T/sVbnQybIsd5SFGkPKg/756OY6jlA==",
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
"integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==",
"dev": true,
"dependencies": {
"base64-js": "^1.3.0",
"unicode-trie": "^2.0.0"
}
},
"node_modules/unicode-properties/node_modules/unicode-trie": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
"integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
"dev": true,
"dependencies": {
"pako": "^0.2.5",
"tiny-inflate": "^1.0.0"
}
},
"node_modules/unicode-property-aliases-ecmascript": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
@@ -13378,9 +12871,9 @@
}
},
"node_modules/unicode-trie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-0.3.1.tgz",
"integrity": "sha1-1nHd3YkQGgi6w3tqUWEBBgIFIIU=",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
"integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
"dev": true,
"dependencies": {
"pako": "^0.2.5",

+ 1
- 1
package.json View File

@@ -108,7 +108,7 @@
"prettier": "^2.8.8",
"rollup": "^3.25.1",
"rollup-plugin-filesize": "^10.0.0",
"svgdom": "^0.1.14",
"svgdom": "^0.1.16",
"typescript": "^5.1.3",
"yargs": "^17.7.2"
},

+ 23
- 0
spec/spec/modules/optional/css.js View File

@@ -34,6 +34,13 @@ describe('css.js', () => {
expect(rect.css('fill')).toBe('none')
})

it('correctly returns css vars', () => {
const rect = new Rect({
style: '--foo: red;'
})
expect(rect.css('--foo')).toBe('red')
})

it('returns undefined if css property is not set', () => {
const rect = new Rect({
style: 'fill: none; outline-width: 1px; stroke: none'
@@ -94,6 +101,22 @@ describe('css.js', () => {
})
expect(rect.css({ fill: null, stroke: 'black' }).css('fill')).toBe('')
})

it('allows single set of css vars', () => {
const rect = new Rect().css('--foo', 'red').css('--foo', 'green')
expect(rect.css()).toEqual({
'--foo': 'green'
})
})

it('allows multiple set of css vars via object', () => {
const rect = new Rect().css({ '--foo': 'red', '--bar': 'green' })

expect(rect.css()).toEqual({
'--foo': 'red',
'--bar': 'green'
})
})
})
})


+ 11
- 5
src/modules/optional/css.js View File

@@ -2,6 +2,8 @@ import { camelCase } from '../../utils/utils.js'
import { isBlank } from '../core/regex.js'
import { registerMethods } from '../../utils/methods.js'

const camelCaseWithVars = (str) => (str.startsWith('--') ? str : camelCase(str))

// Dynamic style generator
export function css(style, val) {
const ret = {}
@@ -23,31 +25,35 @@ export function css(style, val) {
// get style properties as array
if (Array.isArray(style)) {
for (const name of style) {
const cased = camelCase(name)
ret[name] = this.node.style[cased]
const cased = camelCaseWithVars(name)
ret[name] = this.node.style.getPropertyValue(cased)
}
return ret
}

// get style for property
if (typeof style === 'string') {
return this.node.style[camelCase(style)]
return this.node.style.getPropertyValue(camelCaseWithVars(style))
}

// set styles in object
if (typeof style === 'object') {
for (const name in style) {
// set empty string if null/undefined/'' was given
this.node.style[camelCase(name)] =
this.node.style.setProperty(
camelCaseWithVars(name),
style[name] == null || isBlank.test(style[name]) ? '' : style[name]
)
}
}
}

// set style for property
if (arguments.length === 2) {
this.node.style[camelCase(style)] =
this.node.style.setProperty(
camelCaseWithVars(style),
val == null || isBlank.test(val) ? '' : val
)
}

return this

+ 15
- 5
svg.js.d.ts View File

@@ -10,6 +10,11 @@ declare type CSSStyleName = Exclude<
'parentRule' | 'length'
>

// create our own style declaration that includes css vars
export interface CSSStyleDeclarationWithVars extends CSSStyleDeclaration {
[key: `--${string}`]: string
}

declare module '@svgdotjs/svg.js' {
function SVG(): Svg
/**
@@ -1160,11 +1165,16 @@ declare module '@svgdotjs/svg.js' {
toggleClass(name: string): this

// prototype method register in css.js
css(): Partial<CSSStyleDeclaration>
css<T extends CSSStyleName>(style: T): CSSStyleDeclaration[T]
css<T extends CSSStyleName[]>(style: T): Partial<CSSStyleDeclaration>
css<T extends CSSStyleName>(style: T, val: CSSStyleDeclaration[T]): this
css(style: Partial<CSSStyleDeclaration>): this
css(): Partial<CSSStyleDeclarationWithVars>
css<T extends CSSStyleName>(style: T): CSSStyleDeclarationWithVars[T]
css<T extends CSSStyleName[]>(
style: T
): Partial<CSSStyleDeclarationWithVars>
css<T extends CSSStyleName>(
style: T,
val: CSSStyleDeclarationWithVars[T]
): this
css(style: Partial<CSSStyleDeclarationWithVars>): this
show(): this
hide(): this
visible(): boolean

Loading…
Cancel
Save