Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
1e7486aa
V
vscode
项目概览
掘金者说
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
1e7486aa
编写于
6月 13, 2016
作者:
M
Martin Aeschlimann
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Move LESS to extension
上级
0517cce2
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
1252 addition
and
8 deletion
+1252
-8
extensions/css/server/src/cssLanguageService.ts
extensions/css/server/src/cssLanguageService.ts
+18
-6
extensions/css/server/src/cssServerMain.ts
extensions/css/server/src/cssServerMain.ts
+3
-2
extensions/css/server/src/parser/lessParser.ts
extensions/css/server/src/parser/lessParser.ts
+395
-0
extensions/css/server/src/parser/lessScanner.ts
extensions/css/server/src/parser/lessScanner.ts
+73
-0
extensions/css/server/src/services/lessCompletion.ts
extensions/css/server/src/services/lessCompletion.ts
+353
-0
extensions/css/server/src/test/less/lessCompletion.test.ts
extensions/css/server/src/test/less/lessCompletion.test.ts
+73
-0
extensions/css/server/src/test/less/lessNavigation.ts
extensions/css/server/src/test/less/lessNavigation.ts
+55
-0
extensions/css/server/src/test/less/nodes.test.ts
extensions/css/server/src/test/less/nodes.test.ts
+24
-0
extensions/css/server/src/test/less/parser.test.ts
extensions/css/server/src/test/less/parser.test.ts
+218
-0
extensions/css/server/src/test/less/scanner.test.ts
extensions/css/server/src/test/less/scanner.test.ts
+39
-0
extensions/css/server/test/mocha.opts
extensions/css/server/test/mocha.opts
+1
-0
未找到文件。
extensions/css/server/src/cssLanguageService.ts
浏览文件 @
1e7486aa
...
...
@@ -17,6 +17,8 @@ import {CSSValidation} from './services/cssValidation';
import
{
SCSSParser
}
from
'
./parser/scssParser
'
;
import
{
SCSSCompletion
}
from
'
./services/scssCompletion
'
;
import
{
LESSParser
}
from
'
./parser/lessParser
'
;
import
{
LESSCompletion
}
from
'
./services/lessCompletion
'
;
export
interface
LanguageService
{
configure
(
raw
:
LanguageSettings
):
void
;
...
...
@@ -37,12 +39,12 @@ export interface LanguageSettings {
lint
?:
any
;
}
let
cssParser
=
new
Parser
();
let
cssCompletion
=
new
CSSCompletion
();
let
cssHover
=
new
CSSHover
();
let
cssValidation
=
new
CSSValidation
();
let
cssNavigation
=
new
CSSNavigation
();
let
cssCodeActions
=
new
CSSCodeActions
();
let
cssParser
=
new
Parser
();
let
cssCompletion
=
new
CSSCompletion
();
let
cssHover
=
new
CSSHover
();
let
cssValidation
=
new
CSSValidation
();
let
cssNavigation
=
new
CSSNavigation
();
let
cssCodeActions
=
new
CSSCodeActions
();
export
function
getCSSLanguageService
()
:
LanguageService
{
return
{
...
...
@@ -68,4 +70,14 @@ export function getSCSSLanguageService() : LanguageService {
languageService
.
parseStylesheet
=
scssParser
.
parseStylesheet
.
bind
(
scssParser
);
languageService
.
doComplete
=
scssCompletion
.
doComplete
.
bind
(
scssCompletion
);
return
languageService
;
}
let
lessParser
=
new
LESSParser
();
let
lessCompletion
=
new
LESSCompletion
();
export
function
getLESSLanguageService
()
:
LanguageService
{
let
languageService
=
getCSSLanguageService
();
languageService
.
parseStylesheet
=
lessParser
.
parseStylesheet
.
bind
(
lessParser
);
languageService
.
doComplete
=
lessCompletion
.
doComplete
.
bind
(
lessCompletion
);
return
languageService
;
}
\ No newline at end of file
extensions/css/server/src/cssServerMain.ts
浏览文件 @
1e7486aa
...
...
@@ -9,7 +9,7 @@ import {
TextDocuments
,
TextDocument
,
InitializeParams
,
InitializeResult
,
RequestType
}
from
'
vscode-languageserver
'
;
import
{
getCSSLanguageService
,
getSCSSLanguageService
,
LanguageSettings
,
LanguageService
}
from
'
./cssLanguageService
'
;
import
{
getCSSLanguageService
,
getSCSSLanguageService
,
getLESSLanguageService
,
LanguageSettings
,
LanguageService
}
from
'
./cssLanguageService
'
;
import
{
Stylesheet
}
from
'
./parser/cssNodes
'
;
import
*
as
nls
from
'
vscode-nls
'
;
...
...
@@ -57,7 +57,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
let
languageServices
:
{
[
id
:
string
]:
LanguageService
}
=
{
css
:
getCSSLanguageService
(),
scss
:
getSCSSLanguageService
()
scss
:
getSCSSLanguageService
(),
less
:
getLESSLanguageService
()
};
function
getLanguageService
(
document
:
TextDocument
)
{
...
...
extensions/css/server/src/parser/lessParser.ts
0 → 100644
浏览文件 @
1e7486aa
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
lessScanner
from
'
./lessScanner
'
;
import
{
TokenType
}
from
'
./cssScanner
'
;
import
*
as
cssParser
from
'
./cssParser
'
;
import
*
as
nodes
from
'
./cssNodes
'
;
import
{
ParseError
}
from
'
./cssErrors
'
;
/// <summary>
/// A parser for LESS
/// http://lesscss.org/
/// </summary>
export
class
LESSParser
extends
cssParser
.
Parser
{
public
constructor
()
{
super
(
new
lessScanner
.
LESSScanner
());
}
public
_parseStylesheetStatement
():
nodes
.
Node
{
return
this
.
_tryParseMixinDeclaration
()
||
super
.
_parseStylesheetStatement
()
||
this
.
_parseVariableDeclaration
();
}
public
_parseImport
():
nodes
.
Node
{
let
node
=
<
nodes
.
Import
>
this
.
create
(
nodes
.
Import
);
if
(
!
this
.
accept
(
TokenType
.
AtKeyword
,
'
@import
'
)
&&
!
this
.
accept
(
TokenType
.
AtKeyword
,
'
@import-once
'
)
/* deprecated in less 1.4.1 */
)
{
return
null
;
}
// less 1.4.1: @import (css) "lib"
if
(
this
.
accept
(
TokenType
.
ParenthesisL
))
{
if
(
!
this
.
accept
(
TokenType
.
Ident
))
{
return
this
.
finish
(
node
,
ParseError
.
IdentifierExpected
,
[
TokenType
.
SemiColon
]);
}
if
(
!
this
.
accept
(
TokenType
.
ParenthesisR
))
{
return
this
.
finish
(
node
,
ParseError
.
RightParenthesisExpected
,
[
TokenType
.
SemiColon
]);
}
}
if
(
!
this
.
accept
(
TokenType
.
URI
)
&&
!
this
.
accept
(
TokenType
.
String
))
{
return
this
.
finish
(
node
,
ParseError
.
URIOrStringExpected
,
[
TokenType
.
SemiColon
]);
}
node
.
setMedialist
(
this
.
_parseMediaList
());
return
this
.
finish
(
node
);
}
public
_parseMediaQuery
(
resyncStopToken
:
TokenType
[]):
nodes
.
Node
{
let
node
=
<
nodes
.
MediaQuery
>
super
.
_parseMediaQuery
(
resyncStopToken
);
if
(
!
node
)
{
let
node
=
<
nodes
.
MediaQuery
>
this
.
create
(
nodes
.
MediaQuery
);
if
(
node
.
addChild
(
this
.
_parseVariable
()))
{
return
this
.
finish
(
node
);
}
return
null
;
}
return
node
;
}
public
_parseVariableDeclaration
(
panic
:
TokenType
[]
=
[]):
nodes
.
VariableDeclaration
{
let
node
=
<
nodes
.
VariableDeclaration
>
this
.
create
(
nodes
.
VariableDeclaration
);
let
mark
=
this
.
mark
();
if
(
!
node
.
setVariable
(
this
.
_parseVariable
()))
{
return
null
;
}
if
(
this
.
accept
(
TokenType
.
Colon
,
'
:
'
))
{
node
.
colonPosition
=
this
.
prevToken
.
offset
;
if
(
!
node
.
setValue
(
this
.
_parseExpr
()))
{
return
<
nodes
.
VariableDeclaration
>
this
.
finish
(
node
,
ParseError
.
VariableValueExpected
,
[],
panic
);
}
}
else
{
this
.
restoreAtMark
(
mark
);
return
null
;
// at keyword, but no ':', not a variable declaration but some at keyword
}
if
(
this
.
peek
(
TokenType
.
SemiColon
))
{
node
.
semicolonPosition
=
this
.
token
.
offset
;
// not part of the declaration, but useful information for code assist
}
return
<
nodes
.
VariableDeclaration
>
this
.
finish
(
node
);
}
public
_parseVariable
():
nodes
.
Variable
{
let
node
=
<
nodes
.
Variable
>
this
.
create
(
nodes
.
Variable
);
let
mark
=
this
.
mark
();
while
(
this
.
accept
(
TokenType
.
Delim
,
'
@
'
))
{
if
(
this
.
hasWhitespace
())
{
this
.
restoreAtMark
(
mark
);
return
null
;
}
}
if
(
!
this
.
accept
(
TokenType
.
AtKeyword
))
{
this
.
restoreAtMark
(
mark
);
return
null
;
}
return
<
nodes
.
Variable
>
node
;
}
public
_parseTerm
():
nodes
.
Term
{
let
term
=
super
.
_parseTerm
();
if
(
term
)
{
return
term
;
}
term
=
<
nodes
.
Term
>
this
.
create
(
nodes
.
Term
);
if
(
term
.
setExpression
(
this
.
_parseVariable
())
||
term
.
setExpression
(
this
.
_parseEscaped
()))
{
return
<
nodes
.
Term
>
this
.
finish
(
term
);
}
return
null
;
}
public
_parseEscaped
():
nodes
.
Node
{
let
node
=
this
.
createNode
(
nodes
.
NodeType
.
EscapedValue
);
if
(
this
.
accept
(
TokenType
.
EscapedJavaScript
)
||
this
.
accept
(
TokenType
.
BadEscapedJavaScript
))
{
return
this
.
finish
(
node
);
}
if
(
this
.
accept
(
TokenType
.
Delim
,
'
~
'
))
{
return
this
.
finish
(
node
,
this
.
accept
(
TokenType
.
String
)
?
null
:
ParseError
.
TermExpected
);
}
return
null
;
}
public
_parseOperator
():
nodes
.
Node
{
let
node
=
this
.
_parseGuardOperator
();
if
(
node
)
{
return
node
;
}
else
{
return
super
.
_parseOperator
();
}
}
public
_parseGuardOperator
():
nodes
.
Node
{
let
node
=
this
.
createNode
(
nodes
.
NodeType
.
Operator
);
if
(
this
.
accept
(
TokenType
.
Delim
,
'
>
'
))
{
this
.
accept
(
TokenType
.
Delim
,
'
=
'
);
return
node
;
}
else
if
(
this
.
accept
(
TokenType
.
Delim
,
'
=
'
))
{
this
.
accept
(
TokenType
.
Delim
,
'
<
'
);
return
node
;
}
else
if
(
this
.
accept
(
TokenType
.
Delim
,
'
<
'
))
{
return
node
;
}
return
null
;
}
public
_parseRuleSetDeclaration
():
nodes
.
Node
{
if
(
this
.
peek
(
TokenType
.
AtKeyword
))
{
return
this
.
_parseKeyframe
()
||
this
.
_parseMedia
()
||
this
.
_parseVariableDeclaration
();
// Variable declarations
}
return
this
.
_tryParseMixinDeclaration
()
||
this
.
_tryParseRuleset
(
true
)
// nested ruleset
||
this
.
_parseMixinReference
()
// less mixin reference
||
this
.
_parseExtend
()
// less extend declaration
||
super
.
_parseRuleSetDeclaration
();
// try css ruleset declaration as the last option
}
public
_parseSimpleSelectorBody
():
nodes
.
Node
{
return
this
.
_parseSelectorCombinator
()
||
super
.
_parseSimpleSelectorBody
();
}
public
_parseSelectorCombinator
():
nodes
.
Node
{
let
node
=
this
.
createNode
(
nodes
.
NodeType
.
SelectorCombinator
);
if
(
this
.
accept
(
TokenType
.
Delim
,
'
&
'
))
{
while
(
!
this
.
hasWhitespace
()
&&
(
this
.
accept
(
TokenType
.
Delim
,
'
-
'
)
||
node
.
addChild
(
this
.
_parseIdent
())
||
this
.
accept
(
TokenType
.
Delim
,
'
&
'
)))
{
// support &-foo
}
return
this
.
finish
(
node
);
}
return
null
;
}
public
_parseSelectorIdent
():
nodes
.
Node
{
return
this
.
_parseIdent
()
||
this
.
_parseSelectorInterpolation
();
}
public
_parseSelectorInterpolation
():
nodes
.
Node
{
// Selector interpolation; old: ~"@{name}", new: @{name}
let
node
=
this
.
createNode
(
nodes
.
NodeType
.
SelectorInterpolation
);
if
(
this
.
accept
(
TokenType
.
Delim
,
'
~
'
))
{
if
(
!
this
.
hasWhitespace
()
&&
(
this
.
accept
(
TokenType
.
String
)
||
this
.
accept
(
TokenType
.
BadString
)))
{
return
this
.
finish
(
node
);
}
return
this
.
finish
(
node
,
ParseError
.
StringLiteralExpected
);
}
else
if
(
this
.
accept
(
TokenType
.
Delim
,
'
@
'
))
{
if
(
this
.
hasWhitespace
()
||
!
this
.
accept
(
TokenType
.
CurlyL
))
{
return
this
.
finish
(
node
,
ParseError
.
LeftCurlyExpected
);
}
if
(
!
node
.
addChild
(
this
.
_parseIdent
()))
{
return
this
.
finish
(
node
,
ParseError
.
IdentifierExpected
);
}
if
(
!
this
.
accept
(
TokenType
.
CurlyR
))
{
return
this
.
finish
(
node
,
ParseError
.
RightCurlyExpected
);
}
return
this
.
finish
(
node
);
}
return
null
;
}
public
_tryParseMixinDeclaration
():
nodes
.
Node
{
if
(
!
this
.
peek
(
TokenType
.
Delim
,
'
.
'
))
{
return
null
;
}
let
mark
=
this
.
mark
();
let
node
=
<
nodes
.
MixinDeclaration
>
this
.
create
(
nodes
.
MixinDeclaration
);
if
(
!
node
.
setIdentifier
(
this
.
_parseMixinDeclarationIdentifier
())
||
!
this
.
accept
(
TokenType
.
ParenthesisL
))
{
this
.
restoreAtMark
(
mark
);
return
null
;
}
if
(
node
.
getParameters
().
addChild
(
this
.
_parseMixinParameter
()))
{
while
(
this
.
accept
(
TokenType
.
Comma
)
||
this
.
accept
(
TokenType
.
SemiColon
))
{
if
(
!
node
.
getParameters
().
addChild
(
this
.
_parseMixinParameter
()))
{
return
this
.
finish
(
node
,
ParseError
.
IdentifierExpected
);
}
}
}
if
(
!
this
.
accept
(
TokenType
.
ParenthesisR
))
{
return
this
.
finish
(
node
,
ParseError
.
RightParenthesisExpected
);
}
node
.
setGuard
(
this
.
_parseGuard
());
if
(
!
this
.
peek
(
TokenType
.
CurlyL
))
{
this
.
restoreAtMark
(
mark
);
return
null
;
}
return
this
.
_parseBody
(
node
,
this
.
_parseRuleSetDeclaration
.
bind
(
this
));
}
public
_parseMixinDeclarationIdentifier
():
nodes
.
Identifier
{
let
identifier
=
<
nodes
.
Identifier
>
this
.
create
(
nodes
.
Identifier
);
// identifier should contain dot
this
.
consumeToken
();
// .
if
(
this
.
hasWhitespace
()
||
!
this
.
accept
(
TokenType
.
Ident
))
{
return
null
;
}
identifier
.
referenceTypes
=
[
nodes
.
ReferenceType
.
Mixin
];
return
this
.
finish
(
identifier
);
}
public
_parseExtend
():
nodes
.
Node
{
if
(
!
this
.
peek
(
TokenType
.
Delim
,
'
&
'
))
{
return
null
;
}
let
mark
=
this
.
mark
();
let
node
=
<
nodes
.
ExtendsReference
>
this
.
create
(
nodes
.
ExtendsReference
);
this
.
consumeToken
();
// &
if
(
this
.
hasWhitespace
()
||
!
this
.
accept
(
TokenType
.
Colon
)
||
!
this
.
accept
(
TokenType
.
Ident
,
'
extend
'
))
{
this
.
restoreAtMark
(
mark
);
return
null
;
}
if
(
!
this
.
accept
(
TokenType
.
ParenthesisL
))
{
return
this
.
finish
(
node
,
ParseError
.
LeftParenthesisExpected
);
}
if
(
!
node
.
setSelector
(
this
.
_parseSimpleSelector
()))
{
return
this
.
finish
(
node
,
ParseError
.
SelectorExpected
);
}
if
(
!
this
.
accept
(
TokenType
.
ParenthesisR
))
{
return
this
.
finish
(
node
,
ParseError
.
RightParenthesisExpected
);
}
return
this
.
finish
(
node
);
}
public
_parseMixinReference
():
nodes
.
Node
{
if
(
!
this
.
peek
(
TokenType
.
Delim
,
'
.
'
))
{
return
null
;
}
let
node
=
<
nodes
.
MixinReference
>
this
.
create
(
nodes
.
MixinReference
);
let
identifier
=
<
nodes
.
Identifier
>
this
.
create
(
nodes
.
Identifier
);
this
.
consumeToken
();
// dot, part of the identifier
if
(
this
.
hasWhitespace
()
||
!
this
.
accept
(
TokenType
.
Ident
))
{
return
this
.
finish
(
node
,
ParseError
.
IdentifierExpected
);
}
node
.
setIdentifier
(
this
.
finish
(
identifier
));
if
(
!
this
.
hasWhitespace
()
&&
this
.
accept
(
TokenType
.
ParenthesisL
))
{
if
(
node
.
getArguments
().
addChild
(
this
.
_parseFunctionArgument
()))
{
while
(
this
.
accept
(
TokenType
.
Comma
)
||
this
.
accept
(
TokenType
.
SemiColon
))
{
if
(
!
node
.
getArguments
().
addChild
(
this
.
_parseExpr
()))
{
return
this
.
finish
(
node
,
ParseError
.
ExpressionExpected
);
}
}
}
if
(
!
this
.
accept
(
TokenType
.
ParenthesisR
))
{
return
this
.
finish
(
node
,
ParseError
.
RightParenthesisExpected
);
}
identifier
.
referenceTypes
=
[
nodes
.
ReferenceType
.
Mixin
];
}
else
{
identifier
.
referenceTypes
=
[
nodes
.
ReferenceType
.
Mixin
,
nodes
.
ReferenceType
.
Rule
];
}
node
.
addChild
(
this
.
_parsePrio
());
return
this
.
finish
(
node
);
}
public
_parseMixinParameter
():
nodes
.
Node
{
let
node
=
<
nodes
.
FunctionParameter
>
this
.
create
(
nodes
.
FunctionParameter
);
// special rest variable: @rest...
if
(
this
.
peek
(
TokenType
.
AtKeyword
,
'
@rest
'
))
{
let
restNode
=
this
.
create
(
nodes
.
Node
);
this
.
consumeToken
();
if
(
!
this
.
accept
(
lessScanner
.
Ellipsis
))
{
return
this
.
finish
(
node
,
ParseError
.
DotExpected
,
[],
[
TokenType
.
Comma
,
TokenType
.
ParenthesisR
]);
}
node
.
setIdentifier
(
this
.
finish
(
restNode
));
return
this
.
finish
(
node
);
}
// special let args: ...
if
(
this
.
peek
(
lessScanner
.
Ellipsis
))
{
let
varargsNode
=
this
.
create
(
nodes
.
Node
);
this
.
consumeToken
();
node
.
setIdentifier
(
this
.
finish
(
varargsNode
));
return
this
.
finish
(
node
);
}
// default variable declaration: @param: 12 or @name
if
(
node
.
setIdentifier
(
this
.
_parseVariable
()))
{
this
.
accept
(
TokenType
.
Colon
);
}
node
.
setDefaultValue
(
this
.
_parseExpr
(
true
));
return
this
.
finish
(
node
);
}
public
_parseGuard
():
nodes
.
LessGuard
{
let
node
=
<
nodes
.
LessGuard
>
this
.
create
(
nodes
.
LessGuard
);
if
(
!
this
.
accept
(
TokenType
.
Ident
,
'
when
'
))
{
return
null
;
}
node
.
isNegated
=
this
.
accept
(
TokenType
.
Ident
,
'
not
'
);
if
(
!
node
.
getConditions
().
addChild
(
this
.
_parseGuardCondition
()))
{
return
<
nodes
.
LessGuard
>
this
.
finish
(
node
,
ParseError
.
ConditionExpected
);
}
while
(
this
.
accept
(
TokenType
.
Ident
,
'
and
'
)
||
this
.
accept
(
TokenType
.
Comma
,
'
,
'
))
{
if
(
!
node
.
getConditions
().
addChild
(
this
.
_parseGuardCondition
()))
{
return
<
nodes
.
LessGuard
>
this
.
finish
(
node
,
ParseError
.
ConditionExpected
);
}
}
return
<
nodes
.
LessGuard
>
this
.
finish
(
node
);
}
public
_parseGuardCondition
():
nodes
.
Node
{
let
node
=
this
.
create
(
nodes
.
GuardCondition
);
if
(
!
this
.
accept
(
TokenType
.
ParenthesisL
))
{
return
null
;
}
if
(
!
node
.
addChild
(
this
.
_parseExpr
()))
{
// empty (?)
}
if
(
!
this
.
accept
(
TokenType
.
ParenthesisR
))
{
return
this
.
finish
(
node
,
ParseError
.
RightParenthesisExpected
);
}
return
this
.
finish
(
node
);
}
public
_parseFunctionIdentifier
():
nodes
.
Identifier
{
if
(
this
.
peek
(
TokenType
.
Delim
,
'
%
'
))
{
let
node
=
<
nodes
.
Identifier
>
this
.
create
(
nodes
.
Identifier
);
node
.
referenceTypes
=
[
nodes
.
ReferenceType
.
Function
];
this
.
consumeToken
();
return
this
.
finish
(
node
);
}
return
super
.
_parseFunctionIdentifier
();
}
}
extensions/css/server/src/parser/lessScanner.ts
0 → 100644
浏览文件 @
1e7486aa
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
scanner
from
'
./cssScanner
'
;
const
_FSL
=
'
/
'
.
charCodeAt
(
0
);
const
_NWL
=
'
\n
'
.
charCodeAt
(
0
);
const
_CAR
=
'
\r
'
.
charCodeAt
(
0
);
const
_LFD
=
'
\
f
'
.
charCodeAt
(
0
);
const
_TIC
=
'
`
'
.
charCodeAt
(
0
);
const
_DOT
=
'
.
'
.
charCodeAt
(
0
);
let
customTokenValue
=
scanner
.
TokenType
.
CustomToken
;
export
const
Ellipsis
:
scanner
.
TokenType
=
customTokenValue
++
;
export
class
LESSScanner
extends
scanner
.
Scanner
{
public
scan
():
scanner
.
IToken
{
let
triviaToken
=
this
.
trivia
();
if
(
triviaToken
!==
null
)
{
return
triviaToken
;
}
let
offset
=
this
.
stream
.
pos
();
// LESS: escaped JavaScript code `let a = "dddd"`
let
tokenType
=
this
.
escapedJavaScript
();
if
(
tokenType
!==
null
)
{
return
this
.
finishToken
(
offset
,
tokenType
);
}
if
(
this
.
stream
.
advanceIfChars
([
_DOT
,
_DOT
,
_DOT
]))
{
return
this
.
finishToken
(
offset
,
Ellipsis
);
}
return
super
.
scan
();
}
protected
comment
():
boolean
{
if
(
super
.
comment
())
{
return
true
;
}
if
(
this
.
stream
.
advanceIfChars
([
_FSL
,
_FSL
]))
{
this
.
stream
.
advanceWhileChar
((
ch
:
number
)
=>
{
switch
(
ch
)
{
case
_NWL
:
case
_CAR
:
case
_LFD
:
return
false
;
default
:
return
true
;
}
});
return
true
;
}
else
{
return
false
;
}
}
private
escapedJavaScript
():
scanner
.
TokenType
{
let
ch
=
this
.
stream
.
peekChar
();
if
(
ch
===
_TIC
)
{
this
.
stream
.
advance
(
1
);
this
.
stream
.
advanceWhileChar
((
ch
)
=>
{
return
ch
!==
_TIC
;
});
return
this
.
stream
.
advanceIfChar
(
_TIC
)
?
scanner
.
TokenType
.
EscapedJavaScript
:
scanner
.
TokenType
.
BadEscapedJavaScript
;
}
return
null
;
}
}
\ No newline at end of file
extensions/css/server/src/services/lessCompletion.ts
0 → 100644
浏览文件 @
1e7486aa
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
languageFacts
from
'
./languageFacts
'
;
import
{
CSSCompletion
}
from
'
./cssCompletion
'
;
import
{
CompletionList
,
CompletionItemKind
}
from
'
vscode-languageserver
'
;
import
*
as
nls
from
'
vscode-nls
'
;
const
localize
=
nls
.
loadMessageBundle
();
export
class
LESSCompletion
extends
CSSCompletion
{
private
static
builtInProposals
=
[
{
'
name
'
:
'
escape
'
,
'
example
'
:
'
escape(@string);
'
,
'
description
'
:
localize
(
'
less.builtin.escape
'
,
'
URL encodes a string
'
)
},
{
'
name
'
:
'
e
'
,
'
example
'
:
'
e(@string);
'
,
'
description
'
:
localize
(
'
less.builtin.e
'
,
'
escape string content
'
)
},
{
'
name
'
:
'
replace
'
,
'
example
'
:
'
replace(@string, @pattern, @replacement[, @flags]);
'
,
'
description
'
:
localize
(
'
less.builtin.replace
'
,
'
string replace
'
)
},
{
'
name
'
:
'
unit
'
,
'
example
'
:
'
unit(@dimension, [@unit:
\'\'
]);
'
,
'
description
'
:
localize
(
'
less.builtin.unit
'
,
'
remove or change the unit of a dimension
'
)
},
{
'
name
'
:
'
color
'
,
'
example
'
:
'
color(@string);
'
,
'
description
'
:
localize
(
'
less.builtin.color
'
,
'
parses a string to a color
'
)
},
{
'
name
'
:
'
convert
'
,
'
example
'
:
'
convert(@value, unit);
'
,
'
description
'
:
localize
(
'
less.builtin.convert
'
,
'
converts numbers from one type into another
'
)
},
{
'
name
'
:
'
data-uri
'
,
'
example
'
:
'
data-uri([mimetype,] url);
'
,
'
description
'
:
localize
(
'
less.builtin.data-uri
'
,
'
inlines a resource and falls back to `url()`
'
)
},
{
'
name
'
:
'
length
'
,
'
example
'
:
'
length(@list);
'
,
'
description
'
:
localize
(
'
less.builtin.length
'
,
'
returns the number of elements in a value list
'
)
},
{
'
name
'
:
'
extract
'
,
'
example
'
:
'
extract(@list, index);
'
,
'
description
'
:
localize
(
'
less.builtin.extract
'
,
'
returns a value at the specified position in the list
'
)
},
{
'
name
'
:
'
abs
'
,
'
description
'
:
localize
(
'
less.builtin.abs
'
,
'
absolute value of a number
'
),
'
example
'
:
'
abs(number);
'
},
{
'
name
'
:
'
acos
'
,
'
description
'
:
localize
(
'
less.builtin.acos
'
,
'
arccosine - inverse of cosine function
'
),
'
example
'
:
'
acos(number);
'
},
{
'
name
'
:
'
asin
'
,
'
description
'
:
localize
(
'
less.builtin.asin
'
,
'
arcsine - inverse of sine function
'
),
'
example
'
:
'
asin(number);
'
},
{
'
name
'
:
'
ceil
'
,
'
example
'
:
'
ceil(@number);
'
,
'
description
'
:
localize
(
'
less.builtin.ceil
'
,
'
rounds up to an integer
'
)
},
{
'
name
'
:
'
cos
'
,
'
description
'
:
localize
(
'
less.builtin.cos
'
,
'
cosine function
'
),
'
example
'
:
'
cos(number);
'
},
{
'
name
'
:
'
floor
'
,
'
description
'
:
localize
(
'
less.builtin.floor
'
,
'
rounds down to an integer
'
),
'
example
'
:
'
floor(@number);
'
},
{
'
name
'
:
'
percentage
'
,
'
description
'
:
localize
(
'
less.builtin.percentage
'
,
'
converts to a %, e.g. 0.5 > 50%
'
),
'
example
'
:
'
percentage(@number);
'
},
{
'
name
'
:
'
round
'
,
'
description
'
:
localize
(
'
less.builtin.round
'
,
'
rounds a number to a number of places
'
),
'
example
'
:
'
round(number, [places: 0]);
'
},
{
'
name
'
:
'
sqrt
'
,
'
description
'
:
localize
(
'
less.builtin.sqrt
'
,
'
calculates square root of a number
'
),
'
example
'
:
'
sqrt(number);
'
},
{
'
name
'
:
'
sin
'
,
'
description
'
:
localize
(
'
less.builtin.sin
'
,
'
sine function
'
),
'
example
'
:
'
sin(number);
'
},
{
'
name
'
:
'
tan
'
,
'
description
'
:
localize
(
'
less.builtin.tan
'
,
'
tangent function
'
),
'
example
'
:
'
tan(number);
'
},
{
'
name
'
:
'
atan
'
,
'
description
'
:
localize
(
'
less.builtin.atan
'
,
'
arctangent - inverse of tangent function
'
),
'
example
'
:
'
atan(number);
'
},
{
'
name
'
:
'
pi
'
,
'
description
'
:
localize
(
'
less.builtin.pi
'
,
'
returns pi
'
),
'
example
'
:
'
pi();
'
},
{
'
name
'
:
'
pow
'
,
'
description
'
:
localize
(
'
less.builtin.pow
'
,
'
first argument raised to the power of the second argument
'
),
'
example
'
:
'
pow(@base, @exponent);
'
},
{
'
name
'
:
'
mod
'
,
'
description
'
:
localize
(
'
less.builtin.mod
'
,
'
first argument modulus second argument
'
),
'
example
'
:
'
mod(number, number);
'
},
{
'
name
'
:
'
min
'
,
'
description
'
:
localize
(
'
less.builtin.min
'
,
'
returns the lowest of one or more values
'
),
'
example
'
:
'
min(@x, @y);
'
},
{
'
name
'
:
'
max
'
,
'
description
'
:
localize
(
'
less.builtin.max
'
,
'
returns the lowest of one or more values
'
),
'
example
'
:
'
max(@x, @y);
'
}
];
private
static
colorProposals
=
[
{
'
name
'
:
'
argb
'
,
'
example
'
:
'
argb(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.argb
'
,
'
creates a #AARRGGBB
'
)
},
{
'
name
'
:
'
hsl
'
,
'
example
'
:
'
hsl(@hue, @saturation, @lightness);
'
,
'
description
'
:
localize
(
'
less.builtin.hsl
'
,
'
creates a color
'
)
},
{
'
name
'
:
'
hsla
'
,
'
example
'
:
'
hsla(@hue, @saturation, @lightness, @alpha);
'
,
'
description
'
:
localize
(
'
less.builtin.hsla
'
,
'
creates a color
'
)
},
{
'
name
'
:
'
hsv
'
,
'
example
'
:
'
hsv(@hue, @saturation, @value);
'
,
'
description
'
:
localize
(
'
less.builtin.hsv
'
,
'
creates a color
'
)
},
{
'
name
'
:
'
hsva
'
,
'
example
'
:
'
hsva(@hue, @saturation, @value, @alpha);
'
,
'
description
'
:
localize
(
'
less.builtin.hsva
'
,
'
creates a color
'
)
},
{
'
name
'
:
'
hue
'
,
'
example
'
:
'
hue(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.hue
'
,
'
returns the `hue` channel of `@color` in the HSL space
'
)
},
{
'
name
'
:
'
saturation
'
,
'
example
'
:
'
saturation(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.saturation
'
,
'
returns the `saturation` channel of `@color` in the HSL space
'
)
},
{
'
name
'
:
'
lightness
'
,
'
example
'
:
'
lightness(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.lightness
'
,
'
returns the `lightness` channel of `@color` in the HSL space
'
)
},
{
'
name
'
:
'
hsvhue
'
,
'
example
'
:
'
hsvhue(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.hsvhue
'
,
'
returns the `hue` channel of `@color` in the HSV space
'
)
},
{
'
name
'
:
'
hsvsaturation
'
,
'
example
'
:
'
hsvsaturation(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.hsvsaturation
'
,
'
returns the `saturation` channel of `@color` in the HSV space
'
)
},
{
'
name
'
:
'
hsvvalue
'
,
'
example
'
:
'
hsvvalue(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.hsvvalue
'
,
'
returns the `value` channel of `@color` in the HSV space
'
)
},
{
'
name
'
:
'
red
'
,
'
example
'
:
'
red(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.red
'
,
'
returns the `red` channel of `@color`
'
)
},
{
'
name
'
:
'
green
'
,
'
example
'
:
'
green(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.green
'
,
'
returns the `green` channel of `@color`
'
)
},
{
'
name
'
:
'
blue
'
,
'
example
'
:
'
blue(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.blue
'
,
'
returns the `blue` channel of `@color`
'
)
},
{
'
name
'
:
'
alpha
'
,
'
example
'
:
'
alpha(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.alpha
'
,
'
returns the `alpha` channel of `@color`
'
)
},
{
'
name
'
:
'
luma
'
,
'
example
'
:
'
luma(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.luma
'
,
'
returns the `luma` value (perceptual brightness) of `@color`
'
)
},
{
'
name
'
:
'
saturate
'
,
'
example
'
:
'
saturate(@color, 10%);
'
,
'
description
'
:
localize
(
'
less.builtin.saturate
'
,
'
return `@color` 10% points more saturated
'
)
},
{
'
name
'
:
'
desaturate
'
,
'
example
'
:
'
desaturate(@color, 10%);
'
,
'
description
'
:
localize
(
'
less.builtin.desaturate
'
,
'
return `@color` 10% points less saturated
'
)
},
{
'
name
'
:
'
lighten
'
,
'
example
'
:
'
lighten(@color, 10%);
'
,
'
description
'
:
localize
(
'
less.builtin.lighten
'
,
'
return `@color` 10% points lighter
'
)
},
{
'
name
'
:
'
darken
'
,
'
example
'
:
'
darken(@color, 10%);
'
,
'
description
'
:
localize
(
'
less.builtin.darken
'
,
'
return `@color` 10% points darker
'
)
},
{
'
name
'
:
'
fadein
'
,
'
example
'
:
'
fadein(@color, 10%);
'
,
'
description
'
:
localize
(
'
less.builtin.fadein
'
,
'
return `@color` 10% points less transparent
'
)
},
{
'
name
'
:
'
fadeout
'
,
'
example
'
:
'
fadeout(@color, 10%);
'
,
'
description
'
:
localize
(
'
less.builtin.fadeout
'
,
'
return `@color` 10% points more transparent
'
)
},
{
'
name
'
:
'
fade
'
,
'
example
'
:
'
fade(@color, 50%);
'
,
'
description
'
:
localize
(
'
less.builtin.fade
'
,
'
return `@color` with 50% transparency
'
)
},
{
'
name
'
:
'
spin
'
,
'
example
'
:
'
spin(@color, 10);
'
,
'
description
'
:
localize
(
'
less.builtin.spin
'
,
'
return `@color` with a 10 degree larger in hue
'
)
},
{
'
name
'
:
'
mix
'
,
'
example
'
:
'
mix(@color1, @color2, [@weight: 50%]);
'
,
'
description
'
:
localize
(
'
less.builtin.mix
'
,
'
return a mix of `@color1` and `@color2`
'
)
},
{
'
name
'
:
'
greyscale
'
,
'
example
'
:
'
greyscale(@color);
'
,
'
description
'
:
localize
(
'
less.builtin.greyscale
'
,
'
returns a grey, 100% desaturated color
'
)
},
{
'
name
'
:
'
contrast
'
,
'
example
'
:
'
contrast(@color1, [@darkcolor: black], [@lightcolor: white], [@threshold: 43%]);
'
,
'
description
'
:
localize
(
'
less.builtin.contrast
'
,
'
return `@darkcolor` if `@color1 is> 43% luma` otherwise return `@lightcolor`, see notes
'
)
},
{
'
name
'
:
'
multiply
'
,
'
example
'
:
'
multiply(@color1, @color2);
'
},
{
'
name
'
:
'
screen
'
,
'
example
'
:
'
screen(@color1, @color2);
'
},
{
'
name
'
:
'
overlay
'
,
'
example
'
:
'
overlay(@color1, @color2);
'
},
{
'
name
'
:
'
softlight
'
,
'
example
'
:
'
softlight(@color1, @color2);
'
},
{
'
name
'
:
'
hardlight
'
,
'
example
'
:
'
hardlight(@color1, @color2);
'
},
{
'
name
'
:
'
difference
'
,
'
example
'
:
'
difference(@color1, @color2);
'
},
{
'
name
'
:
'
exclusion
'
,
'
example
'
:
'
exclusion(@color1, @color2);
'
},
{
'
name
'
:
'
average
'
,
'
example
'
:
'
average(@color1, @color2);
'
},
{
'
name
'
:
'
negation
'
,
'
example
'
:
'
negation(@color1, @color2);
'
}
];
constructor
()
{
super
(
'
@
'
);
}
private
createFunctionProposals
(
proposals
:
{
name
:
string
;
example
:
string
;
description
?:
string
;
}[],
result
:
CompletionList
):
CompletionList
{
proposals
.
forEach
(
p
=>
{
result
.
items
.
push
({
label
:
p
.
name
,
detail
:
p
.
example
,
documentation
:
p
.
description
,
insertText
:
p
.
name
+
'
({{}})
'
,
kind
:
CompletionItemKind
.
Function
});
});
return
result
;
}
public
getTermProposals
(
result
:
CompletionList
):
CompletionList
{
this
.
createFunctionProposals
(
LESSCompletion
.
builtInProposals
,
result
);
return
super
.
getTermProposals
(
result
);
}
protected
getColorProposals
(
entry
:
languageFacts
.
IEntry
,
result
:
CompletionList
):
CompletionList
{
this
.
createFunctionProposals
(
LESSCompletion
.
colorProposals
,
result
);
return
super
.
getColorProposals
(
entry
,
result
);
}
}
extensions/css/server/src/test/less/lessCompletion.test.ts
0 → 100644
浏览文件 @
1e7486aa
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
assert
from
'
assert
'
;
import
{
LESSParser
}
from
'
../../parser/lessParser
'
;
import
{
LESSCompletion
}
from
'
../../services/lessCompletion
'
;
import
*
as
nodes
from
'
../../parser/cssNodes
'
;
import
{
TextDocument
,
Position
}
from
'
vscode-languageserver
'
;
import
{
assertCompletion
,
ItemDescription
}
from
'
../css/completion.test
'
;
suite
(
'
LESS - Completions
'
,
()
=>
{
let
testCompletionFor
=
function
(
value
:
string
,
stringBefore
:
string
,
expected
:
{
count
?:
number
,
items
?:
ItemDescription
[]
}):
Thenable
<
void
>
{
let
idx
=
stringBefore
?
value
.
indexOf
(
stringBefore
)
+
stringBefore
.
length
:
0
;
let
completionProvider
=
new
LESSCompletion
();
let
document
=
TextDocument
.
create
(
'
test://test/test.less
'
,
'
less
'
,
0
,
value
);
let
position
=
Position
.
create
(
0
,
idx
);
let
jsonDoc
=
new
LESSParser
().
parseStylesheet
(
document
);
return
completionProvider
.
doComplete
(
document
,
position
,
jsonDoc
).
then
(
list
=>
{
if
(
expected
.
count
)
{
assert
.
equal
(
list
.
items
,
expected
.
count
);
}
if
(
expected
.
items
)
{
for
(
let
item
of
expected
.
items
)
{
assertCompletion
(
list
,
item
,
document
);
}
}
});
};
test
(
'
sylesheet
'
,
function
(
testDone
):
any
{
Promise
.
all
([
testCompletionFor
(
'
body {
'
,
'
{
'
,
{
items
:
[
{
label
:
'
display
'
},
{
label
:
'
background
'
}
]
}),
testCompletionFor
(
'
body { ver
'
,
'
ver
'
,
{
items
:
[
{
label
:
'
vertical-align
'
}
]
}),
testCompletionFor
(
'
body { word-break:
'
,
'
:
'
,
{
items
:
[
{
label
:
'
keep-all
'
}
]
}),
testCompletionFor
(
'
body { inner { vertical-align: }
'
,
'
:
'
,
{
items
:
[
{
label
:
'
bottom
'
}
]
}),
testCompletionFor
(
'
@var1: 3; body { inner { vertical-align: }
'
,
'
align:
'
,
{
items
:
[
{
label
:
'
@var1
'
}
]
}),
testCompletionFor
(
'
.foo { background-color: d
'
,
'
background-color: d
'
,
{
items
:
[
{
label
:
'
darken
'
},
{
label
:
'
desaturate
'
}
]
})
]).
then
(()
=>
testDone
(),
(
error
)
=>
testDone
(
error
));
});
});
extensions/css/server/src/test/less/lessNavigation.ts
0 → 100644
浏览文件 @
1e7486aa
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
{
LESSParser
}
from
'
../../parser/lessParser
'
;
import
*
as
nodes
from
'
../../parser/cssNodes
'
;
import
{
assertScopeBuilding
,
assertSymbolsInScope
,
assertScopesAndSymbols
,
assertHighlights
}
from
'
../css/navigation.test
'
;
suite
(
'
LESS - Symbols
'
,
()
=>
{
test
(
'
scope building
'
,
function
()
{
let
p
=
new
LESSParser
();
assertScopeBuilding
(
p
,
'
@let: blue
'
);
assertScopeBuilding
(
p
,
'
.class { .nested {} }
'
,
{
offset
:
7
,
length
:
14
},
{
offset
:
17
,
length
:
2
});
});
test
(
'
symbols in scopes
'
,
function
()
{
let
p
=
new
LESSParser
();
assertSymbolsInScope
(
p
,
'
@let: iable;
'
,
0
,
{
name
:
'
@let
'
,
type
:
nodes
.
ReferenceType
.
Variable
});
assertSymbolsInScope
(
p
,
'
@let: iable;
'
,
11
,
{
name
:
'
@let
'
,
type
:
nodes
.
ReferenceType
.
Variable
});
assertSymbolsInScope
(
p
,
'
@let: iable; .class { @color: blue; }
'
,
11
,
{
name
:
'
@let
'
,
type
:
nodes
.
ReferenceType
.
Variable
},
{
name
:
'
.class
'
,
type
:
nodes
.
ReferenceType
.
Rule
});
assertSymbolsInScope
(
p
,
'
@let: iable; .class { @color: blue; }
'
,
21
,
{
name
:
'
@color
'
,
type
:
nodes
.
ReferenceType
.
Variable
});
assertSymbolsInScope
(
p
,
'
@let: iable; .class { @color: blue; }
'
,
36
,
{
name
:
'
@color
'
,
type
:
nodes
.
ReferenceType
.
Variable
});
assertSymbolsInScope
(
p
,
'
@namespace "x"; .mixin() {}
'
,
0
,
{
name
:
'
.mixin
'
,
type
:
nodes
.
ReferenceType
.
Mixin
});
assertSymbolsInScope
(
p
,
'
.mixin() { .nested() {} }
'
,
10
,
{
name
:
'
.nested
'
,
type
:
nodes
.
ReferenceType
.
Mixin
});
assertSymbolsInScope
(
p
,
'
.mixin() { .nested() {} }
'
,
11
);
assertSymbolsInScope
(
p
,
'
@keyframes animation {};
'
,
0
,
{
name
:
'
animation
'
,
type
:
nodes
.
ReferenceType
.
Keyframe
});
});
test
(
'
scopes and symbols
'
,
function
()
{
let
p
=
new
LESSParser
();
assertScopesAndSymbols
(
p
,
'
@var1: 1; @var2: 2; .foo { @var3: 3; }
'
,
'
@var1,@var2,.foo,[@var3]
'
);
assertScopesAndSymbols
(
p
,
'
.mixin1 { @var0: 1} .mixin2(@var1) { @var3: 3 }
'
,
'
.mixin1,.mixin2,[@var0],[@var1,@var3]
'
);
assertScopesAndSymbols
(
p
,
'
a b { @var0: 1; c { d { } } }
'
,
'
[@var0,c,[d,[]]]
'
);
});
test
(
'
mark highlights
'
,
function
(
testDone
)
{
let
p
=
new
LESSParser
();
Promise
.
all
([
assertHighlights
(
p
,
'
@var1: 1; @var2: /**/@var1;
'
,
'
/**/
'
,
2
,
1
,
'
@var1
'
),
assertHighlights
(
p
,
'
@var1: 1; p { @var2: /**/@var1; }
'
,
'
/**/
'
,
2
,
1
,
'
@var1
'
),
assertHighlights
(
p
,
'
r1 { @var1: 1; p1: @var1;} r2,r3 { @var1: 1; p1: /**/@var1 + @var1;}
'
,
'
/**/
'
,
3
,
1
,
'
@var1
'
),
assertHighlights
(
p
,
'
.r1 { r1: 1em; } r2 { r1: 2em; /**/.r1;}
'
,
'
/**/
'
,
2
,
1
,
'
.r1
'
),
assertHighlights
(
p
,
'
.r1(@p1) { r1: @p1; } r2 { r1: 2em; /**/.r1(2px); }
'
,
'
/**/
'
,
2
,
1
,
'
.r1
'
),
assertHighlights
(
p
,
'
/**/.r1(@p1) { r1: @p1; } r2 { r1: 2em; .r1(2px); }
'
,
'
/**/
'
,
2
,
1
,
'
.r1
'
),
assertHighlights
(
p
,
'
@p1 : 1; .r1(@p1) { r1: /**/@p1; }
'
,
'
/**/
'
,
2
,
1
,
'
@p1
'
),
assertHighlights
(
p
,
'
/**/@p1 : 1; .r1(@p1) { r1: @p1; }
'
,
'
/**/
'
,
1
,
1
,
'
@p1
'
),
assertHighlights
(
p
,
'
@p1 : 1; .r1(/**/@p1) { r1: @p1; }
'
,
'
/**/
'
,
2
,
1
,
'
@p1
'
),
]).
then
(()
=>
testDone
(),
(
error
)
=>
testDone
(
error
));
});
});
\ No newline at end of file
extensions/css/server/src/test/less/nodes.test.ts
0 → 100644
浏览文件 @
1e7486aa
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
{
assertNodes
}
from
'
../css/nodes.test
'
;
import
*
as
nodes
from
'
../../parser/cssNodes
'
;
import
{
LESSParser
}
from
'
../../parser/lessParser
'
;
suite
(
'
LESS - Nodes
'
,
()
=>
{
function
ruleset
(
input
:
string
):
nodes
.
RuleSet
{
let
parser
=
new
LESSParser
();
let
node
=
parser
.
internalParse
(
input
,
parser
.
_parseRuleset
);
return
node
;
}
test
(
'
RuleSet
'
,
function
()
{
assertNodes
(
ruleset
,
'
selector { prop: value }
'
,
'
ruleset,...,selector,...,declaration,...,property,...,expression
'
);
assertNodes
(
ruleset
,
'
selector { prop; }
'
,
'
ruleset,...,selector,...,selector
'
);
assertNodes
(
ruleset
,
'
selector { prop {} }
'
,
'
ruleset,...,ruleset
'
);
});
});
extensions/css/server/src/test/less/parser.test.ts
0 → 100644
浏览文件 @
1e7486aa
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
assert
from
'
assert
'
;
import
{
Parser
}
from
'
../../parser/cssParser
'
;
import
{
TokenType
}
from
'
../../parser/cssScanner
'
;
import
*
as
nodes
from
'
../../parser/cssNodes
'
;
import
{
ParseError
}
from
'
../../parser/cssErrors
'
;
import
{
LESSParser
}
from
'
../../parser/lessParser
'
;
import
{
assertNode
,
assertNoNode
,
assertError
}
from
'
../css/parser.test
'
;
suite
(
'
LESS - Parser
'
,
()
=>
{
test
(
'
Variable
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
@color
'
,
parser
,
parser
.
_parseVariable
.
bind
(
parser
));
assertNode
(
'
@co42lor
'
,
parser
,
parser
.
_parseVariable
.
bind
(
parser
));
assertNode
(
'
@-co42lor
'
,
parser
,
parser
.
_parseVariable
.
bind
(
parser
));
assertNode
(
'
@@foo
'
,
parser
,
parser
.
_parseVariable
.
bind
(
parser
));
assertNode
(
'
@@@foo
'
,
parser
,
parser
.
_parseVariable
.
bind
(
parser
));
assertNode
(
'
@12ooo
'
,
parser
,
parser
.
_parseVariable
.
bind
(
parser
));
assertNoNode
(
'
@ @foo
'
,
parser
,
parser
.
_parseFunction
.
bind
(
parser
));
assertNoNode
(
'
@-@foo
'
,
parser
,
parser
.
_parseFunction
.
bind
(
parser
));
});
test
(
'
Media
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
@media @phone {}
'
,
parser
,
parser
.
_parseMedia
.
bind
(
parser
));
});
test
(
'
VariableDeclaration
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
@color: #F5F5F5
'
,
parser
,
parser
.
_parseVariableDeclaration
.
bind
(
parser
));
assertNode
(
'
@color: 0
'
,
parser
,
parser
.
_parseVariableDeclaration
.
bind
(
parser
));
assertNode
(
'
@color: 255
'
,
parser
,
parser
.
_parseVariableDeclaration
.
bind
(
parser
));
assertNode
(
'
@color: 25.5
'
,
parser
,
parser
.
_parseVariableDeclaration
.
bind
(
parser
));
assertNode
(
'
@color: 25px
'
,
parser
,
parser
.
_parseVariableDeclaration
.
bind
(
parser
));
assertNode
(
'
@color: 25.5px
'
,
parser
,
parser
.
_parseVariableDeclaration
.
bind
(
parser
));
assertNode
(
'
@primary-font: "wf_SegoeUI","Segoe UI","Segoe","Segoe WP"
'
,
parser
,
parser
.
_parseVariableDeclaration
.
bind
(
parser
));
assertNode
(
'
@greeting: `"hello".toUpperCase() + "!";`
'
,
parser
,
parser
.
_parseVariableDeclaration
.
bind
(
parser
));
});
test
(
'
MixinDeclaration
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
.color (@color: 25.5px) { }
'
,
parser
,
parser
.
_tryParseMixinDeclaration
.
bind
(
parser
));
assertNode
(
'
.color(@color: 25.5px) { }
'
,
parser
,
parser
.
_tryParseMixinDeclaration
.
bind
(
parser
));
assertNode
(
'
.color(@color) { }
'
,
parser
,
parser
.
_tryParseMixinDeclaration
.
bind
(
parser
));
assertNode
(
'
.color(@color; @border) { }
'
,
parser
,
parser
.
_tryParseMixinDeclaration
.
bind
(
parser
));
assertNode
(
'
.color() { }
'
,
parser
,
parser
.
_tryParseMixinDeclaration
.
bind
(
parser
));
assertNode
(
'
.color( ) { }
'
,
parser
,
parser
.
_tryParseMixinDeclaration
.
bind
(
parser
));
assertNode
(
'
.mixin (@a) when (@a > 10), (@a < -10) { }
'
,
parser
,
parser
.
_tryParseMixinDeclaration
.
bind
(
parser
));
assertNode
(
'
.mixin (@a) when (isnumber(@a)) and (@a > 0) { }
'
,
parser
,
parser
.
_tryParseMixinDeclaration
.
bind
(
parser
));
assertNode
(
'
.mixin (@b) when not (@b >= 0) { }
'
,
parser
,
parser
.
_tryParseMixinDeclaration
.
bind
(
parser
));
assertNode
(
'
.mixin (@b) when not (@b > 0) { }
'
,
parser
,
parser
.
_tryParseMixinDeclaration
.
bind
(
parser
));
assertNode
(
'
.mixin (@a, @rest...) { }
'
,
parser
,
parser
.
_tryParseMixinDeclaration
.
bind
(
parser
));
assertNode
(
'
.mixin (@a) when (lightness(@a) >= 50%) { }
'
,
parser
,
parser
.
_tryParseMixinDeclaration
.
bind
(
parser
));
});
test
(
'
MixinReference
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
.box-shadow(0 0 5px, 30%)
'
,
parser
,
parser
.
_parseMixinReference
.
bind
(
parser
));
assertNode
(
'
.box-shadow
'
,
parser
,
parser
.
_parseMixinReference
.
bind
(
parser
));
assertNode
(
'
.mixin(10) !important
'
,
parser
,
parser
.
_parseMixinReference
.
bind
(
parser
));
});
test
(
'
MixinParameter
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
@_
'
,
parser
,
parser
.
_parseMixinParameter
.
bind
(
parser
));
assertNode
(
'
@let: value
'
,
parser
,
parser
.
_parseMixinParameter
.
bind
(
parser
));
assertNode
(
'
@let
'
,
parser
,
parser
.
_parseMixinParameter
.
bind
(
parser
));
assertNode
(
'
@rest...
'
,
parser
,
parser
.
_parseMixinParameter
.
bind
(
parser
));
assertNode
(
'
...
'
,
parser
,
parser
.
_parseMixinParameter
.
bind
(
parser
));
assertNode
(
'
value
'
,
parser
,
parser
.
_parseMixinParameter
.
bind
(
parser
));
assertNode
(
'
"string"
'
,
parser
,
parser
.
_parseMixinParameter
.
bind
(
parser
));
assertNode
(
'
50%
'
,
parser
,
parser
.
_parseMixinParameter
.
bind
(
parser
));
});
test
(
'
Parser - function
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
%()
'
,
parser
,
parser
.
_parseFunction
.
bind
(
parser
));
assertNoNode
(
'
% ()
'
,
parser
,
parser
.
_parseFunction
.
bind
(
parser
));
});
test
(
'
Expr
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
(@let + 20)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(@let - 20)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(@let * 20)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(@let / 20)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(20 + @let)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(20 - @let)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(20 * @let)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(20 / @let)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(20 / 20 + @let)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(20 + 20 + @let)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(20 + 20 + 20 + @let)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(20 + 20 + 20 + 20 + @let)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(20 + 20 + @let + 20 + 20 + @let)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(20 + 20)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(@var1 + @var2)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
((@let + 5) * 2)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
((@let + (5 + 2)) * 2)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(@let + ((5 + 2) * 2))
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
@color
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
@color, @color
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
@color, 42%
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
@color, 42%, @color
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
@color - (@color + 10%)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(@base + @filler)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
(100% / 2 + @filler)
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
assertNode
(
'
100% / 2 + @filler
'
,
parser
,
parser
.
_parseExpr
.
bind
(
parser
));
});
test
(
'
LessOperator
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
>=
'
,
parser
,
parser
.
_parseOperator
.
bind
(
parser
));
assertNode
(
'
>
'
,
parser
,
parser
.
_parseOperator
.
bind
(
parser
));
assertNode
(
'
<
'
,
parser
,
parser
.
_parseOperator
.
bind
(
parser
));
assertNode
(
'
=<
'
,
parser
,
parser
.
_parseOperator
.
bind
(
parser
));
});
test
(
'
Extend
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
nav { &:extend(.inline); }
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
});
test
(
'
Declaration
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
border: thin solid 1px
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
assertNode
(
'
dummy: @color
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
assertNode
(
'
dummy: blue
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
assertNode
(
'
dummy: (20 / @let)
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
assertNode
(
'
dummy: (20 / 20 + @let)
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
assertNode
(
'
dummy: func(@red)
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
assertNode
(
'
dummy: desaturate(@red, 10%)
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
assertNode
(
'
dummy: desaturate(16, 10%)
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
assertNode
(
'
color: @base-color + #111
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
assertNode
(
'
color: 100% / 2 + @ref
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
assertNode
(
'
border: (@width * 2) solid black
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
assertNode
(
'
property: @class
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
assertNode
(
'
prop-erty: fnc(@t, 10%)
'
,
parser
,
parser
.
_parseDeclaration
.
bind
(
parser
));
});
test
(
'
Stylesheet
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
.color (@radius: 5px){ -border-radius: #F5F5F5 }
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
.color (@radius: 5px){ -border-radius: @radius }
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
.color (@radius: 5px){ -border-radius: #F5F5F5 } .color (@radius: 5px) { -border-radius: #F5F5F5 }
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
.color (@radius: 5px) { -border-radius: #F5F5F5 } .color (@radius: 5px) { -border-radius: #F5F5F5 } .color (@radius: 5px) { -border-radius: #F5F5F5 }
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
.color (@radius: 5px) { -border-radius: #F5F5F5 } .color (@radius: 5px) { -border-radius: #F5F5F5 } .color (@radius: 5px) { -border-radius: #F5F5F5 }
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
.mixin (@a, @rest...) {}
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
.mixin (@a) when (lightness(@a) >= 50%) { background-color: black;}
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
.some-mixin { font-weight:bold; } h1 { .some-mixin; font-size:40px; }
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
@color: #F5F5F5;
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
@color: #F5F5F5; @color: #F5F5F5;
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
@color: #F5F5F5; @color: #F5F5F5; @color: #F5F5F5;
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
@color: #F5F5F5; .color (@radius: 5px) { -border-radius: #F5F5F5 } @color: #F5F5F5;
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
@import-once "lib";
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertNode
(
'
@import-once (css) "hello";
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
));
assertError
(
'
@import-once () "hello";
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
),
ParseError
.
IdentifierExpected
);
assertError
(
'
@import-once (less);
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
),
ParseError
.
URIOrStringExpected
);
});
test
(
'
Ruleset
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
.selector { prop: erty @let 1px; }
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
selector { .mixin; }
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
selector { .mixin(1px); .mixin(blue, 1px,
\'
farboo
\'
) }
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
selector { .mixin(blue; 1px;
\'
farboo
\'
) }
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
selector:active { property:value; nested:hover {}}
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
selector {}
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
selector { property: declaration }
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
selector { @variable: declaration }
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
selector { nested {}}
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
selector { nested, a, b {}}
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
selector { property: value; property: value; }
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
selector { property: value; @keyframes foo {} @-moz-keyframes foo {}}
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
});
test
(
'
term
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
%(
\'
repetitions: %S file: %S
\'
, 1 + 2, "directory/file.less")
'
,
parser
,
parser
.
_parseTerm
.
bind
(
parser
));
assertNode
(
'
~"ms:alwaysHasItsOwnSyntax.For.Stuff()"
'
,
parser
,
parser
.
_parseTerm
.
bind
(
parser
));
// less syntax
});
test
(
'
Nested Ruleset
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
.class1 { @let: 1; .class { @let: 2; three: @let; let: 3; } one: @let; }
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
.class1 { @let: 1; > .class2 { display: none; } }
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
});
test
(
'
Selector Interpolation
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
.@{name} { }
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertNode
(
'
~"@{name}" { }
'
,
parser
,
parser
.
_parseRuleset
.
bind
(
parser
));
assertError
(
'
~{ }
'
,
parser
,
parser
.
_parseStylesheet
.
bind
(
parser
),
ParseError
.
StringLiteralExpected
);
assertError
(
'
@
'
,
parser
,
parser
.
_parseSelectorInterpolation
.
bind
(
parser
),
ParseError
.
LeftCurlyExpected
);
assertError
(
'
@{
'
,
parser
,
parser
.
_parseSelectorInterpolation
.
bind
(
parser
),
ParseError
.
IdentifierExpected
);
assertError
(
'
@{dd
'
,
parser
,
parser
.
_parseSelectorInterpolation
.
bind
(
parser
),
ParseError
.
RightCurlyExpected
);
});
test
(
'
Selector Combinator
'
,
function
()
{
let
parser
=
new
LESSParser
();
assertNode
(
'
&:hover
'
,
parser
,
parser
.
_parseSimpleSelector
.
bind
(
parser
));
assertNode
(
'
&.float
'
,
parser
,
parser
.
_parseSimpleSelector
.
bind
(
parser
));
assertNode
(
'
&-foo
'
,
parser
,
parser
.
_parseSimpleSelector
.
bind
(
parser
));
assertNode
(
'
&--&
'
,
parser
,
parser
.
_parseSimpleSelector
.
bind
(
parser
));
});
});
\ No newline at end of file
extensions/css/server/src/test/less/scanner.test.ts
0 → 100644
浏览文件 @
1e7486aa
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
assert
from
'
assert
'
;
import
{
Scanner
,
TokenType
}
from
'
../../parser/cssScanner
'
;
import
{
LESSScanner
}
from
'
../../parser/lessScanner
'
;
function
assertSingleToken
(
source
:
string
,
len
:
number
,
offset
:
number
,
text
:
string
,
type
:
TokenType
):
void
{
let
scan
=
new
LESSScanner
();
scan
.
setSource
(
source
);
let
token
=
scan
.
scan
();
assert
.
equal
(
token
.
len
,
len
);
assert
.
equal
(
token
.
offset
,
offset
);
assert
.
equal
(
token
.
text
,
text
);
assert
.
equal
(
token
.
type
,
type
);
}
suite
(
'
LESS - Scanner
'
,
()
=>
{
test
(
'
Test Escaped JavaScript
'
,
function
()
{
assertSingleToken
(
'
`
'
,
1
,
0
,
'
`
'
,
TokenType
.
BadEscapedJavaScript
);
assertSingleToken
(
'
`a
'
,
2
,
0
,
'
`a
'
,
TokenType
.
BadEscapedJavaScript
);
assertSingleToken
(
'
`let a = "ssss"`
'
,
16
,
0
,
'
`let a = "ssss"`
'
,
TokenType
.
EscapedJavaScript
);
assertSingleToken
(
'
`let a = "ss
\n
s"`
'
,
16
,
0
,
'
`let a = "ss
\n
s"`
'
,
TokenType
.
EscapedJavaScript
);
});
// less deactivated comments
test
(
'
Test Token SingleLineComment
'
,
function
()
{
assertSingleToken
(
'
//
'
,
0
,
2
,
''
,
TokenType
.
EOF
);
assertSingleToken
(
'
//this is a comment test
'
,
0
,
24
,
''
,
TokenType
.
EOF
);
assertSingleToken
(
'
// this is a comment test
'
,
0
,
25
,
''
,
TokenType
.
EOF
);
assertSingleToken
(
'
// this is a
\n
a
'
,
1
,
13
,
'
a
'
,
TokenType
.
Ident
);
assertSingleToken
(
'
// this is a
\n
// more
\n
\n
/* comment */a
'
,
1
,
38
,
'
a
'
,
TokenType
.
Ident
);
});
});
extensions/css/server/test/mocha.opts
浏览文件 @
1e7486aa
--ui tdd
--useColors true
./out/test/css
./out/test/less
./out/test/scss
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录