UNPKG

typescript-plugin-styled-components

Version:

TypeScript transformer for improving the debugging experience of styled-components

287 lines (286 loc) 9.16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.minifyTemplate = exports.createMinifier = void 0; const ts = require("typescript"); const ts_is_kind_1 = require("./ts-is-kind"); function isSymbol(ch) { return ch == ';' || ch == ':' || ch == '{' || ch == '}' || ch == ','; } function isSpace(ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; } const stateMachine = { ';': { next(ch) { if (ch == '(') return { state: ['(', { count: 1 }] }; if (ch == '\'' || ch == '"') return { state: ch }; if (isSpace(ch)) return { skipEmit: true }; if (ch == '/') return { state: ';/', skipEmit: true }; if (isSymbol(ch)) return; return { state: 'x' }; }, flush() { return { state: ';$' }; } }, ';$': { next(ch) { if (ch == '(') return { state: ['(', { count: 1 }] }; if (ch == '\'' || ch == '"') return { state: ch }; if (isSpace(ch)) return { skipEmit: true, state: ' ' }; // we may need a space if (ch == '/') return { state: '/', skipEmit: true }; if (isSymbol(ch)) return { state: ';' }; return { state: 'x' }; } }, 'x': { next(ch) { if (ch == '(') return { state: ['(', { count: 1 }] }; if (ch == '\'' || ch == '"') return { state: ch }; if (isSpace(ch)) return { state: ' ', skipEmit: true }; if (ch == '/') return { state: '/', skipEmit: true }; if (isSymbol(ch)) return { state: ';' }; } }, ' ': { next(ch) { if (ch == '(') return { state: ['(', { count: 1 }], emit: ' ' + ch }; if (ch == '\'' || ch == '"') return { state: ch, emit: ' ' + ch }; if (isSpace(ch)) return { state: ' ', skipEmit: true }; if (ch == '/') return { state: '/', skipEmit: true }; if (isSymbol(ch)) return { state: ';' }; return { state: 'x', emit: ' ' + ch }; }, flush(last) { if (!last) return { emit: ' ', state: ';$' }; } }, '\n': { next(ch) { if (ch == '(') return { state: ['(', { count: 1 }], emit: '\n' + ch }; if (ch == '\'' || ch == '"') return { state: ch, emit: '\n' + ch }; if (isSpace(ch)) return { state: '\n', skipEmit: true }; if (ch == '/') return { state: '/', emit: '\n' }; if (isSymbol(ch)) return { state: ';', emit: '\n' + ch }; return { state: 'x', emit: '\n' + ch }; } }, "'": { next(ch) { if (ch == '\'') return { state: ';' }; } }, '"': { next(ch) { if (ch == '"') return { state: ';' }; } }, '(': { next(ch, { count }) { if (ch == '(') return { state: ['(', { count: count + 1 }] }; if (ch == ')') if (count > 1) return { state: ['(', { count: count - 1 }] }; else return { state: ';' }; // maybe return ' '? then it'd always add space after } }, '/': { next(ch) { if (ch == '/') return { state: '//', skipEmit: true }; if (ch == '*') return { state: '/*', skipEmit: true }; return { state: ';', emit: '/' + ch }; }, flush() { return { state: '/$', emit: '/' }; } }, '//': { next(ch) { if (ch == '\n') return { state: ' ', skipEmit: true }; return { skipEmit: true }; }, flush(last) { if (last) return { skipEmit: true }; return { state: '//$', emit: '//' }; } }, ';/': { next(ch) { if (ch == '/') return { state: ';//', skipEmit: true }; if (ch == '*') return { state: ';/*', skipEmit: true }; return { state: ';', emit: '/' + ch }; }, flush() { return { state: '/$', emit: '/' }; } }, ';//': { next(ch) { if (ch == '\n') return { state: ';', skipEmit: true }; return { skipEmit: true }; }, flush(last) { if (last) return { skipEmit: true }; return { state: '//$', emit: '//' }; } }, '/$': {}, '//$': { next(ch) { if (ch == '\n') return { state: '\n', skipEmit: true }; return { skipEmit: true }; } }, '/*': { next(ch) { if (ch == '*') return { state: '/**', skipEmit: true }; return { skipEmit: true }; }, flush(last) { if (last) return { skipEmit: true }; return { state: '/*$', emit: '/*' }; } }, '/**': { next(ch) { if (ch == '/') return { state: ' ', skipEmit: true }; return { state: '/*', skipEmit: true }; } }, ';/*': { next(ch) { if (ch == '*') return { state: ';/**', skipEmit: true }; return { skipEmit: true }; }, flush(last) { if (last) return { skipEmit: true }; return { state: '/*$', emit: '/*' }; } }, ';/**': { next(ch) { if (ch == '/') return { state: ';', skipEmit: true }; return { state: ';/*', skipEmit: true }; } }, '/*$': { next(ch) { if (ch == '*') return { state: '/*$*', skipEmit: true }; return { skipEmit: true }; } }, '/*$*': { next(ch) { if (ch == '/') return { state: ';', emit: '*/' }; return { state: '/*$', skipEmit: true }; } } }; function createMinifier() { let state = ';'; let stateData = undefined; return (next, last = false) => { let minified = ''; function apply(result, ch) { if (!result) { if (ch !== undefined) minified += ch; } else { if (result.state !== undefined) { if (typeof result.state === 'string') state = result.state; else { state = result.state[0]; stateData = result.state[1]; } } if (result.emit !== undefined) minified += result.emit; else if (result.skipEmit !== true && ch !== undefined) minified += ch; } } let pos = 0; let len = next.length; while (pos < len) { const ch = next[pos++]; const reducer = stateMachine[state]; const prevState = state; const reducerResult = reducer.next && reducer.next(ch, stateData); apply(reducerResult, ch); // console.log('next(', { ch, state: prevState }, '): ', reducerResult, ' -> ', { state, minified }); } const reducer = stateMachine[state]; const prevState = state; const reducerResult = reducer.flush && reducer.flush(last); apply(reducerResult); // console.log('flush', { state: prevState }, '): ', reducerResult, ' -> ', { state, minified }); return minified; }; } exports.createMinifier = createMinifier; function minifyTemplate(templateLiteral, factory) { const minifier = createMinifier(); if ((0, ts_is_kind_1.isNoSubstitutionTemplateLiteral)(templateLiteral)) { const node = factory.createNoSubstitutionTemplateLiteral(minifier(templateLiteral.text, true)); return node; } else if ((0, ts_is_kind_1.isTemplateExpression)(templateLiteral)) { const head = factory.createTemplateHead(minifier(templateLiteral.head.text)); const templateSpans = templateLiteral.templateSpans.map(span => factory.createTemplateSpan(span.expression, span.literal.kind === ts.SyntaxKind.TemplateMiddle ? factory.createTemplateMiddle(minifier(span.literal.text)) : factory.createTemplateTail(minifier(span.literal.text, true)))); const node = factory.createTemplateExpression(head, templateSpans); return node; } return templateLiteral; } exports.minifyTemplate = minifyTemplate;