Skip to content

Commit

Permalink
fix: eslint-plugin, make sure dictionary settings make it to cspell-l…
Browse files Browse the repository at this point in the history
…ib (#4872)
  • Loading branch information
Jason3S authored Sep 27, 2023
1 parent 2056e98 commit 4e28046
Show file tree
Hide file tree
Showing 19 changed files with 273 additions and 70 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ out

temp
tmp
*.log

# Dependency directories

Expand Down
5 changes: 2 additions & 3 deletions cspell.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -777,9 +777,8 @@
"type": "string"
},
"DictionaryPath": {
"description": "A File System Path to a dictionary file.",
"markdownDescription": "A File System Path to a dictionary file.",
"pattern": "^.*\\.(?:txt|trie)(?:\\.gz)?$",
"description": "A File System Path to a dictionary file. Pattern: `^.*\\.(?:txt|trie|dic)(?:\\.gz)?$`",
"markdownDescription": "A File System Path to a dictionary file.\nPattern: `^.*\\.(?:txt|trie|dic)(?:\\.gz)?$`",
"type": "string"
},
"DictionaryRef": {
Expand Down
4 changes: 1 addition & 3 deletions packages/cspell-eslint-plugin/assets/options.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
},
"path": {
"description": "Path to the file.",
"pattern": "^.*\\.(?:txt|trie)(?:\\.gz)?$",
"type": "string"
},
"repMap": {
Expand Down Expand Up @@ -192,8 +191,7 @@
"description": "Specify a path to a custom word list file.\n\nexample: ```js customWordListFile: \"./myWords.txt\" ```"
},
"debugMode": {
"default": false,
"description": "Output debug logs",
"description": "Output debug logs to `.cspell-eslint-plugin.log` default false",
"type": "boolean"
},
"generateSuggestions": {
Expand Down
35 changes: 35 additions & 0 deletions packages/cspell-eslint-plugin/fixtures/issue-4870/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module.exports = {
env: {
browser: true,
commonjs: true,
es6: true,
jest: true,
node: true,
},
extends: ['eslint:recommended', 'plugin:@cspell/recommended'],
parserOptions: {
ecmaFeatures: { jsx: true },
ecmaVersion: 2018,
sourceType: 'module',
},
plugins: ['@cspell'],
root: true,
rules: {
'@cspell/spellchecker': [
'warn',
{
debugMode: true,
autoFix: true,
cspell: {
dictionaries: ['business-terminology'],
dictionaryDefinitions: [
{
name: 'business-terminology',
path: './dictionaries/business-terminology.txt',
},
],
},
},
],
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# dictionaries:
# - business-terminology
# dictionaryDefinitions:
# - name: business-terminology
# path: ./dictionaries/business-terminology.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bestbusiness
friendz
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('hello bestbusiness and friendz');
13 changes: 8 additions & 5 deletions packages/cspell-eslint-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
"homepage": "https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell-eslint-plugin#readme",
"license": "MIT",
"exports": {
"types": "./dist/plugin/index.d.cts",
"require": "./dist/plugin/index.cjs",
"import": "./dist/plugin/index.cjs",
"default": "./dist/plugin/index.cjs"
"./package.json": "./package.json",
".": {
"types": "./dist/plugin/index.d.cts",
"require": "./dist/plugin/index.cjs",
"import": "./dist/plugin/index.cjs",
"default": "./dist/plugin/index.cjs"
}
},
"type": "module",
"main": "dist/plugin/index.cjs",
Expand All @@ -38,7 +41,7 @@
"build": "pnpm build:schema && pnpm build:src",
"build:src": "tsc -b ./tsconfig.json",
"build:schema": "ts-json-schema-generator --no-top-ref --expose none --path src/common/options.cts --type Options -o ./assets/options.schema.json",
"watch": "tsc -p . --watch",
"watch": "tsc -b ./tsconfig.json --watch",
"clean": "shx rm -rf dist temp coverage \"*.tsbuildInfo\"",
"clean-build": "pnpm run clean && pnpm run build",
"coverage": "echo coverage",
Expand Down
60 changes: 60 additions & 0 deletions packages/cspell-eslint-plugin/src/common/logger.cts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import fs from 'fs';
import path from 'path';
import { format } from 'util';

const debugMode = false;

export interface LoggerOptions {
logFile?: string;
cwd?: string;
/** true - write to file, false - output to console. */
logToFile?: boolean;
/** enable logging by default? */
enabled?: boolean;
useAsync?: boolean;
}

export class Logger {
readonly logFile: string;
readonly cwd: string;
logToFile = true;
enabled = true;
useAsync = false;

constructor(readonly options: LoggerOptions) {
this.cwd = path.resolve(options.cwd || '.');
const logFileBasename = options.logFile || '.cspell-eslint-plugin.log';
this.logFile = path.resolve(this.cwd, logFileBasename);
this.logToFile = options.logToFile ?? true;
this.enabled = options.enabled ?? debugMode;
this.useAsync = options.useAsync ?? false;
}

private _log(...p: Parameters<typeof console.log>): void {
if (!this.enabled) return;
if (!this.logToFile) return console.log(...p);
const message = new Date().toISOString() + ' ' + prefixLines(format(...p), ' ') + '\n';
this.useAsync
? fs.appendFile(this.logFile, message, (err) => err && console.error(err))
: fs.appendFileSync(this.logFile, message);
return;
}

log = this._log.bind(this);
}

let logger: Logger | undefined;

export function getDefaultLogger(): Logger {
if (logger) return logger;
logger = new Logger({});
return logger;
}

function prefixLines(text: string, prefix: string, startIndex = 1): string {
return text
.split('\n')
.map((line, index) => (index >= startIndex ? prefix + line : line))
.map((line) => (line.trim() == '' ? '' : line))
.join('\n');
}
6 changes: 3 additions & 3 deletions packages/cspell-eslint-plugin/src/common/options.cts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ export interface Options extends Check {
autoFix: boolean;

/**
* Output debug logs
* @default false
* Output debug logs to `.cspell-eslint-plugin.log`
* default false
*/
debugMode?: boolean;
}
Expand All @@ -46,7 +46,7 @@ export type CSpellOptions = Pick<
dictionaryDefinitions?: DictionaryDefinition[];
};

export type RequiredOptions = Required<Options>;
export type RequiredOptions = Required<Pick<Options, Exclude<keyof Options, 'debugMode'>>> & Pick<Options, 'debugMode'>;

export interface Check {
/**
Expand Down
49 changes: 27 additions & 22 deletions packages/cspell-eslint-plugin/src/plugin/cspell-eslint-plugin.cts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { readFileSync } from 'fs';
import { join as pathJoin } from 'path';
import { createSyncFn } from 'synckit';

import { getDefaultLogger } from '../common/logger.cjs';
import type { Issue, SpellCheckSyncFn } from '../worker/types.cjs';
import { normalizeOptions } from './defaultCheckOptions.cjs';

Expand Down Expand Up @@ -54,28 +55,27 @@ const meta: Rule.RuleMetaData = {
};

let isDebugMode = false;
function log(...args: Parameters<typeof console.log>) {
if (!isDebugMode) return;
console.log(...args);
}

function nullFix(): null {
return null;
}

function create(context: Rule.RuleContext): Rule.RuleListener {
const options = normalizeOptions(context.options[0], context.getCwd());
const logger = getDefaultLogger();
const log = logger.log;
const options = normalizeOptions(context.options[0], context.cwd);
const autoFix = options.autoFix;
isDebugMode = options.debugMode || false;
isDebugMode && logContext(context);
isDebugMode = options.debugMode ?? isDebugMode;
logger.enabled = options.debugMode ?? (logger.enabled || isDebugMode);
logContext(log, context);

function reportIssue(issue: Issue) {
const messageId: MessageIds = issue.severity === 'Forbidden' ? 'wordForbidden' : 'wordUnknown';
const { word, start, end } = issue;
const data = {
word,
};
const code = context.getSourceCode();
const code = context.sourceCode;
const startPos = code.getLocFromIndex(start);
const endPos = code.getLocFromIndex(end);
const loc = { start: startPos, end: endPos };
Expand All @@ -97,7 +97,7 @@ function create(context: Rule.RuleContext): Rule.RuleListener {
};
}

log('Suggestions: %o', issue.suggestions);
// log('Suggestions: %o', issue.suggestions);

const issueSuggestions = issue.suggestions;
const fixable = issueSuggestions?.filter((sug) => !!sug.isPreferred);
Expand All @@ -120,8 +120,15 @@ function create(context: Rule.RuleContext): Rule.RuleListener {
}

function checkProgram() {
const sc = context.getSourceCode();
const issues = spellCheck(context.getFilename(), sc.text, sc.ast, options);
const sc = context.sourceCode;
const { issues, errors } = spellCheck(context.filename, sc.text, sc.ast, options);
if (errors && errors.length) {
log(
'errors: %o',
errors.map((e) => e.message),
);
errors.forEach((error) => console.error('%s', error.message));
}
issues.forEach((issue) => reportIssue(issue));
}

Expand All @@ -135,17 +142,15 @@ export const rules: PluginRules = {
},
};

function logContext(context: Rule.RuleContext) {
log('\n\n************************');
// log(context.getSourceCode().text);
log(`
id: ${context.id}
cwd: ${context.getCwd()}
filename: ${context.getFilename()}
physicalFilename: ${context.getPhysicalFilename()}
scope: ${context.getScope().type}
`);
function logContext(log: typeof console.log, context: Rule.RuleContext) {
log('context: %o', {
id: context.id,
cwd: context.cwd,
filename: context.filename,
physicalFilename: context.physicalFilename,
scope: context.getScope().type,
options: context.options.length === 1 ? context.options[0] : context.options,
});
}

export const configs = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export const defaultOptions: RequiredOptions = {
...defaultCheckOptions,
numSuggestions: 8,
generateSuggestions: true,
debugMode: false,
autoFix: false,
};

Expand Down
35 changes: 28 additions & 7 deletions packages/cspell-eslint-plugin/src/plugin/index.test.cts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const parsers: Record<string, string | undefined> = {
'.ts': resolveFromMonoRepo('node_modules/@typescript-eslint/parser'),
};

type CachedSample = RuleTester.ValidTestCase;
type ValidTestCase = RuleTester.ValidTestCase;
type Options = Partial<Rule.Options>;

const ruleTester = new RuleTester({
Expand Down Expand Up @@ -54,6 +54,17 @@ ruleTester.run('cspell', Rule.rules.spellchecker, {
ignoreWords: ['Guuide', 'Gallaxy', 'BADD', 'functionn', 'coool'],
},
}),
readFix('issue-4870/sample.js', {
cspell: {
dictionaries: ['business-terms'],
dictionaryDefinitions: [
{
name: 'business-terms',
path: fixtureRelativeToCwd('issue-4870/dictionaries/business-terminology.txt'),
},
],
},
}),
],
invalid: [
// cspell:ignore Guuide Gallaxy BADD functionn coool
Expand Down Expand Up @@ -148,6 +159,11 @@ ruleTester.run('cspell', Rule.rules.spellchecker, {
],
{ ignoreImports: false, customWordListFile: resolveFix('with-errors/creepyData.dict.txt') },
),
// cspell:ignore bestbusiness friendz
readInvalid('issue-4870/sample.js', ['Unknown word: "bestbusiness"', 'Unknown word: "friendz"'], {}),
readInvalid('issue-4870/sample.js', ['Unknown word: "friendz"'], {
cspell: { allowCompoundWords: true },
}),
],
});

Expand Down Expand Up @@ -195,19 +211,19 @@ function resolveFix(filename: string): string {
return path.resolve(fixturesDir, filename);
}

function readFix(_filename: string, options?: Options): CachedSample {
const filename = resolveFix(_filename);
const code = fs.readFileSync(filename, 'utf-8');
function readFix(filename: string, options?: Options): ValidTestCase {
const __filename = resolveFix(filename);
const code = fs.readFileSync(__filename, 'utf-8');

const sample: CachedSample = {
const sample: ValidTestCase = {
code,
filename,
filename: __filename,
};
if (options) {
sample.options = [options];
}

const parser = parsers[path.extname(filename)];
const parser = parsers[path.extname(__filename)];
if (parser) {
sample.parser = parser;
}
Expand All @@ -226,3 +242,8 @@ function readInvalid(filename: string, errors: RuleTester.InvalidTestCase['error
errors,
};
}

function fixtureRelativeToCwd(filename: string) {
const fixFile = resolveFix(filename);
return path.relative(process.cwd(), fixFile);
}
Loading

0 comments on commit 4e28046

Please sign in to comment.