From e87788341e9490bb080c14dfc9398e06941de89c Mon Sep 17 00:00:00 2001 From: Xiaoji Chen Date: Thu, 22 Feb 2024 20:29:40 -0800 Subject: [PATCH] feat(dev-tools): add ts-transform-remove-glsl-comments (#455) --- .eslintignore | 1 + .prettierignore | 1 + modules/dev-tools/package.json | 6 +- .../index.ts | 109 ++++++++++++++++++ modules/dev-tools/test/index.ts | 1 + .../test/ts-plugins/test-transformer.ts | 51 +++++++- .../ts-transform-append-extension.spec.ts | 4 +- .../index.spec.ts | 61 ++++++++++ .../test-case-0-expected.ts | 4 + .../test-case-0.ts | 4 + .../test-case-1-expected.ts | 34 ++++++ .../test-case-1.ts | 43 +++++++ .../test-case-2-expected.ts | 19 +++ .../test-case-2.ts | 23 ++++ .../ts-transform-version-inline.spec.ts | 4 +- yarn.lock | 29 +---- 16 files changed, 362 insertions(+), 32 deletions(-) create mode 100644 modules/dev-tools/src/ts-plugins/ts-transform-remove-glsl-comments/index.ts create mode 100644 modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/index.spec.ts create mode 100644 modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-0-expected.ts create mode 100644 modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-0.ts create mode 100644 modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-1-expected.ts create mode 100644 modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-1.ts create mode 100644 modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-2-expected.ts create mode 100644 modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-2.ts diff --git a/.eslintignore b/.eslintignore index 849ddff3..7bcb2970 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,2 @@ dist/ +test-case-*.ts diff --git a/.prettierignore b/.prettierignore index 6cca00eb..23559acc 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,2 @@ **/dist*/**/*.js +test-case-*.ts \ No newline at end of file diff --git a/modules/dev-tools/package.json b/modules/dev-tools/package.json index 855b8761..c5f4838e 100644 --- a/modules/dev-tools/package.json +++ b/modules/dev-tools/package.json @@ -36,6 +36,10 @@ "./ts-transform-append-extension": { "require": "./dist/ts-plugins/ts-transform-append-extension/index.cjs", "import": "./dist/ts-plugins/ts-transform-append-extension/index.js" + }, + "./ts-transform-remove-glsl-comments": { + "require": "./dist/ts-plugins/ts-transform-remove-glsl-comments/index.cjs", + "import": "./dist/ts-plugins/ts-transform-remove-glsl-comments/index.js" } }, "types": "./dist/index.d.ts", @@ -86,6 +90,7 @@ "eslint-plugin-react-hooks": "^4.0.0", "glob": "^7.1.4", "lerna": "^3.14.1", + "minimatch": "^3.0.0", "prettier": "3.0.3", "prettier-check": "2.0.0", "tape": "^4.11.0", @@ -94,7 +99,6 @@ "ts-node": "~10.9.0", "ts-patch": "^3.1.2", "tsconfig-paths": "^4.1.1", - "url": "^0.11.0", "vite": "^4.0.1", "vite-plugin-html": "^3.2.0" }, diff --git a/modules/dev-tools/src/ts-plugins/ts-transform-remove-glsl-comments/index.ts b/modules/dev-tools/src/ts-plugins/ts-transform-remove-glsl-comments/index.ts new file mode 100644 index 00000000..35fcd346 --- /dev/null +++ b/modules/dev-tools/src/ts-plugins/ts-transform-remove-glsl-comments/index.ts @@ -0,0 +1,109 @@ +/** + * TypeScript transform to remove comments and unnecessary white space from GLSL source. + * A template string is considered GLSL source if: + a) the file matches the pattern specified in the plugin config; or + b) it is tagged as glsl`...` + * Usage with ts-patch: + { + "plugins": [ + { + "transform": "ocular-dev-tools/ts-transform-remove-glsl-comments", + "pattern": ["*.glsl.ts"] + } + ] + } + */ +import * as path from 'path'; +import type {Program, TransformationContext, SourceFile, Node} from 'typescript'; +import type {TransformerExtras, PluginConfig} from 'ts-patch'; +import minimatch from 'minimatch'; + +// inline comment is only safe to remove if it's followed by a return (i.e. end of comment) +const INLINE_COMMENT_REGEX = /\s*\/\/.*[\n\r]/g; +const BLOCK_COMMENT_REGEX = /\s*\/\*(\*(?!\/)|[^*])*\*\//g; +const WHITESPACE_REGEX = /\s*[\n\r]\s*/gm; +const DEFAULT_PATTERNS = []; + +type RemoveGLSLCommentsPluginConfig = PluginConfig & { + /** Glob patterns of shader files to include. */ + pattern?: string[]; +}; + +export default function ( + program: Program, + pluginConfig: RemoveGLSLCommentsPluginConfig, + {ts}: TransformerExtras +) { + const {pattern = DEFAULT_PATTERNS} = pluginConfig; + + return (ctx: TransformationContext) => { + const {factory} = ctx; + + return (sourceFile: SourceFile) => { + const isShaderFile = matchFilePath(sourceFile.fileName, pattern); + + function replaceShaderString(node: Node): Node { + if (ts.isNoSubstitutionTemplateLiteral(node)) { + const text = node.rawText ?? ''; + // Convert source text to string content + const newText = filterShaderSource(text); + if (newText === text) { + return node; + } + return factory.createNoSubstitutionTemplateLiteral(newText, newText); + } + if (ts.isTemplateLiteralToken(node)) { + const text = node.rawText ?? ''; + const newText = filterShaderSource(text); + if (newText === text) { + return node; + } + if (ts.isTemplateHead(node)) { + return factory.createTemplateHead(newText, newText); + } + if (ts.isTemplateMiddle(node)) { + return factory.createTemplateMiddle(newText, newText); + } + if (ts.isTemplateTail(node)) { + return factory.createTemplateTail(newText, newText); + } + return node; + } + return ts.visitEachChild(node, replaceShaderString, ctx); + } + + function visit(node: Node): Node { + if ( + ts.isTaggedTemplateExpression(node) && + // First child is the tag identifier + node.getChildAt(0).getText() === 'glsl' + ) { + // Strip the template tag + return replaceShaderString(node.getChildAt(1)); + } + if (isShaderFile && ts.isTemplateLiteral(node)) { + return replaceShaderString(node); + } + return ts.visitEachChild(node, visit, ctx); + } + return ts.visitNode(sourceFile, visit); + }; + }; +} + +function matchFilePath(filePath: string, includePatterns: string[]): boolean { + const relPath = path.relative(process.env.PWD ?? '', filePath); + for (const pattern of includePatterns) { + if (minimatch(relPath, pattern)) { + return true; + } + } + return false; +} + +function filterShaderSource(source: string): string { + return source + .replace(INLINE_COMMENT_REGEX, '\n') + .replace(BLOCK_COMMENT_REGEX, '') + .replace(WHITESPACE_REGEX, '\n'); +} diff --git a/modules/dev-tools/test/index.ts b/modules/dev-tools/test/index.ts index 93f4a61e..40fb339d 100644 --- a/modules/dev-tools/test/index.ts +++ b/modules/dev-tools/test/index.ts @@ -3,3 +3,4 @@ import './lib/configuration.spec'; import './ts-plugins/ts-transform-version-inline.spec'; import './ts-plugins/ts-transform-append-extension.spec'; +import './ts-plugins/ts-transform-remove-glsl-comments/index.spec'; diff --git a/modules/dev-tools/test/ts-plugins/test-transformer.ts b/modules/dev-tools/test/ts-plugins/test-transformer.ts index 31b78b6c..747626fa 100644 --- a/modules/dev-tools/test/ts-plugins/test-transformer.ts +++ b/modules/dev-tools/test/ts-plugins/test-transformer.ts @@ -5,11 +5,13 @@ import type {PluginConfig} from 'ts-patch'; * Transpile ts code with TypeScript compiler API */ export function transpile({ + sourceFileName = 'test.ts', source, transformer, config = {}, outputType = 'js' }: { + sourceFileName?: string; source: string; transformer: Function; config?: PluginConfig; @@ -25,7 +27,7 @@ export function transpile({ } }); - project.createSourceFile('test.ts', source); + project.createSourceFile(sourceFileName, source); const customTransformers: ts.CustomTransformers = {}; const transform: ts.TransformerFactory = transformer( @@ -49,3 +51,50 @@ export function transpile({ return result.getFiles()[0].text; } + +/** + * Compare two pieces of source code. Returns a description of the difference, or null if identical. + */ +export function assertSourceEqual( + actual: string, + expected: string, + options: { + /** If true, ignore difference in indent + * @default true + */ + ignoreIndent?: boolean; + /** If true, ignore empty lines + * @default true + */ + ignoreEmptyLines?: boolean; + } = {} +): true | Error { + const {ignoreIndent = true, ignoreEmptyLines = true} = options; + const actualLines = actual.split('\n'); + const expectedLines = expected.split('\n'); + let i1 = 0; + let i2 = 0; + + while (i1 < actualLines.length || i2 < expectedLines.length) { + let t1 = actualLines[i1] ?? ''; + let t2 = expectedLines[i2] ?? ''; + if (ignoreIndent) { + t1 = t1.trimStart(); + t2 = t2.trimStart(); + } + if (t1 === t2) { + i1++; + i2++; + } else if (ignoreEmptyLines && !t1) { + i1++; + } else if (ignoreEmptyLines && !t2) { + i2++; + } else { + return new Error(`Mismatch at line ${i1} + Actual: ${t1} + Expected: ${t2} + `); + } + } + return true; +} diff --git a/modules/dev-tools/test/ts-plugins/ts-transform-append-extension.spec.ts b/modules/dev-tools/test/ts-plugins/ts-transform-append-extension.spec.ts index c06d77f2..c5e16ddd 100644 --- a/modules/dev-tools/test/ts-plugins/ts-transform-append-extension.spec.ts +++ b/modules/dev-tools/test/ts-plugins/ts-transform-append-extension.spec.ts @@ -1,5 +1,5 @@ import test from 'tape-promise/tape'; -import {transpile} from './test-transformer.js'; +import {transpile, assertSourceEqual} from './test-transformer.js'; // @ts-expect-error Aliased import, remapped to valid path in esm-loader import appendExtension from 'ocular-dev-tools/ts-plugins/ts-transform-append-extension'; @@ -50,7 +50,7 @@ test('ts-transform-append-extension', (t) => { outputType: testCase.config.afterDeclarations ? 'd.ts' : 'js' }); - t.is(result.trim(), testCase.output, testCase.title); + t.is(assertSourceEqual(result, testCase.output), true, testCase.title); } t.end(); diff --git a/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/index.spec.ts b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/index.spec.ts new file mode 100644 index 00000000..b0b167e5 --- /dev/null +++ b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/index.spec.ts @@ -0,0 +1,61 @@ +import fs from 'fs'; +import path from 'path'; +import {fileURLToPath} from 'node:url'; + +import test from 'tape-promise/tape'; +import {transpile, assertSourceEqual} from '../test-transformer.js'; +// @ts-expect-error Aliased import, remapped to valid path in esm-loader +import removeGLSLComments from 'ocular-dev-tools/ts-plugins/ts-transform-remove-glsl-comments'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +function loadSourceFromFile(fileName: string): string { + return fs.readFileSync(path.join(__dirname, fileName), 'utf8'); +} + +const testCases = [ + { + title: 'no comments', + fileName: 'test.glsl.ts', + config: {pattern: ['**/*.glsl.ts']}, + input: 'test-case-0.ts', + output: 'test-case-0-expected.ts' + }, + { + title: 'remove comments from template literal', + fileName: 'test.glsl.ts', + config: {pattern: ['**/*.glsl.ts']}, + input: 'test-case-1.ts', + output: 'test-case-1-expected.ts' + }, + { + title: 'excluded by file name', + fileName: 'test.ts', + config: {}, + input: 'test-case-1.ts', + output: 'test-case-1.ts' + }, + { + title: 'included by template tag', + fileName: 'test.ts', + config: {}, + input: 'test-case-2.ts', + output: 'test-case-2-expected.ts' + } +]; + +test('ts-transform-remove-glsl-comments', (t) => { + for (const testCase of testCases) { + const result = transpile({ + sourceFileName: testCase.fileName, + source: loadSourceFromFile(testCase.input), + transformer: removeGLSLComments, + config: testCase.config + }); + const expected = loadSourceFromFile(testCase.output); + + t.is(assertSourceEqual(result, expected, {ignoreEmptyLines: false}), true, testCase.title); + } + + t.end(); +}); diff --git a/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-0-expected.ts b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-0-expected.ts new file mode 100644 index 00000000..c011b2af --- /dev/null +++ b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-0-expected.ts @@ -0,0 +1,4 @@ +export function getTime() { + // Template literal that is not shader + return `The time is ${Date.now()}`; +} diff --git a/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-0.ts b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-0.ts new file mode 100644 index 00000000..c011b2af --- /dev/null +++ b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-0.ts @@ -0,0 +1,4 @@ +export function getTime() { + // Template literal that is not shader + return `The time is ${Date.now()}`; +} diff --git a/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-1-expected.ts b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-1-expected.ts new file mode 100644 index 00000000..c1dcd27c --- /dev/null +++ b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-1-expected.ts @@ -0,0 +1,34 @@ +// Constants +const COORDINATE_SYSTEM = { + CARTESIAN: 0, + LNGLAT: 1 +}; +const constantDefinitions = Object.keys(COORDINATE_SYSTEM) + .map((key) => `const int COORDINATE_SYSTEM_${key} = ${COORDINATE_SYSTEM[key]};`) + .join('\n'); +// Vertex shader +export const vs = `\ +#version 300 es +${constantDefinitions} +in vec4 position; +in vec4 color; +uniform mat4 pMatrix; +uniform mat4 mMatrix; +uniform float opacity; +out vec4 vColor; +main() { + gl_Position = pMatrix * mMatrix * position; + vColor = vec4(color, color.a * opacity); +} +`; +// Fragment shader +export const fs = `\ +#version 300 es +in vec4 vColor; +main() { + if (vColor.a == 0.0) { + discard; + } + gl_FragColor = vColor; +} +`; diff --git a/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-1.ts b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-1.ts new file mode 100644 index 00000000..4c431fce --- /dev/null +++ b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-1.ts @@ -0,0 +1,43 @@ +// Constants +const COORDINATE_SYSTEM = { + CARTESIAN: 0, + LNGLAT: 1 +}; +const constantDefinitions = Object.keys(COORDINATE_SYSTEM) + .map((key) => `const int COORDINATE_SYSTEM_${key} = ${COORDINATE_SYSTEM[key]};`) + .join('\n'); +// Vertex shader +export const vs = `\ +#version 300 es +${constantDefinitions} + +in vec4 position; +in vec4 color; + +uniform mat4 pMatrix; // Projection matrix +uniform mat4 mMatrix; // Model matrix +uniform float opacity; + +out vec4 vColor; + +main() { + gl_Position = pMatrix * mMatrix * position; + vColor = vec4(color, /* inline comment */ color.a * opacity); +} +`; +// Fragment shader +export const fs = `\ +#version 300 es + +in vec4 vColor; + +main() { + if (vColor.a == 0.0) { + /* + Remove transparent fragment + */ + discard; + } + gl_FragColor = vColor; +} +`; diff --git a/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-2-expected.ts b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-2-expected.ts new file mode 100644 index 00000000..e8f3667b --- /dev/null +++ b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-2-expected.ts @@ -0,0 +1,19 @@ +const glsl = (x) => `${x}`; +export default { + name: 'shader-module', + getUniforms: () => ({ + useFloatColors: false + }), + inject: { + 'vs:DECKGL_FILTER_COLOR': ` + picking_setPickingColor(geometry.pickingColor); + `, + 'fs:DECKGL_FILTER_COLOR': { + order: 99, + injection: ` + color = picking_filterHighlightColor(color); + color = picking_filterPickingColor(color); + ` + } + } +}; diff --git a/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-2.ts b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-2.ts new file mode 100644 index 00000000..4f65c0dd --- /dev/null +++ b/modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-2.ts @@ -0,0 +1,23 @@ +const glsl = (x: TemplateStringsArray) => `${x}`; +export default { + name: 'shader-module', + getUniforms: () => ({ + useFloatColors: false + }), + inject: { + 'vs:DECKGL_FILTER_COLOR': glsl` + // pickingColor is expected to be populated by this point + picking_setPickingColor(geometry.pickingColor); + `, + 'fs:DECKGL_FILTER_COLOR': { + order: 99, + injection: glsl` + // use highlight color if this fragment belongs to the selected object. + color = picking_filterHighlightColor(color); + + // use picking color if rendering to picking FBO. + color = picking_filterPickingColor(color); + ` + } + } +}; diff --git a/modules/dev-tools/test/ts-plugins/ts-transform-version-inline.spec.ts b/modules/dev-tools/test/ts-plugins/ts-transform-version-inline.spec.ts index f69d4ddb..c96a5946 100644 --- a/modules/dev-tools/test/ts-plugins/ts-transform-version-inline.spec.ts +++ b/modules/dev-tools/test/ts-plugins/ts-transform-version-inline.spec.ts @@ -1,5 +1,5 @@ import test from 'tape-promise/tape'; -import {transpile} from './test-transformer.js'; +import {transpile, assertSourceEqual} from './test-transformer.js'; // @ts-expect-error Aliased import, remapped to valid path in esm-loader import versionInline from 'ocular-dev-tools/ts-plugins/ts-transform-version-inline'; @@ -32,7 +32,7 @@ test('ts-transform-version-inline', (t) => { config: testCase.config }); - t.is(result.trim(), testCase.output, testCase.title); + t.is(assertSourceEqual(result, testCase.output), true, testCase.title); } t.end(); diff --git a/yarn.lock b/yarn.lock index c2e4cef9..3410b3e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -44,7 +44,7 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.2.tgz#6a12ced93455827037bfb5ed8492820d60fc32cc" integrity sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ== -"@babel/core@^7.14.5", "@babel/core@^7.7.5": +"@babel/core@^7.14.5": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.2.tgz#ed10df0d580fff67c5f3ee70fd22e2e4c90a9f94" integrity sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ== @@ -6097,16 +6097,6 @@ istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-instrument@4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" - integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== - dependencies: - "@babel/core" "^7.7.5" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - istanbul-lib-report@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" @@ -6738,7 +6728,7 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.0, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -7848,11 +7838,6 @@ pumpify@^1.3.3: inherits "^2.0.3" pump "^2.0.0" -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== - punycode@^2.1.0, punycode@^2.1.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -7884,7 +7869,7 @@ q@^1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qs@^6.11.2, qs@^6.9.4: +qs@^6.9.4: version "6.11.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== @@ -9476,14 +9461,6 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== -url@^0.11.0: - version "0.11.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.3.tgz#6f495f4b935de40ce4a0a52faee8954244f3d3ad" - integrity sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw== - dependencies: - punycode "^1.4.1" - qs "^6.11.2" - urlpattern-polyfill@10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz#f0a03a97bfb03cdf33553e5e79a2aadd22cac8ec"