Skip to content

Commit

Permalink
add codemods for next-minor (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikearnaldi authored Feb 5, 2024
1 parent 90a610b commit 0bc879b
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 161 deletions.
5 changes: 5 additions & 0 deletions .changeset/spotty-snails-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/codemod": patch
---

Add codemods for swap-type-params in Effect,Exit,STM,Stream,Layer,Schema and add-tag-identifier
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"access": "public",
"directory": "dist"
},
"packageManager": "[email protected]",
"description": "Code mod's for the Effect ecosystem",
"engines": {
"node": ">=16.17.1"
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 49 additions & 0 deletions public/codemods/add-tag-identifier.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type cs from "jscodeshift"

export default function transformer(file: cs.FileInfo, api: cs.API) {
const j = api.jscodeshift
const root = j(file.source)

root.find(j.VariableDeclaration).forEach(ast => {
writeTagIdentifier(ast, j)
})

return root.toSource()
}

const writeTagIdentifier = (
ast: cs.ASTPath<cs.VariableDeclaration>,
j: cs.API["jscodeshift"],
) => {
if (ast.value.declarations.length === 1) {
const declaration = ast.value.declarations[0]
if (
declaration.type === "VariableDeclarator"
&& declaration.init
&& declaration.init.type === "CallExpression"
) {
const init = declaration.init
const callee = init.callee
const isTag = (node: typeof callee): boolean => {
switch (node.type) {
case "Identifier": {
return node.name === "Tag"
}
case "MemberExpression": {
return isTag(node.property)
}
default: {
return false
}
}
}
if (
isTag(callee)
&& init.arguments.length === 0
&& declaration.id.type === "Identifier"
) {
init.arguments.push(j.stringLiteral(`@services/${declaration.id.name}`))
}
}
}
}
155 changes: 0 additions & 155 deletions public/codemods/swap-params.ts

This file was deleted.

120 changes: 120 additions & 0 deletions public/codemods/swap-type-params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import type k from "ast-types/gen/kinds.js"
import type cs from "jscodeshift"
import type { Collection } from "jscodeshift/src/Collection"

export default function transformer(file: cs.FileInfo, api: cs.API) {
const j = api.jscodeshift
const root = j(file.source)

forEveryTypeReference(root, j, ast => {
swapParams(ast, "Effect", 3)
swapParams(ast, "Stream", 3)
swapParams(ast, "STM", 3)
swapParams(ast, "Layer", 3)
swapParams(ast, "Exit", 2)
swapSchema(ast, j)
})

return root.toSource()
}

//
// utilities
//

const swapParams = (
ast: cs.ASTPath<cs.TSTypeReference>,
name: string,
size: number,
) => {
if (hasName(ast, name) && ast.value.typeParameters?.params.length === size) {
const params = ast.value.typeParameters.params
params.reverse()
for (let i = 0; i < size - 1; i++) {
popNever(params)
}
}
}

const swapSchema = (
ast: cs.ASTPath<cs.TSTypeReference>,
j: cs.API["jscodeshift"],
) => {
if (hasName(ast, "Schema") && ast.value.typeParameters?.params.length === 3) {
const params = ast.value.typeParameters.params
params.reverse()
popNever(params)
if (
params.length === 2
&& j(params[0]).toSource() === j(params[1]).toSource()
) {
params.pop()
}
}
}

const popNever = (params: Array<k.TSTypeKind>) => {
if (
params.length > 0
&& params[params.length - 1].type === "TSNeverKeyword"
) {
params.pop()
}
}

const hasName = (reference: cs.ASTPath<cs.TSTypeReference>, name: string) => {
const initial = reference.value.typeName
const loop = (node: typeof initial): boolean => {
switch (node.type) {
case "Identifier": {
return node.name === name
}
case "JSXIdentifier": {
return false
}
case "TSQualifiedName": {
return loop(node.right)
}
case "TSTypeParameter": {
return false
}
}
}
return loop(initial)
}

//
// this is needed to resolve a bug in jscodeshift that
// forgets to traverse type parameters in call expressions
//

declare module "ast-types/gen/namedTypes" {
namespace namedTypes {
interface CallExpression extends TSHasOptionalTypeParameterInstantiation {}
}
}

const forEveryTypeReference = (
node: Collection<any>,
j: cs.API["jscodeshift"],
f: (ast: cs.ASTPath<cs.TSTypeReference>) => void,
) => {
const visited = new Set()
node.find(j.TSTypeReference).forEach(ast => {
if (!visited.has(ast)) {
visited.add(ast)
f(ast)
}
})
node.find(j.CallExpression).forEach(path => {
const typeParams = path.value.typeParameters
if (typeParams) {
j(typeParams).find(j.TSTypeReference).forEach(ast => {
if (!visited.has(ast)) {
visited.add(ast)
f(ast)
}
})
}
})
}
4 changes: 3 additions & 1 deletion scripts/copy-package-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ const read = pipe(
name: json.name,
version: json.version,
description: json.description,
bin: "main.js",
bin: {
"effect-codemod": "main.js",
},
engines: json.engines,
repository: json.repository,
author: json.author,
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const codemod = Args.choice<string>(
Args.withDescription("The code modification to run"),
)

const run = Command.make("codemod", {
const run = Command.make("effect-codemod", {
codemod,
paths: Args.text({ name: "paths" }).pipe(
Args.repeated,
Expand Down
14 changes: 11 additions & 3 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
"noEmit": true,
"module": "commonjs",
"moduleResolution": "node",
"lib": ["es6"],
"lib": [
"es6"
],
"sourceMap": false,
"strict": true,
"noImplicitReturns": true,
Expand All @@ -16,7 +18,13 @@
"forceConsistentCasingInFileNames": true,
"stripInternal": true,
"skipLibCheck": true,
"types": ["vitest/globals"],
"types": [
"vitest/globals"
],
},
"include": ["./src", "./public/codemods", "./test"],
"include": [
"./src",
"./public/codemods",
"./test"
],
}

0 comments on commit 0bc879b

Please sign in to comment.