diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..6a88fff6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,48 @@ +name: ci + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + Test: + if: "!contains(github.event.head_commit.message, '[skip ci]')" + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - macos-latest + - windows-latest + atom_channel: + - stable + - nightly + steps: + - uses: actions/checkout@v2 + + - name: Cache + uses: actions/cache@v2 + with: + path: | + 'node_modules' + 'C:/Program Files (x86)/MSBuild/Microsoft.Cpp/v4.0/v140' + key: ${{ runner.os }}-${{ matrix.atom_channel }}-${{ hashFiles('package.json') }} + + - uses: UziTech/action-setup-atom@v1 + with: + channel: ${{ matrix.atom_channel }} + + - name: Install Visual Studio 2015 on Windows + if: ${{ contains(matrix.os, 'windows') }} + run: | + choco install visualcpp-build-tools --version=14.0.25420.1 --ignore-dependencies -y --params "'/IncludeRequired'" + echo ::set-env name=VCTargetsPath::'C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\v140' + + - name: Install dependencies + run: apm install + + - name: Run tests + run: apm test diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 47ee9a1a..00000000 --- a/.travis.yml +++ /dev/null @@ -1,41 +0,0 @@ -### Project specific config ### -language: generic - -env: - global: - - APM_TEST_PACKAGES="" - - ATOM_LINT_WITH_BUNDLED_NODE="true" - - matrix: - - ATOM_CHANNEL=stable - - ATOM_CHANNEL=beta - -### Generic setup follows ### -script: - - curl -s -O https://raw.githubusercontent.com/atom/ci/master/build-package.sh - - chmod u+x build-package.sh - - ./build-package.sh - -notifications: - email: - on_success: never - on_failure: change - -branches: - only: - - master - -git: - depth: 10 - -sudo: false - -dist: trusty - -addons: - apt: - packages: - - build-essential - - fakeroot - - git - - libsecret-1-dev diff --git a/appveyor.yml b/appveyor.yml index 7d07d05d..8ab396a6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,29 +1,6 @@ -version: "{build}" - -image: Visual Studio 2015 - -platform: x64 +build: off branches: - only: - - master - -clone_depth: 10 - -skip_tags: true - -environment: - APM_TEST_PACKAGES: - - matrix: - - ATOM_CHANNEL: stable - - ATOM_CHANNEL: beta - -install: - - ps: Install-Product node 4 - -build_script: - - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/atom/ci/master/build-package.ps1')) - -test: off -deploy: off + only: + - non-existing + diff --git a/grammars/javascript.cson b/grammars/javascript.cson index de6c9df6..248c1e2c 100644 --- a/grammars/javascript.cson +++ b/grammars/javascript.cson @@ -287,8 +287,8 @@ ] } { - # [.|?.]foo = function... - 'begin': '(?=(\\.|\\?\\.)?[a-zA-Z_$][\\w$]*\\s*=\\s*(\\basync\\b\\s*)?\\bfunction\\b)' + # [?].foo = function... + 'begin': '(?=(\\?\\.|\\.)?[a-zA-Z_$][\\w$]*\\s*=\\s*(\\basync\\b\\s*)?\\bfunction\\b)' 'end': '(?<=})' 'patterns': [ { @@ -303,7 +303,7 @@ 'name': 'meta.function.js' 'patterns': [ { - 'match': '(\\.|\\?\\.)?([a-zA-Z_$][\\w$]*)\\s*(=)\\s*' + 'match': '(\\?\\.|\\.)?([a-zA-Z_$][\\w$]*)\\s*(=)\\s*' 'captures': '1': 'name': 'meta.delimiter.method.js' @@ -539,7 +539,7 @@ # [.|?.]foo = ... => ... 'begin': '''(?x) (?= - (\\.|\\?\\.)?[a-zA-Z_$][\\w$]* + (\\?\\.|\\.)?[a-zA-Z_$][\\w$]* \\s*(=)\\s* ((\\(([^\\(\\)]*)?\\))|[\\w$]+) \\s*=> @@ -549,8 +549,8 @@ (?<=})| ((?! \\s*{| - \\G(\\.|\\?\\.)?[a-zA-Z_$][\\w$]*\\s*(=)\\s*\\(| - \\G(\\.|\\?\\.)?[a-zA-Z_$][\\w$]*\\s*(=)\\s*[\\w$]+| + \\G(\\?\\.|\\.)?[a-zA-Z_$][\\w$]*\\s*(=)\\s*\\(| + \\G(\\?\\.|\\.)?[a-zA-Z_$][\\w$]*\\s*(=)\\s*[\\w$]+| \\s*/\\*|\\s*// )(?=\\s*\\S)) ''' @@ -567,7 +567,7 @@ 'name': 'meta.function.arrow.js' 'patterns': [ { - 'match': '\\G(\\.|\\?\\.)?([a-zA-Z_$][\\w$]*)\\s*(=)' + 'match': '\\G(\\?\\.|\\.)?([a-zA-Z_$][\\w$]*)\\s*(=)' 'captures': '1': 'name': 'meta.delimiter.method.js' @@ -732,7 +732,7 @@ 'name': 'entity.name.type.instance.js' 'patterns': [ { - 'match': '\\.|\\?\\.' + 'match': '\\?\\.|\\.' 'name': 'meta.delimiter.property.js' } ] @@ -746,7 +746,7 @@ 'name': 'entity.name.type.object.console.js' 'end': '''(?x) (?<=\\)) | (?= - (?! (\\s*//)|(\\s*/\\*)|(\\s*(\\.|\\?\\.)\\s* + (?! (\\s*//)|(\\s*/\\*)|(\\s*(\\?\\.|\\.)\\s* (assert|clear|debug|error|info|log|profile|profileEnd|time|timeEnd|warn) \\s*\\( )) \\s*\\S @@ -757,7 +757,7 @@ 'include': '#comments' } { - 'begin': '\\s*(\\.|\\?\\.)\\s*(\\w+)\\s*(?=\\()' + 'begin': '\\s*(\\?\\.|\\.)\\s*(\\w+)\\s*(?=\\()' 'beginCaptures': '1': 'name': 'meta.delimiter.method.js' @@ -782,7 +782,7 @@ 'end': '''(?x) (?<=E|LN10|LN2|LOG10E|LOG2E|PI|SQRT1_2|SQRT2|\\) ) | (?= - (?! (\\s*//)|(\\s*/\\*)|(\\s*(\\.|\\?\\.)\\s* ( + (?! (\\s*//)|(\\s*/\\*)|(\\s*(\\?\\.|\\.)\\s* ( ((abs|acos|acosh|asin|asinh|atan|atan2|atanh|cbrt|ceil|clz32|cos|cosh|exp| expm1|floor|fround|hypot|imul|log|log10|log1p|log2|max|min|pow|random| round|sign|sin|sinh|sqrt|tan|tanh|trunc)\\s*\\( @@ -796,7 +796,7 @@ } { # Math.random() - 'begin': '\\s*(\\.|\\?\\.)\\s*(\\w+)\\s*(?=\\()' + 'begin': '\\s*(\\?\\.|\\.)\\s*(\\w+)\\s*(?=\\()' 'beginCaptures': '1': 'name': 'meta.delimiter.method.js' @@ -812,7 +812,7 @@ } { # Math.PI - 'match': '\\s*(\\.|\\?\\.)\\s*(\\w+)\\b' + 'match': '\\s*(\\?\\.|\\.)\\s*(\\w+)\\b' 'captures': '1': 'name': 'meta.delimiter.property.js' @@ -829,7 +829,7 @@ 'name': 'support.class.promise.js' 'end': '''(?x) (?<=\\)) | (?= - (?! (\\s*//)|(\\s*/\\*)|(\\s*(\\.|\\?\\.)\\s*(all|race|reject|resolve)\\s*\\() )\\s*\\S + (?! (\\s*//)|(\\s*/\\*)|(\\s*(\\?\\.|\\.)\\s*(all|race|reject|resolve)\\s*\\() )\\s*\\S ) ''' 'patterns': [ @@ -838,7 +838,7 @@ } { # Promise.all() - 'begin': '\\s*(\\.|\\?\\.)\\s*(\\w+)\\s*(?=\\()' + 'begin': '\\s*(\\?\\.|\\.)\\s*(\\w+)\\s*(?=\\()' 'beginCaptures': '1': 'name': 'meta.delimiter.method.js' @@ -986,7 +986,7 @@ 'name': 'support.class.js' } { - 'match': '''(?x) (\\.|\\?\\.) \\s* (?: + 'match': '''(?x) (\\?\\.|\\.) \\s* (?: (constructor|length|prototype) | (EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY) )\\b @@ -1001,7 +1001,7 @@ } { 'match': '''(?x) (? expect(tokens[1]).toEqual value: '--', scopes: ['source.js', 'keyword.operator.decrement.js'] describe "logical", -> - operators = ["&&", "||", "!"] + operators = ["&&", "||", "!", "??"] it "tokenizes them", -> for operator in operators @@ -1488,6 +1488,10 @@ describe "JavaScript grammar", -> expect(tokens[1]).toEqual value: '...', scopes: ['source.js', 'meta.function.arrow.js', 'meta.parameters.js', 'keyword.operator.spread.js'] expect(tokens[2]).toEqual value: 'args', scopes: ['source.js', 'meta.function.arrow.js', 'meta.parameters.js', 'variable.parameter.rest.function.js'] + {tokens} = grammar.tokenizeLine('(c, ...val) => c + val') + expect(tokens[4]).toEqual value: '...', scopes: ['source.js', 'meta.function.arrow.js', 'meta.parameters.js', 'keyword.operator.spread.js'] + expect(tokens[5]).toEqual value: 'val', scopes: ['source.js', 'meta.function.arrow.js', 'meta.parameters.js', 'variable.parameter.rest.function.js'] + it "tokenizes illegal parameters", -> {tokens} = grammar.tokenizeLine('0abc => {}') expect(tokens[0]).toEqual value: '0abc', scopes: ['source.js', 'meta.function.arrow.js', 'meta.parameters.js', 'invalid.illegal.identifier.js'] @@ -1770,6 +1774,28 @@ describe "JavaScript grammar", -> expect(tokens[1]).toEqual value: '.', scopes: ['source.js', 'meta.delimiter.property.js'] expect(tokens[2]).toEqual value: 'C', scopes: ['source.js', 'constant.other.property.js'] + it "supports the optional chaining operator", -> + {tokens} = grammar.tokenizeLine('obj?.prop') + expect(tokens[0]).toEqual value: 'obj', scopes: ['source.js', 'variable.other.object.js'] + expect(tokens[1]).toEqual value: '?.', scopes: ['source.js', 'meta.delimiter.property.js'] + expect(tokens[2]).toEqual value: 'prop', scopes: ['source.js', 'variable.other.property.js'] + + {tokens} = grammar.tokenizeLine('obj?.$_') + expect(tokens[0]).toEqual value: 'obj', scopes: ['source.js', 'variable.other.object.js'] + expect(tokens[1]).toEqual value: '?.', scopes: ['source.js', 'meta.delimiter.property.js'] + expect(tokens[2]).toEqual value: '$_', scopes: ['source.js', 'variable.other.property.js'] + + {tokens} = grammar.tokenizeLine('a()?.b()') + expect(tokens[2]).toEqual value: ')', scopes: ['source.js', 'meta.function-call.js', 'meta.arguments.js', 'punctuation.definition.arguments.end.bracket.round.js'] + expect(tokens[3]).toEqual value: '?.', scopes: ['source.js', 'meta.method-call.js', 'meta.delimiter.method.js'] + expect(tokens[4]).toEqual value: 'b', scopes: ['source.js', 'meta.method-call.js', 'entity.name.function.js'] + + {tokens} = grammar.tokenizeLine('a()?.MY_CONSTANT') + expect(tokens[0]).toEqual value: 'a', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js'] + expect(tokens[3]).toEqual value: '?.', scopes: ['source.js', 'meta.delimiter.property.js'] + expect(tokens[4]).toEqual value: 'MY_CONSTANT', scopes: ['source.js', 'constant.other.property.js'] + + describe "strings and functions", -> it "doesn't confuse them", -> {tokens} = grammar.tokenizeLine("'a'.b(':c(d)')") @@ -1832,11 +1858,6 @@ describe "JavaScript grammar", -> expect(tokens[1]).toEqual value: ' foo ', scopes: ['source.js', 'comment.block.documentation.js'] expect(tokens[2]).toEqual value: '*/', scopes: ['source.js', 'comment.block.documentation.js', 'punctuation.definition.comment.end.js'] - it "tokenizes // comments", -> - {tokens} = grammar.tokenizeLine('// comment') - expect(tokens[0]).toEqual value: '//', scopes: ['source.js', 'comment.line.double-slash.js', 'punctuation.definition.comment.js'] - expect(tokens[1]).toEqual value: ' comment', scopes: ['source.js', 'comment.line.double-slash.js'] - it "tokenizes comments inside constant definitions", -> {tokens} = grammar.tokenizeLine('const a, // comment') expect(tokens[0]).toEqual value: 'const', scopes: ['source.js', 'storage.type.const.js']