Skip to content

Commit

Permalink
Allow glob to be sync
Browse files Browse the repository at this point in the history
  • Loading branch information
ehmicky committed Jun 5, 2022
1 parent 301bf87 commit 667f207
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 10 deletions.
31 changes: 21 additions & 10 deletions src/config/normalize/lib/keywords/list/glob.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,36 @@ import { basename } from 'path'
import fastGlob from 'fast-glob'
import { isNotJunk } from 'junk'

import { create, call } from '../../../../../utils/async_sync.js'
import { validateDefinedString, normalizeBoolean } from '../normalize/common.js'

const mainAsync = async function (definition, input, { cwd }) {
// eslint-disable-next-line max-params
const mainSyncAsync = function (sync, definition, input, { cwd }) {
if (!definition) {
return
}

validateDefinedString(input)
const filePaths = await fastGlob(input, {
cwd,
absolute: true,
unique: true,
onlyFiles: true,
})
const filePathsA = filePaths.filter((filePath) =>
isNotJunk(basename(filePath)),
return call(
sync,
fastGlob.sync,
fastGlob,
[input, { cwd, absolute: true, unique: true, onlyFiles: true }],
returnFilePaths,
)
return { input: filePathsA }
}

const returnFilePaths = function (filePaths) {
const input = filePaths.filter(shouldKeepFilePath)
return { input }
}

const shouldKeepFilePath = function (filePath) {
return isNotJunk(basename(filePath))
}

const [main, mainAsync] = create(mainSyncAsync)

// Apply `glob[(input, info)]` which resolves the input as a globbing pattern
// when `true` (default: `false`).
// Duplicates and temporary files are also removed.
Expand All @@ -37,5 +47,6 @@ export default {
hasInput: true,
exampleDefinition: true,
normalize: normalizeBoolean,
main,
mainAsync,
}
1 change: 1 addition & 0 deletions src/config/normalize/lib/keywords/normalize/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const DEFAULT_VALUES = {

// `keyword.normalize()` must be a pure function, because it is memoized for
// performance reasons.
// Due to `isPromise`, async methods should always return promises.
const memoizeNormalize = function ({ normalize, normalizeSync }) {
return normalize === undefined
? normalize
Expand Down
64 changes: 64 additions & 0 deletions src/utils/async_sync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Split functions into two: sync and async.
// A `sync` boolean is passed as first argument.
// The async method uses `async`/`await` to:
// - Ensure the return value is always a promise
// - Keep the top-level call in the stack trace
export const create = function (func) {
return [
(...args) => func(true, ...args),
async (...args) => await func(false, ...args),
]
}

// Call either a sync or async function depending on the `sync` boolean argument
// If passed, a `callback()` is called with the return value.
// The caller must immediately return this function's return value as it might
// be a promise.
// Stack traces:
// - When async, stack traces of the caller functions are lost unless using
// those are using `async`/`await`.
// - This is not possible for the function calling `thenCall()`, and is
// often not possible either for the parents.
// - Stack traces of `callback()` and children are kept.
// eslint-disable-next-line max-params, complexity
export const call = function (
sync,
syncMethod,
asyncMethod,
// eslint-disable-next-line default-param-last
args = [],
callback,
errorHandler,
) {
const maybePromise = sync ? syncMethod(...args) : asyncMethod(...args)

if (callback === undefined) {
return maybePromise
}

if (isPromise(maybePromise)) {
// eslint-disable-next-line promise/prefer-await-to-then, promise/no-callback-in-promise
return maybePromise.then(callback, errorHandler)
}

if (errorHandler === undefined) {
// eslint-disable-next-line promise/prefer-await-to-callbacks
return callback(maybePromise)
}

try {
// eslint-disable-next-line promise/prefer-await-to-callbacks
return callback(maybePromise)
} catch (error) {
return errorHandler(error)
}
}

const isPromise = function (maybePromise) {
return (
typeof maybePromise === 'object' &&
maybePromise !== null &&
// eslint-disable-next-line promise/prefer-await-to-then
typeof maybePromise.then === 'function'
)
}

0 comments on commit 667f207

Please sign in to comment.