Skip to content

Commit

Permalink
Sasslint precommit hook (elastic#28095)
Browse files Browse the repository at this point in the history
* Remove SCSS linting from dev server

* Add sasslint to precommit hook
  • Loading branch information
chandlerprall authored Jan 4, 2019
1 parent d745694 commit dd47972
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 2 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -396,8 +396,8 @@
"ts-node": "^7.0.1",
"tslint": "^5.11.0",
"tslint-config-prettier": "^1.15.0",
"tslint-plugin-prettier": "^2.0.0",
"tslint-microsoft-contrib": "^6.0.0",
"tslint-plugin-prettier": "^2.0.0",
"typescript": "^3.0.3",
"vinyl-fs": "^3.0.2",
"xml2js": "^0.4.19",
Expand Down
4 changes: 4 additions & 0 deletions src/dev/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ export class File {
return this.ext === '.ts' || this.ext === '.tsx';
}

public isSass() {
return this.ext === '.sass' || this.ext === '.scss';
}

public isFixture() {
return this.relativePath.split(sep).includes('__fixtures__');
}
Expand Down
3 changes: 2 additions & 1 deletion src/dev/run_precommit_hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import { run, combineErrors } from './run';
import * as Eslint from './eslint';
import * as Tslint from './tslint';
import * as Sasslint from './sasslint';
import { getFilesForCommit, checkFileCasing } from './precommit_hook';

run(async ({ log }) => {
Expand All @@ -32,7 +33,7 @@ run(async ({ log }) => {
errors.push(error);
}

for (const Linter of [Eslint, Tslint]) {
for (const Linter of [Eslint, Tslint, Sasslint]) {
const filesToLint = Linter.pickFilesToLint(log, files);
if (filesToLint.length > 0) {
try {
Expand Down
21 changes: 21 additions & 0 deletions src/dev/sasslint/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export { pickFilesToLint } from './pick_files_to_lint';
export { lintFiles } from './lint_files';
59 changes: 59 additions & 0 deletions src/dev/sasslint/lint_files.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import sassLint from 'sass-lint';
import path from 'path';
import { createFailError } from '../run';

/**
* Lints a list of files with eslint. eslint reports are written to the log
* and a FailError is thrown when linting errors occur.
*
* @param {ToolingLog} log
* @param {Array<File>} files
* @return {undefined}
*/
export function lintFiles(log, files) {
const paths = files.map(file => file.getRelativePath());

const report = sassLint.lintFiles(
paths.join(', '),
{},
path.resolve(__dirname, '..', '..', '..', '.sass-lint.yml')
);

const failTypes = Object.keys(
report.reduce(
(failTypes, reportEntry) => {
if (reportEntry.warningCount > 0) failTypes.warning = true;
if (reportEntry.errorCount > 0) failTypes.errors = true;
return failTypes;
},
{}
)
);

if (!failTypes.length) {
log.success('[sasslint] %d files linted successfully', files.length);
return;
}

log.error(sassLint.format(report));
throw createFailError(`[sasslint] ${failTypes.join(' & ')}`, 1);
}
44 changes: 44 additions & 0 deletions src/dev/sasslint/pick_files_to_lint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import fs from 'fs';
import { safeLoad } from 'js-yaml';
import { makeRe } from 'minimatch';
import path from 'path';

// load the include globs from .sass-lint.yml and convert them to regular expressions for filtering files
const sassLintPath = path.resolve(__dirname, '..', '..', '..', '.sass-lint.yml');
const sassLintConfig = safeLoad(fs.readFileSync(sassLintPath));
const { files: { include: includeGlobs } } = sassLintConfig;
const includeRegex = includeGlobs.map(glob => makeRe(glob));

function matchesInclude(file) {
for (let i = 0; i < includeRegex.length; i++) {
if (includeRegex[i].test(file.relativePath)) {
return true;
}
}
return false;
}

export function pickFilesToLint(log, files) {
return files
.filter(file => file.isSass())
.filter(matchesInclude);
}

0 comments on commit dd47972

Please sign in to comment.