/
sass-lint-auto-fix.ts
executable file
·125 lines (105 loc) · 3.31 KB
/
sass-lint-auto-fix.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { SentryService } from './services';
import {
ConfigOpts,
CreateModuleConfig,
Resolution,
Resolver,
ResolverConstructable,
ValidFileType,
} from './types';
import * as fs from 'fs';
import * as glob from 'glob';
import * as path from 'path';
import { parse } from 'gonzales-pe-sl';
import { LintOpts, SlRule } from 'sass-lint';
import getConfig from 'sass-lint/lib/config';
import getRules from 'sass-lint/lib/rules';
export function autoFixSassFactory(config: ConfigOpts) {
const { logger } = config;
const _getRules = config.slRules || getRules;
const _getConfig = config.slConfig || getConfig;
const patternsToInclude =
typeof config.files.include === 'string'
? [config.files.include]
: config.files.include;
return function* autoFixSass(
options: LintOpts,
): IterableIterator<Resolution> {
for (const pattern of patternsToInclude) {
const files = glob.sync(pattern, {
ignore: config.files.ignore,
});
for (const filename of files) {
const content = fs.readFileSync(filename).toString();
if (content !== null && content !== undefined && content.length > 0) {
const fileExtension = path
.extname(filename)
.substr(1)
.toLowerCase();
if (isValidExtension(fileExtension)) {
let ast;
try {
ast = parse(content, {
syntax: fileExtension,
});
} catch (e) {
logger.warn('parse', filename, e);
return;
}
const rules = _getRules(_getConfig(options));
const filteredRules: SlRule[] = rules.filter(
(rule: SlRule) => config.resolvers[rule.rule.name],
);
for (const rule of filteredRules) {
const { name } = rule.rule;
let resolver: Resolver;
try {
resolver = createModule({
name,
ast,
rule,
});
} catch (e) {
SentryService.reportIncident(e);
logger.warn('resolver', `Module '${name}' doesn't exist.`);
return;
}
try {
const detects = rule.rule.detect(ast, rule);
if (detects.length > 0) {
logger.verbose(
'fix',
`Running resolver "${name}" on "${filename}"`,
);
ast = resolver.fix(detects);
yield {
ast,
filename,
rule,
};
}
} catch (e) {
if (!config.options.optOut) {
SentryService.reportIncident(e);
}
// TODO: Friendly way to inform user that an unexpected error occured
logger.warn('error', e);
}
}
}
}
}
}
};
}
export function createModule({
ast,
name,
rule,
}: CreateModuleConfig): Resolver {
const _module: ResolverConstructable = require(`./resolvers/${name}`).default;
return new _module(ast, rule);
}
export function isValidExtension(fileExtension: string): boolean {
return fileExtension in ValidFileType;
}