UNPKG

@riddance/env

Version:

It slows you down, creates risks, increases maintainability burdens. So let's commit less of it.

91 lines 12.7 kB
import { spellCheckFile } from 'cspell-lib'; import { readFile, writeFile } from 'node:fs/promises'; import { join, resolve } from 'node:path'; export function isSpellingDictionaryFile(files) { return files.length === 1 && files[0] === 'dictionary.txt'; } export async function spelling(reporter, path, files, abort) { const dictionaryWords = await readWords(path); const words = [...commonInducedWords, ...dictionaryWords]; const checkFiles = ['package.json', 'example/package.json', ...files]; const [, ...results] = await Promise.all([ syncConfigFile(path, dictionaryWords), ...checkFiles.map(file => spellCheckFile(resolve(path, file), { generateSuggestions: false }, { noConfigSearch: true, words })), ]); if (abort.aborted) { return false; } const errors = results.flatMap((r, ix) => (r.errors ?? []) .filter(e => !isFileNotFound(e)) .map(error => ({ file: checkFiles[ix], error }))); if (errors.length !== 0) { for (const e of errors) { reporter.fatal('Unexpected error checking spelling.', e.error, e.file); } return false; } const issues = results.flatMap((r, ix) => r.issues.map((issue) => ({ file: checkFiles[ix], issue, }))); if (issues.length !== 0) { for (const i of issues) { reporter.error(i.issue.message ?? 'Unknown word: ' + i.issue.text, i.file, i.issue.line.position && i.issue.line.position.line + 1); } return false; } return true; } const commonInducedWords = ['camelcase', 'postpublish']; async function readWords(dir) { try { const dictionary = await readFile(join(dir, 'dictionary.txt')); return dictionary .toString('utf-8') .split('\n') .filter(l => !!l) .map(l => l.trim()); } catch (e) { if (isFileNotFound(e)) { return []; } throw e; } } export async function setupSpelling(dir) { await syncConfigFile(dir, await readWords(dir)); } async function syncConfigFile(dir, words) { const config = JSON.stringify({ version: '0.2', files: ['**/*.ts', 'package.json', 'example/package.json'], words: commonInducedWords, ...(words.length !== 0 && { dictionaries: ['project'], dictionaryDefinitions: [ { name: 'project', path: './dictionary.txt', }, ], }), }, undefined, ' '); try { const existing = await readFile(join(dir, 'cspell.json'), 'utf-8'); if (existing !== config) { await writeFile(join(dir, 'cspell.json'), config); } } catch (e) { if (isFileNotFound(e)) { await writeFile(join(dir, 'cspell.json'), config); return; } throw e; } } function isFileNotFound(e) { return e.code === 'ENOENT'; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BlbGxpbmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzcGVsbGluZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQW1CLGNBQWMsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUM1RCxPQUFPLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxNQUFNLGtCQUFrQixDQUFBO0FBQ3RELE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBR3pDLE1BQU0sVUFBVSx3QkFBd0IsQ0FBQyxLQUFlO0lBQ3BELE9BQU8sS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLGdCQUFnQixDQUFBO0FBQzlELENBQUM7QUFFRCxNQUFNLENBQUMsS0FBSyxVQUFVLFFBQVEsQ0FDMUIsUUFBa0IsRUFDbEIsSUFBWSxFQUNaLEtBQWUsRUFDZixLQUFrQjtJQUVsQixNQUFNLGVBQWUsR0FBRyxNQUFNLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUM3QyxNQUFNLEtBQUssR0FBRyxDQUFDLEdBQUcsa0JBQWtCLEVBQUUsR0FBRyxlQUFlLENBQUMsQ0FBQTtJQUN6RCxNQUFNLFVBQVUsR0FBRyxDQUFDLGNBQWMsRUFBRSxzQkFBc0IsRUFBRSxHQUFHLEtBQUssQ0FBQyxDQUFBO0lBQ3JFLE1BQU0sQ0FBQyxFQUFFLEdBQUcsT0FBTyxDQUFDLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDO1FBQ3JDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsZUFBZSxDQUFDO1FBQ3JDLEdBQUcsVUFBVSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUNyQixjQUFjLENBQ1YsT0FBTyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsRUFDbkIsRUFBRSxtQkFBbUIsRUFBRSxLQUFLLEVBQUUsRUFDOUIsRUFBRSxjQUFjLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxDQUNsQyxDQUNKO0tBQ0osQ0FBQyxDQUFBO0lBQ0YsSUFBSSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDaEIsT0FBTyxLQUFLLENBQUE7SUFDaEIsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FDckMsQ0FBQyxDQUFDLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztTQUNYLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQy9CLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsVUFBVSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FDdkQsQ0FBQTtJQUNELElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUN0QixLQUFLLE1BQU0sQ0FBQyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ3JCLFFBQVEsQ0FBQyxLQUFLLENBQUMscUNBQXFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDMUUsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFBO0lBQ2hCLENBQUM7SUFDRCxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQ3JDLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBa0UsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNsRixJQUFJLEVBQUUsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUNwQixLQUFLO0tBQ1IsQ0FBQyxDQUFDLENBQ04sQ0FBQTtJQUNELElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUN0QixLQUFLLE1BQU0sQ0FBQyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ3JCLFFBQVEsQ0FBQyxLQUFLLENBQ1YsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLElBQUksZ0JBQWdCLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQ2xELENBQUMsQ0FBQyxJQUFJLEVBQ04sQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUMxRCxDQUFBO1FBQ0wsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFBO0lBQ2hCLENBQUM7SUFDRCxPQUFPLElBQUksQ0FBQTtBQUNmLENBQUM7QUFFRCxNQUFNLGtCQUFrQixHQUFHLENBQUMsV0FBVyxFQUFFLGFBQWEsQ0FBQyxDQUFBO0FBRXZELEtBQUssVUFBVSxTQUFTLENBQUMsR0FBVztJQUNoQyxJQUFJLENBQUM7UUFDRCxNQUFNLFVBQVUsR0FBRyxNQUFNLFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLGdCQUFnQixDQUFDLENBQUMsQ0FBQTtRQUM5RCxPQUFPLFVBQVU7YUFDWixRQUFRLENBQUMsT0FBTyxDQUFDO2FBQ2pCLEtBQUssQ0FBQyxJQUFJLENBQUM7YUFDWCxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2FBQ2hCLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBQzNCLENBQUM7SUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQ1QsSUFBSSxjQUFjLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNwQixPQUFPLEVBQUUsQ0FBQTtRQUNiLENBQUM7UUFDRCxNQUFNLENBQUMsQ0FBQTtJQUNYLENBQUM7QUFDTCxDQUFDO0FBRUQsTUFBTSxDQUFDLEtBQUssVUFBVSxhQUFhLENBQUMsR0FBVztJQUMzQyxNQUFNLGNBQWMsQ0FBQyxHQUFHLEVBQUUsTUFBTSxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQTtBQUNuRCxDQUFDO0FBRUQsS0FBSyxVQUFVLGNBQWMsQ0FBQyxHQUFXLEVBQUUsS0FBZTtJQUN0RCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsU0FBUyxDQUN6QjtRQUNJLE9BQU8sRUFBRSxLQUFLO1FBQ2QsS0FBSyxFQUFFLENBQUMsU0FBUyxFQUFFLGNBQWMsRUFBRSxzQkFBc0IsQ0FBQztRQUMxRCxLQUFLLEVBQUUsa0JBQWtCO1FBQ3pCLEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSTtZQUN0QixZQUFZLEVBQUUsQ0FBQyxTQUFTLENBQUM7WUFDekIscUJBQXFCLEVBQUU7Z0JBQ25CO29CQUNJLElBQUksRUFBRSxTQUFTO29CQUNmLElBQUksRUFBRSxrQkFBa0I7aUJBQzNCO2FBQ0o7U0FDSixDQUFDO0tBQ0wsRUFDRCxTQUFTLEVBQ1QsSUFBSSxDQUNQLENBQUE7SUFDRCxJQUFJLENBQUM7UUFDRCxNQUFNLFFBQVEsR0FBRyxNQUFNLFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFBO1FBQ2xFLElBQUksUUFBUSxLQUFLLE1BQU0sRUFBRSxDQUFDO1lBQ3RCLE1BQU0sU0FBUyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsYUFBYSxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUE7UUFDckQsQ0FBQztJQUNMLENBQUM7SUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQ1QsSUFBSSxjQUFjLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNwQixNQUFNLFNBQVMsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFBO1lBQ2pELE9BQU07UUFDVixDQUFDO1FBQ0QsTUFBTSxDQUFDLENBQUE7SUFDWCxDQUFDO0FBQ0wsQ0FBQztBQUVELFNBQVMsY0FBYyxDQUFDLENBQVU7SUFDOUIsT0FBUSxDQUF1QixDQUFDLElBQUksS0FBSyxRQUFRLENBQUE7QUFDckQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFZhbGlkYXRpb25Jc3N1ZSwgc3BlbGxDaGVja0ZpbGUgfSBmcm9tICdjc3BlbGwtbGliJ1xuaW1wb3J0IHsgcmVhZEZpbGUsIHdyaXRlRmlsZSB9IGZyb20gJ25vZGU6ZnMvcHJvbWlzZXMnXG5pbXBvcnQgeyBqb2luLCByZXNvbHZlIH0gZnJvbSAnbm9kZTpwYXRoJ1xuaW1wb3J0IHsgUmVwb3J0ZXIgfSBmcm9tICcuL3JlcG9ydGVyLmpzJ1xuXG5leHBvcnQgZnVuY3Rpb24gaXNTcGVsbGluZ0RpY3Rpb25hcnlGaWxlKGZpbGVzOiBzdHJpbmdbXSkge1xuICAgIHJldHVybiBmaWxlcy5sZW5ndGggPT09IDEgJiYgZmlsZXNbMF0gPT09ICdkaWN0aW9uYXJ5LnR4dCdcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNwZWxsaW5nKFxuICAgIHJlcG9ydGVyOiBSZXBvcnRlcixcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgZmlsZXM6IHN0cmluZ1tdLFxuICAgIGFib3J0OiBBYm9ydFNpZ25hbCxcbikge1xuICAgIGNvbnN0IGRpY3Rpb25hcnlXb3JkcyA9IGF3YWl0IHJlYWRXb3JkcyhwYXRoKVxuICAgIGNvbnN0IHdvcmRzID0gWy4uLmNvbW1vbkluZHVjZWRXb3JkcywgLi4uZGljdGlvbmFyeVdvcmRzXVxuICAgIGNvbnN0IGNoZWNrRmlsZXMgPSBbJ3BhY2thZ2UuanNvbicsICdleGFtcGxlL3BhY2thZ2UuanNvbicsIC4uLmZpbGVzXVxuICAgIGNvbnN0IFssIC4uLnJlc3VsdHNdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICBzeW5jQ29uZmlnRmlsZShwYXRoLCBkaWN0aW9uYXJ5V29yZHMpLFxuICAgICAgICAuLi5jaGVja0ZpbGVzLm1hcChmaWxlID0+XG4gICAgICAgICAgICBzcGVsbENoZWNrRmlsZShcbiAgICAgICAgICAgICAgICByZXNvbHZlKHBhdGgsIGZpbGUpLFxuICAgICAgICAgICAgICAgIHsgZ2VuZXJhdGVTdWdnZXN0aW9uczogZmFsc2UgfSxcbiAgICAgICAgICAgICAgICB7IG5vQ29uZmlnU2VhcmNoOiB0cnVlLCB3b3JkcyB9LFxuICAgICAgICAgICAgKSxcbiAgICAgICAgKSxcbiAgICBdKVxuICAgIGlmIChhYm9ydC5hYm9ydGVkKSB7XG4gICAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cbiAgICBjb25zdCBlcnJvcnMgPSByZXN1bHRzLmZsYXRNYXAoKHIsIGl4KSA9PlxuICAgICAgICAoci5lcnJvcnMgPz8gW10pXG4gICAgICAgICAgICAuZmlsdGVyKGUgPT4gIWlzRmlsZU5vdEZvdW5kKGUpKVxuICAgICAgICAgICAgLm1hcChlcnJvciA9PiAoeyBmaWxlOiBjaGVja0ZpbGVzW2l4XSwgZXJyb3IgfSkpLFxuICAgIClcbiAgICBpZiAoZXJyb3JzLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICBmb3IgKGNvbnN0IGUgb2YgZXJyb3JzKSB7XG4gICAgICAgICAgICByZXBvcnRlci5mYXRhbCgnVW5leHBlY3RlZCBlcnJvciBjaGVja2luZyBzcGVsbGluZy4nLCBlLmVycm9yLCBlLmZpbGUpXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfVxuICAgIGNvbnN0IGlzc3VlcyA9IHJlc3VsdHMuZmxhdE1hcCgociwgaXgpID0+XG4gICAgICAgIHIuaXNzdWVzLm1hcCgoaXNzdWU6IFZhbGlkYXRpb25Jc3N1ZSAmIHsgbGluZTogeyBwb3NpdGlvbj86IHsgbGluZTogbnVtYmVyIH0gfSB9KSA9PiAoe1xuICAgICAgICAgICAgZmlsZTogY2hlY2tGaWxlc1tpeF0sXG4gICAgICAgICAgICBpc3N1ZSxcbiAgICAgICAgfSkpLFxuICAgIClcbiAgICBpZiAoaXNzdWVzLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICBmb3IgKGNvbnN0IGkgb2YgaXNzdWVzKSB7XG4gICAgICAgICAgICByZXBvcnRlci5lcnJvcihcbiAgICAgICAgICAgICAgICBpLmlzc3VlLm1lc3NhZ2UgPz8gJ1Vua25vd24gd29yZDogJyArIGkuaXNzdWUudGV4dCxcbiAgICAgICAgICAgICAgICBpLmZpbGUsXG4gICAgICAgICAgICAgICAgaS5pc3N1ZS5saW5lLnBvc2l0aW9uICYmIGkuaXNzdWUubGluZS5wb3NpdGlvbi5saW5lICsgMSxcbiAgICAgICAgICAgIClcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2VcbiAgICB9XG4gICAgcmV0dXJuIHRydWVcbn1cblxuY29uc3QgY29tbW9uSW5kdWNlZFdvcmRzID0gWydjYW1lbGNhc2UnLCAncG9zdHB1Ymxpc2gnXVxuXG5hc3luYyBmdW5jdGlvbiByZWFkV29yZHMoZGlyOiBzdHJpbmcpIHtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCBkaWN0aW9uYXJ5ID0gYXdhaXQgcmVhZEZpbGUoam9pbihkaXIsICdkaWN0aW9uYXJ5LnR4dCcpKVxuICAgICAgICByZXR1cm4gZGljdGlvbmFyeVxuICAgICAgICAgICAgLnRvU3RyaW5nKCd1dGYtOCcpXG4gICAgICAgICAgICAuc3BsaXQoJ1xcbicpXG4gICAgICAgICAgICAuZmlsdGVyKGwgPT4gISFsKVxuICAgICAgICAgICAgLm1hcChsID0+IGwudHJpbSgpKVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGlzRmlsZU5vdEZvdW5kKGUpKSB7XG4gICAgICAgICAgICByZXR1cm4gW11cbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBlXG4gICAgfVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2V0dXBTcGVsbGluZyhkaXI6IHN0cmluZykge1xuICAgIGF3YWl0IHN5bmNDb25maWdGaWxlKGRpciwgYXdhaXQgcmVhZFdvcmRzKGRpcikpXG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN5bmNDb25maWdGaWxlKGRpcjogc3RyaW5nLCB3b3Jkczogc3RyaW5nW10pIHtcbiAgICBjb25zdCBjb25maWcgPSBKU09OLnN0cmluZ2lmeShcbiAgICAgICAge1xuICAgICAgICAgICAgdmVyc2lvbjogJzAuMicsXG4gICAgICAgICAgICBmaWxlczogWycqKi8qLnRzJywgJ3BhY2thZ2UuanNvbicsICdleGFtcGxlL3BhY2thZ2UuanNvbiddLFxuICAgICAgICAgICAgd29yZHM6IGNvbW1vbkluZHVjZWRXb3JkcyxcbiAgICAgICAgICAgIC4uLih3b3Jkcy5sZW5ndGggIT09IDAgJiYge1xuICAgICAgICAgICAgICAgIGRpY3Rpb25hcmllczogWydwcm9qZWN0J10sXG4gICAgICAgICAgICAgICAgZGljdGlvbmFyeURlZmluaXRpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU6ICdwcm9qZWN0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhdGg6ICcuL2RpY3Rpb25hcnkudHh0JyxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgfSksXG4gICAgICAgIH0sXG4gICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgJyAgJyxcbiAgICApXG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgZXhpc3RpbmcgPSBhd2FpdCByZWFkRmlsZShqb2luKGRpciwgJ2NzcGVsbC5qc29uJyksICd1dGYtOCcpXG4gICAgICAgIGlmIChleGlzdGluZyAhPT0gY29uZmlnKSB7XG4gICAgICAgICAgICBhd2FpdCB3cml0ZUZpbGUoam9pbihkaXIsICdjc3BlbGwuanNvbicpLCBjb25maWcpXG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGlmIChpc0ZpbGVOb3RGb3VuZChlKSkge1xuICAgICAgICAgICAgYXdhaXQgd3JpdGVGaWxlKGpvaW4oZGlyLCAnY3NwZWxsLmpzb24nKSwgY29uZmlnKVxuICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZVxuICAgIH1cbn1cblxuZnVuY3Rpb24gaXNGaWxlTm90Rm91bmQoZTogdW5rbm93bikge1xuICAgIHJldHVybiAoZSBhcyB7IGNvZGU6IHVua25vd24gfSkuY29kZSA9PT0gJ0VOT0VOVCdcbn1cbiJdfQ==