From 6842b47cc719fbdc22eecb6306f09fe7a8c89cc7 Mon Sep 17 00:00:00 2001 From: Sebastian Kreft Date: Thu, 4 Mar 2021 10:30:28 -0300 Subject: [PATCH] Add TS support (#1370) Added Typescript support via JSDoc comments for some files. The code has really outdated type signatures, so in order to fully type the codebase the changes need to be incremental. To check the types run: npx tsc --- .github/workflows/main.yml | 1 + lib/css-tools.js | 20 ++++++++++---------- lib/svgo/css-style-declaration.js | 26 +++++++++++++------------- lib/svgo/plugins.js | 4 ++-- lib/svgo/tools.js | 28 ++++++++++++++++------------ package-lock.json | 6 ++++++ package.json | 4 +++- tsconfig.json | 21 +++++++++++++++++++++ 8 files changed, 72 insertions(+), 38 deletions(-) create mode 100644 tsconfig.json diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8720f41b..437f4ec3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,6 +29,7 @@ jobs: ${{ runner.os }}-node-${{ env.NODE }}-${{ hashFiles('package-lock.json') }} - run: npm ci - run: npm run lint + - run: npm run typecheck test: name: Node.js ${{ matrix.node-version }} runs-on: ubuntu-latest diff --git a/lib/css-tools.js b/lib/css-tools.js index 715f696c..ba8708bc 100644 --- a/lib/css-tools.js +++ b/lib/css-tools.js @@ -8,7 +8,7 @@ var csstree = require('css-tree'), /** * Flatten a CSS AST to a selectors list. * - * @param {Object} cssAst css-tree AST to flatten + * @param {import('css-tree').CssNode} cssAst css-tree AST to flatten * @return {Array} selectors */ function flattenToSelectors(cssAst) { @@ -29,7 +29,7 @@ function flattenToSelectors(cssAst) { item: selectorItem, atrule: atrule, rule: rule, - pseudos: [], + pseudos: /** @type {{item: any; list: any[]}[]} */ ([]), }; selectorNode.children.each(function ( @@ -108,7 +108,7 @@ function filterByPseudos(selectors, usePseudos) { * Remove pseudo-elements and/or -classes from the selectors for proper matching. * * @param {Array} selectors to clean - * @return {Array} Selectors without pseudo-elements and/or -classes + * @return {void} */ function cleanPseudos(selectors) { selectors.forEach(function (selector) { @@ -124,7 +124,7 @@ function cleanPseudos(selectors) { * * @param {Array} aSpecificity Specificity of selector A * @param {Array} bSpecificity Specificity of selector B - * @return {Number} Score of selector specificity A compared to selector specificity B + * @return {number} Score of selector specificity A compared to selector specificity B */ function compareSpecificity(aSpecificity, bSpecificity) { for (var i = 0; i < 4; i += 1) { @@ -143,7 +143,7 @@ function compareSpecificity(aSpecificity, bSpecificity) { * * @param {Object} aSimpleSelectorNode Simple selector A * @param {Object} bSimpleSelectorNode Simple selector B - * @return {Number} Score of selector A compared to selector B + * @return {number} Score of selector A compared to selector B */ function compareSimpleSelectorNode(aSimpleSelectorNode, bSimpleSelectorNode) { var aSpecificity = specificity(aSimpleSelectorNode), @@ -168,7 +168,7 @@ function sortSelectors(selectors) { /** * Convert a css-tree AST style declaration to CSSStyleDeclaration property. * - * @param {Object} declaration css-tree style declaration + * @param {import('css-tree').CssNode} declaration css-tree style declaration * @return {Object} CSSStyleDeclaration property */ function csstreeToStyleDeclaration(declaration) { @@ -185,8 +185,8 @@ function csstreeToStyleDeclaration(declaration) { /** * Gets the CSS string of a style element * - * @param {Object} element style element - * @return {String|Array} CSS string or empty array if no styles are set + * @param {Object} elem style element + * @return {string|Array} CSS string or empty array if no styles are set */ function getCssStr(elem) { return elem.content[0].text || elem.content[0].cdata || []; @@ -195,8 +195,8 @@ function getCssStr(elem) { /** * Sets the CSS string of a style element * - * @param {Object} element style element - * @param {String} CSS string to be set + * @param {Object} elem style element + * @param {string} css string to be set * @return {Object} reference to field with CSS */ function setCssStr(elem, css) { diff --git a/lib/svgo/css-style-declaration.js b/lib/svgo/css-style-declaration.js index 6d07952d..3bffcf9c 100644 --- a/lib/svgo/css-style-declaration.js +++ b/lib/svgo/css-style-declaration.js @@ -139,7 +139,7 @@ CSSStyleDeclaration.prototype._loadCssText = function () { /** * Get the textual representation of the declaration block (equivalent to .cssText attribute). * - * @return {String} Textual representation of the declaration block (empty string for no properties) + * @return {string} Textual representation of the declaration block (empty string for no properties) */ CSSStyleDeclaration.prototype.getCssText = function () { var properties = this.getProperties(); @@ -183,8 +183,8 @@ CSSStyleDeclaration.prototype._getProperty = function (propertyName) { /** * Return the optional priority, "important". * - * @param {String} propertyName representing the property name to be checked. - * @return {String} priority that represents the priority (e.g. "important") if one exists. If none exists, returns the empty string. + * @param {string} propertyName representing the property name to be checked. + * @return {string} priority that represents the priority (e.g. "important") if one exists. If none exists, returns the empty string. */ CSSStyleDeclaration.prototype.getPropertyPriority = function (propertyName) { var property = this._getProperty(propertyName); @@ -194,8 +194,8 @@ CSSStyleDeclaration.prototype.getPropertyPriority = function (propertyName) { /** * Return the property value given a property name. * - * @param {String} propertyName representing the property name to be checked. - * @return {String} value containing the value of the property. If not set, returns the empty string. + * @param {string} propertyName representing the property name to be checked. + * @return {string} value containing the value of the property. If not set, returns the empty string. */ CSSStyleDeclaration.prototype.getPropertyValue = function (propertyName) { var property = this._getProperty(propertyName); @@ -205,8 +205,8 @@ CSSStyleDeclaration.prototype.getPropertyValue = function (propertyName) { /** * Return a property name. * - * @param {Number} index of the node to be fetched. The index is zero-based. - * @return {String} propertyName that is the name of the CSS property at the specified index. + * @param {number} index of the node to be fetched. The index is zero-based. + * @return {string} propertyName that is the name of the CSS property at the specified index. */ CSSStyleDeclaration.prototype.item = function (index) { if (typeof index === 'undefined') { @@ -234,8 +234,8 @@ CSSStyleDeclaration.prototype.getProperties = function () { /** * Remove a property from the CSS declaration block. * - * @param {String} propertyName representing the property name to be removed. - * @return {String} oldValue equal to the value of the CSS property before it was removed. + * @param {string} propertyName representing the property name to be removed. + * @return {string} oldValue equal to the value of the CSS property before it was removed. */ CSSStyleDeclaration.prototype.removeProperty = function (propertyName) { if (typeof propertyName === 'undefined') { @@ -255,10 +255,10 @@ CSSStyleDeclaration.prototype.removeProperty = function (propertyName) { /** * Modify an existing CSS property or creates a new CSS property in the declaration block. * - * @param {String} propertyName representing the CSS property name to be modified. - * @param {String} [value] containing the new property value. If not specified, treated as the empty string. value must not contain "!important" -- that should be set using the priority parameter. - * @param {String} [priority] allowing the "important" CSS priority to be set. If not specified, treated as the empty string. - * @return {undefined} + * @param {string} propertyName representing the CSS property name to be modified. + * @param {string} value containing the new property value. If not specified, treated as the empty string. value must not contain "!important" -- that should be set using the priority parameter. + * @param {string} priority allowing the "important" CSS priority to be set. If not specified, treated as the empty string. + * @return {{value: string, priority: string}} */ CSSStyleDeclaration.prototype.setProperty = function ( propertyName, diff --git a/lib/svgo/plugins.js b/lib/svgo/plugins.js index b4b32e06..f99e7fe9 100644 --- a/lib/svgo/plugins.js +++ b/lib/svgo/plugins.js @@ -7,7 +7,7 @@ * * @param {Object} data input data * @param {Object} info extra information - * @param {Object} plugins plugins object from config + * @param {Array} plugins plugins object from config * @return {Object} output data */ module.exports = function (data, info, plugins) { @@ -45,7 +45,7 @@ module.exports = function (data, info, plugins) { * @param {Object} data input data * @param {Object} info extra information * @param {Array} plugins plugins list to process - * @param {Boolean} [reverse] reverse pass? + * @param {boolean} [reverse] reverse pass? * @return {Object} output data */ function perItem(data, info, plugins, reverse) { diff --git a/lib/svgo/tools.js b/lib/svgo/tools.js index ec183209..f52e9c81 100644 --- a/lib/svgo/tools.js +++ b/lib/svgo/tools.js @@ -3,9 +3,9 @@ /** * Encode plain SVG data string into Data URI string. * - * @param {String} str input string - * @param {String} type Data URI type - * @return {String} output string + * @param {string} str input string + * @param {string} type Data URI type + * @return {string} output string */ exports.encodeSVGDatauri = function (str, type) { var prefix = 'data:image/svg+xml'; @@ -27,7 +27,7 @@ exports.encodeSVGDatauri = function (str, type) { * Decode SVG Data URI string into plain SVG string. * * @param {string} str input string - * @return {String} output string + * @return {string} output string */ exports.decodeSVGDatauri = function (str) { var regexp = /data:image\/svg\+xml(;charset=[^;,]*)?(;base64)?,(.*)/; @@ -51,6 +51,10 @@ exports.decodeSVGDatauri = function (str) { return str; }; +/** + * @param {any[]} a + * @param {any[]} b + */ exports.intersectArrays = function (a, b) { return a.filter(function (n) { return b.indexOf(n) > -1; @@ -65,7 +69,7 @@ exports.intersectArrays = function (a, b) { * * @param {number[]} data * @param {Object} params - * @param {string?} command path data instruction + * @param {string} [command] path data instruction * @return {string} */ exports.cleanupOutData = function (data, params, command) { @@ -90,22 +94,22 @@ exports.cleanupOutData = function (data, params, command) { // remove floating-point numbers leading zeros // 0.5 → .5 // -0.5 → -.5 - if (params.leadingZero) { - item = removeLeadingZero(item); - } + const itemStr = params.leadingZero + ? removeLeadingZero(item) + : item.toString(); // no extra space in front of negative number or // in front of a floating number if a previous number is floating too if ( params.negativeExtraSpace && delimiter != '' && - (item < 0 || (String(item).charCodeAt(0) == 46 && prev % 1 !== 0)) + (item < 0 || (itemStr.charCodeAt(0) == 46 && prev % 1 !== 0)) ) { delimiter = ''; } // save prev item value prev = item; - str += delimiter + item; + str += delimiter + itemStr; }); return str; }; @@ -119,9 +123,9 @@ exports.cleanupOutData = function (data, params, command) { * @example * -0.5 → -.5 * - * @param {Float} num input number + * @param {number} num input number * - * @return {String} output number as string + * @return {string} output number as string */ var removeLeadingZero = function (num) { var strNum = num.toString(); diff --git a/package-lock.json b/package-lock.json index cd75a172..16f97769 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2337,6 +2337,12 @@ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true }, + "typescript": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.2.tgz", + "integrity": "sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ==", + "dev": true + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", diff --git a/package.json b/package.json index ce218867..a1bf522d 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "scripts": { "test": "c8 --reporter=html --reporter=text mocha \"test/*/_index.js\" \"**/*.test.js\" --ignore=\"node_modules/**\"", "lint": "eslint .", + "typecheck": "tsc", "test-browser": "rollup -c && node ./test/browser.js", "prepublishOnly": "rm -rf dist && rollup -c" }, @@ -113,7 +114,8 @@ "mock-stdin": "^1.0.0", "playwright": "^1.8.1", "prettier": "^2.2.1", - "rollup": "^2.39.0" + "rollup": "^2.39.0", + "typescript": "^4.2.2" }, "engines": { "node": ">=10.13.0" diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..72e9c13c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "noEmit": true, + "module": "commonjs", + "target": "es2018", + "lib": ["es2018"], + "allowJs": true, + "checkJs": true, + "strict": true, + "resolveJsonModule": true, + "noImplicitAny": false + }, + "include": [ + "lib/css-tools.js", + "lib/svgo/css-class-list.js", + "lib/svgo/css-select-adapter.js", + "lib/svgo/css-style-declaration.js", + "lib/svgo/plugins.js", + "lib/svgo/tools.js" + ] +}