Skip to content
This repository has been archived by the owner on Aug 7, 2023. It is now read-only.

Commit

Permalink
Merge pull request #395 from AtomLinter/export-directly
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya authored Apr 5, 2021
2 parents 07e92dc + 376dbae commit 9cf6de5
Show file tree
Hide file tree
Showing 12 changed files with 911 additions and 183 deletions.
31 changes: 31 additions & 0 deletions lib/compat-shim.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type * as Tslint from "tslint";

/**
* Shim for TSLint v3 interoperability
* @param {Function} Linter TSLint v3 linter
* @return {Function} TSLint v4-compatible linter
*/
export function shim(Linter: Function): typeof Tslint.Linter {
function LinterShim(options) {
this.options = options;
this.results = {};
}

// Assign class properties
Object.assign(LinterShim, Linter);

// Assign instance methods
LinterShim.prototype = {
...Linter.prototype,
lint(filePath, text, configuration) {
const options = { ...this.options, configuration };
const linter = new Linter(filePath, text, options);
this.results = linter.lint();
},
getResult() {
return this.results;
},
};

return LinterShim;
}
4 changes: 2 additions & 2 deletions lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ export interface ConfigSchema {
globalNodePath: string | null,
}

export const defaultConfig = {
export const defaultConfig = Object.freeze({
enableSemanticRules: false,
rulesDirectory: "",
fixOnSave: false,
ignoreTypings: false,
useLocalTslint: true,
useGlobalTslint: false,
globalNodePath: "",
}
} as const)
259 changes: 129 additions & 130 deletions lib/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ import path from 'path';
import { promises } from 'fs';
const { stat } = promises;
import { WorkerHelper } from './workerHelper';
export { config } from './config';
import { defaultConfig } from "./config"
import { defaultConfig, ConfigSchema } from "./config"

const grammarScopes = ['source.ts', 'source.tsx'];
const editorClass = 'linter-tslint-compatible-editor';
const idleCallbacks = new Set();
const config = defaultConfig;
const config: ConfigSchema = { ...defaultConfig } // copy of default config

// Worker still hasn't initialized, since the queued idle callbacks are
// done in order, waiting on a newly queued idle callback will ensure that
Expand All @@ -24,141 +23,141 @@ function waitOnIdle() {
});
};

