UNPKG

5.12 kBJavaScriptView Raw
1"use strict";
2
3exports.__esModule = true;
4exports.buildDependencyError = buildDependencyError;
5exports.collectStyles = collectStyles;
6exports.replaceStyleTemplates = replaceStyleTemplates;
7exports.resolveOptions = resolveOptions;
8
9var _codeFrame = require("@babel/code-frame");
10
11var _fastLevenshtein = _interopRequireDefault(require("fast-levenshtein"));
12
13var _sortBy = _interopRequireDefault(require("lodash/sortBy"));
14
15var _magicString = _interopRequireDefault(require("magic-string"));
16
17var _picocolors = _interopRequireDefault(require("picocolors"));
18
19var _config = _interopRequireDefault(require("../config"));
20
21var _traverse = _interopRequireDefault(require("../traverse"));
22
23var _createFilename = require("./createFilename");
24
25function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
26
27class AstroturfLoaderError extends Error {
28 constructor(errorOrMessage, codeFrame) {
29 super();
30 this.name = 'AstroturfLoaderError';
31
32 if (typeof errorOrMessage !== 'string') {
33 this.error = errorOrMessage;
34
35 if (errorOrMessage.name === 'CssSyntaxError') {
36 this.handleCssError(errorOrMessage);
37 } else {
38 this.handleBabelError(errorOrMessage);
39 }
40 } else {
41 this.message = errorOrMessage;
42 Error.captureStackTrace(this, AstroturfLoaderError);
43 }
44
45 if (codeFrame) this.message += `\n\n${codeFrame}\n`;
46 }
47
48 handleBabelError(error) {
49 this.message = error.message;
50
51 try {
52 this.stack = error.stack.replace(/^(.*?):/, `${this.name}:`);
53 } catch (e) {
54 Error.captureStackTrace(this, AstroturfLoaderError);
55 }
56 }
57
58 handleCssError(error) {
59 const {
60 line,
61 column,
62 reason,
63 plugin,
64 file
65 } = error;
66 this.message = `${this.name}\n\n`;
67
68 if (typeof line !== 'undefined') {
69 this.message += `(${line}:${column}) `;
70 }
71
72 this.message += plugin ? `${plugin}: ` : '';
73 this.message += file ? `${file} ` : '<css input> ';
74 this.message += `${reason}`;
75 const code = error.showSourceCode();
76
77 if (code) {
78 this.message += `\n\n${code}\n`;
79 } // @ts-ignore
80
81
82 this.stack = false;
83 }
84
85}
86
87function buildDependencyError(content, {
88 type,
89 identifier,
90 request
91}, styles, resource, loc) {
92 let idents = styles.map(s => s.identifier);
93 let closest;
94 let minDistance = 2;
95 idents.forEach(ident => {
96 const d = _fastLevenshtein.default.get(ident, identifier);
97
98 if (d < minDistance) {
99 minDistance = d;
100 closest = ident;
101 }
102 });
103 const isDefaultImport = type === 'ImportDefaultSpecifier';
104
105 if (!closest && isDefaultImport) {
106 closest = idents.find(ident => ident === (0, _createFilename.getNameFromFile)(resource));
107 }
108
109 if (closest) idents = idents.filter(ident => ident !== closest);
110 const identMsg = idents.map(s => _picocolors.default.yellow(s)).join(', ');
111 const alternative = isDefaultImport ? `Instead try: ${_picocolors.default.yellow(`import ${closest} from '${request}';`)}` : `Did you mean to import as ${_picocolors.default.yellow(closest)} instead?`;
112 return new AstroturfLoaderError( // eslint-disable-next-line prefer-template
113 `Could not find a style associated with the interpolated value. ` + `Styles should use the same name used by the intended component or class set in the imported file.\n\n` + (0, _codeFrame.codeFrameColumns)(content, {
114 start: loc.start
115 }, {
116 highlightCode: true,
117 message: !isDefaultImport ? `(Imported as ${_picocolors.default.bold(identifier)})` : ''
118 }) + `\n\n${closest ? `${alternative}\n\nAlso available: ${identMsg}` : `Available: ${identMsg}`}`);
119}
120
121function collectStyles(src, filename, resolveDependency, opts) {
122 // maybe eventually return the ast directly if babel-loader supports it
123 try {
124 const {
125 metadata
126 } = (0, _traverse.default)(src, filename, { ...opts,
127 resolveDependency,
128 writeFiles: false,
129 generateInterpolations: true
130 });
131 return metadata.astroturf;
132 } catch (err) {
133 throw new AstroturfLoaderError(err);
134 }
135}
136
137function replaceStyleTemplates(loaderContext, filename, src, locations // content: Map<string, string>,
138) {
139 locations = (0, _sortBy.default)(locations, i => i.start || 0);
140 const magic = new _magicString.default(src);
141 locations.forEach(({
142 start = 0,
143 end = 0,
144 code = ''
145 }) => {
146 if (code.endsWith(';')) code = code.slice(0, -1); // remove trailing semicolon
147
148 if (start === end) {
149 magic.appendLeft(start, code);
150 } else {
151 magic.overwrite(start, end, code);
152 }
153 });
154 return {
155 code: magic.toString(),
156 map: loaderContext.sourceMap ? magic.generateMap({
157 includeContent: true,
158 source: filename
159 }) : null
160 };
161}
162
163async function resolveOptions(loaderContext) {
164 const loaderOpts = loaderContext.getOptions() || {};
165
166 if (loaderOpts.config === false) {
167 return loaderOpts;
168 }
169
170 const result = await (typeof loaderOpts.config === 'string' ? _config.default.load(loaderOpts.config) : _config.default.search(loaderContext.resourcePath));
171 return (result == null ? void 0 : result.config) || loaderOpts;
172}
\No newline at end of file