UNPKG

@styled/typescript-styled-plugin

Version:

TypeScript language service plugin that adds IntelliSense for styled components

110 lines 4.05 kB
"use strict"; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. Object.defineProperty(exports, "__esModule", { value: true }); exports.getSubstitutions = void 0; function getSubstitutions(contents, spans) { const parts = []; let lastIndex = 0; const lineStarts = contents .split('\n') .map(line => line.length) .reduce((previousValue, currentValue, currentIndex) => [...previousValue, currentValue + previousValue[currentIndex] + 1], [0]); let lineStartIndex = 0; for (const span of spans) { while (lineStarts[lineStartIndex] <= span.start) { lineStartIndex++; } const preTillLineStart = contents.slice(lineStarts[lineStartIndex - 1], span.start); const preTillLastIndex = contents.slice(lastIndex, span.start); const post = contents.slice(span.end); const placeholder = contents.slice(span.start, span.end); parts.push(preTillLastIndex); parts.push(getSubstitution({ preTillLineStart, preTillLastIndex, placeholder, post })); lastIndex = span.end; } parts.push(contents.slice(lastIndex)); return parts.join(''); } exports.getSubstitutions = getSubstitutions; function getSubstitution(context) { // Check to see if it's an in-property interplation, or a mixin, // and determine which character to use in either case // if in-property, replace with "xxxxxx" // if a mixin, replace with " " const replacementChar = getReplacementCharacter(context.preTillLineStart, context.preTillLastIndex, context.post); const result = context.placeholder.replace(/./gm, c => c === '\n' ? '\n' : replacementChar); // If followed by a semicolon, we may have to eat the semi colon using a false property if (replacementChar === ' ' && context.post.match(/^\s*;/)) { // Handle case where we need to eat the semi colon: // // styled.x` // ${'color: red'}; // ` // // vs. the other case where we do not: // // styled.x` // color: ${'red'}; // ` if (context.preTillLastIndex.match(/(;|^|\}|\{)[\s|\n]*$/)) { // Mixin, replace with a dummy variable declaration, so scss server doesn't complain about rogue semicolon return '$a:0' + result.slice(4); } return context.placeholder.replace(/./gm, c => c === '\n' ? '\n' : 'x'); } // Placeholder used as property name: // // styled.x` // ${'color'}: red; // ` // // But note that this shouldn't be included: // // styled.x` // ${'button'}:hover & { // color: red // } // ` // // Replace with fake property name if (context.post.match(/^\s*[:]/) && !context.post.match(/^\s*[:].+?[\{&]/)) { return '$a' + result.slice(2); } // Placeholder for component // // styled.x` // ${'button'}:hover & { // color: red // } // ` // Replace with fake selector if (context.post.match(/^\s*[:].+?[\{&]/)) { return '&' + ' '.repeat(result.length - 1); } // Placeholder used as hex value: // // styled.x` // color: #${'000'}; // ` if (context.preTillLastIndex.match(/#\s*$/)) { return '000' + ' '.repeat(Math.max(context.placeholder.length - 3, 0)); } return result; } function getReplacementCharacter(preTillLineStart, preTillLastIndex, post) { const emptySpacesRegExp = /(^|\n)\s*$/g; if (preTillLineStart.match(emptySpacesRegExp) && preTillLastIndex.match(emptySpacesRegExp)) { if (!post.match(/^\s*[{:,]/)) { // ${'button'} { return ' '; } } // If the placeholder looks like a unit that would not work when replaced with an identifier, // try replaceing with a number. if (post.match(/^%/)) { return '0'; } // Otherwise replace with an identifier return 'x'; } //# sourceMappingURL=_substituter.js.map