From f13253486890ecbbb4fbc249d41e0b6fc3de7011 Mon Sep 17 00:00:00 2001 From: jamsonchan Date: Fri, 25 Aug 2023 12:04:22 +0800 Subject: [PATCH] ZK-4928: expose widget private functions and variables as public ones --- .browserslistrc | 2 +- ...-expose-private-functions-and-variables.js | 87 +++++++++++++++++++ babel.config.js | 1 + package-lock.json | 9 +- zkdoc/release-note | 1 + 5 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 babel-plugin-expose-private-functions-and-variables.js diff --git a/.browserslistrc b/.browserslistrc index 635fdf53ffa..f4762634ad9 100644 --- a/.browserslistrc +++ b/.browserslistrc @@ -1,2 +1,2 @@ defaults -ie >= 11 \ No newline at end of file +not dead \ No newline at end of file diff --git a/babel-plugin-expose-private-functions-and-variables.js b/babel-plugin-expose-private-functions-and-variables.js new file mode 100644 index 00000000000..f0807e3397b --- /dev/null +++ b/babel-plugin-expose-private-functions-and-variables.js @@ -0,0 +1,87 @@ +// eslint-disable-next-line no-undef +module.exports = function ({types: t}) { + + function createNestedMemberExpression(identifiers) { + if (identifiers.length === 1) { + return t.identifier(identifiers[0]); + } else { + const [head, ...tail] = identifiers; + return t.memberExpression( + createNestedMemberExpression(tail), + t.identifier(head) + ); + } + } + + return { + visitor: { + Program: { + exit(path) { + let dir = this.file.opts.filename.replace(/-/g, '_').split('/'); + const jsLoc = dir.findIndex(x => x === 'js'), + file = dir[dir.length - 1], + exports = {}; + + // pass if [not in js folder] or [not ts file] or [is global.d.ts] or [is index.ts] + if (jsLoc === -1 || !file.endsWith('ts') || file === 'global.d.ts' || file === 'index.ts') return; + + // simplify whole dir + dir = dir.slice(jsLoc + 1); + dir[dir.length - 1] = file.replace('.ts', ''); + + // sort order for follow-up + dir.unshift('window'); + dir.push('_'); + dir.reverse(); + + // visit all nodes + path.node.body.forEach((node, index) => { + if (t.isVariableDeclaration(node)) { + node.declarations.forEach((declaration) => { + if (t.isIdentifier(declaration.id)) { + exports[declaration.id.name] = declaration.id.name; + } + }); + } else if (t.isFunctionDeclaration(node) && t.isIdentifier(node.id)) { + exports[node.id.name] = node.id.name; + } + }); + + // add check-exist if statements + for (let i = dir.length - 2; i > 0; i--) { + const nestedExpression = createNestedMemberExpression(dir.slice(i)); + path.pushContainer('body', + t.ifStatement( + t.unaryExpression('!', nestedExpression), + t.expressionStatement( + t.assignmentExpression( + '=', + nestedExpression, + t.objectExpression([]) + ) + ) + ) + ); + } + + // export all global variables and functions + path.pushContainer('body', + // window.x.x.x._ = {...} + t.expressionStatement( + t.assignmentExpression( + '=', + createNestedMemberExpression(dir), + t.objectExpression( + Object.entries(exports).map(([k, v]) => { + return t.objectProperty(t.identifier(k), t.identifier(v)); + }) + ) + ) + ) + ); + + } + } + } + }; +}; \ No newline at end of file diff --git a/babel.config.js b/babel.config.js index 1cb9413d5c9..96372fcd6c5 100644 --- a/babel.config.js +++ b/babel.config.js @@ -17,6 +17,7 @@ module.exports = function (api) { ["@babel/plugin-proposal-decorators", { "legacy": true }], '@babel/plugin-proposal-class-properties', '@babel/plugin-proposal-object-rest-spread', + './babel-plugin-expose-private-functions-and-variables', ], overrides: [{ test: /[\\/]ext[\\/]//* treat as script for 3rd-party library */, diff --git a/package-lock.json b/package-lock.json index c6a4560b26d..9d48223aced 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15327,10 +15327,9 @@ } }, "node_modules/uglify-js": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.0.tgz", - "integrity": "sha512-FEikl6bR30n0T3amyBh3LoiBdqHRy/f4H80+My34HOesOKyHfOsxAPAxOoqC0JUnC1amnO0IwkYC3sko51caSw==", + "version": "3.17.4", "dev": true, + "license": "BSD-2-Clause", "bin": { "uglifyjs": "bin/uglifyjs" }, @@ -27837,9 +27836,7 @@ "dev": true }, "uglify-js": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.0.tgz", - "integrity": "sha512-FEikl6bR30n0T3amyBh3LoiBdqHRy/f4H80+My34HOesOKyHfOsxAPAxOoqC0JUnC1amnO0IwkYC3sko51caSw==", + "version": "3.17.4", "dev": true }, "unc-path-regex": { diff --git a/zkdoc/release-note b/zkdoc/release-note index a7e3cf379e6..6edd1d8ac8a 100644 --- a/zkdoc/release-note +++ b/zkdoc/release-note @@ -20,6 +20,7 @@ ZK 10.0.0 ZK-5533: Add all new HTML5 tags in ZK 10 ZHTML ZK-5049: Deprecate org.zkoss.zk.ui.uuidRecycle.disabled in ZK10 ZK-5437: Upgrade WCAG with the lighthouse 10.x detection tools + ZK-4928: expose widget private functions and variables as public ones * Bugs ZK-5089: AfterSizeEvent doesn't return a correct size of a Window component