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 #57 from AtomLinter/arcanemagus/js-rewrite
Browse files Browse the repository at this point in the history
Rewrite in JS
  • Loading branch information
Arcanemagus authored Aug 27, 2017
2 parents 10c8173 + 3c03c40 commit b72cac7
Showing 8 changed files with 259 additions and 41 deletions.
122 changes: 122 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
'use babel';

// eslint-disable-next-line import/no-extraneous-dependencies, import/extensions
import { CompositeDisposable } from 'atom';

// Dependencies
let helpers;

const loadDeps = () => {
if (!helpers) {
helpers = require('atom-linter');
}
};

export default {
activate() {
this.idleCallbacks = new Set();
let depsCallbackID;
const installLinterClojureDeps = () => {
this.idleCallbacks.delete(depsCallbackID);
if (!atom.inSpecMode()) {
require('atom-package-deps').install('linter-clojure');
}
loadDeps();
};
depsCallbackID = window.requestIdleCallback(installLinterClojureDeps);
this.idleCallbacks.add(depsCallbackID);

this.subscriptions = new CompositeDisposable();
this.subscriptions.add(
atom.config.observe('linter-clojure.javaExecutablePath', (value) => {
this.javaExecutablePath = value;
}),
atom.config.observe('linter-clojure.clojureExecutablePath', (value) => {
this.clojureExecutablePath = value;
}),
);
},

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

provideLinter() {
return {
name: 'Clojure',
grammarScopes: ['source.clojure', 'source.clojurescript'],
scope: 'file',
lintOnFly: false,
lint: async (textEditor) => {
loadDeps();

if (!atom.workspace.isTextEditor(textEditor)) {
// Somehow we got fed an invalid TextEditor
return null;
}

const filePath = textEditor.getPath();

if (!filePath) {
// The TextEditor had no path associated with it somehow
return null;
}

const fileText = textEditor.getText();

const parameters = [
'-jar', this.clojureExecutablePath,
'-i', filePath,
];

const execOpts = {
stream: 'stderr',
allowEmptyStderr: true,
};

const output = await helpers.exec(this.javaExecutablePath, parameters, execOpts);

// Check for invalid jarfile specification
const invalidJarCheck = /Error: Unable to access jarfile (.+)/.exec(output);
if (invalidJarCheck !== null) {
const message = 'linter-clojure: Unable to find Clojure!';
const options = {
detail: `Java was unable to find the Clojure jarfile at '${invalidJarCheck[1]}'.`,
};
atom.notifications.addError(message, options);
return [];
}

if (textEditor.getText() !== fileText) {
// File has changed since the lint was triggered, tell Linter not to update
return null;
}

const toReturn = [];
const regex = /RuntimeException: (.+), compiling:\((.+):(\d+):(\d+)\)/g;

let match = regex.exec(output);
while (match !== null) {
// Reports 1 indexed positions normally, but can report 0:0.
let line = Number.parseInt(match[3], 10);
line = line > 0 ? line - 1 : 0;
let col = Number.parseInt(match[4], 10);
col = col > 0 ? col - 1 : 0;

toReturn.push({
severity: 'error',
excerpt: match[1],
location: {
file: match[2],
position: helpers.generateRange(textEditor, line, col),
},
});
match = regex.exec(output);
}
return toReturn;
},
};
},
};
35 changes: 0 additions & 35 deletions lib/init.coffee

This file was deleted.

