Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decaff helper jscodemods. #5732

Merged
merged 21 commits into from
Dec 6, 2019
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bulk-decaffeinate.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,10 @@ module.exports = {
path.resolve('node_modules', 'jscodemods', 'decaffeinate', 'fix-multi-assign-class-export.js'),
path.resolve('node_modules', 'jscodemods', 'decaffeinate', 'fix-implicit-return-assignment.js'),
path.resolve('node_modules', 'jscodemods', 'decaffeinate', 'fix-existential-conditional-assignment.js'),
'./scripts/decaff/remove-comment-sharp.js',
'./scripts/decaff/switch-false.js',
'./scripts/decaff/empty-catch.js',
'./scripts/decaff/no-cond-assign.js',
'./scripts/decaff/arrow-comment.js',
],
}
2 changes: 2 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ jobs:
- run: npm run test-mocha-snapshot
# make sure packages with TypeScript can be transpiled to JS
- run: npm run all build-js
# test codemods
- run: npm run test-jscodeshift
# run unit tests from individual packages
- run: npm run all test -- --package cli
- run: npm run all test -- --package electron
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"stop-only-all": "npm run stop-only -- --folder packages",
"test": "echo '⚠️ This root monorepo is only for local development and new contributions. There are no tests.'",
"test-debug-package": "node ./scripts/test-debug-package.js",
"test-jscodeshift": "jest ./scripts/decaff",
"test-mocha": "mocha --reporter spec scripts/spec.js",
"test-mocha-snapshot": "mocha scripts/mocha-snapshot-spec.js",
"test-s3-api": "node -r ./packages/coffee/register -r ./packages/ts/register scripts/binary/s3-api-demo.ts",
Expand Down Expand Up @@ -133,6 +134,7 @@
"husky": "2.4.1",
"inquirer": "3.3.0",
"inquirer-confirm": "2.0.3",
"jest": "24.9.0",
"js-codemod": "cpojer/js-codemod#29dafed",
"jscodemods": "cypress-io/jscodemods#01b546e",
"jscodeshift": "0.6.3",
Expand Down
3 changes: 3 additions & 0 deletions scripts/decaff/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"parser": "espree"
}
11 changes: 11 additions & 0 deletions scripts/decaff/__testfixtures__/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"parser": "espree",
"rules": {
"no-empty": "off",
"no-undef": "off",
"no-cond-assign": "off",
"semi": "off",
"brace-style": "off",
"no-case-declarations": "off"
}
}
10 changes: 10 additions & 0 deletions scripts/decaff/__testfixtures__/arrow-comment.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Original comment
const func = (a, b) =>
// Multiline comment
// is here
{
a.works()
b.check.thisOut()
}

func()
10 changes: 10 additions & 0 deletions scripts/decaff/__testfixtures__/arrow-comment.output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Original comment
// Multiline comment
// is here
const func = (a, b) =>
{
a.works()
b.check.thisOut()
};

func()
7 changes: 7 additions & 0 deletions scripts/decaff/__testfixtures__/empty-catch.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
try {
// do something
} catch (e) {}

try {
// do something
} finally {}
7 changes: 7 additions & 0 deletions scripts/decaff/__testfixtures__/empty-catch.output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
try {
// do something
} catch (e) {} // eslint-disable-line no-empty

try {
// do something
} finally {}
6 changes: 6 additions & 0 deletions scripts/decaff/__testfixtures__/no-cond-assign.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
let a

// Comment
if (a = c()) {
a.fix()
}
8 changes: 8 additions & 0 deletions scripts/decaff/__testfixtures__/no-cond-assign.output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
let a

// Comment
a = c();

if (a) {
a.fix()
}
6 changes: 6 additions & 0 deletions scripts/decaff/__testfixtures__/remove-comment-sharp.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//# Testing this
// eslint-disable-next-line
console.log('it works') //# Test

// This # should not be removed.
/*# it's not wrong */
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Testing this
// eslint-disable-next-line
console.log('it works') // Test

// This # should not be removed.
/*# it's not wrong */
33 changes: 33 additions & 0 deletions scripts/decaff/__testfixtures__/switch-false.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
function f () {
switch (false) {
// Comment should be reserved
case !a.subject(a):
let x = 30

b.doSomething(x)
break
// Multi line comment
// should be reserved
case c.isGood:
c.checkThisOut()
findThings()
break
case isBad:
c.neverCheck()
break
case !isAwesome:
a.subject(a)
break
case hi:
// This should be reserved, too
return 3
case you:
// This comment is preserved
break
default:
b.goToNext()
break
}
}

f()
25 changes: 25 additions & 0 deletions scripts/decaff/__testfixtures__/switch-false.output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
function f () {
if (a.subject(a)) {
// Comment should be reserved
let x = 30;

b.doSomething(x)
} else if (!c.isGood) {
// Multi line comment
// should be reserved
c.checkThisOut();
findThings()
} else if (!isBad) {
c.neverCheck();
} else if (isAwesome) {
a.subject(a);
} else if (!hi) {
// This should be reserved, too
return 3
} else if (!you) // This comment is preserved
{} else {
b.goToNext();
}
}