const TsLintPackage = {
activate() {
const depsCallbackID = window.requestIdleCallback(() => {
idleCallbacks.delete(depsCallbackID);
// Install package dependencies
require('atom-package-deps').install('linter-tslint');
});
idleCallbacks.add(depsCallbackID);

this.subscriptions = new CompositeDisposable();
this.workerHelper = new WorkerHelper();

// Config subscriptions
this.subscriptions.add(
atom.config.observe('linter-tslint.rulesDirectory', async (dir) => {
if (dir && path.isAbsolute(dir)) {
const stats = await stat(dir);
if (stats && stats.isDirectory()) {
config.rulesDirectory = dir;
this.workerHelper.changeConfig('rulesDirectory', dir);
}
}
}),
atom.config.observe('linter-tslint.useLocalTslint', (use) => {
config.useLocalTslint = use;
this.workerHelper.changeConfig('useLocalTslint', use);
}),
atom.config.observe('linter-tslint.enableSemanticRules', (enableSemanticRules) => {
config.enableSemanticRules = enableSemanticRules;
this.workerHelper.changeConfig('enableSemanticRules', enableSemanticRules);
}),
atom.config.observe('linter-tslint.useGlobalTslint', (use) => {
config.useGlobalTslint = use;
this.workerHelper.changeConfig('useGlobalTslint', use);
}),
atom.config.observe('linter-tslint.globalNodePath', (globalNodePath) => {
config.globalNodePath = globalNodePath;
this.workerHelper.changeConfig('globalNodePath', globalNodePath);
}),
atom.config.observe('linter-tslint.ignoreTypings', (ignoreTypings) => {
this.ignoreTypings = ignoreTypings;
}),
atom.workspace.observeTextEditors((textEditor) => {
// Marks each TypeScript editor with a CSS class so that
// we can enable commands only for TypeScript editors.
const rootScopes = textEditor.getRootScopeDescriptor().getScopesArray();
if (rootScopes.some((scope) => grammarScopes.includes(scope))) {
atom.views.getView(textEditor).classList.add(editorClass);
textEditor.onDidSave(async () => {
if (atom.config.get('linter-tslint.fixOnSave')) {
if (!this.workerHelper.isRunning()) {
// Wait for worker to initialize
await waitOnIdle();
}

await this.workerHelper.requestJob('fix', textEditor);
}
});
}
}),
atom.commands.add(`atom-text-editor.${editorClass}`, {
// Command subscriptions
'linter-tslint:fix-file': async () => {
const textEditor = atom.workspace.getActiveTextEditor();

if (!textEditor || textEditor.isModified()) {
// Abort for invalid or unsaved text editors
atom.notifications.addError('Linter-TSLint: Please save before fixing');
return;
}
const subscriptions = new CompositeDisposable();
const workerHelper = new WorkerHelper();

// The fix replaces the file content and the cursor can jump automatically
// to the beginning of the file, so save current cursor position
const cursorPosition = textEditor.getCursorBufferPosition();
export function activate() {
const depsCallbackID = window.requestIdleCallback(() => {
idleCallbacks.delete(depsCallbackID);
// Install package dependencies
require('atom-package-deps').install('linter-tslint');
});
idleCallbacks.add(depsCallbackID);

try {
const results = await this.workerHelper.requestJob('fix', textEditor);

const notificationText = results && results.length === 0
? 'Linter-TSLint: Fix complete.'
: 'Linter-TSLint: Fix attempt complete, but linting errors remain.';
// Config subscriptions
subscriptions.add(
atom.config.observe('linter-tslint.rulesDirectory', async (dir) => {
if (dir && path.isAbsolute(dir)) {
const stats = await stat(dir);
if (stats && stats.isDirectory()) {
config.rulesDirectory = dir;
workerHelper.changeConfig('rulesDirectory', dir);
}
}
}),
atom.config.observe('linter-tslint.useLocalTslint', (use) => {
config.useLocalTslint = use;
workerHelper.changeConfig('useLocalTslint', use);
}),
atom.config.observe('linter-tslint.enableSemanticRules', (enableSemanticRules) => {
config.enableSemanticRules = enableSemanticRules;
workerHelper.changeConfig('enableSemanticRules', enableSemanticRules);
}),
atom.config.observe('linter-tslint.useGlobalTslint', (use) => {
config.useGlobalTslint = use;
workerHelper.changeConfig('useGlobalTslint', use);
}),
atom.config.observe('linter-tslint.globalNodePath', (globalNodePath) => {
config.globalNodePath = globalNodePath;
workerHelper.changeConfig('globalNodePath', globalNodePath);
}),
atom.config.observe('linter-tslint.ignoreTypings', (ignoreTypings) => {
config.ignoreTypings = ignoreTypings;
}),
atom.workspace.observeTextEditors((textEditor) => {
// Marks each TypeScript editor with a CSS class so that
// we can enable commands only for TypeScript editors.
const rootScopes = textEditor.getRootScopeDescriptor().getScopesArray();
if (rootScopes.some((scope) => grammarScopes.includes(scope))) {
atom.views.getView(textEditor).classList.add(editorClass);
textEditor.onDidSave(async () => {
if (atom.config.get('linter-tslint.fixOnSave')) {
if (!workerHelper.isRunning()) {
// Wait for worker to initialize
await waitOnIdle();
}

atom.notifications.addSuccess(notificationText);
} catch (err) {
atom.notifications.addWarning(err.message);
} finally {
// Restore cursor to the position before fix job
textEditor.setCursorBufferPosition(cursorPosition);
await workerHelper.requestJob('fix', textEditor);
}
},
}),
);

const createWorkerCallback = window.requestIdleCallback(() => {
this.workerHelper.startWorker(config);
idleCallbacks.delete(createWorkerCallback);
});
idleCallbacks.add(createWorkerCallback);
},

deactivate() {
idleCallbacks.forEach((callbackID) => window.cancelIdleCallback(callbackID));
idleCallbacks.clear();
this.subscriptions.dispose();

this.workerHelper.terminateWorker();
},

provideLinter() {
return {
name: 'TSLint',
grammarScopes,
scope: 'file',
lintsOnChange: true,
lint: async (textEditor: TextEditor) => {
if (this.ignoreTypings && textEditor.getPath().toLowerCase().endsWith('.d.ts')) {
return [];
});
}
}),
atom.commands.add(`atom-text-editor.${editorClass}`, {
// Command subscriptions
'linter-tslint:fix-file': async () => {
const textEditor = atom.workspace.getActiveTextEditor();

if (!textEditor || textEditor.isModified()) {
// Abort for invalid or unsaved text editors
atom.notifications.addError('Linter-TSLint: Please save before fixing');
return;
}

if (!this.workerHelper.isRunning()) {
// Wait for worker to initialize
await waitOnIdle();
}
// The fix replaces the file content and the cursor can jump automatically
// to the beginning of the file, so save current cursor position
const cursorPosition = textEditor.getCursorBufferPosition();

const text = textEditor.getText();
const results = await this.workerHelper.requestJob('lint', textEditor);
try {
const results = await workerHelper.requestJob('fix', textEditor);

if (textEditor.getText() !== text) {
// Text has been modified since the lint was triggered, tell linter not to update
return null;
}
const notificationText = results && results.length === 0
? 'Linter-TSLint: Fix complete.'
: 'Linter-TSLint: Fix attempt complete, but linting errors remain.';

return results;
atom.notifications.addSuccess(notificationText);
} catch (err) {
atom.notifications.addWarning(err.message);
} finally {
// Restore cursor to the position before fix job
textEditor.setCursorBufferPosition(cursorPosition);
}
},
};
},
};
export default TsLintPackage;
}),
);

const createWorkerCallback = window.requestIdleCallback(() => {
workerHelper.startWorker(config);
idleCallbacks.delete(createWorkerCallback);
});
idleCallbacks.add(createWorkerCallback);
}

export function deactivate() {
idleCallbacks.forEach((callbackID) => window.cancelIdleCallback(callbackID));
idleCallbacks.clear();
subscriptions.dispose();

workerHelper.terminateWorker();
}

export function provideLinter() {
return {
name: 'TSLint',
grammarScopes,
scope: 'file',
lintsOnChange: true,
lint: async (textEditor: TextEditor) => {
if (config.ignoreTypings && (textEditor.getPath() ?? "").toLowerCase().endsWith('.d.ts')) {
return [];
}

if (!workerHelper.isRunning()) {
// Wait for worker to initialize
await waitOnIdle();
}

const text = textEditor.getText();
const results = await workerHelper.requestJob('lint', textEditor);

if (textEditor.getText() !== text) {
// Text has been modified since the lint was triggered, tell linter not to update
return null;
}

return results;
},
};
}

export { config } from './config';
7 changes: 7 additions & 0 deletions lib/module_types/consistent_path.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
declare module "consistent-path" {
const getPath: {
(): string;
async(): Promise<string>;
}
export = getPath;
}
10 changes: 10 additions & 0 deletions lib/module_types/tslint-rule-documentation.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
declare module "tslint-rule-documentation" {
export interface IRuleResult {
found: boolean; // true if the rule is a TSLint core rule, or a known plugin rule, false otherwise
uri: string; // If found is true, uri of the documentation of the rule. If found is false, uri of the contribution guidelines
}
/** Find the url for the documentation of a TSLint rule
* @param {string} ruleID The ID of a TSLint rule such as `no-var-keyword` or `__example/foo`
*/
export function getRuleUri(ruleID: string): IRuleResult
}
16 changes: 8 additions & 8 deletions lib/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"compilerOptions": {
"strict": false,
"strictNullChecks": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noImplicitReturns": false,
"noImplicitAny": false,
"noImplicitThis": false,
"noFallthroughCasesInSwitch": false,
"strict": true,
"strictNullChecks": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noImplicitAny": true,
"noImplicitThis": true,
"noFallthroughCasesInSwitch": true,
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
Expand Down
Loading

0 comments on commit 9cf6de5

Please sign in to comment.