Add global lint decisions
MODIFY
packages/@romejs/core/master/commands/lint.ts
packages/@romejs/core/master/commands/lint.ts
*/
import {MasterRequest} from '@romejs/core';
-import Linter, {LinterOptions} from '../linter/Linter';
+import Linter, {
+ LinterCompilerOptionsPerFile,
+ LinterOptions,
+} from '../linter/Linter';
import {markup} from '@romejs/string-markup';
import {createMasterCommand} from '../commands';
-import {parseDecisionStrings} from '@romejs/js-compiler';
+import {
+ LintCompilerOptionsDecisions,
+ parseDecisionStrings,
+} from '@romejs/js-compiler';
import {Consumer} from '@romejs/consume';
import {commandCategories} from '@romejs/core/common/commands';
@@ -39,10 +45,11 @@ export default createMasterCommand<Flags>({
async callback(req: MasterRequest, flags: Flags): Promise<void> {
const {reporter} = req;
- let compilerOptionsPerFile: LinterOptions['compilerOptionsPerFile'] = {};
+ let lintCompilerOptionsPerFile: LinterCompilerOptionsPerFile = {};
+ let globalDecisions: LintCompilerOptionsDecisions = [];
const {decisions} = flags;
if (decisions !== undefined) {
- compilerOptionsPerFile = parseDecisionStrings(
+ ({lintCompilerOptionsPerFile, globalDecisions} = parseDecisionStrings(
decisions,
req.client.flags.cwd,
(description) => {
@@ -51,7 +58,7 @@ export default createMasterCommand<Flags>({
target: {type: 'flag', key: 'decisions'},
});
},
- );
+ ));
}
// Look up arguments manually in vsc if we were passed a changes branch
@@ -75,7 +82,8 @@ export default createMasterCommand<Flags>({
const opts: LinterOptions = {
hasDecisions: flags.decisions.length > 0,
- compilerOptionsPerFile,
+ lintCompilerOptionsPerFile,
+ globalDecisions,
save: flags.save,
formatOnly: flags.formatOnly,
args,

MODIFY
packages/@romejs/core/master/linter/Linter.ts
packages/@romejs/core/master/linter/Linter.ts
@@ -22,6 +22,7 @@ import {ReporterProgress, ReporterProgressOptions} from '@romejs/cli-reporter';
import DependencyNode from '../dependencies/DependencyNode';
import {
LintCompilerOptions,
+ LintCompilerOptionsDecisions,
areAnalyzeDependencyResultsEqual,
} from '@romejs/js-compiler';
import {markup} from '@romejs/string-markup';
@@ -34,12 +35,15 @@ type LintWatchChanges = Array<{
diagnostics: Diagnostics;
}>;
+export type LinterCompilerOptionsPerFile = Dict<Required<LintCompilerOptions>>;
+
export type LinterOptions = {
save: boolean;
args?: Array<string>;
hasDecisions: boolean;
formatOnly: boolean;
- compilerOptionsPerFile?: Dict<Required<LintCompilerOptions>>;
+ globalDecisions?: LintCompilerOptionsDecisions;
+ lintCompilerOptionsPerFile?: LinterCompilerOptionsPerFile;
};
type ProgressFactory = (opts: ReporterProgressOptions) => ReporterProgress;
@@ -160,7 +164,11 @@ class LintRunner {
let savedCount = 0;
const {master} = this.request;
- const {compilerOptionsPerFile, hasDecisions} = this.options;
+ const {
+ lintCompilerOptionsPerFile = {},
+ globalDecisions = [],
+ hasDecisions,
+ } = this.options;
const shouldSave = this.linter.shouldSave();
const shouldApplyFixes = this.linter.shouldApplyFixes();
@@ -174,18 +182,27 @@ class LintRunner {
const text = markup`<filelink target="${filename}" />`;
progress.pushText(text);
- let compilerOptions =
- compilerOptionsPerFile === undefined
- ? undefined
- : compilerOptionsPerFile[filename];
+ let compilerOptions = lintCompilerOptionsPerFile[filename];
// If we have decisions then make sure it's declared on all files
if (hasDecisions) {
+ if (compilerOptions === undefined) {
compilerOptions = {
+ hasDecisions: true,
+ globalDecisions,
decisionsByPosition: {},
+ };
+ } else {
+ compilerOptions = {
...compilerOptions,
+ hasDecisions: true,
+ globalDecisions: [
+ ...(compilerOptions.globalDecisions || []),
+ ...globalDecisions,
+ ],
};
}
+ }
const {
diagnostics,

MODIFY
packages/@romejs/js-compiler/lib/CompilerContext.ts
packages/@romejs/js-compiler/lib/CompilerContext.ts
@@ -37,7 +37,6 @@ import {RootScope} from '../scope/Scope';
import reduce from '../methods/reduce';
import {UnknownFilePath, createUnknownFilePath} from '@romejs/path';
import {
- LintCompilerOptions,
LintCompilerOptionsDecision,
TransformProjectDefinition,
TransformVisitor,
@@ -47,14 +46,17 @@ import {
matchesSuppression,
} from '../suppressions';
import CommentsConsumer from '@romejs/js-parser/CommentsConsumer';
-import {ob1Get0, ob1Get1} from '@romejs/ob1';
+import {ob1Get0} from '@romejs/ob1';
import {hookVisitors} from '../transforms';
import stringDiff from '@romejs/string-diff';
import {formatJS} from '@romejs/js-formatter';
import {REDUCE_REMOVE} from '../constants';
import {FileReference} from '@romejs/core';
import {DEFAULT_PROJECT_CONFIG} from '@romejs/project';
-import {buildLintDecisionAdviceAction} from '../lint/decisions';
+import {
+ buildLintDecisionAdviceAction,
+ deriveDecisionPositionKey,
+} from '../lint/decisions';
export type ContextArg = {
ast: Program;
@@ -239,38 +241,28 @@ export default class CompilerContext {
}
hasLintDecisions(): boolean {
- return this.getLintDecisions() !== undefined;
+ const {lint} = this.options;
+ return lint !== undefined && lint.hasDecisions === true;
}
- getLintDecisions(): LintCompilerOptions['decisionsByPosition'] {
+ getLintDecisions(key: undefined | string): Array<LintCompilerOptionsDecision> {
const {lint} = this.options;
if (lint === undefined) {
- return undefined;
- }
-
- return lint.decisionsByPosition;
- }
-
- findLintDecisions(
- loc: undefined | DiagnosticLocation,
- ): Array<LintCompilerOptionsDecision> {
- if (loc === undefined) {
return [];
}
- const {start} = loc;
- if (start === undefined) {
- return [];
+ const {globalDecisions = []} = lint;
+
+ if (key === undefined) {
+ return globalDecisions;
}
- const decisionsByPosition = this.getLintDecisions();
+ const {decisionsByPosition} = lint;
if (decisionsByPosition === undefined) {
- return [];
+ return globalDecisions;
}
- // Keep in update with packages/@romejs/core/client/commands/lint.ts
- const pos = `${ob1Get1(start.line)}:${ob1Get0(start.column)}`;
- return decisionsByPosition[pos] || [];
+ return [...globalDecisions, ...(decisionsByPosition[key] || [])];
}
addFixableDiagnostic<Old extends AnyNode, New extends TransformExitResult>(
@@ -332,13 +324,17 @@ export default class CompilerContext {
start: loc.start,
}),
);
+
+ // TODO add fix all with this category option
}
}
if (suggestions !== undefined) {
// If we have lint decisions then find the fix that corresponds with this suggestion
if (this.hasLintDecisions()) {
- const decisions = this.findLintDecisions(loc);
+ const decisions = this.getLintDecisions(
+ deriveDecisionPositionKey('fix', loc),
+ );
for (const decision of decisions) {
if (
decision.category === category &&
@@ -458,6 +454,8 @@ export default class CompilerContext {
start: loc.start,
}),
);
+
+ // TODO add suppress all action
}
const {marker, ...diag} = contextDiag;
@@ -486,7 +484,9 @@ export default class CompilerContext {
if (this.hasLintDecisions()) {
suppressed = true;
- const decisions = this.findLintDecisions(loc);
+ const decisions = this.getLintDecisions(
+ deriveDecisionPositionKey('fix', loc),
+ );
for (const {category, action} of decisions) {
if (category === diagCategory && action === 'fix') {
suppressed = false;

MODIFY
packages/@romejs/js-compiler/lint/decisions.ts
packages/@romejs/js-compiler/lint/decisions.ts
@@ -10,50 +10,104 @@ import {
DiagnosticAdviceAction,
DiagnosticCategory,
DiagnosticDescriptionOptionalCategory,
+ DiagnosticLocation,
descriptions,
} from '@romejs/diagnostics';
-import {LintCompilerOptionsDecision} from '../types';
+import {
+ LintCompilerOptionsDecision,
+ LintCompilerOptionsDecisionAction,
+} from '../types';
import {ob1Get0, ob1Get1} from '@romejs/ob1';
import {AbsoluteFilePath} from '@romejs/path';
-import {LinterOptions} from '@romejs/core/master/linter/Linter';
+import {LinterCompilerOptionsPerFile} from '@romejs/core/master/linter/Linter';
import {escapeSplit} from '@romejs/string-utils';
+type UnexpectedDecision = (
+ description: DiagnosticDescriptionOptionalCategory,
+) => void;
+
+function validateAction(
+ raw: string,
+ unexpected: UnexpectedDecision,
+): undefined | LintCompilerOptionsDecisionAction {
+ if (raw === 'fix' || raw === 'suppress' || raw === 'ignore') {
+ return raw;
+ } else {
+ unexpected(descriptions.LINT_COMMAND.INVALID_DECISION_ACTION(raw));
+ return undefined;
+ }
+}
+
+export function deriveDecisionPositionKey(
+ action: LintCompilerOptionsDecisionAction,
+ loc: undefined | DiagnosticLocation,
+): undefined | string {
+ if (loc === undefined) {
+ return undefined;
+ }
+
+ const {start} = loc;
+ if (start === undefined) {
+ return undefined;
+ }
+
+ if (action === 'suppress') {
+ return `${ob1Get1(start.line)}`;
+ } else {
+ return `${ob1Get1(start.line)}:${ob1Get0(start.column)}`;
+ }
+}
+
export function parseDecisionStrings(
decisions: Array<string>,
cwd: AbsoluteFilePath,
- unexpected: (description: DiagnosticDescriptionOptionalCategory) => void,
-): LinterOptions['compilerOptionsPerFile'] {
- const compilerOptionsPerFile: LinterOptions['compilerOptionsPerFile'] = {};
+ unexpected: UnexpectedDecision,
+): {
+ lintCompilerOptionsPerFile: LinterCompilerOptionsPerFile;
+ globalDecisions: Array<LintCompilerOptionsDecision>;
+} {
+ const lintCompilerOptionsPerFile: LinterCompilerOptionsPerFile = {};
+ const globalDecisions: Array<LintCompilerOptionsDecision> = [];
+
+ function parseGlobalDecision(parts: Array<string>, i: number) {
+ if (parts.length < 3) {
+ unexpected(descriptions.LINT_COMMAND.INVALID_DECISION_PART_COUNT(i));
+ }
- for (let i = 0; i < decisions.length; i++) {
- const segment = decisions[i];
- const parts = escapeSplit(segment, '-');
+ const [rawAction, rawCategory] = parts;
+
+ const action = validateAction(rawAction, unexpected);
+ if (action === undefined) {
+ return;
+ }
+
+ const category = (rawCategory as DiagnosticCategory);
+ globalDecisions.push({category, action});
+ }
+ function parseLineDecision(parts: Array<string>, i: number) {
if (parts.length < 4) {
unexpected(descriptions.LINT_COMMAND.INVALID_DECISION_PART_COUNT(i));
}
const [rawAction, rawCategory, rawFilename, pos, id] = parts;
- if (
- rawAction !== 'fix' &&
- rawAction !== 'suppress' &&
- rawAction !== 'ignore'
- ) {
- unexpected(descriptions.LINT_COMMAND.INVALID_DECISION_ACTION(rawAction));
- break;
+ const action = validateAction(rawAction, unexpected);
+ if (action === undefined) {
+ return;
}
- const action = rawAction;
const category = (rawCategory as DiagnosticCategory);
const resolvedFilename = cwd.resolve(rawFilename).join();
- let compilerOptions = compilerOptionsPerFile[resolvedFilename];
+ let compilerOptions = lintCompilerOptionsPerFile[resolvedFilename];
if (compilerOptions === undefined) {
compilerOptions = {
+ hasDecisions: true,
+ globalDecisions: [],
decisionsByPosition: {},
};
- compilerOptionsPerFile[resolvedFilename] = compilerOptions;
+ lintCompilerOptionsPerFile[resolvedFilename] = compilerOptions;
}
let decisionsForPosition = compilerOptions.decisionsByPosition[pos];
@@ -69,7 +123,18 @@ export function parseDecisionStrings(
});
}
- return compilerOptionsPerFile;
+ for (let i = 0; i < decisions.length; i++) {
+ const segment = decisions[i];
+ const parts = escapeSplit(segment, '-');
+
+ if (parts[0] === 'global') {
+ parseGlobalDecision(parts, i);
+ } else {
+ parseLineDecision(parts, i);
+ }
+ }
+
+ return {lintCompilerOptionsPerFile, globalDecisions};
}
export function buildLintDecisionAdviceAction(
@@ -95,10 +160,7 @@ export function buildLintDecisionAdviceAction(
): DiagnosticAdviceAction {
const escapedFilename = filename.replace(/-/, '\\-');
- const pos =
- action === 'suppress'
- ? `${ob1Get1(start.line)}`
- : `${ob1Get1(start.line)}:${ob1Get0(start.column)}`;
+ const pos = deriveDecisionPositionKey(action, {start});
const parts = [action, category, escapedFilename, pos];

MODIFY
packages/@romejs/js-compiler/lint/suppressions.ts
packages/@romejs/js-compiler/lint/suppressions.ts
@@ -27,8 +27,7 @@ function buildSuppressionCommentValue(categories: Set<string>): string {
}
export function addSuppressions(context: CompilerContext, ast: Program): Program {
- const decisionsByPosition = context.getLintDecisions();
- if (decisionsByPosition === undefined) {
+ if (!context.hasLintDecisions()) {
return ast;
}
@@ -124,8 +123,8 @@ export function addSuppressions(context: CompilerContext, ast: Program): Program
return node;
}
- const decisions = decisionsByPosition[ob1Get1(line)];
- if (decisions === undefined) {
+ const decisions = context.getLintDecisions(String(ob1Get1(line)));
+ if (decisions.length === 0) {
return node;
}

MODIFY
packages/@romejs/js-compiler/types.ts
packages/@romejs/js-compiler/types.ts
@@ -96,13 +96,17 @@ export type BundleCompileOptions = {
};
export type LintCompilerOptions = {
+ hasDecisions?: boolean;
+ globalDecisions?: LintCompilerOptionsDecisions;
decisionsByPosition?: Dict<LintCompilerOptionsDecisions>;
};
export type LintCompilerOptionsDecisions = Array<LintCompilerOptionsDecision>;
+export type LintCompilerOptionsDecisionAction = 'suppress' | 'fix' | 'ignore';
+
export type LintCompilerOptionsDecision = {
- action: 'suppress' | 'fix' | 'ignore';
+ action: LintCompilerOptionsDecisionAction;
category: DiagnosticCategory;
id?: number;
};

Add global lint decisions