1 | 'use strict';
|
2 |
|
3 | const execall = require('execall');
|
4 | const splitLines = require('split-lines');
|
5 | const reindent = require('./lib/reindent');
|
6 |
|
7 | const sourceToLineMap = new Map();
|
8 |
|
9 | module.exports = function (options) {
|
10 | options = options || {};
|
11 | options.startTag = options.startTag || '[^`\'"]<style[\\s\\S]*?>';
|
12 | options.endTag = options.endTag || '</\\s*?style>';
|
13 | options.body = options.body || '[\\s\\S]*?';
|
14 | options.fileFilterRegex = options.fileFilterRegex || [];
|
15 |
|
16 | const snippetRegexp = new RegExp(`(${options.startTag})(${options.body})\\s*${options.endTag}`, 'g');
|
17 |
|
18 | |
19 |
|
20 |
|
21 | function isFileProcessable(filepath) {
|
22 | if (options.fileFilterRegex.length === 0) {
|
23 | return true;
|
24 | }
|
25 |
|
26 | return options.fileFilterRegex.some((regex) => filepath.match(regex) !== null);
|
27 | }
|
28 |
|
29 | function transformCode(sourceCode, filepath) {
|
30 | if (!isFileProcessable(filepath)) {
|
31 | return sourceCode;
|
32 | }
|
33 |
|
34 | const extractedToSourceLineMap = new Map();
|
35 | let extractedCode = '';
|
36 | let currentExtractedCodeLine = 0;
|
37 |
|
38 | execall(snippetRegexp, sourceCode).forEach((match) => {
|
39 | const reindentData = reindent(match.sub[1]);
|
40 | const chunkCode = reindentData.text;
|
41 | if (!chunkCode) return;
|
42 |
|
43 | const openingTag = match.sub[0];
|
44 | const startIndex = match.index + openingTag.length;
|
45 | const startLine = splitLines(sourceCode.slice(0, startIndex)).length;
|
46 | const linesWithin = splitLines(chunkCode).length;
|
47 |
|
48 | for (let i = 0; i < linesWithin; i++) {
|
49 | currentExtractedCodeLine += 1;
|
50 | extractedToSourceLineMap.set(currentExtractedCodeLine, {
|
51 | line: startLine + i,
|
52 | indentColumns: reindentData.indentColumns,
|
53 | });
|
54 | }
|
55 |
|
56 | extractedCode += chunkCode + '\n';
|
57 | });
|
58 |
|
59 | sourceToLineMap.set(filepath, extractedToSourceLineMap);
|
60 | return extractedCode;
|
61 | }
|
62 |
|
63 | function transformResult(result, filepath) {
|
64 | if (!isFileProcessable(filepath)) {
|
65 | return;
|
66 | }
|
67 |
|
68 | const extractedToSourceLineMap = sourceToLineMap.get(filepath);
|
69 | const newWarnings = result.warnings.reduce((memo, warning) => {
|
70 |
|
71 |
|
72 |
|
73 | const warningSourceMap = extractedToSourceLineMap.get(warning.line);
|
74 |
|
75 | if (warning.line && warningSourceMap) {
|
76 | warning.line = warningSourceMap.line;
|
77 | }
|
78 |
|
79 | if (warning.column && warningSourceMap) {
|
80 | warning.column = warning.column + warningSourceMap.indentColumns;
|
81 | }
|
82 |
|
83 | memo.push(warning);
|
84 | return memo;
|
85 | }, []);
|
86 |
|
87 | return Object.assign(result, { warnings: newWarnings });
|
88 | }
|
89 |
|
90 | return {
|
91 | code: transformCode,
|
92 | result: transformResult,
|
93 | };
|
94 | };
|