UNPKG

3.81 kBJavaScriptView Raw
1'use strict';
2
3const isEqual = require('lodash/isEqual');
4const unique = require('lodash/uniqWith');
5
6const COLUMN = ' ';
7// Line starting with '//'
8const RE_COMMENT_SINGLE_LINE = /^\s*(?:\/\/|#).+$/gm;
9// Multi line block '/** ... */'
10const RE_COMMENT_MULTI_LINES = /((?:\/\*(?:[^*]|(?:\*+[^*\/]))*\*+\/))$/gm;
11const RE_LINE_BEGIN = /^/gm;
12const RE_SOURCE_MAPPING_URL = /\n?\/\/# sourceMappingURL=[^\s]+/;
13const SEG_LENGTH = 30;
14
15module.exports = {
16 commentStrip,
17 sourceMapCommentStrip,
18 commentWrap,
19 indent,
20 uniqueMatch,
21 regexpEscape,
22 truncate,
23 getLocationFromIndex
24};
25
26/**
27 * Strip comments from 'string'
28 * @param {String} string
29 * @returns {String}
30 */
31function commentStrip(string) {
32 // Remove commented lines
33 string = string.replace(RE_COMMENT_SINGLE_LINE, '');
34 string = string.replace(RE_COMMENT_MULTI_LINES, '');
35 return string;
36}
37
38/**
39 * Strip source map comment from 'string'
40 * @param {String} string
41 * @returns {String}
42 */
43function sourceMapCommentStrip(string) {
44 return string.replace(RE_SOURCE_MAPPING_URL, '');
45}
46
47/**
48 * Wrap 'string' in comment based on 'type'
49 * @param {String} string
50 * @param {String} type
51 * @returns {String}
52 */
53function commentWrap(string, type) {
54 let open, close;
55
56 if (type == 'html') {
57 open = '<!-- ';
58 close = ' -->';
59 } else {
60 open = '/* ';
61 close = ' */';
62 }
63
64 return open + string + close;
65}
66
67/**
68 * Indent the given 'string' a specific number of columns
69 * @param {String} string
70 * @param {Int} column
71 * @returns {String}
72 */
73function indent(string, column) {
74 const spaces = new Array(++column).join(COLUMN);
75
76 return string.replace(RE_LINE_BEGIN, spaces);
77}
78
79/**
80 * Match unique occurrences in 'string'
81 * @param {String} string
82 * @param {RegExp} regexp
83 * @returns {Array}
84 */
85function uniqueMatch(string, regexp) {
86 const results = [];
87 let match;
88
89 while ((match = regexp.exec(string))) {
90 results.push({
91 context: match[0],
92 match: match[1] || ''
93 });
94 }
95
96 // Filter duplicates
97 return unique(results, isEqual);
98}
99
100/**
101 * Escape 'string' for use in RegExp constructor
102 * @param {String} string
103 * @returns {String}
104 */
105function regexpEscape(string) {
106 return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
107}
108
109/**
110 * Truncate 'string'
111 * @param {String} string
112 * @returns {String}
113 */
114function truncate(string) {
115 if (string.length > SEG_LENGTH * 2 + 3) {
116 return string.slice(0, SEG_LENGTH) + '...' + string.slice(-SEG_LENGTH);
117 }
118
119 return string;
120}
121
122/**
123 * Retrieve line/column from 'index' of 'string'
124 * Column is zero-indexed
125 * @param {String} string
126 * @param {Number} index
127 * @returns {Object}
128 */
129function getLocationFromIndex(string, index) {
130 const lines = string.split('\n');
131 let destructure = false;
132 let idx = 0;
133 const results = [];
134 let found = [];
135
136 // Convert to batch
137 if (!Array.isArray(index)) {
138 index = [index];
139 destructure = true;
140 }
141
142 for (let i = 0, l = lines.length; i < l; i++) {
143 const m = index.length;
144 const line = lines[i];
145 // Add removed line ending
146 const lineLength = line.length + 1;
147
148 // Abort if no more indexes
149 if (!m) break;
150
151 // Loop through remaining indexes
152 for (let j = 0; j < m; j++) {
153 // Store result if index in current line
154 if (idx + lineLength > index[j]) {
155 results.push({
156 line: i + 1,
157 column: index[j] - idx
158 });
159 // Store matched index for later removal
160 found.push(j);
161 }
162 }
163
164 if (found.length) {
165 for (let k = 0, n = found.length; k < n; k++) {
166 // Remove index (correct for previous removals)
167 index.splice(found[k] - k, 1);
168 }
169 found = [];
170 }
171 idx += lineLength;
172 }
173
174 if (results.length) return destructure ? results[0] : results;
175 return { line: 0, column: 0 };
176}