53 changes: 47 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,25 +1,66 @@
{
"name": "linter-clojure",
"main": "./lib/init",
"main": "./lib/index",
"version": "1.1.3",
"description": "Lint Clojure on the fly, using clojure-x.x.x.jar",
"repository": "https://github.com/AtomLinter/linter-clojure",
"license": "MIT",
"engines": {
"atom": ">=1.0.0 <2.0.0"
"atom": ">=1.7.0 <2.0.0"
},
"configSchema": {
"javaExecutablePath": {
"type": "string",
"default": "java"
},
"clojureExecutablePath": {
"type": "string",
"default": "clojure-x.x.x.jar"
}
},
"scripts": {
"lint": "eslint .",
"test": "apm test"
},
"providedServices": {
"linter": {
"versions": {
"1.0.0": "provideLinter"
"2.0.0": "provideLinter"
}
}
},
"dependencies": {
"atom-linter": "^10.0.0",
"atom-package-deps": "^4.0.1"
"atom-package-deps": "^4.6.0"
},
"package-deps": [
"linter"
]
"linter:2.0.0"
],
"devDependencies": {
"eslint": "^4.3.0",
"eslint-config-airbnb-base": "^11.3.2",
"eslint-plugin-import": "^2.7.0",
"jasmine-fix": "^1.3.0"
},
"eslintConfig": {
"extends": "airbnb-base",
"rules": {
"global-require": "off",
"import/no-unresolved": [
"error",
{
"ignore": [
"atom"
]
}
]
},
"globals": {
"atom": true
},
"env": {
"node": true,
"browser": true
}
}
}
14 changes: 14 additions & 0 deletions spec/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
env: {
jasmine: true,
atomtest: true,
},
rules: {
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": true
}
]
}
};
2 changes: 2 additions & 0 deletions spec/fixtures/bad.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(+ 1 2 3)
xyz
Empty file added spec/fixtures/empty.clj
Empty file.
1 change: 1 addition & 0 deletions spec/fixtures/good.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(+ 1 2 3)
73 changes: 73 additions & 0 deletions spec/linter-clojure-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
'use babel';

import { join } from 'path';
// eslint-disable-next-line no-unused-vars
import { it, fit, wait, beforeEach, afterEach } from 'jasmine-fix';
import linterClojure from '../lib';

const linterProvider = linterClojure.provideLinter();
const lint = linterProvider.lint;

const fixturePath = join(__dirname, 'fixtures');
const emptyPath = join(fixturePath, 'empty.clj');
const goodPath = join(fixturePath, 'good.clj');
const badPath = join(fixturePath, 'bad.clj');

describe('The Clojure provider for Linter', () => {
beforeEach(async () => {
await atom.packages.activatePackage('language-clojure');
await atom.packages.activatePackage('linter-clojure');
// NOTE: You must set the environment variable `$ClojurePath` to the full path of Clojure
if (Object.prototype.hasOwnProperty.call(process.env, 'CLOJURE_PATH')) {
atom.config.set('linter-clojure.clojureExecutablePath', process.env.CLOJURE_PATH);
}
// Used to check for Clojure path failures
spyOn(atom.notifications, 'addError');
});

it('should be in the packages list', () =>
expect(atom.packages.isPackageLoaded('linter-clojure')).toBe(true),
);

it('should be an active package', () =>
expect(atom.packages.isPackageActive('linter-clojure')).toBe(true),
);

it('finds nothing wrong with a good file', async () => {
const editor = await atom.workspace.open(goodPath);
const messages = await lint(editor);

expect(atom.notifications.addError).not.toHaveBeenCalled();
expect(messages.length).toBe(0);
});

it('reports invalid clojure.jar specifications', async () => {
atom.config.set('linter-clojure.clojureExecutablePath', 'foobar');
const editor = await atom.workspace.open(goodPath);
await lint(editor);
const message = 'linter-clojure: Unable to find Clojure!';
const options = {
detail: "Java was unable to find the Clojure jarfile at 'foobar'.",
};
expect(atom.notifications.addError).toHaveBeenCalledWith(message, options);
});

it('properly reports errors found', async () => {
const editor = await atom.workspace.open(badPath);
const messages = await lint(editor);

expect(atom.notifications.addError).not.toHaveBeenCalled();
expect(messages[0].severity).toBe('error');
expect(messages[0].excerpt).toBe('Unable to resolve symbol: xyz in this context');
expect(messages[0].location.file).toBe(badPath);
expect(messages[0].location.position).toEqual([[0, 0], [0, 4]]);
});

it('finds nothing wrong with an empty file', async () => {
const editor = await atom.workspace.open(emptyPath);
const messages = await lint(editor);

expect(atom.notifications.addError).not.toHaveBeenCalled();
expect(messages.length).toBe(0);
});
});

0 comments on commit b72cac7

Please sign in to comment.