From e976e7edc87927d66570ca41c1a10187d22566e5 Mon Sep 17 00:00:00 2001 From: Rhys Evans Date: Mon, 2 Sep 2024 12:34:39 +0100 Subject: [PATCH] feat: remiving options from methods more or less works --- .../src/__test__/option-codemods.test.js | 92 ++++++++++++------- packages/codemods/src/codemods/methods.js | 33 ++----- packages/codemods/src/codemods/options.js | 59 +++++++++++- packages/codemods/src/index.js | 5 +- packages/codemods/try.js | 2 +- 5 files changed, 134 insertions(+), 57 deletions(-) diff --git a/packages/codemods/src/__test__/option-codemods.test.js b/packages/codemods/src/__test__/option-codemods.test.js index fb6382bf..6d42bd06 100644 --- a/packages/codemods/src/__test__/option-codemods.test.js +++ b/packages/codemods/src/__test__/option-codemods.test.js @@ -36,45 +36,75 @@ describe('codemods operating on options', () => { }); [ + 'sticky', + 'once', + 'get', + 'getOnce', + 'post', + 'postOnce', + 'put', + 'putOnce', + 'delete', + 'deleteOnce', + 'head', + 'headOnce', + 'patch', + 'patchOnce', + 'any', + 'anyOnce', + // all though the src doesn't actually handle these explicitly, + // these tests ensure that the renaming of these methods to ones that + // do get handled happens first + 'getAnyOnce', 'mock', - // 'sticky', - // 'once', - // 'any', - // 'anyOnce', - // 'get', - // 'getAny', - // 'getOnce', - // 'getAnyOnce', - // 'post', - // 'postAny', - // 'postOnce', - // 'postAnyOnce', - // 'put', - // 'putAny', - // 'putOnce', - // 'putAnyOnce', - // 'delete', - // 'deleteAny', - // 'deleteOnce', - // 'deleteAnyOnce', - // 'head', - // 'headAny', - // 'headOnce', - // 'headAnyOnce', - // 'patch', - // 'patchAny', - // 'patchOnce', - // 'patchAnyOnce' ].forEach((methodName) => { describe(`when using ${methodName}`, () => { - it(`Removes as option on first parameter of ${methodName}()`, () => {}); + if (/any/i.test(methodName)) { + it(`Removes as option on third parameter of ${methodName}()`, () => { + expectCodemodResult( + `fetchMock.${methodName}(200, {name: 'rio', ${optionName}: true})`, + `fetchMock.${methodName}(200, { + name: 'rio' + })`, + ); + }); - it(`Removes as option on third parameter of ${methodName}()`, () => {}); + it(`Removes third parameter of ${methodName}() if no other options remain`, () => { + expectCodemodResult( + `fetchMock.${methodName}('*', 200, {${optionName}: true})`, + `fetchMock.${methodName}('*', 200)`, + ); + }); + } else { + it(`Removes as option on first parameter of ${methodName}()`, () => { + expectCodemodResult( + `fetchMock.${methodName}({url: '*', response: 200, ${optionName}: true})`, + `fetchMock.${methodName}({ + url: '*', + response: 200 +})`, + ); + }); + it(`Removes as option on third parameter of ${methodName}()`, () => { + expectCodemodResult( + `fetchMock.${methodName}('*', 200, {name: 'rio', ${optionName}: true})`, + `fetchMock.${methodName}('*', 200, { + name: 'rio' + })`, + ); + }); - it(`Removes third parameter of ${methodName}() if no other options remain`, () => {}); + it(`Removes third parameter of ${methodName}() if no other options remain`, () => { + expectCodemodResult( + `fetchMock.${methodName}('*', 200, {${optionName}: true})`, + `fetchMock.${methodName}('*', 200)`, + ); + }); + } }); }); }); + describe('acting on combinations of the 3 options together', () => {}); }); describe('fallbackToNetwork', () => { // try to replace fallbackToNetwork: always with spyGlobal()... but probably just insert an error / comment that points at the docs diff --git a/packages/codemods/src/codemods/methods.js b/packages/codemods/src/codemods/methods.js index 21edd1dc..5d565ff6 100644 --- a/packages/codemods/src/codemods/methods.js +++ b/packages/codemods/src/codemods/methods.js @@ -1,5 +1,5 @@ -export function simpleMethods(fetchMockVariableName, root, j) { - const fetchMockMethodCalls = root +export function getAllChainedMethodCalls(fetchMockVariableName, root, j) { + return root .find(j.CallExpression, { callee: { object: { @@ -18,6 +18,14 @@ export function simpleMethods(fetchMockVariableName, root, j) { } return paths; }); +} + +export function simpleMethods(fetchMockVariableName, root, j) { + const fetchMockMethodCalls = getAllChainedMethodCalls( + fetchMockVariableName, + root, + j, + ); fetchMockMethodCalls.forEach((path) => { const method = path.value.callee.property.name; @@ -34,28 +42,7 @@ export function simpleMethods(fetchMockVariableName, root, j) { path.value.callee.property.name = `${httpMethod}Once`; } if (prependStar) { - // const options = path.value.arguments.unshift(j.stringLiteral('*')); - // [1]; - // if (!options) { - // path.value.arguments.push( - // j(`const options = {method: '${httpMethod}'}`) - // .find(j.ObjectExpression) - // .get().value, - // ); - // } else if (options.type === 'Literal') { - // path.value.arguments[1] = j( - // `const options = {name: ${options.raw}, method: '${httpMethod}'}`, - // ) - // .find(j.ObjectExpression) - // .get().value; - // } else if (options.type === 'ObjectExpression') { - // options.properties.push( - // j(`const options = {method: '${httpMethod}'}`) - // .find(j.Property) - // .get().value, - // ); - // } } }); }); diff --git a/packages/codemods/src/codemods/options.js b/packages/codemods/src/codemods/options.js index 5b36de4b..daf63672 100644 --- a/packages/codemods/src/codemods/options.js +++ b/packages/codemods/src/codemods/options.js @@ -1,3 +1,5 @@ +import { getAllChainedMethodCalls } from './methods.js'; +const simpleOptionNames = ['overwriteRoutes', 'warnOnFallback', 'sendAsJson']; export function simpleOptions(fetchMockVariableName, root, j) { const configSets = root .find(j.CallExpression, { @@ -20,7 +22,7 @@ export function simpleOptions(fetchMockVariableName, root, j) { secondArg.type === 'ObjectExpression' ); }); - ['overwriteRoutes', 'warnOnFallback', 'sendAsJson'].forEach((name) => { + simpleOptionNames.forEach((name) => { root .find(j.AssignmentExpression, { left: { @@ -46,4 +48,59 @@ export function simpleOptions(fetchMockVariableName, root, j) { return secondArg.properties.length === 0; }) .remove(); + + const fetchMockMethodCalls = getAllChainedMethodCalls( + fetchMockVariableName, + root, + j, + ); + + [ + 'once', + 'route', + 'sticky', + 'any', + 'anyOnce', + 'get', + 'getOnce', + 'post', + 'postOnce', + 'put', + 'putOnce', + 'delete', + 'deleteOnce', + 'head', + 'headOnce', + 'patch', + 'patchOnce', + ].some((methodName) => { + const optionsObjects = fetchMockMethodCalls + .filter((path) => path.value.callee.property.name === methodName) + .map((path) => { + return j(path) + .find(j.ObjectExpression) + .filter((path) => { + return path.value.properties.some(({ key }) => + simpleOptionNames.includes(key.name), + ); + }) + .paths(); + }); + + if (!optionsObjects.length) { + return; + } + simpleOptionNames.forEach((optionName) => { + optionsObjects + .find(j.Property, { + key: { name: optionName }, + }) + .remove(); + }); + optionsObjects + .filter((path) => { + return path.value.properties.length === 0; + }) + .remove(); + }); } diff --git a/packages/codemods/src/index.js b/packages/codemods/src/index.js index 3c6089af..5b279864 100644 --- a/packages/codemods/src/index.js +++ b/packages/codemods/src/index.js @@ -31,8 +31,11 @@ function findFetchMockVariableName(root, j) { export function codemod(source, j) { const root = j(source); const fetchMockVariableName = findFetchMockVariableName(root, j); - simpleOptions(fetchMockVariableName, root, j); simpleMethods(fetchMockVariableName, root, j); + // run after simpleMethods because means the options rewriters have to iterate + // over smaller list of methods + simpleOptions(fetchMockVariableName, root, j); + return root.toSource(); } diff --git a/packages/codemods/try.js b/packages/codemods/try.js index 8e8ef89e..078a5be2 100644 --- a/packages/codemods/try.js +++ b/packages/codemods/try.js @@ -5,7 +5,7 @@ console.log( codemod( ` import fetchMock from 'fetch-mock'; -fetchMock.getAny(200, {name: 'who'}) +fetchMock.once({url: '*', response: 200, sendAsJson: true}) `, jscodeshift, ),