From 6f94b7a5c0646c13e23e61b16f5ef70c612f415a Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Wed, 3 Sep 2025 19:57:31 +0100 Subject: [PATCH 01/20] wip --- recipes/axios-to-whatwg-fetch/README.md | 41 +++++ recipes/axios-to-whatwg-fetch/codemod.yaml | 21 +++ recipes/axios-to-whatwg-fetch/package.json | 23 +++ recipes/axios-to-whatwg-fetch/src/workflow.ts | 142 ++++++++++++++++++ .../tests/expected/debug.js | 2 + .../tests/expected/error.js | 2 + .../tests/expected/esm-import.mjs | 2 + .../tests/expected/esm-namespace-import.mjs | 2 + .../tests/expected/multiple-arguments.js | 2 + .../tests/expected/multiple-imports.cjs | 5 + .../tests/expected/named-import-print-only.js | 3 + .../tests/expected/print.js | 2 + .../tests/expected/puts.js | 2 + .../tests/expected/real-scenario.js | 16 ++ .../tests/expected/simple-scenario.js | 2 + .../tests/expected/with-interpolation.js | 3 + .../tests/input/debug.js | 3 + .../tests/input/error.js | 3 + .../tests/input/esm-import.mjs | 3 + .../tests/input/esm-namespace-import.mjs | 3 + .../tests/input/multiple-arguments.js | 3 + .../tests/input/multiple-imports.cjs | 5 + .../tests/input/named-import-print-only.js | 4 + .../tests/input/print.js | 3 + .../axios-to-whatwg-fetch/tests/input/puts.js | 3 + .../tests/input/real-scenario.js | 17 +++ .../tests/input/simple-scenario.js | 3 + .../tests/input/with-interpolation.js | 4 + recipes/axios-to-whatwg-fetch/workflow.yaml | 25 +++ 29 files changed, 349 insertions(+) create mode 100644 recipes/axios-to-whatwg-fetch/README.md create mode 100644 recipes/axios-to-whatwg-fetch/codemod.yaml create mode 100644 recipes/axios-to-whatwg-fetch/package.json create mode 100644 recipes/axios-to-whatwg-fetch/src/workflow.ts create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/debug.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/error.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/esm-import.mjs create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/esm-namespace-import.mjs create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/multiple-arguments.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/multiple-imports.cjs create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/named-import-print-only.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/print.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/puts.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/real-scenario.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/simple-scenario.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/with-interpolation.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/debug.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/error.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/esm-import.mjs create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/esm-namespace-import.mjs create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/multiple-arguments.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/multiple-imports.cjs create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/named-import-print-only.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/print.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/puts.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/real-scenario.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/simple-scenario.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/with-interpolation.js create mode 100644 recipes/axios-to-whatwg-fetch/workflow.yaml diff --git a/recipes/axios-to-whatwg-fetch/README.md b/recipes/axios-to-whatwg-fetch/README.md new file mode 100644 index 00000000..555d30ba --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/README.md @@ -0,0 +1,41 @@ +# `util.print, util.puts, util.debug, util.error` DEP0026,DEP0027,DEP0028,DEP0029 + +This recipe transforms the usage of log functions from util, `print`, `puts`, `debug`, `error` to use `console.log()` or `console.error()`. + +## Example + +**Before:** + +```js +const util = require("node:util"); + +util.print("Hello world"); +util.puts("Hello world"); +util.debug("Hello world"); +util.error("Hello world"); +``` + +**After:** + +```js +console.log("Hello world"); +console.log("Hello world"); +console.error("Hello world"); +console.error("Hello world"); +``` + +**Before:** + +```js +const { print, error } = require("node:util"); + +print("Application started"); +error("Processing request"); +``` + +After: + +```js +console.log("Application started"); +console.error("Processing request"); +``` diff --git a/recipes/axios-to-whatwg-fetch/codemod.yaml b/recipes/axios-to-whatwg-fetch/codemod.yaml new file mode 100644 index 00000000..afb48c9a --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/codemod.yaml @@ -0,0 +1,21 @@ +schema_version: "1.0" +name: "@nodejs/util-print-to-console-log" +version: 1.0.0 +description: Replace `axios` with `fetch` +author: Bruno Rodrigues +license: MIT +workflow: workflow.yaml +category: migration + +targets: + languages: + - javascript + - typescript + +keywords: + - transformation + - migration + +registry: + access: public + visibility: public diff --git a/recipes/axios-to-whatwg-fetch/package.json b/recipes/axios-to-whatwg-fetch/package.json new file mode 100644 index 00000000..9bf22caf --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/package.json @@ -0,0 +1,23 @@ +{ + "name": "@nodejs/axios-to-whatwg-fetch", + "version": "1.0.0", + "description": "Replace `axios` with `fetch`", + "scripts": { + "test": "npx codemod jssg test -l typescript ./src/workflow.ts ./" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/nodejs/userland-migrations.git", + "directory": "recipes/axios-to-whatwg-fetch", + "bugs": "https://github.com/nodejs/userland-migrations/issues" + }, + "author": "Bruno Rodrigues", + "license": "MIT", + "homepage": "https://github.com/nodejs/userland-migrations/blob/main/recipes/axios-to-whatwg-fetch/README.md", + "devDependencies": { + "@codemod.com/jssg-types": "^1.0.3" + }, + "dependencies": { + "@nodejs/codemod-utils": "*" + } +} diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts new file mode 100644 index 00000000..eb962fcd --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -0,0 +1,142 @@ +import type { + Edit, + Kinds, + Range, + Rule, + SgNode, + SgRoot, + TypesMap, +} from "@codemod.com/jssg-types/main"; +import { getNodeRequireCalls } from "@nodejs/codemod-utils/ast-grep/require-call"; +import { getNodeImportStatements } from "@nodejs/codemod-utils/ast-grep/import-statement"; +import { resolveBindingPath } from "@nodejs/codemod-utils/ast-grep/resolve-binding-path"; +import { removeBinding } from "@nodejs/codemod-utils/ast-grep/remove-binding"; +import { removeLines } from "@nodejs/codemod-utils/ast-grep/remove-lines"; + +type BindingToReplace = { + rule: Rule; + node: SgNode>; + binding: string; + replaceFn: (arg: string) => string; +}; + +const updates = [ + { + oldBind: "$.request", + replaceFn: (arg: string) => `console.log(${arg})`, + }, + { + oldBind: "$.get", + replaceFn: (arg: string) => `console.log(${arg})`, + }, + { + oldBind: "$.post", + replaceFn: (arg: string) => `console.error(${arg})`, + }, + { + oldBind: "$.put", + replaceFn: (arg: string) => `console.error(${arg})`, + }, + { + oldBind: "$.patch", + replaceFn: (arg: string) => `console.error(${arg})`, + }, + { + oldBind: "$.delete", + replaceFn: (arg: string) => `console.error(${arg})`, + }, + { + oldBind: "$.head", + replaceFn: (arg: string) => `console.error(${arg})`, + }, + { + oldBind: "$.options", + replaceFn: (arg: string) => `console.error(${arg})`, + }, +]; + +/* + * Transforms `util.print($$$ARG)` usage to `console.log($$$ARG)`. + * Transforms `util.puts($$$ARG)` usage to `console.log($$$ARG)`. + * Transforms `util.debug($$$ARG)` usage to `console.error($$$ARG)`. + * Transforms `util.error($$$ARG)` usage to `console.error($$$ARG)`. + * + * Steps: + * + * Locate all `util.print|puts|debug|error` import imports, noting the replacement rule, import node, and binding name. + * + * For each binding, replace calls to util.print|puts|debug|error($$$ARG) with the new console.log|error format, + * and determine if the import line should be updated or removed. + * + * Apply all changes, removing or updating the import line as needed. + */ +export default function transform(root: SgRoot): string | null { + const rootNode = root.root(); + const edits: Edit[] = []; + const linesToRemove: Range[] = []; + const bindsToReplace: BindingToReplace[] = []; + + const nodeRequires = getNodeRequireCalls(root, "util"); + const nodeImports = getNodeImportStatements(root, "util"); + const importRequireStatement = [...nodeRequires, ...nodeImports]; + + if (!importRequireStatement.length) return null; + + for (const node of importRequireStatement) { + for (const update of updates) { + const bind = resolveBindingPath(node, update.oldBind); + + // if `fn` function ins't coming from `node:util` + if (!bind) continue; + + bindsToReplace.push({ + rule: { + pattern: `${bind}($$$ARG)`, + }, + node, + binding: bind, + replaceFn: update.replaceFn, + }); + } + } + + for (const bind of bindsToReplace) { + const matches = rootNode.findAll({ + rule: bind.rule, + }); + + for (const match of matches) { + const args = match.getMultipleMatches("ARG"); + + const argsStr = args + .map((arg) => { + const text = arg.text(); + if (text === ",") { + // if arg is a comman, add a space at end + return text.padEnd(2, " "); + } + return text; + }) + .join(""); + + const replace = match.replace(bind.replaceFn(argsStr)); + edits.push(replace); + + const result = removeBinding(bind.node, bind.binding.split(".").at(0)); + + if (result?.lineToRemove) { + linesToRemove.push(result.lineToRemove); + } + + if (result?.edit) { + edits.push(result.edit); + } + } + } + + if (!edits.length) return; + + const sourceCode = rootNode.commitEdits(edits); + + return removeLines(sourceCode, linesToRemove); +} diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/debug.js b/recipes/axios-to-whatwg-fetch/tests/expected/debug.js new file mode 100644 index 00000000..16c7cf20 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/debug.js @@ -0,0 +1,2 @@ + +console.error("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/error.js b/recipes/axios-to-whatwg-fetch/tests/expected/error.js new file mode 100644 index 00000000..16c7cf20 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/error.js @@ -0,0 +1,2 @@ + +console.error("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/esm-import.mjs b/recipes/axios-to-whatwg-fetch/tests/expected/esm-import.mjs new file mode 100644 index 00000000..3fd202c3 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/esm-import.mjs @@ -0,0 +1,2 @@ + +console.log("Server listening on port 3000"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/esm-namespace-import.mjs b/recipes/axios-to-whatwg-fetch/tests/expected/esm-namespace-import.mjs new file mode 100644 index 00000000..214701e1 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/esm-namespace-import.mjs @@ -0,0 +1,2 @@ + +console.log("Debug message"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/multiple-arguments.js b/recipes/axios-to-whatwg-fetch/tests/expected/multiple-arguments.js new file mode 100644 index 00000000..819d6080 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/multiple-arguments.js @@ -0,0 +1,2 @@ + +console.log("User:", "john", "logged in"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/multiple-imports.cjs b/recipes/axios-to-whatwg-fetch/tests/expected/multiple-imports.cjs new file mode 100644 index 00000000..16f7568d --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/multiple-imports.cjs @@ -0,0 +1,5 @@ +const { inspect } = require("node:util"); + +console.log("Starting application"); +const formatted = inspect({ foo: "bar" }); +console.log(formatted); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/named-import-print-only.js b/recipes/axios-to-whatwg-fetch/tests/expected/named-import-print-only.js new file mode 100644 index 00000000..402bee3d --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/named-import-print-only.js @@ -0,0 +1,3 @@ + +console.log("Application started"); +console.log("Processing request"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/print.js b/recipes/axios-to-whatwg-fetch/tests/expected/print.js new file mode 100644 index 00000000..d5fe29bc --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/print.js @@ -0,0 +1,2 @@ + +console.log("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/puts.js b/recipes/axios-to-whatwg-fetch/tests/expected/puts.js new file mode 100644 index 00000000..d5fe29bc --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/puts.js @@ -0,0 +1,2 @@ + +console.log("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/real-scenario.js b/recipes/axios-to-whatwg-fetch/tests/expected/real-scenario.js new file mode 100644 index 00000000..bb7441e3 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/real-scenario.js @@ -0,0 +1,16 @@ +import http from "node:http"; + +console.log("Debug message"); + +const PORT = process.env.PORT || 3000; + +const server = http.createServer((req, res) => { + console.log(`[${req.method}] ${req.url}`); + res.statusCode = 200; + res.setHeader("Content-Type", "text/plain"); + res.end("Hello World\n"); +}); + +server.listen(PORT, () => { + console.log(`Server running at http://localhost:${PORT}/`); +}); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/simple-scenario.js b/recipes/axios-to-whatwg-fetch/tests/expected/simple-scenario.js new file mode 100644 index 00000000..d5fe29bc --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/simple-scenario.js @@ -0,0 +1,2 @@ + +console.log("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/with-interpolation.js b/recipes/axios-to-whatwg-fetch/tests/expected/with-interpolation.js new file mode 100644 index 00000000..bfb1d9d7 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/with-interpolation.js @@ -0,0 +1,3 @@ + +const port = 3000; +console.log(`Server started on port ${port}`); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/debug.js b/recipes/axios-to-whatwg-fetch/tests/input/debug.js new file mode 100644 index 00000000..c1c5db94 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/debug.js @@ -0,0 +1,3 @@ +const util = require("node:util"); + +util.debug("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/error.js b/recipes/axios-to-whatwg-fetch/tests/input/error.js new file mode 100644 index 00000000..420871a5 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/error.js @@ -0,0 +1,3 @@ +const util = require("node:util"); + +util.error("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/esm-import.mjs b/recipes/axios-to-whatwg-fetch/tests/input/esm-import.mjs new file mode 100644 index 00000000..b0fd6cd6 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/esm-import.mjs @@ -0,0 +1,3 @@ +import { print } from "node:util"; + +print("Server listening on port 3000"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/esm-namespace-import.mjs b/recipes/axios-to-whatwg-fetch/tests/input/esm-namespace-import.mjs new file mode 100644 index 00000000..7f4209ac --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/esm-namespace-import.mjs @@ -0,0 +1,3 @@ +import * as util from "node:util"; + +util.print("Debug message"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/multiple-arguments.js b/recipes/axios-to-whatwg-fetch/tests/input/multiple-arguments.js new file mode 100644 index 00000000..30a602eb --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/multiple-arguments.js @@ -0,0 +1,3 @@ +const util = require("node:util"); + +util.print("User:", "john", "logged in"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/multiple-imports.cjs b/recipes/axios-to-whatwg-fetch/tests/input/multiple-imports.cjs new file mode 100644 index 00000000..5660a72a --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/multiple-imports.cjs @@ -0,0 +1,5 @@ +const { print, inspect } = require("node:util"); + +print("Starting application"); +const formatted = inspect({ foo: "bar" }); +console.log(formatted); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/named-import-print-only.js b/recipes/axios-to-whatwg-fetch/tests/input/named-import-print-only.js new file mode 100644 index 00000000..ffc961e9 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/named-import-print-only.js @@ -0,0 +1,4 @@ +const { print } = require("node:util"); + +print("Application started"); +print("Processing request"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/print.js b/recipes/axios-to-whatwg-fetch/tests/input/print.js new file mode 100644 index 00000000..ea0515c3 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/print.js @@ -0,0 +1,3 @@ +const util = require("node:util"); + +util.print("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/puts.js b/recipes/axios-to-whatwg-fetch/tests/input/puts.js new file mode 100644 index 00000000..6642934b --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/puts.js @@ -0,0 +1,3 @@ +const util = require("node:util"); + +util.puts("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/real-scenario.js b/recipes/axios-to-whatwg-fetch/tests/input/real-scenario.js new file mode 100644 index 00000000..10094ca9 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/real-scenario.js @@ -0,0 +1,17 @@ +import util from "node:util"; +import http from "node:http"; + +util.print("Debug message"); + +const PORT = process.env.PORT || 3000; + +const server = http.createServer((req, res) => { + util.print(`[${req.method}] ${req.url}`); + res.statusCode = 200; + res.setHeader("Content-Type", "text/plain"); + res.end("Hello World\n"); +}); + +server.listen(PORT, () => { + util.print(`Server running at http://localhost:${PORT}/`); +}); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/simple-scenario.js b/recipes/axios-to-whatwg-fetch/tests/input/simple-scenario.js new file mode 100644 index 00000000..ea0515c3 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/simple-scenario.js @@ -0,0 +1,3 @@ +const util = require("node:util"); + +util.print("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/with-interpolation.js b/recipes/axios-to-whatwg-fetch/tests/input/with-interpolation.js new file mode 100644 index 00000000..a0366ea2 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/with-interpolation.js @@ -0,0 +1,4 @@ +const { print } = require("node:util"); + +const port = 3000; +print(`Server started on port ${port}`); diff --git a/recipes/axios-to-whatwg-fetch/workflow.yaml b/recipes/axios-to-whatwg-fetch/workflow.yaml new file mode 100644 index 00000000..1efcc5c4 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/workflow.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/codemod-com/codemod/refs/heads/main/schemas/workflow.json + +version: "1" + +nodes: + - id: apply-transforms + name: Apply AST Transformations + type: automatic + steps: + - name: Replace `axios` with `fetch` + js-ast-grep: + js_file: src/workflow.ts + base_path: . + include: + - "**/*.cjs" + - "**/*.cts" + - "**/*.js" + - "**/*.jsx" + - "**/*.mjs" + - "**/*.mts" + - "**/*.ts" + - "**/*.tsx" + exclude: + - "**/node_modules/**" + language: typescript From e51e1cb8722017fa02200cc5fb778fa1c357159b Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Fri, 5 Sep 2025 10:46:58 +0100 Subject: [PATCH 02/20] wip --- recipes/axios-to-whatwg-fetch/package.json | 4 +++- recipes/axios-to-whatwg-fetch/src/workflow.ts | 24 ++++++++++++------- .../tests/expected/debug.js | 2 -- .../tests/expected/error.js | 2 -- .../tests/expected/esm-import.mjs | 2 -- .../tests/expected/esm-namespace-import.mjs | 2 -- .../tests/expected/get.js | 7 ++++++ .../tests/expected/multiple-arguments.js | 2 -- .../tests/expected/multiple-imports.cjs | 5 ---- .../tests/expected/named-import-print-only.js | 3 --- .../tests/expected/print.js | 2 -- .../tests/expected/puts.js | 2 -- .../tests/expected/real-scenario.js | 16 ------------- .../tests/expected/simple-scenario.js | 2 -- .../tests/expected/with-interpolation.js | 3 --- .../tests/input/debug.js | 3 --- .../tests/input/error.js | 3 --- .../tests/input/esm-import.mjs | 3 --- .../tests/input/esm-namespace-import.mjs | 3 --- .../axios-to-whatwg-fetch/tests/input/get.js | 6 +++++ .../tests/input/multiple-arguments.js | 3 --- .../tests/input/multiple-imports.cjs | 5 ---- .../tests/input/named-import-print-only.js | 4 ---- .../tests/input/print.js | 3 --- .../axios-to-whatwg-fetch/tests/input/puts.js | 3 --- .../tests/input/real-scenario.js | 17 ------------- .../tests/input/simple-scenario.js | 3 --- .../tests/input/with-interpolation.js | 4 ---- 28 files changed, 32 insertions(+), 106 deletions(-) delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/debug.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/error.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/esm-import.mjs delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/esm-namespace-import.mjs create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/get.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/multiple-arguments.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/multiple-imports.cjs delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/named-import-print-only.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/print.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/puts.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/real-scenario.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/simple-scenario.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/with-interpolation.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/input/debug.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/input/error.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/input/esm-import.mjs delete mode 100644 recipes/axios-to-whatwg-fetch/tests/input/esm-namespace-import.mjs create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/get.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/input/multiple-arguments.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/input/multiple-imports.cjs delete mode 100644 recipes/axios-to-whatwg-fetch/tests/input/named-import-print-only.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/input/print.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/input/puts.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/input/real-scenario.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/input/simple-scenario.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/input/with-interpolation.js diff --git a/recipes/axios-to-whatwg-fetch/package.json b/recipes/axios-to-whatwg-fetch/package.json index 9bf22caf..6d5db10e 100644 --- a/recipes/axios-to-whatwg-fetch/package.json +++ b/recipes/axios-to-whatwg-fetch/package.json @@ -2,6 +2,7 @@ "name": "@nodejs/axios-to-whatwg-fetch", "version": "1.0.0", "description": "Replace `axios` with `fetch`", + "type": "module", "scripts": { "test": "npx codemod jssg test -l typescript ./src/workflow.ts ./" }, @@ -18,6 +19,7 @@ "@codemod.com/jssg-types": "^1.0.3" }, "dependencies": { - "@nodejs/codemod-utils": "*" + "@nodejs/codemod-utils": "*", + "dedent": "^1.7.0" } } diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts index eb962fcd..d1ac00fc 100644 --- a/recipes/axios-to-whatwg-fetch/src/workflow.ts +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -12,6 +12,7 @@ import { getNodeImportStatements } from "@nodejs/codemod-utils/ast-grep/import-s import { resolveBindingPath } from "@nodejs/codemod-utils/ast-grep/resolve-binding-path"; import { removeBinding } from "@nodejs/codemod-utils/ast-grep/remove-binding"; import { removeLines } from "@nodejs/codemod-utils/ast-grep/remove-lines"; +import dedent from "dedent"; type BindingToReplace = { rule: Rule; @@ -27,7 +28,12 @@ const updates = [ }, { oldBind: "$.get", - replaceFn: (arg: string) => `console.log(${arg})`, + replaceFn: (arg: string) => + dedent` + fetch(${arg}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `, }, { oldBind: "$.post", @@ -56,10 +62,10 @@ const updates = [ ]; /* - * Transforms `util.print($$$ARG)` usage to `console.log($$$ARG)`. - * Transforms `util.puts($$$ARG)` usage to `console.log($$$ARG)`. - * Transforms `util.debug($$$ARG)` usage to `console.error($$$ARG)`. - * Transforms `util.error($$$ARG)` usage to `console.error($$$ARG)`. + * Transforms `util.requestj($$$ARG)` usage to `console.log($$$ARG)`. + * Transforms `util.get($$$ARG)` usage to `console.log($$$ARG)`. + * Transforms `util.post($$$ARG)` usage to `console.error($$$ARG)`. + * Transforms `util.put($$$ARG)` usage to `console.error($$$ARG)`. * * Steps: * @@ -76,8 +82,8 @@ export default function transform(root: SgRoot): string | null { const linesToRemove: Range[] = []; const bindsToReplace: BindingToReplace[] = []; - const nodeRequires = getNodeRequireCalls(root, "util"); - const nodeImports = getNodeImportStatements(root, "util"); + const nodeRequires = getNodeRequireCalls(root, "axios"); + const nodeImports = getNodeImportStatements(root, "axios"); const importRequireStatement = [...nodeRequires, ...nodeImports]; if (!importRequireStatement.length) return null; @@ -86,7 +92,6 @@ export default function transform(root: SgRoot): string | null { for (const update of updates) { const bind = resolveBindingPath(node, update.oldBind); - // if `fn` function ins't coming from `node:util` if (!bind) continue; bindsToReplace.push({ @@ -122,6 +127,9 @@ export default function transform(root: SgRoot): string | null { const replace = match.replace(bind.replaceFn(argsStr)); edits.push(replace); + // const replace = match.replace(bind.replaceFn(argsStr)); + // edits.push(replace); + // const result = removeBinding(bind.node, bind.binding.split(".").at(0)); if (result?.lineToRemove) { diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/debug.js b/recipes/axios-to-whatwg-fetch/tests/expected/debug.js deleted file mode 100644 index 16c7cf20..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/expected/debug.js +++ /dev/null @@ -1,2 +0,0 @@ - -console.error("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/error.js b/recipes/axios-to-whatwg-fetch/tests/expected/error.js deleted file mode 100644 index 16c7cf20..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/expected/error.js +++ /dev/null @@ -1,2 +0,0 @@ - -console.error("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/esm-import.mjs b/recipes/axios-to-whatwg-fetch/tests/expected/esm-import.mjs deleted file mode 100644 index 3fd202c3..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/expected/esm-import.mjs +++ /dev/null @@ -1,2 +0,0 @@ - -console.log("Server listening on port 3000"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/esm-namespace-import.mjs b/recipes/axios-to-whatwg-fetch/tests/expected/esm-namespace-import.mjs deleted file mode 100644 index 214701e1..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/expected/esm-namespace-import.mjs +++ /dev/null @@ -1,2 +0,0 @@ - -console.log("Debug message"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/get.js b/recipes/axios-to-whatwg-fetch/tests/expected/get.js new file mode 100644 index 00000000..045d0c94 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/get.js @@ -0,0 +1,7 @@ +const base = "https://dummyjson.com/todos"; + +const all = await fetch(base) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log("\nGET /todos ->", all.status); +console.log(`Preview: ${all.data.todos.length} todos`); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/multiple-arguments.js b/recipes/axios-to-whatwg-fetch/tests/expected/multiple-arguments.js deleted file mode 100644 index 819d6080..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/expected/multiple-arguments.js +++ /dev/null @@ -1,2 +0,0 @@ - -console.log("User:", "john", "logged in"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/multiple-imports.cjs b/recipes/axios-to-whatwg-fetch/tests/expected/multiple-imports.cjs deleted file mode 100644 index 16f7568d..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/expected/multiple-imports.cjs +++ /dev/null @@ -1,5 +0,0 @@ -const { inspect } = require("node:util"); - -console.log("Starting application"); -const formatted = inspect({ foo: "bar" }); -console.log(formatted); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/named-import-print-only.js b/recipes/axios-to-whatwg-fetch/tests/expected/named-import-print-only.js deleted file mode 100644 index 402bee3d..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/expected/named-import-print-only.js +++ /dev/null @@ -1,3 +0,0 @@ - -console.log("Application started"); -console.log("Processing request"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/print.js b/recipes/axios-to-whatwg-fetch/tests/expected/print.js deleted file mode 100644 index d5fe29bc..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/expected/print.js +++ /dev/null @@ -1,2 +0,0 @@ - -console.log("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/puts.js b/recipes/axios-to-whatwg-fetch/tests/expected/puts.js deleted file mode 100644 index d5fe29bc..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/expected/puts.js +++ /dev/null @@ -1,2 +0,0 @@ - -console.log("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/real-scenario.js b/recipes/axios-to-whatwg-fetch/tests/expected/real-scenario.js deleted file mode 100644 index bb7441e3..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/expected/real-scenario.js +++ /dev/null @@ -1,16 +0,0 @@ -import http from "node:http"; - -console.log("Debug message"); - -const PORT = process.env.PORT || 3000; - -const server = http.createServer((req, res) => { - console.log(`[${req.method}] ${req.url}`); - res.statusCode = 200; - res.setHeader("Content-Type", "text/plain"); - res.end("Hello World\n"); -}); - -server.listen(PORT, () => { - console.log(`Server running at http://localhost:${PORT}/`); -}); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/simple-scenario.js b/recipes/axios-to-whatwg-fetch/tests/expected/simple-scenario.js deleted file mode 100644 index d5fe29bc..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/expected/simple-scenario.js +++ /dev/null @@ -1,2 +0,0 @@ - -console.log("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/with-interpolation.js b/recipes/axios-to-whatwg-fetch/tests/expected/with-interpolation.js deleted file mode 100644 index bfb1d9d7..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/expected/with-interpolation.js +++ /dev/null @@ -1,3 +0,0 @@ - -const port = 3000; -console.log(`Server started on port ${port}`); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/debug.js b/recipes/axios-to-whatwg-fetch/tests/input/debug.js deleted file mode 100644 index c1c5db94..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/input/debug.js +++ /dev/null @@ -1,3 +0,0 @@ -const util = require("node:util"); - -util.debug("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/error.js b/recipes/axios-to-whatwg-fetch/tests/input/error.js deleted file mode 100644 index 420871a5..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/input/error.js +++ /dev/null @@ -1,3 +0,0 @@ -const util = require("node:util"); - -util.error("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/esm-import.mjs b/recipes/axios-to-whatwg-fetch/tests/input/esm-import.mjs deleted file mode 100644 index b0fd6cd6..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/input/esm-import.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import { print } from "node:util"; - -print("Server listening on port 3000"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/esm-namespace-import.mjs b/recipes/axios-to-whatwg-fetch/tests/input/esm-namespace-import.mjs deleted file mode 100644 index 7f4209ac..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/input/esm-namespace-import.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import * as util from "node:util"; - -util.print("Debug message"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/get.js b/recipes/axios-to-whatwg-fetch/tests/input/get.js new file mode 100644 index 00000000..6efc338f --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/get.js @@ -0,0 +1,6 @@ +import axios from "axios"; +const base = "https://dummyjson.com/todos"; + +const all = await axios.get(base); +console.log("\nGET /todos ->", all.status); +console.log(`Preview: ${all.data.todos.length} todos`); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/multiple-arguments.js b/recipes/axios-to-whatwg-fetch/tests/input/multiple-arguments.js deleted file mode 100644 index 30a602eb..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/input/multiple-arguments.js +++ /dev/null @@ -1,3 +0,0 @@ -const util = require("node:util"); - -util.print("User:", "john", "logged in"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/multiple-imports.cjs b/recipes/axios-to-whatwg-fetch/tests/input/multiple-imports.cjs deleted file mode 100644 index 5660a72a..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/input/multiple-imports.cjs +++ /dev/null @@ -1,5 +0,0 @@ -const { print, inspect } = require("node:util"); - -print("Starting application"); -const formatted = inspect({ foo: "bar" }); -console.log(formatted); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/named-import-print-only.js b/recipes/axios-to-whatwg-fetch/tests/input/named-import-print-only.js deleted file mode 100644 index ffc961e9..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/input/named-import-print-only.js +++ /dev/null @@ -1,4 +0,0 @@ -const { print } = require("node:util"); - -print("Application started"); -print("Processing request"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/print.js b/recipes/axios-to-whatwg-fetch/tests/input/print.js deleted file mode 100644 index ea0515c3..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/input/print.js +++ /dev/null @@ -1,3 +0,0 @@ -const util = require("node:util"); - -util.print("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/puts.js b/recipes/axios-to-whatwg-fetch/tests/input/puts.js deleted file mode 100644 index 6642934b..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/input/puts.js +++ /dev/null @@ -1,3 +0,0 @@ -const util = require("node:util"); - -util.puts("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/real-scenario.js b/recipes/axios-to-whatwg-fetch/tests/input/real-scenario.js deleted file mode 100644 index 10094ca9..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/input/real-scenario.js +++ /dev/null @@ -1,17 +0,0 @@ -import util from "node:util"; -import http from "node:http"; - -util.print("Debug message"); - -const PORT = process.env.PORT || 3000; - -const server = http.createServer((req, res) => { - util.print(`[${req.method}] ${req.url}`); - res.statusCode = 200; - res.setHeader("Content-Type", "text/plain"); - res.end("Hello World\n"); -}); - -server.listen(PORT, () => { - util.print(`Server running at http://localhost:${PORT}/`); -}); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/simple-scenario.js b/recipes/axios-to-whatwg-fetch/tests/input/simple-scenario.js deleted file mode 100644 index ea0515c3..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/input/simple-scenario.js +++ /dev/null @@ -1,3 +0,0 @@ -const util = require("node:util"); - -util.print("Hello world"); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/with-interpolation.js b/recipes/axios-to-whatwg-fetch/tests/input/with-interpolation.js deleted file mode 100644 index a0366ea2..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/input/with-interpolation.js +++ /dev/null @@ -1,4 +0,0 @@ -const { print } = require("node:util"); - -const port = 3000; -print(`Server started on port ${port}`); From b74ed68fbe8598758ae398b759e9481e79e2637c Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Fri, 5 Sep 2025 10:47:12 +0100 Subject: [PATCH 03/20] wip --- package-lock.json | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0c422a9a..be350e95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1408,6 +1408,10 @@ "node": ">=22 || ^20.6.0 || ^18.19.0" } }, + "node_modules/@nodejs/axios-to-whatwg-fetch": { + "resolved": "recipes/axios-to-whatwg-fetch", + "link": true + }, "node_modules/@nodejs/codemod-utils": { "resolved": "utils", "link": true @@ -2119,10 +2123,9 @@ } }, "node_modules/dedent": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", - "integrity": "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==", - "dev": true, + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -4061,6 +4064,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "recipes/axios-to-whatwg-fetch": { + "name": "@nodejs/axios-to-whatwg-fetch", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@nodejs/codemod-utils": "*", + "dedent": "^1.7.0" + }, + "devDependencies": { + "@codemod.com/jssg-types": "^1.0.3" + } + }, "recipes/correct-ts-specifiers": { "name": "@nodejs/correct-ts-specifiers", "version": "1.0.0", From 320dd82d24ae027b154b4ad63f5a332f4af5b0e3 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Sat, 6 Sep 2025 13:20:56 +0100 Subject: [PATCH 04/20] wip --- recipes/axios-to-whatwg-fetch/package.json | 3 +- recipes/axios-to-whatwg-fetch/src/workflow.ts | 152 +++++++++++------- .../tests/expected/get-with-config.js | 8 + .../tests/input/get-with-config.js | 7 + 4 files changed, 107 insertions(+), 63 deletions(-) create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/get-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/get-with-config.js diff --git a/recipes/axios-to-whatwg-fetch/package.json b/recipes/axios-to-whatwg-fetch/package.json index 6d5db10e..9b24d6cd 100644 --- a/recipes/axios-to-whatwg-fetch/package.json +++ b/recipes/axios-to-whatwg-fetch/package.json @@ -4,7 +4,8 @@ "description": "Replace `axios` with `fetch`", "type": "module", "scripts": { - "test": "npx codemod jssg test -l typescript ./src/workflow.ts ./" + "test": "npx codemod jssg test -l typescript ./src/workflow.ts ./", + "testu": "npx codemod jssg test -l typescript -u ./src/workflow.ts ./" }, "repository": { "type": "git", diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts index d1ac00fc..2fe681c4 100644 --- a/recipes/axios-to-whatwg-fetch/src/workflow.ts +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -6,60 +6,98 @@ import type { SgNode, SgRoot, TypesMap, -} from "@codemod.com/jssg-types/main"; -import { getNodeRequireCalls } from "@nodejs/codemod-utils/ast-grep/require-call"; -import { getNodeImportStatements } from "@nodejs/codemod-utils/ast-grep/import-statement"; -import { resolveBindingPath } from "@nodejs/codemod-utils/ast-grep/resolve-binding-path"; -import { removeBinding } from "@nodejs/codemod-utils/ast-grep/remove-binding"; -import { removeLines } from "@nodejs/codemod-utils/ast-grep/remove-lines"; -import dedent from "dedent"; +} from '@codemod.com/jssg-types/main'; +import { getNodeRequireCalls } from '@nodejs/codemod-utils/ast-grep/require-call'; +import { getNodeImportStatements } from '@nodejs/codemod-utils/ast-grep/import-statement'; +import { resolveBindingPath } from '@nodejs/codemod-utils/ast-grep/resolve-binding-path'; +import { removeBinding } from '@nodejs/codemod-utils/ast-grep/remove-binding'; +import { removeLines } from '@nodejs/codemod-utils/ast-grep/remove-lines'; +import dedent from 'dedent'; type BindingToReplace = { rule: Rule; node: SgNode>; binding: string; - replaceFn: (arg: string) => string; + replaceFn: (arg: SgNode[]) => string; }; -const updates = [ - { - oldBind: "$.request", - replaceFn: (arg: string) => `console.log(${arg})`, - }, - { - oldBind: "$.get", - replaceFn: (arg: string) => - dedent` - fetch(${arg}) +const transformOptions = (args: SgNode[]) => { + console.log({ argsLength: args.length, args: args.map((t) => t.text()) }); +}; + +const transformBody = (args: SgNode[]) => { + console.log({ argsLength: args.length, args: args.map((t) => t.text()) }); + + return; +}; + +const transformOptionsNode = (options: SgNode) => { + if (!options) return ''; + + const headers = options.find({ + rule: { + kind: 'object', + inside: { + kind: 'pair', + has: { + kind: 'property_identifier', + field: 'key', + regex: 'headers', + }, + }, + }, + }); + + if (headers?.kind()) { + return dedent`, { + headers: ${headers.text()}, + }`; + } +}; + +const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = + [ + { + oldBind: '$.request', + replaceFn: (arg) => `console.log(${arg})`, + }, + { + oldBind: '$.get', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = transformOptionsNode(args[1]); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options}) .then(async (res) => Object.assign(res, { data: await res.json() })) .catch(() => null) - `, - }, - { - oldBind: "$.post", - replaceFn: (arg: string) => `console.error(${arg})`, - }, - { - oldBind: "$.put", - replaceFn: (arg: string) => `console.error(${arg})`, - }, - { - oldBind: "$.patch", - replaceFn: (arg: string) => `console.error(${arg})`, - }, - { - oldBind: "$.delete", - replaceFn: (arg: string) => `console.error(${arg})`, - }, - { - oldBind: "$.head", - replaceFn: (arg: string) => `console.error(${arg})`, - }, - { - oldBind: "$.options", - replaceFn: (arg: string) => `console.error(${arg})`, - }, -]; + `; + }, + }, + { + oldBind: '$.post', + replaceFn: (arg: FunctionArgs) => `console.error(${arg})`, + }, + { + oldBind: '$.put', + replaceFn: (arg: FunctionArgs) => `console.error(${arg})`, + }, + { + oldBind: '$.patch', + replaceFn: (arg: FunctionArgs) => `console.error(${arg})`, + }, + { + oldBind: '$.delete', + replaceFn: (arg: FunctionArgs) => `console.error(${arg})`, + }, + { + oldBind: '$.head', + replaceFn: (arg: FunctionArgs) => `console.error(${arg})`, + }, + { + oldBind: '$.options', + replaceFn: (arg: FunctionArgs) => `console.error(${arg})`, + }, + ]; /* * Transforms `util.requestj($$$ARG)` usage to `console.log($$$ARG)`. @@ -82,8 +120,8 @@ export default function transform(root: SgRoot): string | null { const linesToRemove: Range[] = []; const bindsToReplace: BindingToReplace[] = []; - const nodeRequires = getNodeRequireCalls(root, "axios"); - const nodeImports = getNodeImportStatements(root, "axios"); + const nodeRequires = getNodeRequireCalls(root, 'axios'); + const nodeImports = getNodeImportStatements(root, 'axios'); const importRequireStatement = [...nodeRequires, ...nodeImports]; if (!importRequireStatement.length) return null; @@ -111,26 +149,16 @@ export default function transform(root: SgRoot): string | null { }); for (const match of matches) { - const args = match.getMultipleMatches("ARG"); - - const argsStr = args - .map((arg) => { - const text = arg.text(); - if (text === ",") { - // if arg is a comman, add a space at end - return text.padEnd(2, " "); - } - return text; - }) - .join(""); - - const replace = match.replace(bind.replaceFn(argsStr)); + const argsAndCommaas = match.getMultipleMatches('ARG'); + const args = argsAndCommaas.filter((arg) => arg.text() !== ','); + + const replace = match.replace(bind.replaceFn(args)); edits.push(replace); // const replace = match.replace(bind.replaceFn(argsStr)); // edits.push(replace); // - const result = removeBinding(bind.node, bind.binding.split(".").at(0)); + const result = removeBinding(bind.node, bind.binding.split('.').at(0)); if (result?.lineToRemove) { linesToRemove.push(result.lineToRemove); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/get-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/get-with-config.js new file mode 100644 index 00000000..03a3f88a --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/get-with-config.js @@ -0,0 +1,8 @@ + +const all = await fetch("https://dummyjson.com/todos", { + headers: { "Content-Type": "application/json" }, +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log("\nGET /todos ->", all.status); +console.log(`Preview: ${all.data.todos.length} todos`); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/get-with-config.js b/recipes/axios-to-whatwg-fetch/tests/input/get-with-config.js new file mode 100644 index 00000000..f6103278 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/get-with-config.js @@ -0,0 +1,7 @@ +import axios from "axios"; + +const all = await axios.get("https://dummyjson.com/todos", { + headers: { "Content-Type": "application/json" }, +}); +console.log("\nGET /todos ->", all.status); +console.log(`Preview: ${all.data.todos.length} todos`); From 84c09b7fa910778b13c48c531133f63055dfd359 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Sat, 6 Sep 2025 19:05:59 +0100 Subject: [PATCH 05/20] wip --- recipes/axios-to-whatwg-fetch/src/workflow.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts index 2fe681c4..ebd935d6 100644 --- a/recipes/axios-to-whatwg-fetch/src/workflow.ts +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -21,16 +21,6 @@ type BindingToReplace = { replaceFn: (arg: SgNode[]) => string; }; -const transformOptions = (args: SgNode[]) => { - console.log({ argsLength: args.length, args: args.map((t) => t.text()) }); -}; - -const transformBody = (args: SgNode[]) => { - console.log({ argsLength: args.length, args: args.map((t) => t.text()) }); - - return; -}; - const transformOptionsNode = (options: SgNode) => { if (!options) return ''; From 9bfe594d6f19f68131acab6be97dee01eb830e5c Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Sat, 6 Sep 2025 23:45:38 +0100 Subject: [PATCH 06/20] wip --- recipes/axios-to-whatwg-fetch/package.json | 2 +- recipes/axios-to-whatwg-fetch/src/workflow.ts | 49 +++++++++++++++--- .../tests/expected/.head.js.swp | Bin 0 -> 12288 bytes .../tests/expected/delete-with-config.js | 8 +++ .../tests/expected/delete.js | 7 +++ .../tests/expected/head-with-config.js | 8 +++ .../tests/expected/head.js | 6 +++ .../tests/expected/options-with-config.js | 6 +++ .../tests/expected/options.js | 4 ++ .../tests/input/delete-with-config.js | 7 +++ .../tests/input/delete.js | 6 +++ .../tests/input/head-with-config.js | 7 +++ .../axios-to-whatwg-fetch/tests/input/head.js | 3 ++ .../tests/input/options-with-config.js | 5 ++ .../tests/input/options.js | 3 ++ 15 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/.head.js.swp create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/delete-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/delete.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/head-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/head.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/options-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/options.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/delete-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/delete.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/head-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/head.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/options-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/options.js diff --git a/recipes/axios-to-whatwg-fetch/package.json b/recipes/axios-to-whatwg-fetch/package.json index 9b24d6cd..de2ef888 100644 --- a/recipes/axios-to-whatwg-fetch/package.json +++ b/recipes/axios-to-whatwg-fetch/package.json @@ -4,7 +4,7 @@ "description": "Replace `axios` with `fetch`", "type": "module", "scripts": { - "test": "npx codemod jssg test -l typescript ./src/workflow.ts ./", + "test": "npx codemod jssg test -l typescript --ignore-whitespace ./src/workflow.ts ./", "testu": "npx codemod jssg test -l typescript -u ./src/workflow.ts ./" }, "repository": { diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts index ebd935d6..fd1a478d 100644 --- a/recipes/axios-to-whatwg-fetch/src/workflow.ts +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -21,7 +21,7 @@ type BindingToReplace = { replaceFn: (arg: SgNode[]) => string; }; -const transformOptionsNode = (options: SgNode) => { +const transformOptionsNode = (options: SgNode, prepend?: string) => { if (!options) return ''; const headers = options.find({ @@ -39,7 +39,14 @@ const transformOptionsNode = (options: SgNode) => { }); if (headers?.kind()) { - return dedent`, { + if (prepend) { + return dedent.withOptions({ alignValues: true })`{ + ${prepend} + headers: ${headers.text()}, + }`; + } + + return dedent.withOptions({ alignValues: true })`{ headers: ${headers.text()}, }`; } @@ -57,7 +64,7 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = const url = args.length > 0 && args[0]; const options = transformOptionsNode(args[1]); return dedent.withOptions({ alignValues: true })` - fetch(${url.text()}${options}) + fetch(${url.text()}${options ? `, ${options}` : ''}) .then(async (res) => Object.assign(res, { data: await res.json() })) .catch(() => null) `; @@ -77,15 +84,45 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = }, { oldBind: '$.delete', - replaceFn: (arg: FunctionArgs) => `console.error(${arg})`, + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = args[1] + ? transformOptionsNode(args[1], `method: 'DELETE',`) + : `{ method: 'DELETE' }`; + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}, ${options}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; + }, }, { oldBind: '$.head', - replaceFn: (arg: FunctionArgs) => `console.error(${arg})`, + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = args[1] + ? transformOptionsNode(args[1], `method: 'HEAD',`) + : `{ method: 'HEAD' }`; + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}, ${options}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; + }, }, { oldBind: '$.options', - replaceFn: (arg: FunctionArgs) => `console.error(${arg})`, + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = args[1] + ? transformOptionsNode(args[1], `method: 'OPTIONS',`) + : `{ method: 'OPTIONS' }`; + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}, ${options}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; + }, }, ]; diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/.head.js.swp b/recipes/axios-to-whatwg-fetch/tests/expected/.head.js.swp new file mode 100644 index 0000000000000000000000000000000000000000..336e66ecb4951f14d99a322689298c0c2e2e6874 GIT binary patch literal 12288 zcmeI&F>ll`6bEn@bzz`XFtWISbUBH{Jy_tXB2j?~Lq!LQV5`q@^Qq!+QmoJQriz+|TQ5g|+pbYwCPMLHmjFx3_{EuRni^3WLS3#hQ zNBQF$2ag_3Hq&wM-QD1~Zyj8PljDpKfB*y_009U<00Izzz#tIkE9^7fUmMn|!@ROI z4@*oCfB*y_009U<00Izz00bZa0SH_|0a-FOxk=ysX{7J}zyJULr1e)Cc6hcy^N%&g zzSF=30SG_<0uX=z1Rwwb2tWV=5V#ZqirUIuqp3^1$`1Fv{#fh9l;1y-O;eOI$|Abb zg`&~6ivJU9&Uydl;dqN(FO;PI^eh|m?Wf#!P1A2iqirU`sZ~7lI`j`;&r%zFAw#Gu zn|2@YGoI?0a=DOo Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log('\nGET /todos ->', all.status); +console.log(`Preview: ${all.data.todos.length} todos`); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/delete.js b/recipes/axios-to-whatwg-fetch/tests/expected/delete.js new file mode 100644 index 00000000..9925bcfa --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/delete.js @@ -0,0 +1,7 @@ +const base = 'https://dummyjson.com/todos'; + +const all = await fetch(base, { method: 'DELETE' }) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log('\nGET /todos ->', all.status); +console.log(`Preview: ${all.data.todos.length} todos`); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/head-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/head-with-config.js new file mode 100644 index 00000000..bf7685f5 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/head-with-config.js @@ -0,0 +1,8 @@ +const all = await fetch('https://dummyjson.com/todos', { + method: 'HEAD', + headers: { 'Content-Type': 'application/json' }, +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log('\nGET /todos ->', all.status); +console.log(`Preview: ${all.data.todos.length} todos`); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/head.js b/recipes/axios-to-whatwg-fetch/tests/expected/head.js new file mode 100644 index 00000000..22a91ca6 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/head.js @@ -0,0 +1,6 @@ + +const all = await fetch('https://dummyjson.com/todos', { method: 'HEAD' }) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log('\nGET /todos ->', all.status); +console.log(`Preview: ${all.data.todos.length} todos`); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/options-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/options-with-config.js new file mode 100644 index 00000000..afbd16b2 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/options-with-config.js @@ -0,0 +1,6 @@ +const all = await fetch('https://dummyjson.com/todos', { + method: 'OPTIONS', + headers: { 'Content-Type': 'application/json' }, +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/options.js b/recipes/axios-to-whatwg-fetch/tests/expected/options.js new file mode 100644 index 00000000..255c3c69 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/options.js @@ -0,0 +1,4 @@ + +const all = await fetch('https://dummyjson.com/todos', { method: 'OPTIONS' }) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/delete-with-config.js b/recipes/axios-to-whatwg-fetch/tests/input/delete-with-config.js new file mode 100644 index 00000000..bb3c17dc --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/delete-with-config.js @@ -0,0 +1,7 @@ +import axios from 'axios'; + +const all = await axios.delete('https://dummyjson.com/todos', { + headers: { 'Content-Type': 'application/json' }, +}); +console.log('\nGET /todos ->', all.status); +console.log(`Preview: ${all.data.todos.length} todos`); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/delete.js b/recipes/axios-to-whatwg-fetch/tests/input/delete.js new file mode 100644 index 00000000..e901a4e6 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/delete.js @@ -0,0 +1,6 @@ +import axios from 'axios'; +const base = 'https://dummyjson.com/todos'; + +const all = await axios.delete(base); +console.log('\nGET /todos ->', all.status); +console.log(`Preview: ${all.data.todos.length} todos`); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/head-with-config.js b/recipes/axios-to-whatwg-fetch/tests/input/head-with-config.js new file mode 100644 index 00000000..35b9b706 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/head-with-config.js @@ -0,0 +1,7 @@ +import axios from 'axios'; + +const all = await axios.head('https://dummyjson.com/todos', { + headers: { 'Content-Type': 'application/json' }, +}); +console.log('\nGET /todos ->', all.status); +console.log(`Preview: ${all.data.todos.length} todos`); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/head.js b/recipes/axios-to-whatwg-fetch/tests/input/head.js new file mode 100644 index 00000000..af8e6368 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/head.js @@ -0,0 +1,3 @@ +import axios from 'axios'; + +const all = await axios.head('https://dummyjson.com/todos'); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/options-with-config.js b/recipes/axios-to-whatwg-fetch/tests/input/options-with-config.js new file mode 100644 index 00000000..11039542 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/options-with-config.js @@ -0,0 +1,5 @@ +import axios from 'axios'; + +const all = await axios.options('https://dummyjson.com/todos', { + headers: { 'Content-Type': 'application/json' }, +}); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/options.js b/recipes/axios-to-whatwg-fetch/tests/input/options.js new file mode 100644 index 00000000..9f46c4d4 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/options.js @@ -0,0 +1,3 @@ +import axios from 'axios'; + +const all = await axios.options('https://dummyjson.com/todos'); From a08cf232010c9301d47934082dcf47bd1e4f7d3b Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Sun, 7 Sep 2025 10:31:54 +0100 Subject: [PATCH 07/20] wip --- .../tests/expected/.head.js.swp | Bin 12288 -> 0 bytes .../tests/expected/delete-with-config.js | 6 +++--- .../tests/expected/delete.js | 7 +++---- .../tests/expected/head-with-config.js | 3 +-- .../tests/expected/head.js | 2 -- .../tests/expected/options-with-config.js | 1 + .../tests/input/delete-with-config.js | 5 ++--- .../axios-to-whatwg-fetch/tests/input/delete.js | 7 +++---- .../tests/input/head-with-config.js | 2 -- 9 files changed, 13 insertions(+), 20 deletions(-) delete mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/.head.js.swp diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/.head.js.swp b/recipes/axios-to-whatwg-fetch/tests/expected/.head.js.swp deleted file mode 100644 index 336e66ecb4951f14d99a322689298c0c2e2e6874..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI&F>ll`6bEn@bzz`XFtWISbUBH{Jy_tXB2j?~Lq!LQV5`q@^Qq!+QmoJQriz+|TQ5g|+pbYwCPMLHmjFx3_{EuRni^3WLS3#hQ zNBQF$2ag_3Hq&wM-QD1~Zyj8PljDpKfB*y_009U<00Izzz#tIkE9^7fUmMn|!@ROI z4@*oCfB*y_009U<00Izz00bZa0SH_|0a-FOxk=ysX{7J}zyJULr1e)Cc6hcy^N%&g zzSF=30SG_<0uX=z1Rwwb2tWV=5V#ZqirUIuqp3^1$`1Fv{#fh9l;1y-O;eOI$|Abb zg`&~6ivJU9&Uydl;dqN(FO;PI^eh|m?Wf#!P1A2iqirU`sZ~7lI`j`;&r%zFAw#Gu zn|2@YGoI?0a=DOo Object.assign(res, { data: await res.json() })) .catch(() => null); -console.log('\nGET /todos ->', all.status); -console.log(`Preview: ${all.data.todos.length} todos`); +console.log('\nDELETE /todos1/1 ->', deletedTodo); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/delete.js b/recipes/axios-to-whatwg-fetch/tests/expected/delete.js index 9925bcfa..911eaca1 100644 --- a/recipes/axios-to-whatwg-fetch/tests/expected/delete.js +++ b/recipes/axios-to-whatwg-fetch/tests/expected/delete.js @@ -1,7 +1,6 @@ -const base = 'https://dummyjson.com/todos'; +const base = 'https://dummyjson.com/todos/1'; -const all = await fetch(base, { method: 'DELETE' }) +const deletedTodo = await fetch(base, { method: 'DELETE' }) .then(async (res) => Object.assign(res, { data: await res.json() })) .catch(() => null); -console.log('\nGET /todos ->', all.status); -console.log(`Preview: ${all.data.todos.length} todos`); +console.log('\nDELETE /todos ->', deletedTodo); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/head-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/head-with-config.js index bf7685f5..e6db16bc 100644 --- a/recipes/axios-to-whatwg-fetch/tests/expected/head-with-config.js +++ b/recipes/axios-to-whatwg-fetch/tests/expected/head-with-config.js @@ -1,8 +1,7 @@ + const all = await fetch('https://dummyjson.com/todos', { method: 'HEAD', headers: { 'Content-Type': 'application/json' }, }) .then(async (res) => Object.assign(res, { data: await res.json() })) .catch(() => null); -console.log('\nGET /todos ->', all.status); -console.log(`Preview: ${all.data.todos.length} todos`); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/head.js b/recipes/axios-to-whatwg-fetch/tests/expected/head.js index 22a91ca6..91b01d94 100644 --- a/recipes/axios-to-whatwg-fetch/tests/expected/head.js +++ b/recipes/axios-to-whatwg-fetch/tests/expected/head.js @@ -2,5 +2,3 @@ const all = await fetch('https://dummyjson.com/todos', { method: 'HEAD' }) .then(async (res) => Object.assign(res, { data: await res.json() })) .catch(() => null); -console.log('\nGET /todos ->', all.status); -console.log(`Preview: ${all.data.todos.length} todos`); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/options-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/options-with-config.js index afbd16b2..bd97b59b 100644 --- a/recipes/axios-to-whatwg-fetch/tests/expected/options-with-config.js +++ b/recipes/axios-to-whatwg-fetch/tests/expected/options-with-config.js @@ -1,3 +1,4 @@ + const all = await fetch('https://dummyjson.com/todos', { method: 'OPTIONS', headers: { 'Content-Type': 'application/json' }, diff --git a/recipes/axios-to-whatwg-fetch/tests/input/delete-with-config.js b/recipes/axios-to-whatwg-fetch/tests/input/delete-with-config.js index bb3c17dc..5219afa7 100644 --- a/recipes/axios-to-whatwg-fetch/tests/input/delete-with-config.js +++ b/recipes/axios-to-whatwg-fetch/tests/input/delete-with-config.js @@ -1,7 +1,6 @@ import axios from 'axios'; -const all = await axios.delete('https://dummyjson.com/todos', { +const deletedTodo = await axios.delete('https://dummyjson.com/todos/1', { headers: { 'Content-Type': 'application/json' }, }); -console.log('\nGET /todos ->', all.status); -console.log(`Preview: ${all.data.todos.length} todos`); +console.log('\nDELETE /todos1/1 ->', deletedTodo); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/delete.js b/recipes/axios-to-whatwg-fetch/tests/input/delete.js index e901a4e6..95d91c94 100644 --- a/recipes/axios-to-whatwg-fetch/tests/input/delete.js +++ b/recipes/axios-to-whatwg-fetch/tests/input/delete.js @@ -1,6 +1,5 @@ import axios from 'axios'; -const base = 'https://dummyjson.com/todos'; +const base = 'https://dummyjson.com/todos/1'; -const all = await axios.delete(base); -console.log('\nGET /todos ->', all.status); -console.log(`Preview: ${all.data.todos.length} todos`); +const deletedTodo = await axios.delete(base); +console.log('\nDELETE /todos ->', deletedTodo); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/head-with-config.js b/recipes/axios-to-whatwg-fetch/tests/input/head-with-config.js index 35b9b706..fea04ab6 100644 --- a/recipes/axios-to-whatwg-fetch/tests/input/head-with-config.js +++ b/recipes/axios-to-whatwg-fetch/tests/input/head-with-config.js @@ -3,5 +3,3 @@ import axios from 'axios'; const all = await axios.head('https://dummyjson.com/todos', { headers: { 'Content-Type': 'application/json' }, }); -console.log('\nGET /todos ->', all.status); -console.log(`Preview: ${all.data.todos.length} todos`); From 335b8011fc81c28f8199918ebc64b04e15067df5 Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Sun, 7 Sep 2025 11:47:59 +0100 Subject: [PATCH 08/20] wip --- recipes/axios-to-whatwg-fetch/src/workflow.ts | 80 +++++++++++++------ .../tests/expected/delete-with-config.js | 2 +- .../tests/expected/get-with-config.js | 4 +- .../tests/expected/head-with-config.js | 2 +- .../tests/expected/options-with-config.js | 2 +- .../tests/expected/post.js | 13 +++ .../axios-to-whatwg-fetch/tests/input/post.js | 9 +++ recipes/axios-to-whatwg-fetch/tests/post.js | 11 +++ 8 files changed, 92 insertions(+), 31 deletions(-) create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/post.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/post.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/post.js diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts index fd1a478d..3c3bb3c8 100644 --- a/recipes/axios-to-whatwg-fetch/src/workflow.ts +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -13,6 +13,7 @@ import { resolveBindingPath } from '@nodejs/codemod-utils/ast-grep/resolve-bindi import { removeBinding } from '@nodejs/codemod-utils/ast-grep/remove-binding'; import { removeLines } from '@nodejs/codemod-utils/ast-grep/remove-lines'; import dedent from 'dedent'; +import os from 'node:os'; type BindingToReplace = { rule: Rule; @@ -21,10 +22,14 @@ type BindingToReplace = { replaceFn: (arg: SgNode[]) => string; }; -const transformOptionsNode = (options: SgNode, prepend?: string) => { - if (!options) return ''; - - const headers = options.find({ +type CreateOptionsType = { + oldOptions?: SgNode; + method?: string; + body?: string; +}; +const createOptions = ({ oldOptions, method, body }: CreateOptionsType) => { + if (!oldOptions && !method && !body) return ''; + const headers = oldOptions?.find({ rule: { kind: 'object', inside: { @@ -38,18 +43,25 @@ const transformOptionsNode = (options: SgNode, prepend?: string) => { }, }); - if (headers?.kind()) { - if (prepend) { - return dedent.withOptions({ alignValues: true })`{ - ${prepend} - headers: ${headers.text()}, - }`; - } + const options = []; + + if (method) { + options.push(`method: '${method}'`); + } - return dedent.withOptions({ alignValues: true })`{ - headers: ${headers.text()}, - }`; + if (headers) { + options.push(`headers: ${headers?.text()}`); } + + if (body) { + options.push(`body: JSON.stringify(${body})`); + } + + if (options.length === 1) return `{ ${options.toString()} }`; + + return dedent.withOptions({ alignValues: true })`{ + ${options.join(`,${os.EOL}`)} + }`; }; const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = @@ -62,7 +74,9 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = oldBind: '$.get', replaceFn: (args) => { const url = args.length > 0 && args[0]; - const options = transformOptionsNode(args[1]); + const options = createOptions({ + oldOptions: args[1], + }); return dedent.withOptions({ alignValues: true })` fetch(${url.text()}${options ? `, ${options}` : ''}) .then(async (res) => Object.assign(res, { data: await res.json() })) @@ -72,7 +86,20 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = }, { oldBind: '$.post', - replaceFn: (arg: FunctionArgs) => `console.error(${arg})`, + replaceFn: (args) => { + console.log('pOST'); + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[2], + method: 'POST', + body: args[1]?.text(), + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; + }, }, { oldBind: '$.put', @@ -86,9 +113,10 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = oldBind: '$.delete', replaceFn: (args) => { const url = args.length > 0 && args[0]; - const options = args[1] - ? transformOptionsNode(args[1], `method: 'DELETE',`) - : `{ method: 'DELETE' }`; + const options = createOptions({ + oldOptions: args[1], + method: 'DELETE', + }); return dedent.withOptions({ alignValues: true })` fetch(${url.text()}, ${options}) .then(async (res) => Object.assign(res, { data: await res.json() })) @@ -100,9 +128,10 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = oldBind: '$.head', replaceFn: (args) => { const url = args.length > 0 && args[0]; - const options = args[1] - ? transformOptionsNode(args[1], `method: 'HEAD',`) - : `{ method: 'HEAD' }`; + const options = createOptions({ + oldOptions: args[1], + method: 'HEAD', + }); return dedent.withOptions({ alignValues: true })` fetch(${url.text()}, ${options}) .then(async (res) => Object.assign(res, { data: await res.json() })) @@ -114,9 +143,10 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = oldBind: '$.options', replaceFn: (args) => { const url = args.length > 0 && args[0]; - const options = args[1] - ? transformOptionsNode(args[1], `method: 'OPTIONS',`) - : `{ method: 'OPTIONS' }`; + const options = createOptions({ + oldOptions: args[1], + method: 'OPTIONS', + }); return dedent.withOptions({ alignValues: true })` fetch(${url.text()}, ${options}) .then(async (res) => Object.assign(res, { data: await res.json() })) diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/delete-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/delete-with-config.js index 0e5ea6b1..833410a4 100644 --- a/recipes/axios-to-whatwg-fetch/tests/expected/delete-with-config.js +++ b/recipes/axios-to-whatwg-fetch/tests/expected/delete-with-config.js @@ -1,7 +1,7 @@ const deletedTodo = await fetch('https://dummyjson.com/todos/1', { method: 'DELETE', - headers: { 'Content-Type': 'application/json' }, + headers: { 'Content-Type': 'application/json' } }) .then(async (res) => Object.assign(res, { data: await res.json() })) .catch(() => null); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/get-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/get-with-config.js index 03a3f88a..d4718e39 100644 --- a/recipes/axios-to-whatwg-fetch/tests/expected/get-with-config.js +++ b/recipes/axios-to-whatwg-fetch/tests/expected/get-with-config.js @@ -1,7 +1,5 @@ -const all = await fetch("https://dummyjson.com/todos", { - headers: { "Content-Type": "application/json" }, -}) +const all = await fetch("https://dummyjson.com/todos", { headers: { "Content-Type": "application/json" } }) .then(async (res) => Object.assign(res, { data: await res.json() })) .catch(() => null); console.log("\nGET /todos ->", all.status); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/head-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/head-with-config.js index e6db16bc..cd2390ce 100644 --- a/recipes/axios-to-whatwg-fetch/tests/expected/head-with-config.js +++ b/recipes/axios-to-whatwg-fetch/tests/expected/head-with-config.js @@ -1,7 +1,7 @@ const all = await fetch('https://dummyjson.com/todos', { method: 'HEAD', - headers: { 'Content-Type': 'application/json' }, + headers: { 'Content-Type': 'application/json' } }) .then(async (res) => Object.assign(res, { data: await res.json() })) .catch(() => null); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/options-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/options-with-config.js index bd97b59b..54afce4e 100644 --- a/recipes/axios-to-whatwg-fetch/tests/expected/options-with-config.js +++ b/recipes/axios-to-whatwg-fetch/tests/expected/options-with-config.js @@ -1,7 +1,7 @@ const all = await fetch('https://dummyjson.com/todos', { method: 'OPTIONS', - headers: { 'Content-Type': 'application/json' }, + headers: { 'Content-Type': 'application/json' } }) .then(async (res) => Object.assign(res, { data: await res.json() })) .catch(() => null); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/post.js b/recipes/axios-to-whatwg-fetch/tests/expected/post.js new file mode 100644 index 00000000..3c34eec6 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/post.js @@ -0,0 +1,13 @@ +const base = 'https://dummyjson.com/todos/add'; + +const todoCreated = await fetch(base, { + method: 'POST', + body: JSON.stringify({ + todo: 'Use DummyJSON in the project', + completed: false, + userId: 5, + }) +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log('\nPOST /todos ->', todoCreated); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/post.js b/recipes/axios-to-whatwg-fetch/tests/input/post.js new file mode 100644 index 00000000..2db408de --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/post.js @@ -0,0 +1,9 @@ +import axios from 'axios'; +const base = 'https://dummyjson.com/todos/add'; + +const todoCreated = await axios.post(base, { + todo: 'Use DummyJSON in the project', + completed: false, + userId: 5, +}); +console.log('\nPOST /todos ->', todoCreated); diff --git a/recipes/axios-to-whatwg-fetch/tests/post.js b/recipes/axios-to-whatwg-fetch/tests/post.js new file mode 100644 index 00000000..4b5a44d7 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/post.js @@ -0,0 +1,11 @@ +const base = "https://dummyjson.com/todos/add"; + +const todoCreated = await fetch(base, { method: 'DELETE', +body: JSON.stringify({ +todo: "Use DummyJSON in the project", +completed: false, +userId: 5, +}), }) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log("\nPOST /todos ->", todoCreated); From 398aa8ed7526da8bc3ae834c37f4a80d1ae4760d Mon Sep 17 00:00:00 2001 From: Bruno Rodrigues Date: Sun, 7 Sep 2025 12:26:23 +0100 Subject: [PATCH 09/20] wip --- recipes/axios-to-whatwg-fetch/src/workflow.ts | 29 +++++++++++++++++-- .../tests/expected/post-with-config.js | 15 ++++++++++ .../tests/expected/put-with-config.js | 15 ++++++++++ .../tests/expected/put.js | 13 +++++++++ .../tests/input/post-with-config.js | 15 ++++++++++ .../tests/input/put-with-config.js | 15 ++++++++++ .../axios-to-whatwg-fetch/tests/input/put.js | 9 ++++++ recipes/axios-to-whatwg-fetch/tests/post.js | 11 ------- 8 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/post-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/put-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/put.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/post-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/put-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/put.js delete mode 100644 recipes/axios-to-whatwg-fetch/tests/post.js diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts index 3c3bb3c8..682e0902 100644 --- a/recipes/axios-to-whatwg-fetch/src/workflow.ts +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -87,7 +87,6 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = { oldBind: '$.post', replaceFn: (args) => { - console.log('pOST'); const url = args.length > 0 && args[0]; const options = createOptions({ oldOptions: args[2], @@ -103,11 +102,35 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = }, { oldBind: '$.put', - replaceFn: (arg: FunctionArgs) => `console.error(${arg})`, + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[2], + method: 'PUT', + body: args[1]?.text(), + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; + }, }, { oldBind: '$.patch', - replaceFn: (arg: FunctionArgs) => `console.error(${arg})`, + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[2], + method: 'PATCH', + body: args[1]?.text(), + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; + }, }, { oldBind: '$.delete', diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/post-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/post-with-config.js new file mode 100644 index 00000000..16c40a30 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/post-with-config.js @@ -0,0 +1,15 @@ +const base = 'https://dummyjson.com/todos/add'; + +const createdTodo = await fetch(base, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + todo: 'Use DummyJSON in the project', + completed: false, + userId: 5, + }) + +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log('\nPOST /todos/add ->', createdTodo); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/put-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/put-with-config.js new file mode 100644 index 00000000..8cbff890 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/put-with-config.js @@ -0,0 +1,15 @@ +const base = 'https://dummyjson.com/todos/1'; + +const updatedTodo = await fetch(base, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + todo: 'Use DummyJSON in the project', + completed: false, + userId: 5, + }) + +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log('\nPUT /todos/1 ->', updatedTodo); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/put.js b/recipes/axios-to-whatwg-fetch/tests/expected/put.js new file mode 100644 index 00000000..329c12d2 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/put.js @@ -0,0 +1,13 @@ +const base = 'https://dummyjson.com/todos/1'; + +const updatedTodo = await fetch(base, { + method: 'PUT', + body: JSON.stringify({ + todo: 'Use DummyJSON in the project', + completed: false, + userId: 5, + }) +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log('\nPUT /todos/1 ->', updatedTodo); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/post-with-config.js b/recipes/axios-to-whatwg-fetch/tests/input/post-with-config.js new file mode 100644 index 00000000..f887b607 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/post-with-config.js @@ -0,0 +1,15 @@ +import axios from 'axios'; +const base = 'https://dummyjson.com/todos/add'; + +const createdTodo = await axios.post( + base, + { + todo: 'Use DummyJSON in the project', + completed: false, + userId: 5, + }, + { + headers: { 'Content-Type': 'application/json' }, + }, +); +console.log('\nPOST /todos/add ->', createdTodo); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/put-with-config.js b/recipes/axios-to-whatwg-fetch/tests/input/put-with-config.js new file mode 100644 index 00000000..efc0e103 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/put-with-config.js @@ -0,0 +1,15 @@ +import axios from 'axios'; +const base = 'https://dummyjson.com/todos/1'; + +const updatedTodo = await axios.put( + base, + { + todo: 'Use DummyJSON in the project', + completed: false, + userId: 5, + }, + { + headers: { 'Content-Type': 'application/json' }, + }, +); +console.log('\nPUT /todos/1 ->', updatedTodo); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/put.js b/recipes/axios-to-whatwg-fetch/tests/input/put.js new file mode 100644 index 00000000..d2c98b6d --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/put.js @@ -0,0 +1,9 @@ +import axios from 'axios'; +const base = 'https://dummyjson.com/todos/1'; + +const updatedTodo = await axios.put(base, { + todo: 'Use DummyJSON in the project', + completed: false, + userId: 5, +}); +console.log('\nPUT /todos/1 ->', updatedTodo); diff --git a/recipes/axios-to-whatwg-fetch/tests/post.js b/recipes/axios-to-whatwg-fetch/tests/post.js deleted file mode 100644 index 4b5a44d7..00000000 --- a/recipes/axios-to-whatwg-fetch/tests/post.js +++ /dev/null @@ -1,11 +0,0 @@ -const base = "https://dummyjson.com/todos/add"; - -const todoCreated = await fetch(base, { method: 'DELETE', -body: JSON.stringify({ -todo: "Use DummyJSON in the project", -completed: false, -userId: 5, -}), }) - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null); -console.log("\nPOST /todos ->", todoCreated); From 667a821d328d2b35ff6c744cdd286a13e2afa55f Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Sat, 8 Nov 2025 12:37:53 +0100 Subject: [PATCH 10/20] Update --- recipes/axios-to-whatwg-fetch/README.md | 40 ++----------- recipes/axios-to-whatwg-fetch/src/workflow.ts | 60 +++++++++---------- 2 files changed, 32 insertions(+), 68 deletions(-) diff --git a/recipes/axios-to-whatwg-fetch/README.md b/recipes/axios-to-whatwg-fetch/README.md index 555d30ba..89c3508a 100644 --- a/recipes/axios-to-whatwg-fetch/README.md +++ b/recipes/axios-to-whatwg-fetch/README.md @@ -1,41 +1,11 @@ -# `util.print, util.puts, util.debug, util.error` DEP0026,DEP0027,DEP0028,DEP0029 +# axios-to-whatwg-fetch -This recipe transforms the usage of log functions from util, `print`, `puts`, `debug`, `error` to use `console.log()` or `console.error()`. +This recipe transforms the usage of [axios](https://axios-http.com/) to use the native Fetch API. ## Example -**Before:** +TODO -```js -const util = require("node:util"); +## Limitations -util.print("Hello world"); -util.puts("Hello world"); -util.debug("Hello world"); -util.error("Hello world"); -``` - -**After:** - -```js -console.log("Hello world"); -console.log("Hello world"); -console.error("Hello world"); -console.error("Hello world"); -``` - -**Before:** - -```js -const { print, error } = require("node:util"); - -print("Application started"); -error("Processing request"); -``` - -After: - -```js -console.log("Application started"); -console.error("Processing request"); -``` +TODO diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts index 682e0902..87d291b1 100644 --- a/recipes/axios-to-whatwg-fetch/src/workflow.ts +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -1,32 +1,37 @@ +import dedent from 'dedent'; +import { EOL } from 'node:os'; +import { getNodeRequireCalls } from '@nodejs/codemod-utils/ast-grep/require-call'; +import { getNodeImportStatements } from '@nodejs/codemod-utils/ast-grep/import-statement'; +import { resolveBindingPath } from '@nodejs/codemod-utils/ast-grep/resolve-binding-path'; +import { removeBinding } from '@nodejs/codemod-utils/ast-grep/remove-binding'; +import { removeLines } from '@nodejs/codemod-utils/ast-grep/remove-lines'; import type { Edit, - Kinds, Range, Rule, SgNode, SgRoot, - TypesMap, } from '@codemod.com/jssg-types/main'; -import { getNodeRequireCalls } from '@nodejs/codemod-utils/ast-grep/require-call'; -import { getNodeImportStatements } from '@nodejs/codemod-utils/ast-grep/import-statement'; -import { resolveBindingPath } from '@nodejs/codemod-utils/ast-grep/resolve-binding-path'; -import { removeBinding } from '@nodejs/codemod-utils/ast-grep/remove-binding'; -import { removeLines } from '@nodejs/codemod-utils/ast-grep/remove-lines'; -import dedent from 'dedent'; -import os from 'node:os'; +import type Js from '@codemod.com/jssg-types/langs/javascript'; type BindingToReplace = { - rule: Rule; - node: SgNode>; + rule: Rule; + node: SgNode; binding: string; - replaceFn: (arg: SgNode[]) => string; + replaceFn: (arg: SgNode[]) => string; }; type CreateOptionsType = { - oldOptions?: SgNode; + oldOptions?: SgNode; method?: string; body?: string; }; + +/** + * + * @param param0 + * @returns + */ const createOptions = ({ oldOptions, method, body }: CreateOptionsType) => { if (!oldOptions && !method && !body) return ''; const headers = oldOptions?.find({ @@ -60,7 +65,7 @@ const createOptions = ({ oldOptions, method, body }: CreateOptionsType) => { if (options.length === 1) return `{ ${options.toString()} }`; return dedent.withOptions({ alignValues: true })`{ - ${options.join(`,${os.EOL}`)} + ${options.join(`,${EOL}`)} }`; }; @@ -180,29 +185,17 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = ]; /* - * Transforms `util.requestj($$$ARG)` usage to `console.log($$$ARG)`. - * Transforms `util.get($$$ARG)` usage to `console.log($$$ARG)`. - * Transforms `util.post($$$ARG)` usage to `console.error($$$ARG)`. - * Transforms `util.put($$$ARG)` usage to `console.error($$$ARG)`. - * - * Steps: - * - * Locate all `util.print|puts|debug|error` import imports, noting the replacement rule, import node, and binding name. - * - * For each binding, replace calls to util.print|puts|debug|error($$$ARG) with the new console.log|error format, - * and determine if the import line should be updated or removed. - * - * Apply all changes, removing or updating the import line as needed. */ -export default function transform(root: SgRoot): string | null { +export default function transform(root: SgRoot): string | null { const rootNode = root.root(); const edits: Edit[] = []; const linesToRemove: Range[] = []; const bindsToReplace: BindingToReplace[] = []; - const nodeRequires = getNodeRequireCalls(root, 'axios'); - const nodeImports = getNodeImportStatements(root, 'axios'); - const importRequireStatement = [...nodeRequires, ...nodeImports]; + const importRequireStatement = [ + ...getNodeRequireCalls(root, 'axios'), + ...getNodeImportStatements(root, 'axios'), + ]; if (!importRequireStatement.length) return null; @@ -235,9 +228,10 @@ export default function transform(root: SgRoot): string | null { const replace = match.replace(bind.replaceFn(args)); edits.push(replace); + // @brunocroh it's your code idk what should I (@AugustinMauroy) do here // const replace = match.replace(bind.replaceFn(argsStr)); // edits.push(replace); - // + const result = removeBinding(bind.node, bind.binding.split('.').at(0)); if (result?.lineToRemove) { @@ -250,7 +244,7 @@ export default function transform(root: SgRoot): string | null { } } - if (!edits.length) return; + if (!edits.length) return null; const sourceCode = rootNode.commitEdits(edits); From c828c6017de90a2f014d6a024c73b6b58d8fa1b1 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Sat, 8 Nov 2025 12:39:04 +0100 Subject: [PATCH 11/20] add jsdoc --- recipes/axios-to-whatwg-fetch/src/workflow.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts index 87d291b1..9addf4ae 100644 --- a/recipes/axios-to-whatwg-fetch/src/workflow.ts +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -28,9 +28,13 @@ type CreateOptionsType = { }; /** + * Generates options for the Fetch API based on the provided parameters. * - * @param param0 - * @returns + * @param {Object} param0 - The parameters for creating options. + * @param {SgNode} [param0.oldOptions] - The old options node to extract headers from. + * @param {string} [param0.method] - The HTTP method to use (e.g., 'POST', 'GET'). + * @param {string} [param0.body] - The body content to include in the request. + * @returns {string} The generated options string for the Fetch API. */ const createOptions = ({ oldOptions, method, body }: CreateOptionsType) => { if (!oldOptions && !method && !body) return ''; @@ -184,7 +188,11 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = }, ]; -/* +/** + * Transforms the AST root by replacing axios bindings with Fetch API calls. + * + * @param {SgRoot} root - The root of the AST to transform. + * @returns {string | null} The transformed source code or null if no changes were made. */ export default function transform(root: SgRoot): string | null { const rootNode = root.root(); From 8a5629ae6a9a22f188904b049a6b3cddf8e70061 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Sat, 8 Nov 2025 12:49:31 +0100 Subject: [PATCH 12/20] write readme --- recipes/axios-to-whatwg-fetch/README.md | 105 ++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 6 deletions(-) diff --git a/recipes/axios-to-whatwg-fetch/README.md b/recipes/axios-to-whatwg-fetch/README.md index 89c3508a..7a076bbd 100644 --- a/recipes/axios-to-whatwg-fetch/README.md +++ b/recipes/axios-to-whatwg-fetch/README.md @@ -1,11 +1,104 @@ -# axios-to-whatwg-fetch +# Axios to WHATWG Fetch Codemod -This recipe transforms the usage of [axios](https://axios-http.com/) to use the native Fetch API. +## Description -## Example +This codemod transforms code using Axios to leverage the WHATWG Fetch API, which is now natively available in Node.js. By replacing Axios with Fetch, you can reduce dependencies, mitigate risks, and improve performance. -TODO +## Supported Transformations -## Limitations +The codemod supports the following Axios methods and converts them to their Fetch equivalents: + +- `axios.request(config)` +- `axios.get(url[, config])` +- `axios.delete(url[, config])` +- `axios.head(url[, config])` +- `axios.options(url[, config])` +- `axios.post(url[, data[, config]])` +- `axios.put(url[, data[, config]])` +- `axios.patch(url[, data[, config]])` + +### Examples + +#### GET Request + +```diff + const base = 'https://dummyjson.com/todos'; + +- const all = await axios.get(base); ++ const all = await fetch(base).then(async (res) => Object.assign(res, { data: await res.json() })).catch(() => null); + console.log('\nGET /todos ->', all.status); + console.log(`Preview: ${all.data.todos.length} todos`); +``` + +#### POST Request + +```diff + const base = 'https://dummyjson.com/todos'; + +- const created = await axios.post( +- `${base}/add`, { +- todo: 'Use DummyJSON in the project', +- completed: false, +- userId: 5, +- }, { +- headers: { 'Content-Type': 'application/json' } +- } +- ); ++ const created = await fetch(`${base}/add`, { ++ method: 'POST', ++ headers: { 'Content-Type': 'application/json' }, ++ body: JSON.stringify({ ++ todo: 'Use DummyJSON in the project', ++ completed: false, ++ userId: 5, ++ }), ++ }).then(async (res) => Object.assign(res, { data: await res.json() })); + console.log('\nPOST /todos/add ->', created.status); + console.log('Preview:', created.data?.id ? `created id ${created.data.id}` : JSON.stringify(created.data).slice(0,200)); +``` + +#### PUT Request + +```diff + const base = 'https://dummyjson.com/todos'; + +- const updatedPut = await axios.put( +- `${base}/1`, +- { completed: false }, +- { headers: { 'Content-Type': 'application/json' } } +- ); ++ const updatedPut = await fetch(`${base}/1`, { ++ method: 'PUT', ++ headers: { 'Content-Type': 'application/json' }, ++ body: JSON.stringify({ completed: false }), ++ }).then(async (res) => Object.assign(res, { data: await res.json() })); + console.log('\nPUT /todos/1 ->', updatedPut.status); + console.log('Preview:', updatedPut.data?.completed !== undefined ? `completed=${updatedPut.data.completed}` : JSON.stringify(updatedPut.data).slice(0,200)); +``` + +#### DELETE Request + +```diff + const base = 'https://dummyjson.com/todos'; + +- const deleted = await axios.delete(`${base}/1`); ++ const deleted = await fetch(`${base}/1`, { method: 'DELETE' }) ++ .then(async (res) => Object.assign(res, { data: await res.json() })); + console.log('\nDELETE /todos/1 ->', deleted.status); + console.log('Preview:', deleted.data ? JSON.stringify(deleted.data).slice(0,200) : typeof deleted.data); +``` + +## Unsupported APIs + +The following Axios methods are not supported by this codemod and will generate warnings: + +- `axios.postForm(url[, data[, config]])` +- `axios.putForm(url[, data[, config]])` +- `axios.patchForm(url[, data[, config]])` + +## References + +- [Fetch Spec](https://fetch.spec.whatwg.org) +- [Axios Documentation](https://axios-http.com) +- [Node.js Documentation](https://nodejs.org/docs/latest/api/globals.html#fetch) -TODO From ca6dc942d64dc8441b0c10e4132b8b6745cd933a Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Sat, 8 Nov 2025 12:49:51 +0100 Subject: [PATCH 13/20] test: correct white space --- recipes/axios-to-whatwg-fetch/package.json | 3 +-- .../axios-to-whatwg-fetch/tests/expected/post-with-config.js | 1 - .../axios-to-whatwg-fetch/tests/expected/put-with-config.js | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/recipes/axios-to-whatwg-fetch/package.json b/recipes/axios-to-whatwg-fetch/package.json index de2ef888..6d5db10e 100644 --- a/recipes/axios-to-whatwg-fetch/package.json +++ b/recipes/axios-to-whatwg-fetch/package.json @@ -4,8 +4,7 @@ "description": "Replace `axios` with `fetch`", "type": "module", "scripts": { - "test": "npx codemod jssg test -l typescript --ignore-whitespace ./src/workflow.ts ./", - "testu": "npx codemod jssg test -l typescript -u ./src/workflow.ts ./" + "test": "npx codemod jssg test -l typescript ./src/workflow.ts ./" }, "repository": { "type": "git", diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/post-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/post-with-config.js index 16c40a30..cff1e5d8 100644 --- a/recipes/axios-to-whatwg-fetch/tests/expected/post-with-config.js +++ b/recipes/axios-to-whatwg-fetch/tests/expected/post-with-config.js @@ -8,7 +8,6 @@ const createdTodo = await fetch(base, { completed: false, userId: 5, }) - }) .then(async (res) => Object.assign(res, { data: await res.json() })) .catch(() => null); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/put-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/put-with-config.js index 8cbff890..ae90c942 100644 --- a/recipes/axios-to-whatwg-fetch/tests/expected/put-with-config.js +++ b/recipes/axios-to-whatwg-fetch/tests/expected/put-with-config.js @@ -8,7 +8,6 @@ const updatedTodo = await fetch(base, { completed: false, userId: 5, }) - }) .then(async (res) => Object.assign(res, { data: await res.json() })) .catch(() => null); From 8cf7ab6ef3dec2ec7fd8bbc078a96cbea6907bad Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Sat, 8 Nov 2025 12:50:22 +0100 Subject: [PATCH 14/20] update dep --- package-lock.json | 3 ++- recipes/axios-to-whatwg-fetch/package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 705fa8bd..fb9d101b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1250,6 +1250,7 @@ "node_modules/@types/node": { "version": "24.10.0", "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -3316,7 +3317,7 @@ "dedent": "^1.7.0" }, "devDependencies": { - "@codemod.com/jssg-types": "^1.0.3" + "@codemod.com/jssg-types": "^1.0.9" } }, "recipes/buffer-atob-btoa": { diff --git a/recipes/axios-to-whatwg-fetch/package.json b/recipes/axios-to-whatwg-fetch/package.json index 6d5db10e..b1d1b183 100644 --- a/recipes/axios-to-whatwg-fetch/package.json +++ b/recipes/axios-to-whatwg-fetch/package.json @@ -16,7 +16,7 @@ "license": "MIT", "homepage": "https://github.com/nodejs/userland-migrations/blob/main/recipes/axios-to-whatwg-fetch/README.md", "devDependencies": { - "@codemod.com/jssg-types": "^1.0.3" + "@codemod.com/jssg-types": "^1.0.9" }, "dependencies": { "@nodejs/codemod-utils": "*", From 691931dcd8326ed4df8ffb9f7d045a22d67cbcb2 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Sat, 8 Nov 2025 13:11:35 +0100 Subject: [PATCH 15/20] wip --- recipes/axios-to-whatwg-fetch/src/workflow.ts | 108 +++++++++--------- .../tests/expected/patch.js | 14 +++ .../tests/expected/request.js | 14 +++ .../tests/input/patch.js | 10 ++ .../tests/input/request.js | 14 +++ .../src/fixtures/e2e/test.ts | 10 +- 6 files changed, 114 insertions(+), 56 deletions(-) create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/patch.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/request.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/patch.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/request.js diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts index 9addf4ae..72aef6ea 100644 --- a/recipes/axios-to-whatwg-fetch/src/workflow.ts +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -27,58 +27,15 @@ type CreateOptionsType = { body?: string; }; -/** - * Generates options for the Fetch API based on the provided parameters. - * - * @param {Object} param0 - The parameters for creating options. - * @param {SgNode} [param0.oldOptions] - The old options node to extract headers from. - * @param {string} [param0.method] - The HTTP method to use (e.g., 'POST', 'GET'). - * @param {string} [param0.body] - The body content to include in the request. - * @returns {string} The generated options string for the Fetch API. - */ -const createOptions = ({ oldOptions, method, body }: CreateOptionsType) => { - if (!oldOptions && !method && !body) return ''; - const headers = oldOptions?.find({ - rule: { - kind: 'object', - inside: { - kind: 'pair', - has: { - kind: 'property_identifier', - field: 'key', - regex: 'headers', - }, - }, - }, - }); - - const options = []; - - if (method) { - options.push(`method: '${method}'`); - } - - if (headers) { - options.push(`headers: ${headers?.text()}`); - } - - if (body) { - options.push(`body: JSON.stringify(${body})`); - } - - if (options.length === 1) return `{ ${options.toString()} }`; - - return dedent.withOptions({ alignValues: true })`{ - ${options.join(`,${EOL}`)} - }`; -}; +const unsupportedMethods = ['postForm', 'putForm', 'patchForm']; const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = [ - { + /*{ + It's should be migratable with codemod but not supported for now oldBind: '$.request', replaceFn: (arg) => `console.log(${arg})`, - }, + },*/ { oldBind: '$.get', replaceFn: (args) => { @@ -188,6 +145,52 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = }, ]; +/** + * Generates options for the Fetch API based on the provided parameters. + * + * @param {Object} param0 - The parameters for creating options. + * @param {SgNode} [param0.oldOptions] - The old options node to extract headers from. + * @param {string} [param0.method] - The HTTP method to use (e.g., 'POST', 'GET'). + * @param {string} [param0.body] - The body content to include in the request. + * @returns {string} The generated options string for the Fetch API. + */ +const createOptions = ({ oldOptions, method, body }: CreateOptionsType) => { + if (!oldOptions && !method && !body) return ''; + const headers = oldOptions?.find({ + rule: { + kind: 'object', + inside: { + kind: 'pair', + has: { + kind: 'property_identifier', + field: 'key', + regex: 'headers', + }, + }, + }, + }); + + const options = []; + + if (method) { + options.push(`method: '${method}'`); + } + + if (headers) { + options.push(`headers: ${headers?.text()}`); + } + + if (body) { + options.push(`body: JSON.stringify(${body})`); + } + + if (options.length === 1) return `{ ${options.toString()} }`; + + return dedent.withOptions({ alignValues: true })`{ + ${options.join(`,${EOL}`)} + }`; +}; + /** * Transforms the AST root by replacing axios bindings with Fetch API calls. * @@ -233,13 +236,16 @@ export default function transform(root: SgRoot): string | null { const argsAndCommaas = match.getMultipleMatches('ARG'); const args = argsAndCommaas.filter((arg) => arg.text() !== ','); + if (unsupportedMethods.includes(bind.binding.split('.').at(-1))) { + console.warn( + 'Un-migratable method has been found. Please revise this part of the code.', + ); + continue; + } + const replace = match.replace(bind.replaceFn(args)); edits.push(replace); - // @brunocroh it's your code idk what should I (@AugustinMauroy) do here - // const replace = match.replace(bind.replaceFn(argsStr)); - // edits.push(replace); - const result = removeBinding(bind.node, bind.binding.split('.').at(0)); if (result?.lineToRemove) { diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/patch.js b/recipes/axios-to-whatwg-fetch/tests/expected/patch.js new file mode 100644 index 00000000..1b1ad0fc --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/patch.js @@ -0,0 +1,14 @@ + +// Unsupported method: axios.patch +const base = 'https://dummyjson.com/todos/1'; + +const patchedTodo = await fetch(base, { + method: 'PATCH', + body: JSON.stringify({ + todo: 'Updated todo', + completed: true, + }) +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log('\nPATCH /todos/1 ->', patchedTodo); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/request.js b/recipes/axios-to-whatwg-fetch/tests/expected/request.js new file mode 100644 index 00000000..fcec5de6 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/request.js @@ -0,0 +1,14 @@ +import axios from 'axios'; + +// Unsupported method: axios.request +const base = 'https://dummyjson.com/todos/1'; + +const customRequest = await axios.request({ + url: base, + method: 'PATCH', + data: { + todo: 'Updated todo', + completed: true, + }, +}); +console.log('\nREQUEST /todos/1 ->', customRequest); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/patch.js b/recipes/axios-to-whatwg-fetch/tests/input/patch.js new file mode 100644 index 00000000..e4e92c2d --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/patch.js @@ -0,0 +1,10 @@ +import axios from 'axios'; + +// Unsupported method: axios.patch +const base = 'https://dummyjson.com/todos/1'; + +const patchedTodo = await axios.patch(base, { + todo: 'Updated todo', + completed: true, +}); +console.log('\nPATCH /todos/1 ->', patchedTodo); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/request.js b/recipes/axios-to-whatwg-fetch/tests/input/request.js new file mode 100644 index 00000000..fcec5de6 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/request.js @@ -0,0 +1,14 @@ +import axios from 'axios'; + +// Unsupported method: axios.request +const base = 'https://dummyjson.com/todos/1'; + +const customRequest = await axios.request({ + url: base, + method: 'PATCH', + data: { + todo: 'Updated todo', + completed: true, + }, +}); +console.log('\nREQUEST /todos/1 ->', customRequest); diff --git a/recipes/correct-ts-specifiers/src/fixtures/e2e/test.ts b/recipes/correct-ts-specifiers/src/fixtures/e2e/test.ts index 34df1387..8ce2f40b 100644 --- a/recipes/correct-ts-specifiers/src/fixtures/e2e/test.ts +++ b/recipes/correct-ts-specifiers/src/fixtures/e2e/test.ts @@ -3,17 +3,17 @@ import { URL } from 'node:url'; import { bar } from '@dep/bar'; import { foo } from 'foo'; -import { Bird } from './Bird'; +import { Bird } from './Bird/index.ts'; import { Cat } from './Cat.ts'; -import { Dog } from '…/Dog/index.mjs'; +import { Dog } from '…/Dog/index.mts'; import { baseUrl } from '#config.js'; -import { qux } from './qux.js'; +import { qux } from './qux.js/index.ts'; -export { Zed } from './zed'; +export type { Zed } from './zed.d.ts'; // should.js be unchanged -const nil = await import('./nil.js'); +const nil = await import('./nil.ts'); const bird = new Bird('Tweety'); const cat = new Cat('Milo'); From 4eb9d44931e331a87e3fe9659e4a1ad0c0b11b0b Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Sat, 8 Nov 2025 13:13:23 +0100 Subject: [PATCH 16/20] Update package-lock.json --- package-lock.json | 1011 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 981 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb9d101b..0e86f93d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,8 @@ }, "node_modules/@ast-grep/cli": { "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/cli/-/cli-0.25.7.tgz", + "integrity": "sha512-vklcPRFHPHkwHq05nb2Fuaj4BYNWxhr8GIdB6la090jWob9FdbM/Jz86vlQp2tRELb2rKzuHeksG8qDrbX4REg==", "hasInstallScript": true, "dependencies": { "detect-libc": "2.0.3" @@ -43,6 +45,8 @@ }, "node_modules/@ast-grep/cli-darwin-arm64": { "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/cli-darwin-arm64/-/cli-darwin-arm64-0.25.7.tgz", + "integrity": "sha512-dkj8hy32mWuQwCJUEpnKwTS8tLE+e7dhvu6is+v5Q6AumOVlcL6PJWQsyaA4vedDm6XOGK9+WnyFpCnV3b5ouA==", "cpu": [ "arm64" ], @@ -55,8 +59,106 @@ "node": ">= 10" } }, + "node_modules/@ast-grep/cli-darwin-x64": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/cli-darwin-x64/-/cli-darwin-x64-0.25.7.tgz", + "integrity": "sha512-FBdv7GH3llH5LI0S2yeqgQM5QEUHeoYMhw1pv+C439UeL5BBFFjI+LYVALciwsYzuq/DQDTnT2cM0JhYGajDLQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/cli-linux-arm64-gnu": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-0.25.7.tgz", + "integrity": "sha512-lsE+cSe4rFO8rvLhMM7PM3T83LlmV60H9dOH+1hq8thkWhLCL6vAJijEVWgAQDDvvZf3xnNVgG2GG4jOMfTuTQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/cli-linux-x64-gnu": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/cli-linux-x64-gnu/-/cli-linux-x64-gnu-0.25.7.tgz", + "integrity": "sha512-uuF5GXgeUZtBrftJJYuQU7PvDT7Q9fJkKKwpIscEfQqLndri1tdYzzT9jKj2taWFlhiCVqLaDEHsdfTeWaVjZQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/cli-win32-arm64-msvc": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-0.25.7.tgz", + "integrity": "sha512-GSWRjOnWybzNP5rnvPb6lQ7lSPoEIl64gk4uHE1h+a2nnFhT9REWTKFcmNB2aG8VmKEz1gu0pxpg9HmBe2OUBA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/cli-win32-ia32-msvc": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-0.25.7.tgz", + "integrity": "sha512-5p9PWbTeXaivQYixB+JkkpFKgY7G1Tm6R46Dhq6cHvKksiQ6lWlTOOmhl0QARtY7y3XP0MWuvjDEWCYrvYtO4A==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/cli-win32-x64-msvc": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/cli-win32-x64-msvc/-/cli-win32-x64-msvc-0.25.7.tgz", + "integrity": "sha512-WjsRuyKTCeGWpMhvobzU/6HaWbseENPl5mNMZIKs8gsCpkUyTUfvV8/A2W29oHCgbDWRtixYppWtd87Qjpm6cg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@ast-grep/lang-bash": { "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@ast-grep/lang-bash/-/lang-bash-0.0.4.tgz", + "integrity": "sha512-i9Zpv+phyy94dE5hv5xZT3qqJ6YINi/YhGGhmJvagl+uWBwEkD+Ve5cDqwH+AkGad2xy8+decNE4TkllJEGPww==", "dev": true, "hasInstallScript": true, "license": "ISC", @@ -74,6 +176,8 @@ }, "node_modules/@ast-grep/lang-json": { "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@ast-grep/lang-json/-/lang-json-0.0.4.tgz", + "integrity": "sha512-ig+N5Ub+gV3qEBOZeKOS3e2ms/pYPHfbtC2VyEcW9EnWfRwYChVDEaMtmv8UxnWbAIRIrxHoGUnCh0L4slIbRQ==", "dev": true, "hasInstallScript": true, "license": "ISC", @@ -91,6 +195,8 @@ }, "node_modules/@ast-grep/napi": { "version": "0.39.9", + "resolved": "https://registry.npmjs.org/@ast-grep/napi/-/napi-0.39.9.tgz", + "integrity": "sha512-qtLLQq1a3isK0iaq0Drl7Qt4PqeyjTrpFxNdA/20O/jYkGiA/oJA8DLMn1bzczsfjlUohe4dg39bpeAqG02uvA==", "dev": true, "license": "MIT", "engines": { @@ -110,6 +216,8 @@ }, "node_modules/@ast-grep/napi-darwin-arm64": { "version": "0.39.9", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-darwin-arm64/-/napi-darwin-arm64-0.39.9.tgz", + "integrity": "sha512-0gdBC2oPBkIBsh89yUXxJeK37QYRbp1qNZVuRGizT666ljgCw+2NIxHeQGNjwWuI0+g3exrd8FyqD3gMixRx3w==", "cpu": [ "arm64" ], @@ -123,13 +231,153 @@ "node": ">= 10" } }, + "node_modules/@ast-grep/napi-darwin-x64": { + "version": "0.39.9", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-darwin-x64/-/napi-darwin-x64-0.39.9.tgz", + "integrity": "sha512-7QuQNFwcVj71hDAMBErF+mVq2h92vUdHLKa/vq58HdRpix5G3DZqcTKoFjwhCNzc2wsNRAjV+BiIR01znQSxLA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-linux-arm64-gnu": { + "version": "0.39.9", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-arm64-gnu/-/napi-linux-arm64-gnu-0.39.9.tgz", + "integrity": "sha512-qXTjhagRYkPyHNACEzGi5q26OMRdSvLRRqi799oZaSDf96Xj+8tcB5+tFlH0NpqaP84GsZoQ15SfDXeoP4qdmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-linux-arm64-musl": { + "version": "0.39.9", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-arm64-musl/-/napi-linux-arm64-musl-0.39.9.tgz", + "integrity": "sha512-U9KVohyburVGEWiiREFq+iTxdMdSbRyXL+yzCVvGPmLPW4Ca4zpX9Cret4jCJBp8dljSIK0C7txXAc7fM+6rag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-linux-x64-gnu": { + "version": "0.39.9", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-x64-gnu/-/napi-linux-x64-gnu-0.39.9.tgz", + "integrity": "sha512-C5WwiNr/eE7lS0vl9bNdSXrsGIUAga2SaqV3G+ogVl9HeRU2jtGhv+3AgzGvYWj+PtnbtuZ2Nxkm10gEVPhv1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-linux-x64-musl": { + "version": "0.39.9", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-x64-musl/-/napi-linux-x64-musl-0.39.9.tgz", + "integrity": "sha512-KutzZSMhHP3P43nQ+kNSbuiDaqkCcdqOcXLnq28MRvS+qwvW+01dJ8eWRlpMJC9vCJmaJAZfI7xkNSp74WkdxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-win32-arm64-msvc": { + "version": "0.39.9", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-arm64-msvc/-/napi-win32-arm64-msvc-0.39.9.tgz", + "integrity": "sha512-S2kC6K9I7e70oMVn2FDICzVlz7SPZVWNCRKCBD+Dgy1OTn0byzmMLaGpjth3pqN93UCssEC03ooP3tuclS0JSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-win32-ia32-msvc": { + "version": "0.39.9", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-ia32-msvc/-/napi-win32-ia32-msvc-0.39.9.tgz", + "integrity": "sha512-n18Dqtc7O5q8ZM9gBNkvLd+ajdjLNraw4ZoIcHelI7TnTvh1m6zR3tUuHNxPhL+IJfdKx3ne7ATKlEeiSlMn4g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ast-grep/napi-win32-x64-msvc": { + "version": "0.39.9", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-x64-msvc/-/napi-win32-x64-msvc-0.39.9.tgz", + "integrity": "sha512-YOF7mO+6nvyRtMC179u82Vr1qIGOmoE1yjwr4cmAf7DVNd+vs42y9tbQGYwLmVY8M3Hg1PviB8XX7FQKewuOGQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@ast-grep/setup-lang": { "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@ast-grep/setup-lang/-/setup-lang-0.0.4.tgz", + "integrity": "sha512-us5L9CU4pc/yLQbO82v7gkpwa66qRoQRJ3P+s36EC6ZXiYpQVbd13PLgh9bQ/LhGljEb/pcli0uclN/+S3IMSw==", "dev": true, "license": "ISC" }, "node_modules/@babel/code-frame": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -142,6 +390,8 @@ }, "node_modules/@babel/compat-data": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -149,6 +399,8 @@ }, "node_modules/@babel/core": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "license": "MIT", "peer": true, "dependencies": { @@ -178,6 +430,8 @@ }, "node_modules/@babel/generator": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "license": "MIT", "dependencies": { "@babel/parser": "^7.28.5", @@ -192,6 +446,8 @@ }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "license": "MIT", "dependencies": { "@babel/types": "^7.27.3" @@ -202,6 +458,8 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "license": "MIT", "dependencies": { "@babel/compat-data": "^7.27.2", @@ -216,6 +474,8 @@ }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", + "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -235,6 +495,8 @@ }, "node_modules/@babel/helper-globals": { "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -242,6 +504,8 @@ }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.5", @@ -253,6 +517,8 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -264,6 +530,8 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -279,6 +547,8 @@ }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", "license": "MIT", "dependencies": { "@babel/types": "^7.27.1" @@ -289,6 +559,8 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -296,6 +568,8 @@ }, "node_modules/@babel/helper-replace-supers": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", "license": "MIT", "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", @@ -311,6 +585,8 @@ }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -322,6 +598,8 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -329,6 +607,8 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -336,6 +616,8 @@ }, "node_modules/@babel/helper-validator-option": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -343,6 +625,8 @@ }, "node_modules/@babel/helpers": { "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", @@ -354,6 +638,8 @@ }, "node_modules/@babel/parser": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "license": "MIT", "dependencies": { "@babel/types": "^7.28.5" @@ -367,6 +653,8 @@ }, "node_modules/@babel/plugin-syntax-flow": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz", + "integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -380,6 +668,8 @@ }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -393,6 +683,8 @@ }, "node_modules/@babel/plugin-syntax-typescript": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -406,6 +698,8 @@ }, "node_modules/@babel/plugin-transform-class-properties": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", @@ -420,6 +714,8 @@ }, "node_modules/@babel/plugin-transform-flow-strip-types": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.27.1.tgz", + "integrity": "sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -434,6 +730,8 @@ }, "node_modules/@babel/plugin-transform-modules-commonjs": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.27.1", @@ -448,6 +746,8 @@ }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -461,6 +761,8 @@ }, "node_modules/@babel/plugin-transform-optional-chaining": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", + "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -475,6 +777,8 @@ }, "node_modules/@babel/plugin-transform-private-methods": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", @@ -489,6 +793,8 @@ }, "node_modules/@babel/plugin-transform-typescript": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.5.tgz", + "integrity": "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -506,6 +812,8 @@ }, "node_modules/@babel/preset-flow": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.27.1.tgz", + "integrity": "sha512-ez3a2it5Fn6P54W8QkbfIyyIbxlXvcxyWHHvno1Wg0Ej5eiJY5hBb8ExttoIOJJk7V2dZE6prP7iby5q2aQ0Lg==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -521,6 +829,8 @@ }, "node_modules/@babel/preset-typescript": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -538,6 +848,8 @@ }, "node_modules/@babel/register": { "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.28.3.tgz", + "integrity": "sha512-CieDOtd8u208eI49bYl4z1J22ySFw87IGwE+IswFEExH7e3rLgKb0WNQeumnacQ1+VoDJLYI5QFA3AJZuyZQfA==", "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", @@ -555,6 +867,8 @@ }, "node_modules/@babel/template": { "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -567,6 +881,8 @@ }, "node_modules/@babel/traverse": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -583,6 +899,8 @@ }, "node_modules/@babel/types": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -594,6 +912,8 @@ }, "node_modules/@biomejs/biome": { "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.3.tgz", + "integrity": "sha512-zn/P1pRBCpDdhi+VNSMnpczOz9DnqzOA2c48K8xgxjDODvi5O8gs3a2H233rck/5HXpkFj6TmyoqVvxirZUnvg==", "dev": true, "license": "MIT OR Apache-2.0", "bin": { @@ -619,6 +939,8 @@ }, "node_modules/@biomejs/cli-darwin-arm64": { "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.3.tgz", + "integrity": "sha512-5+JtW6RKmjqL9un0UtHV0ezOslAyYBzyl5ZhYiu7GHesX2x8NCDl6tXYrenv9m7e1RLbkO5E5Kh04kseMtz6lw==", "cpu": [ "arm64" ], @@ -753,11 +1075,15 @@ }, "node_modules/@codemod.com/jssg-types": { "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@codemod.com/jssg-types/-/jssg-types-1.0.9.tgz", + "integrity": "sha512-j+O2nvYnBcmBy0mG5bSmBD7Cn7q3fgp4tI6aqIuF7pVu7j8Dgs45Ohgkpzx9mwqcmAE7vC9CEc8zQZOfwfICyw==", "dev": true, "license": "Apache-2.0" }, "node_modules/@codemod.com/workflow": { "version": "0.0.31", + "resolved": "https://registry.npmjs.org/@codemod.com/workflow/-/workflow-0.0.31.tgz", + "integrity": "sha512-8xmbxwjxr6d0ZUm3RS/eQqud2mUGXwQgf2v+YEjwQQVwOse6yShgoFljrg7ujvJlhzymivYloL0T0VSS9YubNw==", "license": "Apache-2.0", "dependencies": { "@ast-grep/cli": "^0.25.4", @@ -786,6 +1112,8 @@ }, "node_modules/@codemod.com/workflow/node_modules/@ast-grep/napi": { "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/napi/-/napi-0.25.7.tgz", + "integrity": "sha512-kDw/JNyOLttVbm2hl+55C9lXuUcuIFt31LQIpSptUkyTgI+2Cdqdeah2bNPe4/GQM2ysDjBDS4y1+9iQxMdJiw==", "license": "MIT", "engines": { "node": ">= 10" @@ -804,6 +1132,8 @@ }, "node_modules/@codemod.com/workflow/node_modules/@ast-grep/napi-darwin-arm64": { "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-darwin-arm64/-/napi-darwin-arm64-0.25.7.tgz", + "integrity": "sha512-qqI1JvB6ULgOUOVE3YviQNQ6KAYOnkiE8W5fNwVJGUgMkUuM8tUm1Nal3vfKCI7dnYgpcNlKxdTWGlbt7aHKNg==", "cpu": [ "arm64" ], @@ -816,8 +1146,138 @@ "node": ">= 10" } }, + "node_modules/@codemod.com/workflow/node_modules/@ast-grep/napi-darwin-x64": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-darwin-x64/-/napi-darwin-x64-0.25.7.tgz", + "integrity": "sha512-gq1Cf7US322ZJYPrVnAnn6eBLS6xi5catb5t99Wu6Rbm67XadEc81gtPTbPeNIu8FGgPjvKUc010rts2ZZbJeA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@codemod.com/workflow/node_modules/@ast-grep/napi-linux-arm64-gnu": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-arm64-gnu/-/napi-linux-arm64-gnu-0.25.7.tgz", + "integrity": "sha512-q+BzEC7wB7pkK+pQKbn4TVJThrEtvxjObz0okscPtxTNYvSJGv9jr3Nde5SYjdkfk8Ab4NgDMshVjKWVz2TSbQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@codemod.com/workflow/node_modules/@ast-grep/napi-linux-arm64-musl": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-arm64-musl/-/napi-linux-arm64-musl-0.25.7.tgz", + "integrity": "sha512-SEqZ6y0UhzmvZS938jIgR04kgHAW70hJ8yF4x9AkcqEhbeyqgElxIE7ve50ukDzs70fAKccdV8zYmebYN/7iPg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@codemod.com/workflow/node_modules/@ast-grep/napi-linux-x64-gnu": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-x64-gnu/-/napi-linux-x64-gnu-0.25.7.tgz", + "integrity": "sha512-8YuE/zTywTBb/iTm601JXTdWV2Redy9L9ab27aRD0hwX8FLmKUy8gK0fSo3xx+FyvSET49xkoR9tYdNaG2Wrkw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@codemod.com/workflow/node_modules/@ast-grep/napi-linux-x64-musl": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-x64-musl/-/napi-linux-x64-musl-0.25.7.tgz", + "integrity": "sha512-sT3eslR50IU6lHfqvq/c7vpxksJiB3h1NjEy1LpG+CYPuoLsQaB8j9OQlX8TqgVlDty/d/13cSls1Y3n/pm9xw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@codemod.com/workflow/node_modules/@ast-grep/napi-win32-arm64-msvc": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-arm64-msvc/-/napi-win32-arm64-msvc-0.25.7.tgz", + "integrity": "sha512-pDi9vyXzUbpiRwFTif6+R7ZIIVB1ZKcRUJLKSIPyYb39DcSX7aOuxQcSZderWnBrwPGxZKzdgztdQ16TuAz2IQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@codemod.com/workflow/node_modules/@ast-grep/napi-win32-ia32-msvc": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-ia32-msvc/-/napi-win32-ia32-msvc-0.25.7.tgz", + "integrity": "sha512-WFSNDMI5L9N9dK5zFQ6N900nhraOSYtKns/2p/EKZIKPBDXJSzzhT/jBakCSDix1GUs8K0XgkDoq2rXmuiBqXA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@codemod.com/workflow/node_modules/@ast-grep/napi-win32-x64-msvc": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-x64-msvc/-/napi-win32-x64-msvc-0.25.7.tgz", + "integrity": "sha512-HlsoVwQ9XrgNZ0JAmXgV5t8Ltx9tGyWZNS2UMY/2cvNU/SG9EpJLm1Bu9Mlk5seiJLbl28QTTbhZdfPKBzGTVQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@inquirer/external-editor": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", + "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", "license": "MIT", "dependencies": { "chardet": "^2.1.0", @@ -837,6 +1297,8 @@ }, "node_modules/@inquirer/figures": { "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.14.tgz", + "integrity": "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==", "license": "MIT", "engines": { "node": ">=18" @@ -844,6 +1306,8 @@ }, "node_modules/@isaacs/cliui": { "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -859,6 +1323,8 @@ }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -869,6 +1335,8 @@ }, "node_modules/@isaacs/cliui/node_modules/ansi-styles": { "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -879,10 +1347,14 @@ }, "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -898,6 +1370,8 @@ }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -911,6 +1385,8 @@ }, "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -926,6 +1402,8 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -934,6 +1412,8 @@ }, "node_modules/@jridgewell/remapping": { "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -942,6 +1422,8 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "license": "MIT", "engines": { "node": ">=6.0.0" @@ -949,10 +1431,14 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -961,6 +1447,8 @@ }, "node_modules/@kwsites/file-exists": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", "license": "MIT", "dependencies": { "debug": "^4.1.1" @@ -968,10 +1456,14 @@ }, "node_modules/@kwsites/promise-deferred": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", "license": "MIT" }, "node_modules/@nodejs-loaders/alias": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@nodejs-loaders/alias/-/alias-2.1.2.tgz", + "integrity": "sha512-thHaBXfGUbu7WpMqWt6Fw2xA6eN4faMl8kNFO8ufb2Ae4B9+9RhAg4vai1bFvzlBtnSTvUPU6qDz7sbpImFAbA==", "license": "ISC", "dependencies": { "json5": "^2.2.3" @@ -1074,6 +1566,8 @@ }, "node_modules/@octokit/auth-token": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", "license": "MIT", "engines": { "node": ">= 18" @@ -1081,6 +1575,8 @@ }, "node_modules/@octokit/core": { "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", + "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", "license": "MIT", "peer": true, "dependencies": { @@ -1098,6 +1594,8 @@ }, "node_modules/@octokit/endpoint": { "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", + "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", "license": "MIT", "dependencies": { "@octokit/types": "^13.1.0", @@ -1109,6 +1607,8 @@ }, "node_modules/@octokit/graphql": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", + "integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==", "license": "MIT", "dependencies": { "@octokit/request": "^8.4.1", @@ -1121,10 +1621,14 @@ }, "node_modules/@octokit/openapi-types": { "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", "license": "MIT" }, "node_modules/@octokit/plugin-paginate-rest": { "version": "11.4.4-cjs.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.4-cjs.2.tgz", + "integrity": "sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw==", "license": "MIT", "dependencies": { "@octokit/types": "^13.7.0" @@ -1138,6 +1642,8 @@ }, "node_modules/@octokit/plugin-request-log": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz", + "integrity": "sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==", "license": "MIT", "engines": { "node": ">= 18" @@ -1148,6 +1654,8 @@ }, "node_modules/@octokit/plugin-rest-endpoint-methods": { "version": "13.3.2-cjs.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.2-cjs.1.tgz", + "integrity": "sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ==", "license": "MIT", "dependencies": { "@octokit/types": "^13.8.0" @@ -1161,6 +1669,8 @@ }, "node_modules/@octokit/request": { "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", + "integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==", "license": "MIT", "dependencies": { "@octokit/endpoint": "^9.0.6", @@ -1174,6 +1684,8 @@ }, "node_modules/@octokit/request-error": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz", + "integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==", "license": "MIT", "dependencies": { "@octokit/types": "^13.1.0", @@ -1186,6 +1698,8 @@ }, "node_modules/@octokit/rest": { "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.1.2.tgz", + "integrity": "sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA==", "license": "MIT", "dependencies": { "@octokit/core": "^5.0.2", @@ -1199,6 +1713,8 @@ }, "node_modules/@octokit/types": { "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", "license": "MIT", "dependencies": { "@octokit/openapi-types": "^24.2.0" @@ -1206,6 +1722,8 @@ }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "license": "MIT", "optional": true, "engines": { @@ -1214,6 +1732,8 @@ }, "node_modules/@sindresorhus/slugify": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz", + "integrity": "sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==", "license": "MIT", "dependencies": { "@sindresorhus/transliterate": "^1.0.0", @@ -1228,6 +1748,8 @@ }, "node_modules/@sindresorhus/transliterate": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/transliterate/-/transliterate-1.6.0.tgz", + "integrity": "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==", "license": "MIT", "dependencies": { "escape-string-regexp": "^5.0.0" @@ -1241,6 +1763,8 @@ }, "node_modules/@types/jscodeshift": { "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@types/jscodeshift/-/jscodeshift-0.11.11.tgz", + "integrity": "sha512-d7CAfFGOupj5qCDqMODXxNz2/NwCv/Lha78ZFbnr6qpk3K98iSB8I+ig9ERE2+EeYML352VMRsjPyOpeA+04eQ==", "license": "MIT", "dependencies": { "ast-types": "^0.14.1", @@ -1249,14 +1773,17 @@ }, "node_modules/@types/node": { "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } }, "node_modules/@types/node-fetch": { "version": "2.6.13", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", "license": "MIT", "dependencies": { "@types/node": "*", @@ -1264,24 +1791,28 @@ } }, "node_modules/@typescript/native-preview": { - "version": "7.0.0-dev.20251107.1", + "version": "7.0.0-dev.20251108.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20251108.1.tgz", + "integrity": "sha512-v1SNmHbuTYMEIAAJZ5OgKY5kMIgDnS/aVTsP9FdR9FgqyZqgUbA2eHOjjMQHVw/XBLS5ZA32kkGt7cH8RzMlOA==", "dev": true, "license": "Apache-2.0", "bin": { "tsgo": "bin/tsgo.js" }, "optionalDependencies": { - "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20251107.1", - "@typescript/native-preview-darwin-x64": "7.0.0-dev.20251107.1", - "@typescript/native-preview-linux-arm": "7.0.0-dev.20251107.1", - "@typescript/native-preview-linux-arm64": "7.0.0-dev.20251107.1", - "@typescript/native-preview-linux-x64": "7.0.0-dev.20251107.1", - "@typescript/native-preview-win32-arm64": "7.0.0-dev.20251107.1", - "@typescript/native-preview-win32-x64": "7.0.0-dev.20251107.1" + "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20251108.1", + "@typescript/native-preview-darwin-x64": "7.0.0-dev.20251108.1", + "@typescript/native-preview-linux-arm": "7.0.0-dev.20251108.1", + "@typescript/native-preview-linux-arm64": "7.0.0-dev.20251108.1", + "@typescript/native-preview-linux-x64": "7.0.0-dev.20251108.1", + "@typescript/native-preview-win32-arm64": "7.0.0-dev.20251108.1", + "@typescript/native-preview-win32-x64": "7.0.0-dev.20251108.1" } }, "node_modules/@typescript/native-preview-darwin-arm64": { - "version": "7.0.0-dev.20251107.1", + "version": "7.0.0-dev.20251108.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20251108.1.tgz", + "integrity": "sha512-zdD59CWlvJum9hu7Rrb7xntGfkeTlki7Pql/s+Ls0sNSEGimjuJmU88ookUt2UMPLZ9S+RyGfjNbS7duhKuCIw==", "cpu": [ "arm64" ], @@ -1293,9 +1824,9 @@ ] }, "node_modules/@typescript/native-preview-darwin-x64": { - "version": "7.0.0-dev.20251107.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20251107.1.tgz", - "integrity": "sha512-RyRbmdD3Bzglvc8TDr9PFd7O5HaFwiuY7pRMj3S+C2G1uWRVEndVxliHHK+G7kbgcO/oPnRZPV3q+l988OxSRg==", + "version": "7.0.0-dev.20251108.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20251108.1.tgz", + "integrity": "sha512-nxs1vOm6jkwZoA56d6E2pllhYbxK2xNtspG2Yx9kswdp0aqh2jcja1EjMilHv4tnvNixRQvRWhoOz/BgWrxTig==", "cpu": [ "x64" ], @@ -1307,9 +1838,9 @@ ] }, "node_modules/@typescript/native-preview-linux-arm": { - "version": "7.0.0-dev.20251107.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20251107.1.tgz", - "integrity": "sha512-aCWp84B0VsgHOcZ6M8LmZuDFirVoqfOdB5l51h1onLqpNrui25I5g9D5COktdoB6BBWuYmnKjvIENo1EMUYZBg==", + "version": "7.0.0-dev.20251108.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20251108.1.tgz", + "integrity": "sha512-+1UuKod2SJZODnArwHViJEhZxgM1aHK5KCGlHJU61htq3jgNtRfouw4UEJRPTALCnGLun8ZpYuMsJUMeDFFIUQ==", "cpu": [ "arm" ], @@ -1321,9 +1852,9 @@ ] }, "node_modules/@typescript/native-preview-linux-arm64": { - "version": "7.0.0-dev.20251107.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20251107.1.tgz", - "integrity": "sha512-9qGIKu0nvfk5jEpt1MS7vn8gYKPfkcPrm+bOUSpfinsKrQKSCI8rIx0Nn+IyP4aLpSrfIxd0hgOkuYJy7J2NzA==", + "version": "7.0.0-dev.20251108.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20251108.1.tgz", + "integrity": "sha512-Er0P4Dt6fBM6MZidGBKGZs5PS2QHunRPNeIKCATJRcBMn8ymSBdi/IJK/wYVU62HW8CLb1Dt3FbueW5UptSAKA==", "cpu": [ "arm64" ], @@ -1335,9 +1866,9 @@ ] }, "node_modules/@typescript/native-preview-linux-x64": { - "version": "7.0.0-dev.20251107.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20251107.1.tgz", - "integrity": "sha512-3KgYypYr6brGvKstYgDvfuksF7SQTYDoaL3gD7F0VwRtDw9ttMAq7lm66h4FwH/H1aK1mNj8Unua4yI6rQkXSA==", + "version": "7.0.0-dev.20251108.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20251108.1.tgz", + "integrity": "sha512-3ijz+Uo8unENgq22nlyThf1JqhLVOwN881gomoAykALmspXX13aQwnDtbscnQRr1iQqMIrEyyRMwxfVevQkl9w==", "cpu": [ "x64" ], @@ -1349,9 +1880,9 @@ ] }, "node_modules/@typescript/native-preview-win32-arm64": { - "version": "7.0.0-dev.20251107.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20251107.1.tgz", - "integrity": "sha512-oT9mY4huqEEG0zvwl68tlnKjv+7v59uH32FXT6ZHQtT6XOvHV2DZfdcouoAS035pnempXkXLIDJnnqRrSMQa8Q==", + "version": "7.0.0-dev.20251108.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20251108.1.tgz", + "integrity": "sha512-Aeyrj7sdc6GBnLIw9o5dQPzEqrfsJodDYsi7RePm0QLvGVyxOeZVd9CcfdXqPKnD2goEJNOzFoTRyvvi7DjNUg==", "cpu": [ "arm64" ], @@ -1363,9 +1894,9 @@ ] }, "node_modules/@typescript/native-preview-win32-x64": { - "version": "7.0.0-dev.20251107.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20251107.1.tgz", - "integrity": "sha512-vXnu3tY2/5Zu1CzFaATZnzYijLt0mIxWNd12MDFFfk/5JcEBLHSibvnXinalyXviNbnfJIG8+gdbKrlbR3p89w==", + "version": "7.0.0-dev.20251108.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20251108.1.tgz", + "integrity": "sha512-rgfq7AZ7IFfE5EyDuHdpDEPUH3LEesyOVuIHE6YWOSqGOFnlzYbOf37VUYxQTIxFrR7IopgvM4pSDR3KeDcMjQ==", "cpu": [ "x64" ], @@ -1378,6 +1909,8 @@ }, "node_modules/abort-controller": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "license": "MIT", "dependencies": { "event-target-shim": "^5.0.0" @@ -1388,6 +1921,8 @@ }, "node_modules/agentkeepalive": { "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", "license": "MIT", "dependencies": { "humanize-ms": "^1.2.1" @@ -1398,6 +1933,8 @@ }, "node_modules/ansi-escapes": { "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "license": "MIT", "dependencies": { "type-fest": "^0.21.3" @@ -1411,6 +1948,8 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", "engines": { "node": ">=8" @@ -1418,6 +1957,8 @@ }, "node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -1431,6 +1972,8 @@ }, "node_modules/ast-types": { "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", "license": "MIT", "dependencies": { "tslib": "^2.0.1" @@ -1441,10 +1984,14 @@ }, "node_modules/asynckit": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, "node_modules/babel-core": { "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", "license": "MIT", "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -1452,13 +1999,19 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, "node_modules/base-64": { - "version": "0.1.0" + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" }, "node_modules/base64-js": { "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -1477,6 +2030,8 @@ }, "node_modules/baseline-browser-mapping": { "version": "2.8.25", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.25.tgz", + "integrity": "sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -1484,10 +2039,14 @@ }, "node_modules/before-after-hook": { "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", "license": "Apache-2.0" }, "node_modules/bl": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "license": "MIT", "dependencies": { "buffer": "^5.5.0", @@ -1497,6 +2056,8 @@ }, "node_modules/brace-expansion": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -1504,6 +2065,8 @@ }, "node_modules/braces": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -1514,6 +2077,8 @@ }, "node_modules/browserslist": { "version": "4.27.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", + "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", "funding": [ { "type": "opencollective", @@ -1546,6 +2111,8 @@ }, "node_modules/buffer": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "funding": [ { "type": "github", @@ -1568,10 +2135,14 @@ }, "node_modules/buffer-from": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "license": "MIT" }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -1583,6 +2154,8 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001754", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz", + "integrity": "sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==", "funding": [ { "type": "opencollective", @@ -1601,6 +2174,8 @@ }, "node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -1615,10 +2190,14 @@ }, "node_modules/chardet": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", "license": "MIT" }, "node_modules/charenc": { "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", "license": "BSD-3-Clause", "engines": { "node": "*" @@ -1626,6 +2205,8 @@ }, "node_modules/cli-cursor": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" @@ -1636,6 +2217,8 @@ }, "node_modules/cli-spinners": { "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "license": "MIT", "engines": { "node": ">=6" @@ -1646,6 +2229,8 @@ }, "node_modules/cli-width": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "license": "ISC", "engines": { "node": ">= 12" @@ -1653,6 +2238,8 @@ }, "node_modules/clone": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "license": "MIT", "engines": { "node": ">=0.8" @@ -1660,6 +2247,8 @@ }, "node_modules/clone-deep": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", @@ -1672,6 +2261,8 @@ }, "node_modules/color-convert": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -1682,10 +2273,14 @@ }, "node_modules/color-name": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, "node_modules/colors-cli": { "version": "1.0.33", + "resolved": "https://registry.npmjs.org/colors-cli/-/colors-cli-1.0.33.tgz", + "integrity": "sha512-PWGsmoJFdOB0t+BeHgmtuoRZUQucOLl5ii81NBzOOGVxlgE04muFNHlR5j8i8MKbOPELBl3243AI6lGBTj5ICQ==", "license": "MIT", "bin": { "colors": "bin/colors" @@ -1696,6 +2291,8 @@ }, "node_modules/combined-stream": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -1706,18 +2303,26 @@ }, "node_modules/commondir": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, "node_modules/convert-source-map": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -1730,6 +2335,8 @@ }, "node_modules/crypt": { "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", "license": "BSD-3-Clause", "engines": { "node": "*" @@ -1737,6 +2344,8 @@ }, "node_modules/debug": { "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1752,6 +2361,8 @@ }, "node_modules/dedent": { "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -1764,6 +2375,8 @@ }, "node_modules/defaults": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "license": "MIT", "dependencies": { "clone": "^1.0.2" @@ -1774,6 +2387,8 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "license": "MIT", "engines": { "node": ">=0.4.0" @@ -1781,10 +2396,14 @@ }, "node_modules/deprecation": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", "license": "ISC" }, "node_modules/detect-indent": { "version": "7.0.2", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.2.tgz", + "integrity": "sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==", "license": "MIT", "engines": { "node": ">=12.20" @@ -1795,6 +2414,8 @@ }, "node_modules/detect-libc": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", "license": "Apache-2.0", "engines": { "node": ">=8" @@ -1802,6 +2423,8 @@ }, "node_modules/detect-newline": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-4.0.1.tgz", + "integrity": "sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==", "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -1812,6 +2435,8 @@ }, "node_modules/diff": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -1819,6 +2444,8 @@ }, "node_modules/digest-fetch": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", + "integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==", "license": "ISC", "dependencies": { "base-64": "^0.1.0", @@ -1827,6 +2454,8 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -1839,18 +2468,26 @@ }, "node_modules/eastasianwidth": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.248", + "version": "1.5.249", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.249.tgz", + "integrity": "sha512-5vcfL3BBe++qZ5kuFhD/p8WOM1N9m3nwvJPULJx+4xf2usSlZFJ0qoNYO2fOX4hi3ocuDcmDobtA+5SFr4OmBg==", "license": "ISC" }, "node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, "node_modules/es-define-property": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -1858,6 +2495,8 @@ }, "node_modules/es-errors": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -1865,6 +2504,8 @@ }, "node_modules/es-object-atoms": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -1875,6 +2516,8 @@ }, "node_modules/es-set-tostringtag": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -1888,6 +2531,8 @@ }, "node_modules/escalade": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", "engines": { "node": ">=6" @@ -1895,6 +2540,8 @@ }, "node_modules/escape-string-regexp": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "license": "MIT", "engines": { "node": ">=12" @@ -1905,6 +2552,8 @@ }, "node_modules/esprima": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -1916,6 +2565,8 @@ }, "node_modules/event-target-shim": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "license": "MIT", "engines": { "node": ">=6" @@ -1923,6 +2574,8 @@ }, "node_modules/filename-reserved-regex": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", + "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -1933,6 +2586,8 @@ }, "node_modules/filenamify": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-6.0.0.tgz", + "integrity": "sha512-vqIlNogKeyD3yzrm0yhRMQg8hOVwYcYRfjEoODd49iCprMn4HL85gK3HcykQE53EPIpX3HcAbGA5ELQv216dAQ==", "license": "MIT", "dependencies": { "filename-reserved-regex": "^3.0.0" @@ -1946,6 +2601,8 @@ }, "node_modules/fill-range": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -1956,6 +2613,8 @@ }, "node_modules/find-cache-dir": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", "license": "MIT", "dependencies": { "commondir": "^1.0.1", @@ -1968,6 +2627,8 @@ }, "node_modules/find-up": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "license": "MIT", "dependencies": { "locate-path": "^3.0.0" @@ -1978,6 +2639,8 @@ }, "node_modules/flow-parser": { "version": "0.290.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.290.0.tgz", + "integrity": "sha512-9qXeNyrHPIoRK23kX7HNp275RYMy2y1AWb37y86ZTH/2UvfrofBis18aBunzfTIXkRpeD0F/w/uAKFhLUpboqQ==", "license": "MIT", "engines": { "node": ">=0.4.0" @@ -1985,6 +2648,8 @@ }, "node_modules/foreground-child": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -1999,6 +2664,8 @@ }, "node_modules/form-data": { "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -2013,10 +2680,14 @@ }, "node_modules/form-data-encoder": { "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", "license": "MIT" }, "node_modules/formdata-node": { "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", "license": "MIT", "dependencies": { "node-domexception": "1.0.0", @@ -2028,6 +2699,8 @@ }, "node_modules/formdata-node/node_modules/web-streams-polyfill": { "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", "license": "MIT", "engines": { "node": ">= 14" @@ -2035,10 +2708,14 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "license": "ISC" }, "node_modules/function-bind": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2046,6 +2723,8 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -2053,6 +2732,8 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -2075,6 +2756,8 @@ }, "node_modules/get-proto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -2086,6 +2769,8 @@ }, "node_modules/git-up": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", + "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", "license": "MIT", "dependencies": { "is-ssh": "^1.4.0", @@ -2094,6 +2779,8 @@ }, "node_modules/git-url-parse": { "version": "14.1.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-14.1.0.tgz", + "integrity": "sha512-8xg65dTxGHST3+zGpycMMFZcoTzAdZ2dOtu4vmgIfkTFnVHBxHMzBC2L1k8To7EmrSiHesT8JgPLT91VKw1B5g==", "license": "MIT", "dependencies": { "git-up": "^7.0.0" @@ -2101,6 +2788,8 @@ }, "node_modules/glob": { "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -2119,6 +2808,8 @@ }, "node_modules/gopd": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -2129,10 +2820,14 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, "node_modules/has-flag": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", "engines": { "node": ">=8" @@ -2140,6 +2835,8 @@ }, "node_modules/has-symbols": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -2150,6 +2847,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -2163,6 +2862,8 @@ }, "node_modules/hasown": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -2173,6 +2874,8 @@ }, "node_modules/humanize-ms": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", "license": "MIT", "dependencies": { "ms": "^2.0.0" @@ -2180,6 +2883,8 @@ }, "node_modules/iconv-lite": { "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -2194,6 +2899,8 @@ }, "node_modules/ieee754": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -2212,6 +2919,8 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "license": "MIT", "engines": { "node": ">=0.8.19" @@ -2219,6 +2928,9 @@ }, "node_modules/inflight": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -2227,10 +2939,14 @@ }, "node_modules/inherits": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/inquirer": { "version": "9.3.8", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.3.8.tgz", + "integrity": "sha512-pFGGdaHrmRKMh4WoDDSowddgjT1Vkl90atobmTeSmcPGdYiwikch/m/Ef5wRaiamHejtw0cUUMMerzDUXCci2w==", "license": "MIT", "dependencies": { "@inquirer/external-editor": "^1.0.2", @@ -2252,10 +2968,14 @@ }, "node_modules/is-buffer": { "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "license": "MIT" }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", "engines": { "node": ">=8" @@ -2263,6 +2983,8 @@ }, "node_modules/is-interactive": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "license": "MIT", "engines": { "node": ">=8" @@ -2270,6 +2992,8 @@ }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "license": "MIT", "engines": { "node": ">=0.12.0" @@ -2277,6 +3001,8 @@ }, "node_modules/is-plain-object": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "license": "MIT", "dependencies": { "isobject": "^3.0.1" @@ -2287,6 +3013,8 @@ }, "node_modules/is-ssh": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.1.tgz", + "integrity": "sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==", "license": "MIT", "dependencies": { "protocols": "^2.0.1" @@ -2294,6 +3022,8 @@ }, "node_modules/is-unicode-supported": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "license": "MIT", "engines": { "node": ">=10" @@ -2304,10 +3034,14 @@ }, "node_modules/isexe": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/isobject": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2315,6 +3049,8 @@ }, "node_modules/jackspeak": { "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -2328,10 +3064,14 @@ }, "node_modules/js-tokens": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, "node_modules/jscodeshift": { "version": "0.15.2", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.15.2.tgz", + "integrity": "sha512-FquR7Okgmc4Sd0aEDwqho3rEiKR3BdvuG9jfdHjLJ6JQoWSMpavug3AoIfnfWhxFlf+5pzQh8qjqz0DWFrNQzA==", "license": "MIT", "dependencies": { "@babel/core": "^7.23.0", @@ -2369,6 +3109,8 @@ }, "node_modules/jscodeshift/node_modules/ast-types": { "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", "license": "MIT", "dependencies": { "tslib": "^2.0.1" @@ -2379,6 +3121,8 @@ }, "node_modules/jscodeshift/node_modules/recast": { "version": "0.23.11", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", + "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", "license": "MIT", "dependencies": { "ast-types": "^0.16.1", @@ -2393,6 +3137,8 @@ }, "node_modules/jsesc": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -2403,6 +3149,8 @@ }, "node_modules/json5": { "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -2413,6 +3161,8 @@ }, "node_modules/kind-of": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2420,6 +3170,8 @@ }, "node_modules/locate-path": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "license": "MIT", "dependencies": { "p-locate": "^3.0.0", @@ -2431,10 +3183,14 @@ }, "node_modules/lodash-es": { "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "license": "MIT", "dependencies": { "chalk": "^4.1.0", @@ -2449,6 +3205,8 @@ }, "node_modules/lru-cache": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -2456,6 +3214,8 @@ }, "node_modules/magic-string": { "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" @@ -2463,6 +3223,8 @@ }, "node_modules/make-dir": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "license": "MIT", "dependencies": { "pify": "^4.0.1", @@ -2474,6 +3236,8 @@ }, "node_modules/make-dir/node_modules/semver": { "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "license": "ISC", "bin": { "semver": "bin/semver" @@ -2481,6 +3245,8 @@ }, "node_modules/math-intrinsics": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -2488,6 +3254,8 @@ }, "node_modules/md5": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", "license": "BSD-3-Clause", "dependencies": { "charenc": "0.0.2", @@ -2497,6 +3265,8 @@ }, "node_modules/micromatch": { "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -2508,6 +3278,8 @@ }, "node_modules/mime-db": { "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -2515,6 +3287,8 @@ }, "node_modules/mime-types": { "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -2525,6 +3299,8 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "license": "MIT", "engines": { "node": ">=6" @@ -2532,6 +3308,8 @@ }, "node_modules/minimatch": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -2545,6 +3323,8 @@ }, "node_modules/minipass": { "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -2552,10 +3332,14 @@ }, "node_modules/ms": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/mute-stream": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -2563,10 +3347,14 @@ }, "node_modules/neo-async": { "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "license": "MIT" }, "node_modules/node-dir": { "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", "license": "MIT", "dependencies": { "minimatch": "^3.0.2" @@ -2577,6 +3365,8 @@ }, "node_modules/node-dir/node_modules/brace-expansion": { "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -2585,6 +3375,8 @@ }, "node_modules/node-dir/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -2595,6 +3387,9 @@ }, "node_modules/node-domexception": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", "funding": [ { "type": "github", @@ -2612,6 +3407,8 @@ }, "node_modules/node-fetch": { "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" @@ -2630,10 +3427,14 @@ }, "node_modules/node-releases": { "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "license": "MIT" }, "node_modules/once": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "dependencies": { "wrappy": "1" @@ -2641,6 +3442,8 @@ }, "node_modules/onetime": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -2654,6 +3457,8 @@ }, "node_modules/openai": { "version": "4.23.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.23.0.tgz", + "integrity": "sha512-ey2CXh1OTcTUa0AWZWuTpgA9t5GuAG3DVU1MofCRUI7fQJij8XJ3Sr0VtgxoAE69C9wbHBMCux8Z/IQZfSwHiA==", "license": "Apache-2.0", "dependencies": { "@types/node": "^18.11.18", @@ -2672,6 +3477,8 @@ }, "node_modules/openai/node_modules/@types/node": { "version": "18.19.130", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", + "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -2679,10 +3486,14 @@ }, "node_modules/openai/node_modules/undici-types": { "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "license": "MIT" }, "node_modules/ora": { "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "license": "MIT", "dependencies": { "bl": "^4.1.0", @@ -2704,6 +3515,8 @@ }, "node_modules/p-limit": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -2717,6 +3530,8 @@ }, "node_modules/p-locate": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "license": "MIT", "dependencies": { "p-limit": "^2.0.0" @@ -2727,6 +3542,8 @@ }, "node_modules/p-try": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "license": "MIT", "engines": { "node": ">=6" @@ -2734,10 +3551,14 @@ }, "node_modules/package-json-from-dist": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "license": "BlueOak-1.0.0" }, "node_modules/parse-path": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz", + "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==", "license": "MIT", "dependencies": { "protocols": "^2.0.0" @@ -2745,6 +3566,8 @@ }, "node_modules/parse-url": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", + "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", "license": "MIT", "dependencies": { "parse-path": "^7.0.0" @@ -2752,6 +3575,8 @@ }, "node_modules/path-exists": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "license": "MIT", "engines": { "node": ">=4" @@ -2759,6 +3584,8 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2766,6 +3593,8 @@ }, "node_modules/path-key": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", "engines": { "node": ">=8" @@ -2773,6 +3602,8 @@ }, "node_modules/path-scurry": { "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -2787,14 +3618,20 @@ }, "node_modules/path-scurry/node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "license": "ISC" }, "node_modules/picocolors": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -2805,6 +3642,8 @@ }, "node_modules/pify": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "license": "MIT", "engines": { "node": ">=6" @@ -2812,6 +3651,8 @@ }, "node_modules/pirates": { "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "license": "MIT", "engines": { "node": ">= 6" @@ -2819,6 +3660,8 @@ }, "node_modules/pkg-dir": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "license": "MIT", "dependencies": { "find-up": "^3.0.0" @@ -2829,6 +3672,8 @@ }, "node_modules/prettier": { "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" @@ -2842,10 +3687,14 @@ }, "node_modules/protocols": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", + "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==", "license": "MIT" }, "node_modules/readable-stream": { "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -2858,6 +3707,8 @@ }, "node_modules/recast": { "version": "0.20.5", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.20.5.tgz", + "integrity": "sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==", "license": "MIT", "dependencies": { "ast-types": "0.14.2", @@ -2871,6 +3722,8 @@ }, "node_modules/restore-cursor": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "license": "MIT", "dependencies": { "onetime": "^5.1.0", @@ -2882,10 +3735,15 @@ }, "node_modules/restore-cursor/node_modules/signal-exit": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, "node_modules/rimraf": { "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -2896,6 +3754,8 @@ }, "node_modules/rimraf/node_modules/brace-expansion": { "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -2904,6 +3764,9 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -2922,6 +3785,8 @@ }, "node_modules/rimraf/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -2932,6 +3797,8 @@ }, "node_modules/run-async": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", "license": "MIT", "engines": { "node": ">=0.12.0" @@ -2939,6 +3806,8 @@ }, "node_modules/rxjs": { "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" @@ -2946,6 +3815,8 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -2964,10 +3835,14 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, "node_modules/semver": { "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -2975,6 +3850,8 @@ }, "node_modules/shallow-clone": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "license": "MIT", "dependencies": { "kind-of": "^6.0.2" @@ -2985,6 +3862,8 @@ }, "node_modules/shebang-command": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -2995,6 +3874,8 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { "node": ">=8" @@ -3002,6 +3883,8 @@ }, "node_modules/signal-exit": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "license": "ISC", "engines": { "node": ">=14" @@ -3012,6 +3895,8 @@ }, "node_modules/simple-git": { "version": "3.30.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.30.0.tgz", + "integrity": "sha512-q6lxyDsCmEal/MEGhP1aVyQ3oxnagGlBDOVSIB4XUVLl1iZh0Pah6ebC9V4xBap/RfgP2WlI8EKs0WS0rMEJHg==", "license": "MIT", "dependencies": { "@kwsites/file-exists": "^1.1.1", @@ -3025,6 +3910,8 @@ }, "node_modules/source-map": { "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -3032,6 +3919,8 @@ }, "node_modules/source-map-support": { "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -3040,6 +3929,8 @@ }, "node_modules/string_decoder": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -3047,6 +3938,8 @@ }, "node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -3060,6 +3953,8 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -3072,6 +3967,8 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3083,6 +3980,8 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3093,6 +3992,8 @@ }, "node_modules/supports-color": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -3103,6 +4004,8 @@ }, "node_modules/temp": { "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", "license": "MIT", "dependencies": { "rimraf": "~2.6.2" @@ -3113,10 +4016,14 @@ }, "node_modules/tiny-invariant": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -3127,10 +4034,14 @@ }, "node_modules/tr46": { "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "license": "MIT" }, "node_modules/tree-kill": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "license": "MIT", "bin": { "tree-kill": "cli.js" @@ -3138,6 +4049,8 @@ }, "node_modules/ts-invariant": { "version": "0.10.3", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz", + "integrity": "sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==", "license": "MIT", "dependencies": { "tslib": "^2.1.0" @@ -3148,10 +4061,14 @@ }, "node_modules/tslib": { "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/type-fest": { "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -3162,14 +4079,20 @@ }, "node_modules/undici-types": { "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, "node_modules/universal-user-agent": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", "license": "ISC" }, "node_modules/update-browserslist-db": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", "funding": [ { "type": "opencollective", @@ -3198,10 +4121,14 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, "node_modules/wcwidth": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "license": "MIT", "dependencies": { "defaults": "^1.0.3" @@ -3209,6 +4136,8 @@ }, "node_modules/web-streams-polyfill": { "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "license": "MIT", "engines": { "node": ">= 8" @@ -3216,10 +4145,14 @@ }, "node_modules/webidl-conversions": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "license": "BSD-2-Clause" }, "node_modules/whatwg-url": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "license": "MIT", "dependencies": { "tr46": "~0.0.3", @@ -3228,6 +4161,8 @@ }, "node_modules/which": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -3241,6 +4176,8 @@ }, "node_modules/wrap-ansi": { "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -3254,6 +4191,8 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -3269,10 +4208,14 @@ }, "node_modules/wrappy": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, "node_modules/write-file-atomic": { "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", "license": "ISC", "dependencies": { "graceful-fs": "^4.1.11", @@ -3282,14 +4225,20 @@ }, "node_modules/write-file-atomic/node_modules/signal-exit": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, "node_modules/yallist": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "license": "ISC" }, "node_modules/yaml": { "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -3300,6 +4249,8 @@ }, "node_modules/yoctocolors-cjs": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", "license": "MIT", "engines": { "node": ">=18" From 7064c88c30486b7a821764d07f04129d8ed27783 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Mon, 24 Nov 2025 13:14:48 +0100 Subject: [PATCH 17/20] feat(`axios-to-whatwg-fetch`): add support request --- recipes/axios-to-whatwg-fetch/README.md | 22 ++++- recipes/axios-to-whatwg-fetch/src/workflow.ts | 85 +++++++++++++++++++ .../tests/expected/request.js | 17 ++-- .../tests/input/request.js | 1 - 4 files changed, 114 insertions(+), 11 deletions(-) diff --git a/recipes/axios-to-whatwg-fetch/README.md b/recipes/axios-to-whatwg-fetch/README.md index 7a076bbd..baa40b39 100644 --- a/recipes/axios-to-whatwg-fetch/README.md +++ b/recipes/axios-to-whatwg-fetch/README.md @@ -16,6 +16,7 @@ The codemod supports the following Axios methods and converts them to their Fetc - `axios.post(url[, data[, config]])` - `axios.put(url[, data[, config]])` - `axios.patch(url[, data[, config]])` +- `axios.request(config)` ### Examples @@ -88,6 +89,26 @@ The codemod supports the following Axios methods and converts them to their Fetc console.log('Preview:', deleted.data ? JSON.stringify(deleted.data).slice(0,200) : typeof deleted.data); ``` +#### `request` axios Method + +```diff + const base = 'https://dummyjson.com/todos'; + +- const customRequest = await axios.request({ +- url: `${base}/1`, +- method: 'PATCH', +- headers: { 'Content-Type': 'application/json' }, +- data: { completed: true }, +- }); ++ const customRequest = await fetch(`${base}/1`, { ++ method: 'PATCH', ++ headers: { 'Content-Type': 'application/json' }, ++ body: JSON.stringify({ completed: true }), ++ }).then(async (res) => Object.assign(res, { data: await res.json() })); + console.log('\nPATCH /todos/1 ->', customRequest.status); + console.log('Preview:', customRequest.data?.completed !== undefined ? `completed=${customRequest.data.completed}` : JSON.stringify(customRequest.data).slice(0,200)); +``` + ## Unsupported APIs The following Axios methods are not supported by this codemod and will generate warnings: @@ -101,4 +122,3 @@ The following Axios methods are not supported by this codemod and will generate - [Fetch Spec](https://fetch.spec.whatwg.org) - [Axios Documentation](https://axios-http.com) - [Node.js Documentation](https://nodejs.org/docs/latest/api/globals.html#fetch) - diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts index 72aef6ea..e1393cf7 100644 --- a/recipes/axios-to-whatwg-fetch/src/workflow.ts +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -29,6 +29,36 @@ type CreateOptionsType = { const unsupportedMethods = ['postForm', 'putForm', 'patchForm']; +const getObjectPropertyValue = ( + objectNode: SgNode, + propertyName: string, +) => { + if (objectNode.kind() !== 'object') return undefined; + const pair = objectNode.find({ + rule: { + kind: 'pair', + has: { + kind: 'property_identifier', + field: 'key', + regex: `^${propertyName}$`, + }, + }, + }); + + return pair?.field('value'); +}; + +const stripWrappingQuotes = (value: string) => { + const trimmed = value.trim(); + if ( + (trimmed.startsWith("'") && trimmed.endsWith("'")) || + (trimmed.startsWith('"') && trimmed.endsWith('"')) + ) { + return trimmed.slice(1, -1); + } + return trimmed; +}; + const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = [ /*{ @@ -143,6 +173,61 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = `; }, }, + { + oldBind: 'axios.request', + replaceFn: (args) => { + const config = args[0]; + if (!config) { + console.warn( + '[Codemod] Missing config object in axios.request. Skipping migration.', + ); + return ''; + } + + if (config.kind() !== 'object') { + console.warn( + '[Codemod] Unsupported axios.request configuration shape. Skipping migration.', + ); + return ''; + } + + const urlNode = getObjectPropertyValue(config, 'url'); + if (!urlNode) { + console.warn( + '[Codemod] Missing URL in axios.request config. Skipping migration.', + ); + return ''; + } + const url = urlNode.text(); + + const methodNode = getObjectPropertyValue(config, 'method'); + let method = methodNode?.text(); + if (method) { + method = stripWrappingQuotes(method); + if (methodNode.kind() === 'string') { + method = method.toUpperCase(); + } + } + if (!method) { + method = 'GET'; + } + + const dataNode = getObjectPropertyValue(config, 'data'); + const data = dataNode?.text() || null; + + const options = createOptions({ + oldOptions: config, + method, + body: data, + }); + + return dedent.withOptions({ alignValues: true })` + fetch(${url}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; + }, + }, ]; /** diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/request.js b/recipes/axios-to-whatwg-fetch/tests/expected/request.js index fcec5de6..0d229ccc 100644 --- a/recipes/axios-to-whatwg-fetch/tests/expected/request.js +++ b/recipes/axios-to-whatwg-fetch/tests/expected/request.js @@ -1,14 +1,13 @@ -import axios from 'axios'; -// Unsupported method: axios.request const base = 'https://dummyjson.com/todos/1'; -const customRequest = await axios.request({ - url: base, +const customRequest = await fetch(base, { method: 'PATCH', - data: { - todo: 'Updated todo', - completed: true, - }, -}); + body: JSON.stringify({ + todo: 'Updated todo', + completed: true, + }) +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); console.log('\nREQUEST /todos/1 ->', customRequest); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/request.js b/recipes/axios-to-whatwg-fetch/tests/input/request.js index fcec5de6..edb41798 100644 --- a/recipes/axios-to-whatwg-fetch/tests/input/request.js +++ b/recipes/axios-to-whatwg-fetch/tests/input/request.js @@ -1,6 +1,5 @@ import axios from 'axios'; -// Unsupported method: axios.request const base = 'https://dummyjson.com/todos/1'; const customRequest = await axios.request({ From 560db6d22bc42765b15c0af6cd61d60613d21dfa Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Mon, 24 Nov 2025 13:37:34 +0100 Subject: [PATCH 18/20] WIP --- recipes/axios-to-whatwg-fetch/README.md | 28 +++- recipes/axios-to-whatwg-fetch/src/workflow.ts | 137 ++++++++++++++++-- .../tests/expected/patch-form-with-config.js | 11 ++ .../tests/expected/post-form-formdata.js | 14 ++ .../tests/expected/post-form.js | 12 ++ .../tests/expected/put-form.js | 14 ++ .../tests/input/patch-form-with-config.js | 12 ++ .../tests/input/post-form-formdata.js | 6 + .../tests/input/post-form.js | 8 + .../tests/input/put-form.js | 6 + 10 files changed, 229 insertions(+), 19 deletions(-) create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/patch-form-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/post-form-formdata.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/post-form.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/put-form.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/patch-form-with-config.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/post-form-formdata.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/post-form.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/put-form.js diff --git a/recipes/axios-to-whatwg-fetch/README.md b/recipes/axios-to-whatwg-fetch/README.md index baa40b39..56abdac3 100644 --- a/recipes/axios-to-whatwg-fetch/README.md +++ b/recipes/axios-to-whatwg-fetch/README.md @@ -16,6 +16,9 @@ The codemod supports the following Axios methods and converts them to their Fetc - `axios.post(url[, data[, config]])` - `axios.put(url[, data[, config]])` - `axios.patch(url[, data[, config]])` +- `axios.postForm(url[, data[, config]])` +- `axios.putForm(url[, data[, config]])` +- `axios.patchForm(url[, data[, config]])` - `axios.request(config)` ### Examples @@ -58,6 +61,25 @@ The codemod supports the following Axios methods and converts them to their Fetc console.log('Preview:', created.data?.id ? `created id ${created.data.id}` : JSON.stringify(created.data).slice(0,200)); ``` + #### POST Form Request + + ```diff + const formEndpoint = '/submit'; + + - const created = await axios.postForm(formEndpoint, { + - title: 'Form Demo', + - completed: false, + - }); + + const created = await fetch(formEndpoint, { + + method: 'POST', + + body: new URLSearchParams({ + + title: 'Form Demo', + + completed: false, + + }), + + }).then(async (res) => Object.assign(res, { data: await res.json() })); + console.log('Preview:', created.data); + ``` + #### PUT Request ```diff @@ -111,11 +133,7 @@ The codemod supports the following Axios methods and converts them to their Fetc ## Unsupported APIs -The following Axios methods are not supported by this codemod and will generate warnings: - -- `axios.postForm(url[, data[, config]])` -- `axios.putForm(url[, data[, config]])` -- `axios.patchForm(url[, data[, config]])` +The codemod does not yet cover Axios features outside of direct request helpers, such as interceptors, cancel tokens, or instance configuration from `axios.create()`. ## References diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts index e1393cf7..2fb012fe 100644 --- a/recipes/axios-to-whatwg-fetch/src/workflow.ts +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -24,10 +24,11 @@ type BindingToReplace = { type CreateOptionsType = { oldOptions?: SgNode; method?: string; - body?: string; + bodyNode?: SgNode | null; + payloadKind?: 'json' | 'form'; }; -const unsupportedMethods = ['postForm', 'putForm', 'patchForm']; +const unsupportedMethods: string[] = []; const getObjectPropertyValue = ( objectNode: SgNode, @@ -59,6 +60,51 @@ const stripWrappingQuotes = (value: string) => { return trimmed; }; +const getBodyExpression = ( + bodyNode: SgNode, + payloadKind: NonNullable, +) => { + const source = bodyNode.text(); + const trimmed = source.trim(); + if (!trimmed || trimmed === 'undefined' || trimmed === 'null') return null; + + if (payloadKind === 'form') { + return getFormBodyExpression(bodyNode, source, trimmed); + } + + return `JSON.stringify(${source})`; +}; + +const getFormBodyExpression = ( + bodyNode: SgNode, + source: string, + trimmed: string, +) => { + if (bodyNode.kind() === 'object') { + return `new URLSearchParams(${source})`; + } + + if ( + trimmed.startsWith('new URLSearchParams') || + trimmed.startsWith('URLSearchParams(') || + trimmed.startsWith('await new URLSearchParams') + ) { + return source; + } + + if (/FormData/.test(trimmed)) { + return source; + } + + return dedent` + (() => { + const value = ${source}; + if (value instanceof FormData || value instanceof URLSearchParams) return value; + return new URLSearchParams(value); + })() + `; +}; + const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = [ /*{ @@ -87,7 +133,8 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = const options = createOptions({ oldOptions: args[2], method: 'POST', - body: args[1]?.text(), + bodyNode: args[1] ?? null, + payloadKind: 'json', }); return dedent.withOptions({ alignValues: true })` fetch(${url.text()}${options ? `, ${options}` : ''}) @@ -103,7 +150,8 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = const options = createOptions({ oldOptions: args[2], method: 'PUT', - body: args[1]?.text(), + bodyNode: args[1] ?? null, + payloadKind: 'json', }); return dedent.withOptions({ alignValues: true })` fetch(${url.text()}${options ? `, ${options}` : ''}) @@ -119,7 +167,59 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = const options = createOptions({ oldOptions: args[2], method: 'PATCH', - body: args[1]?.text(), + bodyNode: args[1] ?? null, + payloadKind: 'json', + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; + }, + }, + { + oldBind: '$.postForm', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[2], + method: 'POST', + bodyNode: args[1] ?? null, + payloadKind: 'form', + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; + }, + }, + { + oldBind: '$.putForm', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[2], + method: 'PUT', + bodyNode: args[1] ?? null, + payloadKind: 'form', + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; + }, + }, + { + oldBind: '$.patchForm', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[2], + method: 'PATCH', + bodyNode: args[1] ?? null, + payloadKind: 'form', }); return dedent.withOptions({ alignValues: true })` fetch(${url.text()}${options ? `, ${options}` : ''}) @@ -174,7 +274,7 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = }, }, { - oldBind: 'axios.request', + oldBind: '$.request', replaceFn: (args) => { const config = args[0]; if (!config) { @@ -212,13 +312,11 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = method = 'GET'; } - const dataNode = getObjectPropertyValue(config, 'data'); - const data = dataNode?.text() || null; - const options = createOptions({ oldOptions: config, method, - body: data, + bodyNode: getObjectPropertyValue(config, 'data') ?? null, + payloadKind: 'json', }); return dedent.withOptions({ alignValues: true })` @@ -239,8 +337,16 @@ const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = * @param {string} [param0.body] - The body content to include in the request. * @returns {string} The generated options string for the Fetch API. */ -const createOptions = ({ oldOptions, method, body }: CreateOptionsType) => { - if (!oldOptions && !method && !body) return ''; +const createOptions = ({ + oldOptions, + method, + bodyNode, + payloadKind = 'json', +}: CreateOptionsType) => { + const bodySource = bodyNode?.text(); + const hasBody = Boolean(bodySource?.trim()); + if (!oldOptions && !method && !hasBody) return ''; + const headers = oldOptions?.find({ rule: { kind: 'object', @@ -265,8 +371,11 @@ const createOptions = ({ oldOptions, method, body }: CreateOptionsType) => { options.push(`headers: ${headers?.text()}`); } - if (body) { - options.push(`body: JSON.stringify(${body})`); + if (bodyNode) { + const bodyExpression = getBodyExpression(bodyNode, payloadKind); + if (bodyExpression) { + options.push(`body: ${bodyExpression}`); + } } if (options.length === 1) return `{ ${options.toString()} }`; diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/patch-form-with-config.js b/recipes/axios-to-whatwg-fetch/tests/expected/patch-form-with-config.js new file mode 100644 index 00000000..2df7fbe5 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/patch-form-with-config.js @@ -0,0 +1,11 @@ + +const patched = await fetch('https://dummyjson.com/forms/2', { + method: 'PATCH', + headers: { + Accept: 'application/json', + }, + body: new URLSearchParams({ done: true }) +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log(patched.status); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/post-form-formdata.js b/recipes/axios-to-whatwg-fetch/tests/expected/post-form-formdata.js new file mode 100644 index 00000000..cf718397 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/post-form-formdata.js @@ -0,0 +1,14 @@ + +const formData = new FormData(); +formData.append('name', 'Node.js'); + +await fetch('https://dummyjson.com/forms', { + method: 'POST', + body: (() => { + const value = formData; + if (value instanceof FormData || value instanceof URLSearchParams) return value; + return new URLSearchParams(value); + })() +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/post-form.js b/recipes/axios-to-whatwg-fetch/tests/expected/post-form.js new file mode 100644 index 00000000..29fcce8d --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/post-form.js @@ -0,0 +1,12 @@ +const base = 'https://dummyjson.com/forms'; + +const created = await fetch(`${base}/submit`, { + method: 'POST', + body: new URLSearchParams({ + title: 'Form Demo', + completed: false, + }) +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log(created); diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/put-form.js b/recipes/axios-to-whatwg-fetch/tests/expected/put-form.js new file mode 100644 index 00000000..bf14ecb2 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/put-form.js @@ -0,0 +1,14 @@ + +const payload = { status: 'open' }; + +const updated = await fetch('https://dummyjson.com/forms/1', { + method: 'PUT', + body: (() => { + const value = payload; + if (value instanceof FormData || value instanceof URLSearchParams) return value; + return new URLSearchParams(value); + })() +}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +console.log(updated.status); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/patch-form-with-config.js b/recipes/axios-to-whatwg-fetch/tests/input/patch-form-with-config.js new file mode 100644 index 00000000..f26b9c55 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/patch-form-with-config.js @@ -0,0 +1,12 @@ +import axios from 'axios'; + +const patched = await axios.patchForm( + 'https://dummyjson.com/forms/2', + { done: true }, + { + headers: { + Accept: 'application/json', + }, + }, +); +console.log(patched.status); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/post-form-formdata.js b/recipes/axios-to-whatwg-fetch/tests/input/post-form-formdata.js new file mode 100644 index 00000000..c798815e --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/post-form-formdata.js @@ -0,0 +1,6 @@ +import axios from 'axios'; + +const formData = new FormData(); +formData.append('name', 'Node.js'); + +await axios.postForm('https://dummyjson.com/forms', formData); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/post-form.js b/recipes/axios-to-whatwg-fetch/tests/input/post-form.js new file mode 100644 index 00000000..499347c7 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/post-form.js @@ -0,0 +1,8 @@ +import axios from 'axios'; +const base = 'https://dummyjson.com/forms'; + +const created = await axios.postForm(`${base}/submit`, { + title: 'Form Demo', + completed: false, +}); +console.log(created); diff --git a/recipes/axios-to-whatwg-fetch/tests/input/put-form.js b/recipes/axios-to-whatwg-fetch/tests/input/put-form.js new file mode 100644 index 00000000..2acceecf --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/put-form.js @@ -0,0 +1,6 @@ +import axios from 'axios'; + +const payload = { status: 'open' }; + +const updated = await axios.putForm('https://dummyjson.com/forms/1', payload); +console.log(updated.status); From faf6ac2038bfa3130c84968b976c3990221e0281 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:26:36 +0100 Subject: [PATCH 19/20] update --- recipes/axios-to-whatwg-fetch/src/workflow.ts | 430 +++++++++--------- .../tests/expected/component.tsx | 27 ++ .../tests/expected/dynamic-import.js | 7 + .../tests/expected/import-alias.js | 9 + .../tests/expected/require.js | 8 + .../tests/input/component.tsx | 27 ++ .../tests/input/dynamic-import.js | 6 + .../tests/input/import-alias.js | 8 + .../tests/input/require.js | 7 + 9 files changed, 323 insertions(+), 206 deletions(-) create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/component.tsx create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/dynamic-import.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/import-alias.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/expected/require.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/component.tsx create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/dynamic-import.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/import-alias.js create mode 100644 recipes/axios-to-whatwg-fetch/tests/input/require.js diff --git a/recipes/axios-to-whatwg-fetch/src/workflow.ts b/recipes/axios-to-whatwg-fetch/src/workflow.ts index 2fb012fe..b222894c 100644 --- a/recipes/axios-to-whatwg-fetch/src/workflow.ts +++ b/recipes/axios-to-whatwg-fetch/src/workflow.ts @@ -1,7 +1,10 @@ import dedent from 'dedent'; import { EOL } from 'node:os'; import { getNodeRequireCalls } from '@nodejs/codemod-utils/ast-grep/require-call'; -import { getNodeImportStatements } from '@nodejs/codemod-utils/ast-grep/import-statement'; +import { + getNodeImportCalls, + getNodeImportStatements, +} from '@nodejs/codemod-utils/ast-grep/import-statement'; import { resolveBindingPath } from '@nodejs/codemod-utils/ast-grep/resolve-binding-path'; import { removeBinding } from '@nodejs/codemod-utils/ast-grep/remove-binding'; import { removeLines } from '@nodejs/codemod-utils/ast-grep/remove-lines'; @@ -105,228 +108,242 @@ const getFormBodyExpression = ( `; }; -const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = - [ - /*{ - It's should be migratable with codemod but not supported for now - oldBind: '$.request', - replaceFn: (arg) => `console.log(${arg})`, - },*/ - { - oldBind: '$.get', - replaceFn: (args) => { - const url = args.length > 0 && args[0]; - const options = createOptions({ - oldOptions: args[1], - }); - return dedent.withOptions({ alignValues: true })` - fetch(${url.text()}${options ? `, ${options}` : ''}) - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null) - `; - }, +const baseUpdates: { + oldBind: string; + replaceFn: BindingToReplace['replaceFn']; + supportDefaultAccess?: boolean; +}[] = [ + { + oldBind: '$.get', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[1], + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; }, - { - oldBind: '$.post', - replaceFn: (args) => { - const url = args.length > 0 && args[0]; - const options = createOptions({ - oldOptions: args[2], - method: 'POST', - bodyNode: args[1] ?? null, - payloadKind: 'json', - }); - return dedent.withOptions({ alignValues: true })` - fetch(${url.text()}${options ? `, ${options}` : ''}) - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null) - `; - }, + }, + { + oldBind: '$.post', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[2], + method: 'POST', + bodyNode: args[1] ?? null, + payloadKind: 'json', + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; }, - { - oldBind: '$.put', - replaceFn: (args) => { - const url = args.length > 0 && args[0]; - const options = createOptions({ - oldOptions: args[2], - method: 'PUT', - bodyNode: args[1] ?? null, - payloadKind: 'json', - }); - return dedent.withOptions({ alignValues: true })` - fetch(${url.text()}${options ? `, ${options}` : ''}) - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null) - `; - }, + }, + { + oldBind: '$.put', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[2], + method: 'PUT', + bodyNode: args[1] ?? null, + payloadKind: 'json', + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; }, - { - oldBind: '$.patch', - replaceFn: (args) => { - const url = args.length > 0 && args[0]; - const options = createOptions({ - oldOptions: args[2], - method: 'PATCH', - bodyNode: args[1] ?? null, - payloadKind: 'json', - }); - return dedent.withOptions({ alignValues: true })` - fetch(${url.text()}${options ? `, ${options}` : ''}) - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null) - `; - }, + }, + { + oldBind: '$.patch', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[2], + method: 'PATCH', + bodyNode: args[1] ?? null, + payloadKind: 'json', + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; }, - { - oldBind: '$.postForm', - replaceFn: (args) => { - const url = args.length > 0 && args[0]; - const options = createOptions({ - oldOptions: args[2], - method: 'POST', - bodyNode: args[1] ?? null, - payloadKind: 'form', - }); - return dedent.withOptions({ alignValues: true })` - fetch(${url.text()}${options ? `, ${options}` : ''}) - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null) - `; - }, + }, + { + oldBind: '$.postForm', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[2], + method: 'POST', + bodyNode: args[1] ?? null, + payloadKind: 'form', + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; }, - { - oldBind: '$.putForm', - replaceFn: (args) => { - const url = args.length > 0 && args[0]; - const options = createOptions({ - oldOptions: args[2], - method: 'PUT', - bodyNode: args[1] ?? null, - payloadKind: 'form', - }); - return dedent.withOptions({ alignValues: true })` - fetch(${url.text()}${options ? `, ${options}` : ''}) - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null) - `; - }, + }, + { + oldBind: '$.putForm', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[2], + method: 'PUT', + bodyNode: args[1] ?? null, + payloadKind: 'form', + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; }, - { - oldBind: '$.patchForm', - replaceFn: (args) => { - const url = args.length > 0 && args[0]; - const options = createOptions({ - oldOptions: args[2], - method: 'PATCH', - bodyNode: args[1] ?? null, - payloadKind: 'form', - }); - return dedent.withOptions({ alignValues: true })` - fetch(${url.text()}${options ? `, ${options}` : ''}) - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null) - `; - }, + }, + { + oldBind: '$.patchForm', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[2], + method: 'PATCH', + bodyNode: args[1] ?? null, + payloadKind: 'form', + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; }, - { - oldBind: '$.delete', - replaceFn: (args) => { - const url = args.length > 0 && args[0]; - const options = createOptions({ - oldOptions: args[1], - method: 'DELETE', - }); - return dedent.withOptions({ alignValues: true })` - fetch(${url.text()}, ${options}) - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null) - `; - }, + }, + { + oldBind: '$.delete', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[1], + method: 'DELETE', + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}, ${options}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; }, - { - oldBind: '$.head', - replaceFn: (args) => { - const url = args.length > 0 && args[0]; - const options = createOptions({ - oldOptions: args[1], - method: 'HEAD', - }); - return dedent.withOptions({ alignValues: true })` - fetch(${url.text()}, ${options}) - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null) - `; - }, + }, + { + oldBind: '$.head', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[1], + method: 'HEAD', + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}, ${options}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; }, - { - oldBind: '$.options', - replaceFn: (args) => { - const url = args.length > 0 && args[0]; - const options = createOptions({ - oldOptions: args[1], - method: 'OPTIONS', - }); - return dedent.withOptions({ alignValues: true })` - fetch(${url.text()}, ${options}) - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null) - `; - }, + }, + { + oldBind: '$.options', + replaceFn: (args) => { + const url = args.length > 0 && args[0]; + const options = createOptions({ + oldOptions: args[1], + method: 'OPTIONS', + }); + return dedent.withOptions({ alignValues: true })` + fetch(${url.text()}, ${options}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + `; }, - { - oldBind: '$.request', - replaceFn: (args) => { - const config = args[0]; - if (!config) { - console.warn( - '[Codemod] Missing config object in axios.request. Skipping migration.', - ); - return ''; - } + }, + { + oldBind: '$.request', + replaceFn: (args) => { + const config = args[0]; + if (!config) { + console.warn( + '[Codemod] Missing config object in axios.request. Skipping migration.', + ); + return ''; + } - if (config.kind() !== 'object') { - console.warn( - '[Codemod] Unsupported axios.request configuration shape. Skipping migration.', - ); - return ''; - } + if (config.kind() !== 'object') { + console.warn( + '[Codemod] Unsupported axios.request configuration shape. Skipping migration.', + ); + return ''; + } - const urlNode = getObjectPropertyValue(config, 'url'); - if (!urlNode) { - console.warn( - '[Codemod] Missing URL in axios.request config. Skipping migration.', - ); - return ''; - } - const url = urlNode.text(); - - const methodNode = getObjectPropertyValue(config, 'method'); - let method = methodNode?.text(); - if (method) { - method = stripWrappingQuotes(method); - if (methodNode.kind() === 'string') { - method = method.toUpperCase(); - } - } - if (!method) { - method = 'GET'; + const urlNode = getObjectPropertyValue(config, 'url'); + if (!urlNode) { + console.warn( + '[Codemod] Missing URL in axios.request config. Skipping migration.', + ); + return ''; + } + const url = urlNode.text(); + + const methodNode = getObjectPropertyValue(config, 'method'); + let method = methodNode?.text(); + if (method) { + method = stripWrappingQuotes(method); + if (methodNode.kind() === 'string') { + method = method.toUpperCase(); } + } + if (!method) { + method = 'GET'; + } - const options = createOptions({ - oldOptions: config, - method, - bodyNode: getObjectPropertyValue(config, 'data') ?? null, - payloadKind: 'json', - }); + const options = createOptions({ + oldOptions: config, + method, + bodyNode: getObjectPropertyValue(config, 'data') ?? null, + payloadKind: 'json', + }); - return dedent.withOptions({ alignValues: true })` - fetch(${url}${options ? `, ${options}` : ''}) - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null) + return dedent.withOptions({ alignValues: true })` + fetch(${url}${options ? `, ${options}` : ''}) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) `; - }, }, - ]; + }, +]; + +const updates: { oldBind: string; replaceFn: BindingToReplace['replaceFn'] }[] = + baseUpdates.flatMap((update) => { + const bindings = [update.oldBind]; + if ( + update.supportDefaultAccess !== false && + !update.oldBind.includes('.default.') + ) { + bindings.push(update.oldBind.replace('$.', '$.default.')); + } + + return bindings.map((binding) => ({ + oldBind: binding, + replaceFn: update.replaceFn, + })); + }); /** * Generates options for the Fetch API based on the provided parameters. @@ -400,6 +417,7 @@ export default function transform(root: SgRoot): string | null { const importRequireStatement = [ ...getNodeRequireCalls(root, 'axios'), ...getNodeImportStatements(root, 'axios'), + ...getNodeImportCalls(root, 'axios'), ]; if (!importRequireStatement.length) return null; diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/component.tsx b/recipes/axios-to-whatwg-fetch/tests/expected/component.tsx new file mode 100644 index 00000000..18ad4406 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/component.tsx @@ -0,0 +1,27 @@ +import { useEffect, useState } from 'react'; + +type Todo = { id: number; title: string }; + +export function TodoList() { + const [todos, setTodos] = useState([]); + + useEffect(() => { + let active = true; + + fetch('/api/todos') + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) + .then((response) => { + if (active) { + setTodos(response.data.todos); + } + }) + .catch(() => {}); + + return () => { + active = false; + }; + }, []); + + return
{todos.length}
; +} diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/dynamic-import.js b/recipes/axios-to-whatwg-fetch/tests/expected/dynamic-import.js new file mode 100644 index 00000000..c2ed881d --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/dynamic-import.js @@ -0,0 +1,7 @@ + +export async function fetchTodos() { + const response = await fetch('https://dummyjson.com/todos') + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); + return response.data; +} diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/import-alias.js b/recipes/axios-to-whatwg-fetch/tests/expected/import-alias.js new file mode 100644 index 00000000..3db6070d --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/import-alias.js @@ -0,0 +1,9 @@ + +async function loadTodo() { + const response = await fetch('/todos/1') + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); + return response.data; +} + +export { loadTodo }; diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/require.js b/recipes/axios-to-whatwg-fetch/tests/expected/require.js new file mode 100644 index 00000000..e8b4f4a1 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/expected/require.js @@ -0,0 +1,8 @@ + +function fetchAllTodos() { + return fetch('https://dummyjson.com/todos') + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null); +} + +module.exports = { fetchAllTodos }; diff --git a/recipes/axios-to-whatwg-fetch/tests/input/component.tsx b/recipes/axios-to-whatwg-fetch/tests/input/component.tsx new file mode 100644 index 00000000..c7c38fa0 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/component.tsx @@ -0,0 +1,27 @@ +import axios from 'axios'; +import { useEffect, useState } from 'react'; + +type Todo = { id: number; title: string }; + +export function TodoList() { + const [todos, setTodos] = useState([]); + + useEffect(() => { + let active = true; + + axios + .get('/api/todos') + .then((response) => { + if (active) { + setTodos(response.data.todos); + } + }) + .catch(() => {}); + + return () => { + active = false; + }; + }, []); + + return
{todos.length}
; +} diff --git a/recipes/axios-to-whatwg-fetch/tests/input/dynamic-import.js b/recipes/axios-to-whatwg-fetch/tests/input/dynamic-import.js new file mode 100644 index 00000000..45350709 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/dynamic-import.js @@ -0,0 +1,6 @@ +const axiosModule = await import('axios'); + +export async function fetchTodos() { + const response = await axiosModule.default.get('https://dummyjson.com/todos'); + return response.data; +} diff --git a/recipes/axios-to-whatwg-fetch/tests/input/import-alias.js b/recipes/axios-to-whatwg-fetch/tests/input/import-alias.js new file mode 100644 index 00000000..18ba71a5 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/import-alias.js @@ -0,0 +1,8 @@ +import ax from 'axios'; + +async function loadTodo() { + const response = await ax.get('/todos/1'); + return response.data; +} + +export { loadTodo }; diff --git a/recipes/axios-to-whatwg-fetch/tests/input/require.js b/recipes/axios-to-whatwg-fetch/tests/input/require.js new file mode 100644 index 00000000..f18a42b5 --- /dev/null +++ b/recipes/axios-to-whatwg-fetch/tests/input/require.js @@ -0,0 +1,7 @@ +const axios = require('axios'); + +function fetchAllTodos() { + return axios.get('https://dummyjson.com/todos'); +} + +module.exports = { fetchAllTodos }; From 03a36d703bb57b5669cc3eb2fe2fbde4e34ade1b Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:38:27 +0100 Subject: [PATCH 20/20] include tsx --- recipes/axios-to-whatwg-fetch/package.json | 2 +- recipes/axios-to-whatwg-fetch/tests/expected/component.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/recipes/axios-to-whatwg-fetch/package.json b/recipes/axios-to-whatwg-fetch/package.json index b1d1b183..5d30ca26 100644 --- a/recipes/axios-to-whatwg-fetch/package.json +++ b/recipes/axios-to-whatwg-fetch/package.json @@ -4,7 +4,7 @@ "description": "Replace `axios` with `fetch`", "type": "module", "scripts": { - "test": "npx codemod jssg test -l typescript ./src/workflow.ts ./" + "test": "npx codemod jssg test -l tsx ./src/workflow.ts ./" }, "repository": { "type": "git", diff --git a/recipes/axios-to-whatwg-fetch/tests/expected/component.tsx b/recipes/axios-to-whatwg-fetch/tests/expected/component.tsx index 18ad4406..9ef9eb66 100644 --- a/recipes/axios-to-whatwg-fetch/tests/expected/component.tsx +++ b/recipes/axios-to-whatwg-fetch/tests/expected/component.tsx @@ -9,8 +9,8 @@ export function TodoList() { let active = true; fetch('/api/todos') - .then(async (res) => Object.assign(res, { data: await res.json() })) - .catch(() => null) + .then(async (res) => Object.assign(res, { data: await res.json() })) + .catch(() => null) .then((response) => { if (active) { setTodos(response.data.todos);