diff --git a/src/__tests__/baselines/minification-only/issue36-extended.ts.baseline b/src/__tests__/baselines/minification-only/issue36-extended.ts.baseline new file mode 100644 index 0000000..ceab77a --- /dev/null +++ b/src/__tests__/baselines/minification-only/issue36-extended.ts.baseline @@ -0,0 +1,46 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`issue36-extended.ts 1`] = ` + +File: issue36-extended.ts +Source code: + + declare const styled: any; + + export const A = styled.div\` + border: \${'solid'} 10px; + \` + + styled.div\` + border: \${'solid'}// comment here + 10px; + border: solid// comment here + 10px; + \` + + styled.div\` + border: \${'solid'}/* comment here + */10px; + border: \${'solid'}/* comment here + */ 10px; + \` + + +TypeScript before transform: + + declare const styled: any; + export const A = styled.div \`\\n border: \${"solid"} 10px;\\n\`; + styled.div \`\\n border: \${"solid"}// comment here\\n10px;\\n border: solid// comment here\\n10px;\\n\`; + styled.div \`\\n border: \${"solid"}/* comment here\\n*/10px;\\n border: \${"solid"}/* comment here\\n*/ 10px;\\n\`; + + +TypeScript after transform: + + declare const styled: any; + export const A = styled.div \`border:\${'solid'} 10px;\`; + styled.div \`border:\${'solid'} 10px;border:solid 10px;\`; + styled.div \`border:\${'solid'} 10px;border:\${'solid'} 10px;\`; + + + +`; diff --git a/src/__tests__/baselines/minification-only/issue36.tsx.baseline b/src/__tests__/baselines/minification-only/issue36.tsx.baseline new file mode 100644 index 0000000..4464da1 --- /dev/null +++ b/src/__tests__/baselines/minification-only/issue36.tsx.baseline @@ -0,0 +1,45 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`issue36.tsx 1`] = ` + +File: issue36.tsx +Source code: + + declare const keyframes: any; + declare const styled: any; + + const rotate360 = keyframes\` + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + \`; + + export const StyledDiv = styled.div\` + width: 100px; + height: 100px; + background-color: greenyellow; + animation: \${rotate360} 2s linear infinite; + \`; + + +TypeScript before transform: + + declare const keyframes: any; + declare const styled: any; + const rotate360 = keyframes \`\\n from {\\n transform: rotate(0deg);\\n }\\n to {\\n transform: rotate(360deg);\\n }\\n\`; + export const StyledDiv = styled.div \`\\n width: 100px;\\n height: 100px;\\n background-color: greenyellow;\\n animation: \${rotate360} 2s linear infinite;\\n\`; + + +TypeScript after transform: + + declare const keyframes: any; + declare const styled: any; + const rotate360 = keyframes \`from{transform:rotate(0deg);}to{transform:rotate(360deg);}\`; + export const StyledDiv = styled.div \`width:100px;height:100px;background-color:greenyellow;animation:\${rotate360} 2s linear infinite;\`; + + + +`; diff --git a/src/__tests__/baselines/minification-only/minify-css-to-use-without-transpilation.ts.baseline b/src/__tests__/baselines/minification-only/minify-css-to-use-without-transpilation.ts.baseline index 9c6652a..0d35718 100644 --- a/src/__tests__/baselines/minification-only/minify-css-to-use-without-transpilation.ts.baseline +++ b/src/__tests__/baselines/minification-only/minify-css-to-use-without-transpilation.ts.baseline @@ -65,7 +65,7 @@ TypeScript after transform: const SpecialCharacters = styled.div \`content:" \${props => props.text} ";color:red;\`; const Comment = styled.div \`width:100%;color:red;\`; const Parens = styled.div \`&:hover{color:blue;}color:red;\`; - const UrlComments = styled.div \`color:red; background:red;border:1px solid green;\`; + const UrlComments = styled.div \`color:red;background:red;border:1px solid green;\`; export {}; diff --git a/src/__tests__/baselines/minification-only/simple.ts.baseline b/src/__tests__/baselines/minification-only/simple.ts.baseline index be2a568..667a159 100644 --- a/src/__tests__/baselines/minification-only/simple.ts.baseline +++ b/src/__tests__/baselines/minification-only/simple.ts.baseline @@ -158,7 +158,7 @@ TypeScript after transform: styled.div \`line one{line:two;}\`; // removes line comments at the end of lines of code // \`valid line with out comments\` - styled.div \`valid line without comments\`; + styled.div \`valid line with out comments\`; // preserves multi-line comments starting with /*! // \`this is a /*! dont ignore me please */ test\` styled.div \`this is a test\`; diff --git a/src/__tests__/baselines/minification/issue36-extended.ts.baseline b/src/__tests__/baselines/minification/issue36-extended.ts.baseline new file mode 100644 index 0000000..37ce843 --- /dev/null +++ b/src/__tests__/baselines/minification/issue36-extended.ts.baseline @@ -0,0 +1,46 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`issue36-extended.ts 1`] = ` + +File: issue36-extended.ts +Source code: + + declare const styled: any; + + export const A = styled.div\` + border: \${'solid'} 10px; + \` + + styled.div\` + border: \${'solid'}// comment here + 10px; + border: solid// comment here + 10px; + \` + + styled.div\` + border: \${'solid'}/* comment here + */10px; + border: \${'solid'}/* comment here + */ 10px; + \` + + +TypeScript before transform: + + declare const styled: any; + export const A = styled.div \`\\n border: \${"solid"} 10px;\\n\`; + styled.div \`\\n border: \${"solid"}// comment here\\n10px;\\n border: solid// comment here\\n10px;\\n\`; + styled.div \`\\n border: \${"solid"}/* comment here\\n*/10px;\\n border: \${"solid"}/* comment here\\n*/ 10px;\\n\`; + + +TypeScript after transform: + + declare const styled: any; + export const A = styled.div.withConfig({ displayName: "A" }) \`border:\${'solid'} 10px;\`; + styled.div \`border:\${'solid'} 10px;border:solid 10px;\`; + styled.div \`border:\${'solid'} 10px;border:\${'solid'} 10px;\`; + + + +`; diff --git a/src/__tests__/baselines/minification/issue36.tsx.baseline b/src/__tests__/baselines/minification/issue36.tsx.baseline new file mode 100644 index 0000000..2f1e92a --- /dev/null +++ b/src/__tests__/baselines/minification/issue36.tsx.baseline @@ -0,0 +1,45 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`issue36.tsx 1`] = ` + +File: issue36.tsx +Source code: + + declare const keyframes: any; + declare const styled: any; + + const rotate360 = keyframes\` + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + \`; + + export const StyledDiv = styled.div\` + width: 100px; + height: 100px; + background-color: greenyellow; + animation: \${rotate360} 2s linear infinite; + \`; + + +TypeScript before transform: + + declare const keyframes: any; + declare const styled: any; + const rotate360 = keyframes \`\\n from {\\n transform: rotate(0deg);\\n }\\n to {\\n transform: rotate(360deg);\\n }\\n\`; + export const StyledDiv = styled.div \`\\n width: 100px;\\n height: 100px;\\n background-color: greenyellow;\\n animation: \${rotate360} 2s linear infinite;\\n\`; + + +TypeScript after transform: + + declare const keyframes: any; + declare const styled: any; + const rotate360 = keyframes \`from{transform:rotate(0deg);}to{transform:rotate(360deg);}\`; + export const StyledDiv = styled.div.withConfig({ displayName: "StyledDiv" }) \`width:100px;height:100px;background-color:greenyellow;animation:\${rotate360} 2s linear infinite;\`; + + + +`; diff --git a/src/__tests__/baselines/minification/minify-css-to-use-without-transpilation.ts.baseline b/src/__tests__/baselines/minification/minify-css-to-use-without-transpilation.ts.baseline index 22c310e..6ea4700 100644 --- a/src/__tests__/baselines/minification/minify-css-to-use-without-transpilation.ts.baseline +++ b/src/__tests__/baselines/minification/minify-css-to-use-without-transpilation.ts.baseline @@ -65,7 +65,7 @@ TypeScript after transform: const SpecialCharacters = styled.div.withConfig({ displayName: "SpecialCharacters" }) \`content:" \${props => props.text} ";color:red;\`; const Comment = styled.div.withConfig({ displayName: "Comment" }) \`width:100%;color:red;\`; const Parens = styled.div.withConfig({ displayName: "Parens" }) \`&:hover{color:blue;}color:red;\`; - const UrlComments = styled.div.withConfig({ displayName: "UrlComments" }) \`color:red; background:red;border:1px solid green;\`; + const UrlComments = styled.div.withConfig({ displayName: "UrlComments" }) \`color:red;background:red;border:1px solid green;\`; export {}; diff --git a/src/__tests__/baselines/minification/simple.ts.baseline b/src/__tests__/baselines/minification/simple.ts.baseline index be2a568..667a159 100644 --- a/src/__tests__/baselines/minification/simple.ts.baseline +++ b/src/__tests__/baselines/minification/simple.ts.baseline @@ -158,7 +158,7 @@ TypeScript after transform: styled.div \`line one{line:two;}\`; // removes line comments at the end of lines of code // \`valid line with out comments\` - styled.div \`valid line without comments\`; + styled.div \`valid line with out comments\`; // preserves multi-line comments starting with /*! // \`this is a /*! dont ignore me please */ test\` styled.div \`this is a test\`; diff --git a/src/__tests__/fixtures/minification/issue36-extended.ts b/src/__tests__/fixtures/minification/issue36-extended.ts new file mode 100644 index 0000000..5493de8 --- /dev/null +++ b/src/__tests__/fixtures/minification/issue36-extended.ts @@ -0,0 +1,19 @@ +declare const styled: any; + +export const A = styled.div` + border: ${'solid'} 10px; +` + +styled.div` + border: ${'solid'}// comment here +10px; + border: solid// comment here +10px; +` + +styled.div` + border: ${'solid'}/* comment here +*/10px; + border: ${'solid'}/* comment here +*/ 10px; +` diff --git a/src/__tests__/fixtures/minification/issue36.tsx b/src/__tests__/fixtures/minification/issue36.tsx new file mode 100644 index 0000000..611c4e2 --- /dev/null +++ b/src/__tests__/fixtures/minification/issue36.tsx @@ -0,0 +1,18 @@ +declare const keyframes: any; +declare const styled: any; + +const rotate360 = keyframes` + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +`; + +export const StyledDiv = styled.div` + width: 100px; + height: 100px; + background-color: greenyellow; + animation: ${rotate360} 2s linear infinite; +`; diff --git a/src/minify.ts b/src/minify.ts index 8ec5708..b7ea956 100644 --- a/src/minify.ts +++ b/src/minify.ts @@ -1,8 +1,8 @@ import * as ts from 'typescript'; import { isNoSubstitutionTemplateLiteral, isTemplateExpression } from './ts-is-kind'; -type State = ';' | 'x' | ' ' | '\n' | '"' | '(' | '\'' | '/' | '//' | '/$' | '//$' | '/*' | '/**' | '/*$' | '/*$*'; -type ReducerResult = { emit?: string; skipEmit?: boolean; state?: State } | void; +type State = ';' | ';$' | 'x' | ' ' | '\n' | '"' | '(' | '\'' | '/' | '//' | ';/' | ';//' | '/$' | '//$' | '/*' | '/**' | ';/*' | ';/**' | '/*$' | '/*$*'; +type ReducerResult = { emit?: string; skipEmit?: boolean; state?: State; } | void; type StateMachine = { [K in State]: { next?(ch: string): ReducerResult; @@ -19,6 +19,18 @@ const stateMachine: StateMachine = { next(ch) { if (ch == '\'' || ch == '"' || ch == '(') return { state: ch } if (ch == ' ' || ch == '\n' || ch == '\r') return { skipEmit: true } + if (ch == '/') return { state: ';/', skipEmit: true } + if (isSymbol(ch)) return; + return { state: 'x' } + }, + flush() { + return { state: ';$' } + } + }, + ';$': { // after placeholder + next(ch) { + if (ch == '\'' || ch == '"' || ch == '(') return { state: ch } + if (ch == ' ' || ch == '\n' || ch == '\r') return { skipEmit: true, state: ' ' } // we may need a space if (ch == '/') return { state: '/', skipEmit: true } if (isSymbol(ch)) return; return { state: 'x' } @@ -76,6 +88,26 @@ const stateMachine: StateMachine = { } }, '//': { + 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 }; @@ -108,6 +140,22 @@ const stateMachine: StateMachine = { 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 }; @@ -141,7 +189,7 @@ function createMinifier(): (next: string, last?: boolean) => string { minified += ch; } } - + let pos = 0; let len = next.length; while (pos < len) {