Skip to content

Commit b1c4ba4

Browse files
robwiseKent C. Dodds
authored andcommitted
feat(format): make format synchronous (#123)
Prettier's resolveConfig function has a .sync function that doesn't require async handling: https://github.com/prettier/prettier#prettierresolveconfigfilepath--options BREAKING CHANGE: the `format` function is now synchronous (again)
1 parent 630bd19 commit b1c4ba4

File tree

4 files changed

+54
-50
lines changed

4 files changed

+54
-50
lines changed

.babelrc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
{
66
"targets": {
77
"node": "4.5"
8-
},
9-
"exclude": ["transform-regenerator"]
8+
}
109
}
1110
]
1211
],

src/__mocks__/prettier.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ const mockFormatSpy = jest.fn(mockFormat)
77

88
Object.assign(prettier, {
99
format: mockFormatSpy,
10-
resolveConfig: jest.fn(prettier.resolveConfig),
10+
resolveConfig: {
11+
sync: jest.fn(prettier.resolveConfig.sync),
12+
},
1113
})
1214

1315
function mockFormat(...args) {

src/__tests__/index.js

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ beforeEach(() => {
184184
eslintMock.mock.executeOnText.mockClear()
185185
eslintMock.mock.getConfigForFile.mockClear()
186186
prettierMock.format.mockClear()
187-
prettierMock.resolveConfig.mockClear()
187+
prettierMock.resolveConfig.sync.mockClear()
188188
fsMock.readFileSync.mockClear()
189189
loglevelMock.mock.clearAll()
190190
global.__PRETTIER_ESLINT_TEST_STATE__ = {}
@@ -195,89 +195,91 @@ tests.forEach(({title, modifier, input, output}) => {
195195
if (modifier) {
196196
fn = test[modifier]
197197
}
198-
fn(title, async () => {
198+
fn(title, () => {
199199
input.text = stripIndent(input.text).trim()
200200
const expected = stripIndent(output).trim()
201-
const actual = await format(input)
201+
const actual = format(input)
202202
// adding the newline in the expected because
203203
// prettier adds a newline to the end of the input
204204
expect(actual).toBe(`${expected}\n`)
205205
})
206206
})
207207

208-
test('failure to fix with eslint throws and logs an error', async () => {
208+
test('failure to fix with eslint throws and logs an error', () => {
209209
const {executeOnText} = eslintMock.mock
210210
const error = new Error('Something happened')
211211
executeOnText.throwError = error
212-
const errorThrown = await format({text: ''}).catch(e => e)
213-
executeOnText.throwError = null
214212

215-
expect(errorThrown).toBe(error)
213+
expect(() => format({text: ''})).toThrowError(error)
216214
expect(logger.error).toHaveBeenCalledTimes(1)
215+
executeOnText.throwError = null
217216
})
218217

219-
test('logLevel is used to configure the logger', async () => {
218+
test('logLevel is used to configure the logger', () => {
220219
logger.setLevel = jest.fn()
221-
await format({text: '', logLevel: 'silent'})
220+
format({text: '', logLevel: 'silent'})
222221
expect(logger.setLevel).toHaveBeenCalledTimes(1)
223222
expect(logger.setLevel).toHaveBeenCalledWith('silent')
224223
})
225224

226-
test(`when prettier throws, log to logger.error and throw the error`, async () => {
225+
test(`when prettier throws, log to logger.error and throw the error`, () => {
227226
const error = new Error('something bad happened')
228227
prettierMock.format.throwError = error
229-
const errorThrown = await format({text: ''}).catch(e => e)
230-
prettierMock.format.throwError = null
231228

232-
expect(errorThrown).toBe(error)
229+
expect(() => format({text: ''})).toThrowError(error)
233230
expect(logger.error).toHaveBeenCalledTimes(1)
231+
prettierMock.format.throwError = null
234232
})
235233

236-
test('can accept a path to an eslint module and uses that instead.', async () => {
234+
test('can accept a path to an eslint module and uses that instead.', () => {
237235
const eslintPath = path.join(__dirname, '../__mocks__/eslint')
238-
await format({text: '', eslintPath})
236+
format({text: '', eslintPath})
239237
expect(eslintMock.mock.executeOnText).toHaveBeenCalledTimes(1)
240238
})
241239

242-
test('fails with an error if the eslint module cannot be resolved.', async () => {
240+
test('fails with an error if the eslint module cannot be resolved.', () => {
243241
const eslintPath = path.join(
244242
__dirname,
245-
'../__mocks__/non-existant-eslint-module',
243+
'../__mocks__/non-existent-eslint-module',
246244
)
247245

248-
const error = await format({text: '', eslintPath}).catch(e => e)
249-
250-
expect(error.message).toMatch(/non-existant-eslint-module/)
246+
expect(() => format({text: '', eslintPath})).toThrowError(
247+
/non-existent-eslint-module/,
248+
)
251249
expect(logger.error).toHaveBeenCalledTimes(1)
252250

253251
const errorString = expect.stringMatching(
254-
/trouble getting.*?eslint.*non-existant-eslint-module/,
252+
/trouble getting.*?eslint.*non-existent-eslint-module/,
255253
)
256254

257255
expect(logger.error).toHaveBeenCalledWith(errorString)
258256
})
259257

260-
test('can accept a path to a prettier module and uses that instead.', async () => {
258+
test('can accept a path to a prettier module and uses that instead.', () => {
261259
const prettierPath = path.join(__dirname, '../__mocks__/prettier')
262-
await format({text: '', prettierPath})
260+
format({text: '', prettierPath})
263261
expect(prettierMock.format).toHaveBeenCalledTimes(1)
264262
})
265263

266-
test('fails with an error if the prettier module cannot be resolved.', async () => {
264+
test('fails with an error if the prettier module cannot be resolved.', () => {
267265
const prettierPath = path.join(
268266
__dirname,
269-
'../__mocks__/non-existant-prettier-module',
267+
'../__mocks__/non-existent-prettier-module',
268+
)
269+
270+
expect(() => format({text: '', prettierPath})).toThrowError(
271+
/non-existent-prettier-module/,
270272
)
271-
const error = await format({text: '', prettierPath}).catch(e => e)
272-
expect(error.message).toMatch(/non-existant-prettier-module/)
273273
expect(logger.error).toHaveBeenCalledTimes(1)
274-
const errorString = expect.stringMatching(/trouble getting.*prettier/)
274+
const errorString = expect.stringMatching(
275+
/trouble getting.*?eslint.*non-existent-prettier-module/,
276+
)
275277
expect(logger.error).toHaveBeenCalledWith(errorString)
276278
})
277279

278-
test('resolves to the eslint module relative to the given filePath', async () => {
280+
test('resolves to the eslint module relative to the given filePath', () => {
279281
const filePath = require.resolve('../../tests/fixtures/paths/foo.js')
280-
await format({text: '', filePath})
282+
format({text: '', filePath})
281283
const stateObj = {
282284
eslintPath: require.resolve(
283285
'../../tests/fixtures/paths/node_modules/eslint/index.js',
@@ -289,9 +291,9 @@ test('resolves to the eslint module relative to the given filePath', async () =>
289291
expect(global.__PRETTIER_ESLINT_TEST_STATE__).toMatchObject(stateObj)
290292
})
291293

292-
test('resolves to the local eslint module', async () => {
294+
test('resolves to the local eslint module', () => {
293295
const filePath = '/blah-blah/default-config'
294-
await format({text: '', filePath})
296+
format({text: '', filePath})
295297
expect(global.__PRETTIER_ESLINT_TEST_STATE__).toMatchObject({
296298
// without Jest's mocking, these would actually resolve to the
297299
// project modules :) The fact that jest's mocking is being
@@ -301,44 +303,45 @@ test('resolves to the local eslint module', async () => {
301303
})
302304
})
303305

304-
test('reads text from fs if filePath is provided but not text', async () => {
306+
test('reads text from fs if filePath is provided but not text', () => {
305307
const filePath = '/blah-blah/some-file.js'
306-
await format({filePath}).catch(() => {})
308+
format({filePath})
309+
// format({filePath}).catch(() => {})
307310
// one hit to get the file and one for the eslintignore
308311
expect(fsMock.readFileSync).toHaveBeenCalledTimes(2)
309312
expect(fsMock.readFileSync).toHaveBeenCalledWith(filePath, 'utf8')
310313
})
311314

312-
test('logs error if it cannot read the file from the filePath', async () => {
315+
test('logs error if it cannot read the file from the filePath', () => {
313316
const originalMock = fsMock.readFileSync
314317
fsMock.readFileSync = jest.fn(() => {
315318
throw new Error('some error')
316319
})
317-
const error = await format({filePath: '/some-path.js'}).catch(e => e)
318-
expect(error.message).toMatch(/some error/)
320+
expect(() => format({filePath: '/some-path.js'})).toThrowError(
321+
/some error/,
322+
)
319323
expect(logger.error).toHaveBeenCalledTimes(1)
320324
fsMock.readFileSync = originalMock
321325
})
322326

323-
test('calls prettier.resolveConfig with the file path', async () => {
327+
test('calls prettier.resolveConfig.sync with the file path', () => {
324328
const filePath = require.resolve('../../tests/fixtures/paths/foo.js')
325-
await format({
329+
format({
326330
filePath,
327331
text: defaultInputText(),
328332
eslintConfig: getESLintConfigWithDefaultRules(),
329333
})
330-
expect(prettierMock.resolveConfig).toHaveBeenCalledTimes(1)
331-
expect(prettierMock.resolveConfig).toHaveBeenCalledWith(filePath)
334+
expect(prettierMock.resolveConfig.sync).toHaveBeenCalledTimes(1)
335+
expect(prettierMock.resolveConfig.sync).toHaveBeenCalledWith(filePath)
332336
})
333337

334-
test('logs if there is a problem making the CLIEngine', async () => {
338+
test('logs if there is a problem making the CLIEngine', () => {
335339
const error = new Error('fake error')
336340
eslintMock.CLIEngine.mockImplementation(() => {
337341
throw error
338342
})
339-
const errorThrown = await format({text: ''}).catch(e => e)
343+
expect(() => format({text: ''})).toThrowError(error)
340344
eslintMock.CLIEngine.mockReset()
341-
expect(errorThrown).toBe(error)
342345
expect(logger.error).toHaveBeenCalledTimes(1)
343346
})
344347

src/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ module.exports = format
3939
* @param {Boolean} options.prettierLast - Run Prettier Last
4040
* @return {String} - the formatted string
4141
*/
42-
async function format(options) {
42+
function format(options) {
4343
const {logLevel = getDefaultLogLevel()} = options
4444
logger.setLevel(logLevel)
4545
logger.trace('called format with options:', prettyFormat(options))
@@ -61,7 +61,7 @@ async function format(options) {
6161

6262
const prettierOptions = merge(
6363
{},
64-
await getPrettierConfig(filePath, prettierPath),
64+
getPrettierConfig(filePath, prettierPath),
6565
options.prettierOptions,
6666
)
6767

@@ -227,7 +227,7 @@ function getConfig(filePath, eslintPath) {
227227

228228
function getPrettierConfig(filePath, prettierPath) {
229229
const prettier = requireModule(prettierPath, 'prettier')
230-
return prettier.resolveConfig(filePath)
230+
return prettier.resolveConfig.sync(filePath)
231231
}
232232

233233
function requireModule(modulePath, name) {

0 commit comments

Comments
 (0)