From 27f2db0abcc4f7f5d46168c761e76a25eca382ae Mon Sep 17 00:00:00 2001 From: John Kenny Date: Tue, 15 Oct 2024 11:16:51 -0700 Subject: [PATCH 1/4] Add command line options. --- bin/svgo.js | 4 ++-- lib/svgo/coa.js | 13 ++++++++----- test/coa/_index.test.js | 4 +--- test/coa/option.disable.test.js | 4 +--- test/coa/option.enable.test.js | 4 +--- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/bin/svgo.js b/bin/svgo.js index a498b85..7531791 100644 --- a/bin/svgo.js +++ b/bin/svgo.js @@ -1,9 +1,9 @@ #!/usr/bin/env node import colors from 'picocolors'; -import { program } from 'commander'; import makeProgram from '../lib/svgo/coa.js'; -makeProgram(program); + +const program = makeProgram(); program.parseAsync(process.argv).catch((error) => { console.error(colors.red(error.stack)); process.exit(1); diff --git a/lib/svgo/coa.js b/lib/svgo/coa.js index 3e288b6..7e1bdbb 100644 --- a/lib/svgo/coa.js +++ b/lib/svgo/coa.js @@ -6,10 +6,8 @@ import { decodeSVGDatauri } from './tools.js'; import { loadConfig, optimize } from '../svgo-node.js'; import { builtin, builtinPresets } from '../builtin.js'; import { SvgoParserError } from '../parser.js'; +import { Command } from 'commander'; -/** - * @typedef {import('commander').Command} Command - */ /** * @typedef {{quiet?:boolean,recursive?:boolean,exclude:RegExp[]}} CommandConfig * @typedef {import('../svgo.js').Config&CommandConfig} ExtendedConfig @@ -36,9 +34,12 @@ export function checkIsDir(filePath) { } /** - * @param {Command} program + * @returns {Command} */ -export default function makeProgram(program) { +export default function makeProgram() { + class SVGOCommand extends Command {} + const program = new SVGOCommand(); + program .name(PKG.name) .description(PKG.description) @@ -112,6 +113,8 @@ export default function makeProgram(program) { 'DEPRECATED. Set number of digits in the fractional part, overrides plugins params', ) .action(action); + + return program; } /** diff --git a/test/coa/_index.test.js b/test/coa/_index.test.js index 20f3b9a..995658a 100644 --- a/test/coa/_index.test.js +++ b/test/coa/_index.test.js @@ -1,6 +1,5 @@ import fs from 'fs'; import path from 'path'; -import { Command } from 'commander'; import { fileURLToPath } from 'url'; import svgo, { checkIsDir } from '../../lib/svgo/coa.js'; @@ -19,8 +18,7 @@ const noop = () => {}; * @param {string[]} args */ function runProgram(args) { - const program = new Command(); - svgo(program); + const program = svgo(); // prevent running process.exit program.exitOverride(() => {}); // parser skips first two arguments diff --git a/test/coa/option.disable.test.js b/test/coa/option.disable.test.js index 632c653..8b88ad4 100644 --- a/test/coa/option.disable.test.js +++ b/test/coa/option.disable.test.js @@ -1,6 +1,5 @@ import fs from 'fs'; import path from 'path'; -import { Command } from 'commander'; import { fileURLToPath } from 'url'; import svgo from '../../lib/svgo/coa.js'; @@ -13,8 +12,7 @@ const tempFolder = 'temp' + Math.random(); * @param {string[]} args */ function runProgram(args) { - const program = new Command(); - svgo(program); + const program = svgo(); // prevent running process.exit program.exitOverride(() => {}); // parser skips first two arguments diff --git a/test/coa/option.enable.test.js b/test/coa/option.enable.test.js index 6fd0e41..f10d3d6 100644 --- a/test/coa/option.enable.test.js +++ b/test/coa/option.enable.test.js @@ -1,6 +1,5 @@ import fs from 'fs'; import path from 'path'; -import { Command } from 'commander'; import { fileURLToPath } from 'url'; import svgo from '../../lib/svgo/coa.js'; @@ -13,8 +12,7 @@ const tempFolder = 'temp' + Math.random(); * @param {string[]} args */ function runProgram(args) { - const program = new Command(); - svgo(program); + const program = svgo(); // prevent running process.exit program.exitOverride(() => {}); // parser skips first two arguments From 60abee88712b05a6b870d592c08cfd2f6540638b Mon Sep 17 00:00:00 2001 From: John Kenny Date: Tue, 15 Oct 2024 15:32:50 -0700 Subject: [PATCH 2/4] Reorder commander options. --- lib/svgo/coa.js | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/svgo/coa.js b/lib/svgo/coa.js index 7e1bdbb..d3984a4 100644 --- a/lib/svgo/coa.js +++ b/lib/svgo/coa.js @@ -6,7 +6,7 @@ import { decodeSVGDatauri } from './tools.js'; import { loadConfig, optimize } from '../svgo-node.js'; import { builtin, builtinPresets } from '../builtin.js'; import { SvgoParserError } from '../parser.js'; -import { Command } from 'commander'; +import { Command, Option } from 'commander'; /** * @typedef {{quiet?:boolean,recursive?:boolean,exclude:RegExp[]}} CommandConfig @@ -37,13 +37,11 @@ export function checkIsDir(filePath) { * @returns {Command} */ export default function makeProgram() { - class SVGOCommand extends Command {} - const program = new SVGOCommand(); + const program = new Command(); program .name(PKG.name) .description(PKG.description) - .version(PKG.version, '-v, --version') .argument('[INPUT...]', 'Alias to --input') .option('-i, --input ', 'Input files, "-" for STDIN') .option('-s, --string ', 'Input SVG data string') @@ -81,16 +79,20 @@ export default function makeProgram() { 'Maximum number of iterations over the plugins.', '10', ) - .option('--multipass', 'DEPRECATED - use --max-passes') + .addOption( + new Option('--multipass', 'DEPRECATED - use --max-passes').hideHelp(), + ) .option('--pretty', 'Add line breaks and indentation to output') .option( '--indent ', 'Number of spaces to indent if --pretty is specified', '4', ) - .option( - '--eol ', - 'Line break to use when outputting SVG. If unspecified, the platform default is used', + .addOption( + new Option( + '--eol ', + 'Line break to use when outputting SVG. If unspecified, the platform default is used', + ).choices(['lf', 'crlf']), ) .option('--final-newline', 'Ensure output ends with a line break') .option( @@ -108,10 +110,13 @@ export default function makeProgram() { .option('--show-plugins', 'Show available plugins and exit') // used by picocolors internally .option('--no-color', 'Output plain text without color') - .option( - '-p, --precision ', - 'DEPRECATED. Set number of digits in the fractional part, overrides plugins params', + .addOption( + new Option( + '-p, --precision ', + 'DEPRECATED. Set number of digits in the fractional part, overrides plugins params', + ).hideHelp(), ) + .version(PKG.version, '-v, --version') .action(action); return program; From fc4b3cae8f918703d0010135e2a74a327ac22aa1 Mon Sep 17 00:00:00 2001 From: John Kenny Date: Wed, 16 Oct 2024 08:39:29 -0700 Subject: [PATCH 3/4] Optimize plugin resolution. --- lib/svgo.d.ts | 2 + lib/svgo.js | 102 +++++++++++++++++++++++++---------------- lib/svgo/coa.js | 65 +++++++++++++------------- lib/svgo/plugins.js | 13 ++---- lib/svgo/tools-node.js | 28 +++++++++++ 5 files changed, 129 insertions(+), 81 deletions(-) create mode 100644 lib/svgo/tools-node.js diff --git a/lib/svgo.d.ts b/lib/svgo.d.ts index 8e751a6..9f17e03 100644 --- a/lib/svgo.d.ts +++ b/lib/svgo.d.ts @@ -75,6 +75,8 @@ export type Config = { preset?: 'default' | 'next' | 'none'; enable?: string[]; disable?: string[]; + // Configuration parameters for plugins. + options?: Record; /** Options for rendering optimized SVG from AST. */ js2svg?: StringifyOptions; /** Output as Data URI string. */ diff --git a/lib/svgo.js b/lib/svgo.js index 5e06469..7c43eb2 100644 --- a/lib/svgo.js +++ b/lib/svgo.js @@ -33,42 +33,56 @@ function getPlugin(name) { /** * @param {import('./svgo.js').PluginConfig} plugin + * @param {string[]} disabled + * @param {Record|undefined} options */ -const resolvePluginConfig = (plugin) => { +function resolvePluginConfig(plugin, disabled, options = {}) { + let resolvedPlugin; + let builtinPlugin; if (typeof plugin === 'string') { // resolve builtin plugin specified as string - const builtinPlugin = getPlugin(plugin); - if (builtinPlugin == null) { - throw Error(`Unknown builtin plugin "${plugin}" specified.`); - } - return { + builtinPlugin = getPlugin(plugin); + resolvedPlugin = { name: plugin, params: {}, fn: builtinPlugin.fn, }; - } - if (typeof plugin === 'object' && plugin != null) { - if (plugin.name == null) { - throw Error(`Plugin name must be specified`); - } + } else if (typeof plugin === 'object') { // use custom plugin implementation let fn = 'fn' in plugin ? plugin.fn : undefined; if (!fn) { // resolve builtin plugin implementation - const builtinPlugin = getPlugin(plugin.name); - if (builtinPlugin == null) { - throw Error(`Unknown builtin plugin "${plugin.name}" specified.`); - } + builtinPlugin = getPlugin(plugin.name); fn = builtinPlugin.fn; } - return { + resolvedPlugin = { name: plugin.name, params: plugin.params, fn, }; + } else { + throw new Error(); + } + + // Override with command line options. + if (options[resolvedPlugin.name]) { + resolvedPlugin.params = options[resolvedPlugin.name]; + } else if (builtinPlugin && builtinPlugin.isPreset && builtinPlugin.plugins) { + /** @type {Object} */ + const overrides = resolvedPlugin.params.overrides ?? {}; + for (const { name } of builtinPlugin.plugins) { + if (options[name] !== undefined) { + overrides[name] = options[name]; + } + if (disabled.includes(name)) { + overrides[name] = false; + } + } + resolvedPlugin.params = { overrides: overrides }; } - return null; -}; + + return resolvedPlugin; +} export { VERSION, builtin as builtinPlugins, _collections }; @@ -77,7 +91,7 @@ export { VERSION, builtin as builtinPlugins, _collections }; * @param {import('svgo-ll').Config} config * @returns {import('svgo-ll').Output} */ -export const optimize = (input, config) => { +export function optimize(input, config) { /** * @param {import('svgo-ll').Config} config * @returns {import('svgo-ll').PluginConfig[]} @@ -99,31 +113,51 @@ export const optimize = (input, config) => { return ['preset-default']; } - const presets = getPreset(); + const plugins = getPreset(); if (config.enable) { for (const builtinName of config.enable) { const builtin = pluginsMap.get(builtinName); if (builtin) { - presets.push(builtin); + plugins.push(builtin); } else { console.warn(`plugin "${builtinName}" not found`); } } } - return presets; + + return plugins; } if (!config) { config = {}; } - if (typeof config !== 'object') { - throw Error('Config should be an object'); + + const disabled = config.disable ?? []; + let plugins = getPlugins(config); + if (disabled.length > 0) { + plugins = plugins.filter( + (p) => typeof p === 'string' && !disabled.includes(p), + ); } + const resolvedPlugins = plugins.map((p) => + resolvePluginConfig(p, disabled, config.options), + ); + + return optimizeResolved(input, config, resolvedPlugins); +} + +/** + * @param {string} input + * @param {{path?:string,maxPasses?:number,floatPrecision?:number}&{js2svg?:import('./types.js').StringifyOptions, datauri?:import('./types.js').DataUri}} config + * @param {import('svgo-ll').CustomPlugin[]} resolvedPlugins + * @returns {import('svgo-ll').Output} + */ +function optimizeResolved(input, config, resolvedPlugins) { let prevResultSize = Number.POSITIVE_INFINITY; let output = ''; /** @type {import('./types.js').PluginInfo} */ const info = {}; - if (config.path != null) { + if (config.path) { info.path = config.path; } @@ -136,23 +170,11 @@ export const optimize = (input, config) => { const maxPasses = config.maxPasses ? Math.max(Math.min(config.maxPasses, 10), 1) : 10; - const plugins = getPlugins(config); + for (let i = 0; i < maxPasses; i += 1) { info.passNumber = i; - if (!Array.isArray(plugins)) { - throw Error('malformed config, `plugins` property must be an array.'); - } - const resolvedPlugins = plugins - .filter((plugin) => plugin != null) - .map(resolvePluginConfig); - - if (resolvedPlugins.length < plugins.length) { - console.warn( - 'Warning: plugins list includes null or undefined elements, these will be ignored.', - ); - } /** @type {import('./svgo.js').Config} */ - const globalOverrides = { disable: config.disable }; + const globalOverrides = {}; if (config.floatPrecision != null) { globalOverrides.floatPrecision = config.floatPrecision; } @@ -181,7 +203,7 @@ export const optimize = (input, config) => { data: output, ast: ast, }; -}; +} export default { VERSION, diff --git a/lib/svgo/coa.js b/lib/svgo/coa.js index d3984a4..8950ffc 100644 --- a/lib/svgo/coa.js +++ b/lib/svgo/coa.js @@ -7,6 +7,7 @@ import { loadConfig, optimize } from '../svgo-node.js'; import { builtin, builtinPresets } from '../builtin.js'; import { SvgoParserError } from '../parser.js'; import { Command, Option } from 'commander'; +import { readJSONFile } from './tools-node.js'; /** * @typedef {{quiet?:boolean,recursive?:boolean,exclude:RegExp[]}} CommandConfig @@ -50,37 +51,46 @@ export default function makeProgram() { 'Input folder, optimize and rewrite all *.svg files', ) .option( - '-o, --output ', - 'Output file or folder (by default the same as the input), "-" for STDOUT', + '-r, --recursive', + "Use with '--folder'. Optimizes *.svg files in folders recursively.", + ) + .option( + '--exclude ', + "Use with '--folder'. Exclude files matching regular expression pattern.", ) .option( '--preset ', 'Specify which set of predefined plugins to use', 'default', ) - .option( - '--config ', - 'Custom config file, only .js, .mjs, and .cjs is supported', - ) .option( '--enable ', 'Specify one or more builtin plugins to run in addition to those in the preset or config', ) + .option( + '--options ', + 'Path to a JSON file containing configuration parameters for enabled plugins', + ) .option( '--disable ', - 'Specify one or more plugins from the preset or config which should not be run ', + 'Specify one or more plugins from the preset or config which should not be run', ) .option( - '--datauri ', - 'Output as Data URI string (base64), URI encoded (enc) or unencoded (unenc)', + '--config ', + 'Custom config file, only .js, .mjs, and .cjs is supported', ) .option( '--max-passes ', 'Maximum number of iterations over the plugins.', '10', ) - .addOption( - new Option('--multipass', 'DEPRECATED - use --max-passes').hideHelp(), + .option( + '-o, --output ', + 'Output file or folder (by default the same as the input), "-" for STDOUT', + ) + .option( + '--datauri ', + 'Output as Data URI string (base64), URI encoded (enc) or unencoded (unenc)', ) .option('--pretty', 'Add line breaks and indentation to output') .option( @@ -95,28 +105,23 @@ export default function makeProgram() { ).choices(['lf', 'crlf']), ) .option('--final-newline', 'Ensure output ends with a line break') - .option( - '-r, --recursive', - "Use with '--folder'. Optimizes *.svg files in folders recursively.", - ) - .option( - '--exclude ', - "Use with '--folder'. Exclude files matching regular expression pattern.", - ) + // used by picocolors internally + .option('--no-color', 'Output plain text without color') .option( '-q, --quiet', 'Only output error messages, not regular status messages', ) .option('--show-plugins', 'Show available plugins and exit') - // used by picocolors internally - .option('--no-color', 'Output plain text without color') + .version(PKG.version, '-v, --version') + .addOption( + new Option('--multipass', 'DEPRECATED - use --max-passes').hideHelp(), + ) .addOption( new Option( '-p, --precision ', 'DEPRECATED. Set number of digits in the fractional part, overrides plugins params', ).hideHelp(), ) - .version(PKG.version, '-v, --version') .action(action); return program; @@ -125,7 +130,7 @@ export default function makeProgram() { /** * @param {string[]} args * @param {import("commander").OptionValues} opts - * @param {import('commander').Command} command + * @param {Command} command */ async function action(args, opts, command) { /** @type {string[]} */ @@ -171,13 +176,6 @@ async function action(args, opts, command) { } } - if (opts.eol != null && opts.eol !== 'lf' && opts.eol !== 'crlf') { - console.error( - "error: option '--eol' must have one of the following values: 'lf' or 'crlf'", - ); - process.exit(1); - } - // --show-plugins if (opts.showPlugins) { showAvailablePlugins(); @@ -196,7 +194,7 @@ async function action(args, opts, command) { } if ( - typeof process == 'object' && + typeof process === 'object' && process.versions && process.versions.node && PKG && @@ -216,7 +214,7 @@ async function action(args, opts, command) { // --config const loadedConfig = await loadConfig(opts.config); - if (loadedConfig != null) { + if (loadedConfig) { config = { ...loadedConfig, exclude: [] }; } @@ -271,6 +269,9 @@ async function action(args, opts, command) { if (opts.disable) { config.disable = opts.disable; } + if (opts.options && !loadedConfig) { + config.options = readJSONFile(opts.options); + } // --pretty if (opts.pretty) { diff --git a/lib/svgo/plugins.js b/lib/svgo/plugins.js index 9a7733c..4f97ad6 100644 --- a/lib/svgo/plugins.js +++ b/lib/svgo/plugins.js @@ -12,7 +12,7 @@ import { visit } from '../xast.js'; * * @param {import('../types.js').XastRoot} ast input ast * @param {import('../types.js').PluginInfo} info - * @param {({ name: string; params?: any; fn: import('../../plugins/plugins-types.js').Plugin; } | null)[]} plugins + * @param {import('../svgo.js').CustomPlugin[]} plugins * @param {Object|null} overrides * @param {import('../svgo.js').Config} globalOverrides */ @@ -31,12 +31,7 @@ export const invokePlugins = ( if (override === false) { continue; } - if ( - globalOverrides.disable && - globalOverrides.disable.includes(plugin.name) - ) { - continue; - } + const params = { ...plugin.params, ...globalOverrides, ...override }; const visitor = plugin.fn(ast, params, info); @@ -57,9 +52,9 @@ export const createPreset = ({ name, plugins, description }) => { isPreset: true, plugins: Object.freeze(plugins), fn: (ast, params, info) => { - const { floatPrecision, disable, overrides } = params; + const { floatPrecision, overrides } = params; /** @type {import('../svgo.js').Config} */ - const globalOverrides = { disable: disable }; + const globalOverrides = {}; if (floatPrecision != null) { globalOverrides.floatPrecision = floatPrecision; } diff --git a/lib/svgo/tools-node.js b/lib/svgo/tools-node.js new file mode 100644 index 0000000..78ba314 --- /dev/null +++ b/lib/svgo/tools-node.js @@ -0,0 +1,28 @@ +import { readFileSync } from 'fs'; +import { SVGOError } from './tools.js'; + +/** + * @param {string} fileName + * @returns {{}} + */ +export function readJSONFile(fileName) { + let str; + try { + str = readFileSync(fileName, 'utf-8'); + } catch (error) { + if (error instanceof Error) { + throw new SVGOError(error.message); + } + throw error; + } + try { + return JSON.parse(str); + } catch (error) { + if (error instanceof SyntaxError) { + throw new SVGOError( + `${error.message.replaceAll('\n', '')} reading file ${fileName}`, + ); + } + throw error; + } +} From 27386a716edb640e6edf7e86a7c5725889c00adf Mon Sep 17 00:00:00 2001 From: John Kenny Date: Wed, 16 Oct 2024 08:57:13 -0700 Subject: [PATCH 4/4] Add --options to regression.js. --- package.json | 2 +- test/regression.js | 6 ++++++ yarn.lock | 44 ++++++++++++++++++++++---------------------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index c2285c5..6ba19dd 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "globals": "^15.9.0", "jest": "^29.7.0", "pixelmatch": "^6.0.0", - "playwright": "^1.48.0", + "playwright": "^1.48.1", "pngjs": "^7.0.0", "prettier": "^3.3.3", "rimraf": "^6.0.1", diff --git a/test/regression.js b/test/regression.js index 0f86b4d..15ee37c 100644 --- a/test/regression.js +++ b/test/regression.js @@ -11,6 +11,7 @@ import playwright from 'playwright'; import { PNG } from 'pngjs'; import { optimize } from '../lib/svgo.js'; import { toFixed } from '../lib/svgo/tools.js'; +import { readJSONFile } from '../lib/svgo/tools-node.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -49,6 +50,7 @@ async function performTests(options) { const config = { preset: options.preset, enable: options.enable, + options: options.options ? readJSONFile(options.options) : undefined, disable: options.disable, }; @@ -257,6 +259,10 @@ program '--enable ', 'Specify one or more builtin plugins to run in addition to those in the preset or config', ) + .option( + '--options ', + 'Path to a JSON file containing configuration parameters for enabled plugins', + ) .option( '--disable ', 'Specify one or more plugins from the preset or config which should not be run ', diff --git a/yarn.lock b/yarn.lock index 7d46e63..a456dbf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1272,11 +1272,11 @@ __metadata: linkType: hard "acorn@npm:^8.12.0, acorn@npm:^8.8.2": - version: 8.12.1 - resolution: "acorn@npm:8.12.1" + version: 8.13.0 + resolution: "acorn@npm:8.13.0" bin: acorn: bin/acorn - checksum: 677880034aee5bdf7434cc2d25b641d7bedb0b5ef47868a78dadabedccf58e1c5457526d9d8249cd253f2df087e081c3fe7d903b448d8e19e5131a3065b83c07 + checksum: f1541f05eb5d6ff67990d1927290809b1ebb663ac96d9c7057c935cf29c5bcaba6d39f37bd007f4bb814f162f142b0f2b2dd4b14128b8fcfaf9f0508a6f05f1c languageName: node linkType: hard @@ -1599,9 +1599,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001663": - version: 1.0.30001668 - resolution: "caniuse-lite@npm:1.0.30001668" - checksum: ce6996901b5883454a8ddb3040f82342277b6a6275876dfefcdecb11f7e472e29877f34cae47c2b674f08f2e71971dd4a2acb9bc01adfe8421b7148a7e9e8297 + version: 1.0.30001669 + resolution: "caniuse-lite@npm:1.0.30001669" + checksum: 8ed0c69d0c6aa3b1cbc5ba4e5f5330943e7b7165e257f6955b8b73f043d07ad922265261f2b54d9bbaf02886bbdba5e6f5b16662310a13f91f17035af3212de1 languageName: node linkType: hard @@ -1940,9 +1940,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.5.28": - version: 1.5.38 - resolution: "electron-to-chromium@npm:1.5.38" - checksum: 8279317608f24f95366b679703c7e4196beb0702384fca211a5db4a53e6c960067d0f5de487883fe807b04eaba3939137a39958d6c5209b4d1e5a693efdd6f6a + version: 1.5.39 + resolution: "electron-to-chromium@npm:1.5.39" + checksum: cd3b644c20f30fc1c393168bafa0e42a3dde576129603266ab61248b76a36837084073895a845676f8fe90dbb31d385bbef53901b60381f3ae82b40a5bece352 languageName: node linkType: hard @@ -3941,27 +3941,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.48.0": - version: 1.48.0 - resolution: "playwright-core@npm:1.48.0" +"playwright-core@npm:1.48.1": + version: 1.48.1 + resolution: "playwright-core@npm:1.48.1" bin: playwright-core: cli.js - checksum: 8c6ecf1ca2484408e8a11bbb107cf4cb19621bbb85c5f4b29206df29ea13b4e6a008fb434df03e3411719c74e4f130a4ece05365fc1a2940e243725a10d04ad4 + checksum: adf5b43e054e49bcc712d70e71dedab92c362ea76a45a767bdf3d928d3c810a42f6f1c49382f3d44ed005986048001f75cb568605031215dc89a3e56d99d2976 languageName: node linkType: hard -"playwright@npm:^1.48.0": - version: 1.48.0 - resolution: "playwright@npm:1.48.0" +"playwright@npm:^1.48.1": + version: 1.48.1 + resolution: "playwright@npm:1.48.1" dependencies: fsevents: 2.3.2 - playwright-core: 1.48.0 + playwright-core: 1.48.1 dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: e19431f432b68fc08109382a0707e18d2034554f0857925d7d9b75b2277136cef2e756bd93e4228c26ece1446761641b398b0cc0e1c799db1b466a0953fda787 + checksum: 81ca13392ad5e5ca87a226d0f5ff2da958c4e06a01dd6b56b4e4e5b4fec45ef8a8f7f0563ef0f4c725814265b931984d0c841e8524362b24480bcd527aa0c054 languageName: node linkType: hard @@ -4553,7 +4553,7 @@ __metadata: jest: ^29.7.0 picocolors: ^1.1.0 pixelmatch: ^6.0.0 - playwright: ^1.48.0 + playwright: ^1.48.1 pngjs: ^7.0.0 prettier: ^3.3.3 rimraf: ^6.0.1 @@ -4592,8 +4592,8 @@ __metadata: linkType: hard "terser@npm:^5.17.4": - version: 5.34.1 - resolution: "terser@npm:5.34.1" + version: 5.35.0 + resolution: "terser@npm:5.35.0" dependencies: "@jridgewell/source-map": ^0.3.3 acorn: ^8.8.2 @@ -4601,7 +4601,7 @@ __metadata: source-map-support: ~0.5.20 bin: terser: bin/terser - checksum: 19a6710e17ff3f20d3b0661090640a572ce5ff6f2e95c731bb5a9eb1dcc1fe563cd0f1e4a22cde89b2717667336252bc2adb8894bdfbec6d1996b3e70b44f365 + checksum: 1d48ad776e690582e52b952e06376d50999809235e1fef5bc759e12f2d09b4ec5ab09895682c988e9a3115e6968319eba93bed0cbaea7c4fa08b8a015dedd5a4 languageName: node linkType: hard