'use strict' ; import * as assert from 'assert' ; import { TextDocument , FoldingRange , FoldingRangeKind , getCSSLanguageService } from '../../cssLanguageService' ; function assertRanges ( lines , expected , languageId = 'css' , rangeLimit = null ) { const document = TextDocument . create ( `test://foo/bar.${ languageId }` , languageId , 1 , lines . join ( '\n' ) ) ; const context = rangeLimit ? { rangeLimit } : { } ; let actualRanges = getCSSLanguageService ( ) . getFoldingRanges ( document , context ) ; actualRanges = actualRanges . sort ( ( r1 , r2 ) => r1 . startLine - r2 . startLine ) ; assert . deepEqual ( actualRanges , expected ) ; } function assertRangesForLanguages ( lines , expected , languageIds ) { languageIds . forEach ( id => { assertRanges ( lines , expected , id ) ; } ) ; } function r ( startLine , endLine , kind ? ) { return { startLine , endLine , kind } ; } suite ( 'CSS Folding - Basic' , ( ) => { test ( 'Fold single rule' , ( ) => { const input = [ '.foo {' , '  color: red;' , '}' ] ; assertRanges ( input , [ r ( 0 , 1 ) ] ) ; } ) ; test ( 'No fold for single line' , ( ) => { const input = [ '.foo { color: red; }' ] ; assertRanges ( input , [ ] ) ; } ) ; test ( 'Fold multiple rules' , ( ) => { const input = [ '.foo {' , '  color: red;' , '  opacity: 1;' , '}' ] ; assertRanges ( input , [ r ( 0 , 2 ) ] ) ; } ) ; test ( 'Fold with no indentation' , ( ) => { const input = [ '.foo{' , 'color: red;' , '}' ] ; assertRanges ( input , [ r ( 0 , 1 ) ] ) ; } ) ; test ( 'Fold with opening curly brace on new line' , ( ) => { const input = [ '.foo' , '{' , 'color: red;' , '}' ] ; assertRanges ( input , [ r ( 1 , 2 ) ] ) ; } ) ; test ( 'Fold with closing curly brace on same line' , ( ) => { const input = [ '.foo' , '{' , 'color: red; }' ] ; assertRanges ( input , [ r ( 1 , 2 ) ] ) ; } ) ; } ) ; suite ( 'CSS Folding - Partial' , ( ) => { test ( 'Without closing curly brace' , ( ) => { const input = [ '.foo {' , 'color: red;' ] ; assertRanges ( input , [ ] ) ; } ) ; test ( 'Without closing curly brace creates correct folding ranges' , ( ) => { const input = [ '.foo {' , 'color: red;' , '.bar {' , 'color: blue;' , '}' , ] ; assertRanges ( input , [ r ( 2 , 3 ) ] ) ; } ) ; /**
     * The correct folding ranges should be (0, 5), (2, 4). However the current naive stack approach cannot handle it
     */ test ( 'Without closing curly brace in nested rules creates correct folding ranges' , ( ) => { const input = [ '.foo {' , '  .bar {' , '  .baz {' , '    color: blue;' , '  }' , '}' ] ; assertRanges ( input , [ r ( 1 , 4 ) , r ( 2 , 3 ) ] ) ; } ) ; test ( 'Without opening curly brace should not throw error' , ( ) => { const input = [ '.foo' , '  color: blue;' , '}}' ] ; assertRanges ( input , [ ] ) ; } ) ; } ) ; suite ( 'CSS Folding - Comments' , ( ) => { test ( 'Comment - single star' , ( ) => { const input = [ '/*' , '.foo {' , '  color: red;' , '}' , '*/' ] ; assertRanges ( input , [ r ( 0 , 4 , 'comment' ) ] ) ; } ) ; test ( 'Comment - double star' , ( ) => { const input = [ '/**' , '.foo {' , '  color: red;' , '}' , '*/' ] ; assertRanges ( input , [ r ( 0 , 4 , 'comment' ) ] ) ; } ) ; test ( 'Comment - wrong indentation and no newline' , ( ) => { const input = [ '/**' , '.foo{' , 'color: red;' , '} */' ] ; assertRanges ( input , [ r ( 0 , 3 , 'comment' ) ] ) ; } ) ; test ( 'Comment - Single line ' , ( ) => { const input = [ './* .foo { color: red; } */' ] ; assertRanges ( input , [ ] ) ; } ) ; } ) ; suite ( 'CSS Folding - Nested' , ( ) => { test ( 'Postcss nested' , ( ) => { const input = [ '.foo {' , '& .bar {' , '  color: red;' , '}' , '}' ] ; assertRanges ( input , [ r ( 0 , 3 ) , r ( 1 , 2 ) ] ) ; } ) ; test ( 'Media query' , ( ) => { const input = [ '@media screen {' , '.foo {' , 'color: red;' , '}' , '}' ] ; assertRanges ( input , [ r ( 0 , 3 ) , r ( 1 , 2 ) ] ) ; } ) ; } ) ; suite ( 'CSS Folding - Regions' , ( ) => { test ( 'Simple region with comment' , ( ) => { const input = [ '/* #region */' , '& .bar {' , '  color: red;' , '}' , '/* #endregion */' ] ; assertRanges ( input , [ r ( 0 , 4 , 'region' ) , r ( 1 , 2 ) ] ) ; } ) ; test ( 'Simple region with padded comment' , ( ) => { const input = [ '/*  #region   */' , '& .bar {' , '  color: red;' , '}' , '/*   #endregion   */' ] ; assertRanges ( input , [ r ( 0 , 4 , 'region' ) , r ( 1 , 2 ) ] ) ; } ) ; test ( 'Simple region without spaces' , ( ) => { const input = [ '/*#region*/' , '& .bar {' , '  color: red;' , '}' , '/*#endregion*/' ] ; assertRanges ( input , [ r ( 0 , 4 , 'region' ) , r ( 1 , 2 ) ] ) ; } ) ; test ( 'Simple region with description' , ( ) => { const input = [ '/* #region Header page */' , '.bar {' , '  color: red;' , '}' , '/* #endregion */' ] ; assertRanges ( input , [ r ( 0 , 4 , 'region' ) , r ( 1 , 2 ) ] ) ; } ) ; } ) ; suite ( 'CSS Folding - maxRanges' , ( ) => { test ( 'Max ranges' , ( ) => { const input = [ '/* #region Header page */' , '.bar {' , '  color: red;' , '}' , '/* #endregion */' ] ; assertRanges ( input , [ r ( 0 , 4 , 'region' ) ] , 'css' , 1 ) ; } ) ; } ) ; suite ( 'CSS Folding - No intersections and always choose first region' , ( ) => { test ( 'region intersecting with declaration' , ( ) => { const input = [ '/* #region */' , '.bar {' , '  color: red;' , '/* #endregion */' , '  display: block;' , '}' , ] ; assertRanges ( input , [ r ( 0 , 3 , 'region' ) ] ) ; } ) ; test ( 'declaration intersecting with region' , ( ) => { const input = [ '.bar {' , '/* #region */' , '  color: red;' , '}' , '/* #endregion */' , ] ; assertRanges ( input , [ r ( 0 , 2 ) ] ) ; } ) ; } ) ; suite ( 'CSS Folding - Incomplete region markers' , ( ) => { test ( 'declaration intersecting with region' , ( ) => { const input = [ '/* #endregion */' , ] ; assertRanges ( input , [ ] ) ; } ) ; } ) ; suite ( 'SCSS Folding' , ( ) => { test ( 'SCSS Mixin' , ( ) => { const input = [ '@mixin clearfix($width) {' , '  @if !$width {' , '    // if width is not passed, or empty do this' , '  } @else {' , '    display: inline-block;' , '    width: $width;' , '  }' , '}' ] ; assertRanges ( input , [ r ( 0 , 6 ) , r ( 1 , 2 ) , r ( 3 , 5 ) ] , 'scss' ) ; } ) ; test ( 'SCSS Interolation' , ( ) => { const input = [ '.orbit-#{$d}-prev {' , '  foo-#{$d}-bar: 1;' , '  #{$d}-bar-#{$d}: 2;' , '}' ] ; assertRanges ( input , [ r ( 0 , 2 ) ] , 'scss' ) ; } ) ; test ( 'SCSS While' , ( ) => { const input = [ '@while $i > 0 {' , '  .item-#{$i} { width: 2em * $i; }' , '  $i: $i - 2;' , '}' ] ; assertRanges ( input , [ r ( 0 , 2 ) ] , 'scss' ) ; } ) ; test ( 'SCSS Nested media query' , ( ) => { const input = [ '@mixin desktop {' , '  $desktop-width: 1024px;' , '  @media(min-width: #{$desktop-width}) {' , '    width: 500px;' , '  }' , '}' ] ; assertRanges ( input , [ r ( 0 , 4 ) , r ( 2 , 3 ) ] , 'scss' ) ; } ) ; } ) ; suite ( 'SCSS/LESS Folding - Regions' , ( ) => { test ( 'Simple region with comment' , ( ) => { const input = [ '/* #region */' , '& .bar {' , '  color: red;' , '}' , '/* #endregion */' ] ; assertRangesForLanguages ( input , [ r ( 0 , 4 , 'region' ) , r ( 1 , 2 ) ] , [ 'scss' , 'less' ] ) ; } ) ; test ( 'Simple region with padded comment' , ( ) => { const input = [ '/*  #region  */' , '& .bar {' , '  color: red;' , '}' , '/*   #endregion   */' ] ; assertRangesForLanguages ( input , [ r ( 0 , 4 , 'region' ) , r ( 1 , 2 ) ] , [ 'scss' , 'less' ] ) ; } ) ; test ( 'Region with SCSS single line comment' , ( ) => { const input = [ '// #region' , '& .bar {' , '  color: red;' , '}' , '// #endregion' ] ; assertRangesForLanguages ( input , [ r ( 0 , 4 , 'region' ) , r ( 1 , 2 ) ] , [ 'scss' , 'less' ] ) ; } ) ; test ( 'Region with SCSS single line padded comment' , ( ) => { const input = [ '//   #region  ' , '& .bar {' , '  color: red;' , '}' , '//   #endregion' ] ; assertRangesForLanguages ( input , [ r ( 0 , 4 , 'region' ) , r ( 1 , 2 ) ] , [ 'scss' , 'less' ] ) ; } ) ; test ( 'Region with both simple comments and region comments' , ( ) => { const input = [ '// #region' , '/*' , 'comments' , '*/' , '& .bar {' , '  color: red;' , '}' , '// #endregion' ] ; assertRangesForLanguages ( input , [ r ( 0 , 7 , 'region' ) , r ( 1 , 3 , 'comment' ) , r ( 4 , 5 ) ] , [ 'scss' , 'less' ] ) ; } ) ; } ) ;