f()
10 changes: 10 additions & 0 deletions scripts/decaff/__tests__/decaff.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* global jest */

jest.autoMockOff()
const defineTest = require('jscodeshift/dist/testUtils').defineTest

defineTest(__dirname, 'switch-false')
defineTest(__dirname, 'empty-catch')
defineTest(__dirname, 'remove-comment-sharp')
defineTest(__dirname, 'arrow-comment')
defineTest(__dirname, 'no-cond-assign')
28 changes: 28 additions & 0 deletions scripts/decaff/arrow-comment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module.exports = (fileInfo, api) => {
const j = api.jscodeshift

return j(fileInfo.source)
.find(j.VariableDeclaration, {
declarations: [{
type: 'VariableDeclarator',
init: {
type: 'ArrowFunctionExpression',
body: {
type: 'BlockStatement',
},
},
}],
})
.replaceWith((nodePath) => {
const { node } = nodePath
const comments = node.declarations[0].init.body.comments

if (comments && comments.length > 0) {
node.comments = [...node.comments, ...comments]
node.declarations[0].init.body.comments = null
}

return node
})
.toSource()
}
28 changes: 28 additions & 0 deletions scripts/decaff/empty-catch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module.exports = (fileInfo, api) => {
const j = api.jscodeshift

const source = j(fileInfo.source)
.find(j.TryStatement)
.replaceWith((nodePath) => {
const { node } = nodePath

// Add trailing eslint-disable-line for empty catch block
if (node.handler && node.handler.body.body.length === 0) {
node.handler.body.comments = [
{
type: 'Line',
value: ' eslint-disable-line no-empty',
leading: false,
trailing: true,
},
]
}

return node
})
.toSource()

// Generated source above creates {}// eslint-disable-line block.
// So, add a space with replace
return source.replace(/\{\}\/\/ eslint-disable-line/g, '{} // eslint-disable-line')
}
29 changes: 29 additions & 0 deletions scripts/decaff/no-cond-assign.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module.exports = (fileInfo, api) => {
const j = api.jscodeshift

return j(fileInfo.source)
.find(j.IfStatement, {
test: {
type: 'AssignmentExpression',
},
})
.replaceWith((nodePath) => {
const { node } = nodePath

const assign = j.expressionStatement(node.test)

assign.comments = node.comments

const ifStatement = j.ifStatement(
node.test.left,
node.consequent,
node.alternate
)

return [
assign,
ifStatement,
]
})
.toSource()
}
4 changes: 4 additions & 0 deletions scripts/decaff/remove-comment-sharp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// This file doesn't use AST because it makes things too complicated.
module.exports = (fileInfo) => {
return fileInfo.source.replace(/\/\/#/g, '//')
}
98 changes: 98 additions & 0 deletions scripts/decaff/switch-false.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
module.exports = (fileInfo, api) => {
const j = api.jscodeshift

return j(fileInfo.source)
.find(j.SwitchStatement, {
discriminant: {
type: 'Literal',
value: false,
},
})
.replaceWith((nodePath) => {
const { node } = nodePath

const cases = node.cases.map((c) => {
const { test, consequent, comments } = c

return {
test: generateTest(j, test),
content: generateContent(j, consequent),
comments,
}
})

const ifStatement = generateIfStatement(j, cases)

ifStatement.comments = node.comments

return ifStatement
})
.toSource()
}

function generateTest (j, test) {
if (test) {
if (test.type === 'UnaryExpression') {
return test.argument
}

return j.unaryExpression('!', test)
}

return null
}

function generateContent (j, consequent) {
if (consequent.length === 1 && consequent[0].type === 'BreakStatement') {
const block = j.blockStatement([])

block.comments = consequent[0].comments

return block
}

return j.blockStatement(consequent.filter((c) => c.type !== 'BreakStatement'))
}

function generateIfStatement (j, cases) {
const nonDefaultCases = cases.filter((c) => c.test !== null)
const defaultCase = cases.filter((c) => c.test === null)[0]

let ifStatement = null

if (defaultCase) {
const content = addComment(defaultCase.content, defaultCase.comments)

ifStatement = content
}

nonDefaultCases.reverse().forEach((c) => {
const content = addComment(c.content, c.comments)

ifStatement = j.ifStatement(
c.test,
content,
ifStatement
)
})

return ifStatement
}

function addComment (content, comments) {
if (content.body.length > 0) {
content.body[0].comments = [...(comments || []), ...(content.body[0].comments || [])]
} else {
const newComments = (comments || []).map((co) => {
return {
...co,
leading: false,
trailing: false,
}
})

content.comments = [...newComments, ...(content.comments || [])]
}

return content
}