Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: fb55/nth-check
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 257338e5bbd53228236abd4cc09539b66b27dd11
Choose a base ref
...
head repository: fb55/nth-check
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 65e40b02b0437daf5d41760352433435ad2370a0
Choose a head ref

Commits on Apr 25, 2015

  1. reordered, added invalid tests

    fb55 committed Apr 25, 2015
    Copy the full SHA
    ed9459c View commit details

Commits on Sep 11, 2015

  1. added LICENSE file

    fb55 committed Sep 11, 2015
    Copy the full SHA
    0ff98a6 View commit details

Commits on Nov 1, 2016

  1. chore: drop support for Node.js 0.10

    BREAKING CHANGE: This module no longer supports Node.js 0.10
    greenkeeperio-bot authored and fb55 committed Nov 1, 2016
    Copy the full SHA
    36e64b5 View commit details

Commits on Dec 10, 2016

  1. Add files to package.json.

    wtgtybhertgeghgtwtg authored and fb55 committed Dec 10, 2016
    Copy the full SHA
    92d5305 View commit details

Commits on Jul 25, 2017

  1. Correct License Name

    maennchen authored Jul 25, 2017
    Copy the full SHA
    8dc13bd View commit details

Commits on Jul 26, 2017

  1. Merge pull request #3 from maennchen/patch-1

    Correct License Name
    fb55 authored Jul 26, 2017
    Copy the full SHA
    5e5e452 View commit details

Commits on Apr 2, 2018

  1. Update README.md

    fb55 authored Apr 2, 2018
    Copy the full SHA
    a023c36 View commit details

Commits on Oct 21, 2018

  1. ignore node_modules

    fb55 committed Oct 21, 2018
    Copy the full SHA
    d29c1d3 View commit details
  2. 1.0.2

    fb55 committed Oct 21, 2018
    Copy the full SHA
    03a0258 View commit details
  3. prettier

    fb55 committed Oct 21, 2018
    Copy the full SHA
    91a7ce7 View commit details
  4. Test on node LTS

    fb55 committed Oct 21, 2018
    Copy the full SHA
    77ae802 View commit details

Commits on Jun 24, 2019

  1. Create FUNDING.yml

    fb55 authored Jun 24, 2019
    Copy the full SHA
    0c7bf8b View commit details
  2. Update README.md

    fb55 authored Jun 24, 2019
    Copy the full SHA
    bc00200 View commit details

Commits on Oct 29, 2019

  1. Add enterprise language

    phated authored and fb55 committed Oct 29, 2019
    Copy the full SHA
    eb73357 View commit details

Commits on Nov 26, 2020

  1. Update .travis.yml

    Added support for ppc64le
    nageshlop authored Nov 26, 2020
    Copy the full SHA
    938b729 View commit details

Commits on Dec 1, 2020

  1. Copy the full SHA
    65d0edf View commit details
  2. Update README.md

    fb55 authored Dec 1, 2020
    Copy the full SHA
    8d05af6 View commit details
  3. refactor: Port module to TS, Jest, ESLint

    BREAKING: The main export is now a `default` export.
    fb55 committed Dec 1, 2020
    Copy the full SHA
    a48a6f9 View commit details
  4. Update package.json

    fb55 committed Dec 1, 2020
    Copy the full SHA
    a9dd9c4 View commit details
  5. refactor: Port module to TS, Jest, ESLint (#7)

    BREAKING: The main export is now a `default` export.
    fb55 authored Dec 1, 2020
    Copy the full SHA
    40b99c2 View commit details
  6. 2.0.0

    fb55 committed Dec 1, 2020
    Copy the full SHA
    3ba66fc View commit details

Commits on Sep 14, 2021

  1. 5
    Copy the full SHA
    9894c1d View commit details
  2. Copy the full SHA
    e02b4dd View commit details
  3. Bump typescript from 4.1.2 to 4.4.3 (#12)

    Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.1.2 to 4.4.3.
    - [Release notes](https://github.com/Microsoft/TypeScript/releases)
    - [Commits](microsoft/TypeScript@v4.1.2...v4.4.3)
    
    ---
    updated-dependencies:
    - dependency-name: typescript
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Sep 14, 2021
    Copy the full SHA
    e91102c View commit details
  4. Bump eslint from 7.14.0 to 7.32.0 (#14)

    Bumps [eslint](https://github.com/eslint/eslint) from 7.14.0 to 7.32.0.
    - [Release notes](https://github.com/eslint/eslint/releases)
    - [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
    - [Commits](eslint/eslint@v7.14.0...v7.32.0)
    
    ---
    updated-dependencies:
    - dependency-name: eslint
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Sep 14, 2021
    Copy the full SHA
    7efd9da View commit details
  5. Bump ts-jest from 26.4.4 to 26.5.6 (#15)

    Bumps [ts-jest](https://github.com/kulshekhar/ts-jest) from 26.4.4 to 26.5.6.
    - [Release notes](https://github.com/kulshekhar/ts-jest/releases)
    - [Changelog](https://github.com/kulshekhar/ts-jest/blob/main/CHANGELOG.md)
    - [Commits](kulshekhar/ts-jest@v26.4.4...v26.5.6)
    
    ---
    updated-dependencies:
    - dependency-name: ts-jest
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Sep 14, 2021
    Copy the full SHA
    732ab0a View commit details
  6. Bump @types/jest from 26.0.15 to 27.0.1 (#13)

    Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 26.0.15 to 27.0.1.
    - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
    - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)
    
    ---
    updated-dependencies:
    - dependency-name: "@types/jest"
      dependency-type: direct:development
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Sep 14, 2021
    Copy the full SHA
    3ddd820 View commit details
  7. Bump prettier from 2.2.1 to 2.4.0 (#20)

    Bumps [prettier](https://github.com/prettier/prettier) from 2.2.1 to 2.4.0.
    - [Release notes](https://github.com/prettier/prettier/releases)
    - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
    - [Commits](prettier/prettier@2.2.1...2.4.0)
    
    ---
    updated-dependencies:
    - dependency-name: prettier
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Sep 14, 2021
    Copy the full SHA
    a11c0c1 View commit details
  8. Bump @typescript-eslint/eslint-plugin from 4.9.0 to 4.31.1 (#19)

    Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.9.0 to 4.31.1.
    - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
    - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md)
    - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.31.1/packages/eslint-plugin)
    
    ---
    updated-dependencies:
    - dependency-name: "@typescript-eslint/eslint-plugin"
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Sep 14, 2021
    Copy the full SHA
    5f39402 View commit details
  9. Bump @types/node from 14.14.10 to 16.9.1 (#16)

    Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 14.14.10 to 16.9.1.
    - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
    - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)
    
    ---
    updated-dependencies:
    - dependency-name: "@types/node"
      dependency-type: direct:development
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Sep 14, 2021
    Copy the full SHA
    fa35caf View commit details
  10. Bump @typescript-eslint/parser from 4.9.0 to 4.31.1 (#18)

    Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 4.9.0 to 4.31.1.
    - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
    - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/CHANGELOG.md)
    - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.31.1/packages/parser)
    
    ---
    updated-dependencies:
    - dependency-name: "@typescript-eslint/parser"
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Sep 14, 2021
    Copy the full SHA
    da9d78a View commit details

Commits on Sep 16, 2021

  1. Bump jest from 26.6.3 to 27.2.0 (#17)

    Bumps [jest](https://github.com/facebook/jest) from 26.6.3 to 27.2.0.
    - [Release notes](https://github.com/facebook/jest/releases)
    - [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
    - [Commits](jestjs/jest@v26.6.3...v27.2.0)
    
    ---
    updated-dependencies:
    - dependency-name: jest
      dependency-type: direct:development
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Sep 16, 2021
    Copy the full SHA
    ff24c93 View commit details
  2. Bump eslint-config-prettier from 6.15.0 to 8.3.0 (#11)

    * Bump eslint-config-prettier from 6.15.0 to 8.3.0
    
    Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 6.15.0 to 8.3.0.
    - [Release notes](https://github.com/prettier/eslint-config-prettier/releases)
    - [Changelog](https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md)
    - [Commits](prettier/eslint-config-prettier@v6.15.0...v8.3.0)
    
    ---
    updated-dependencies:
    - dependency-name: eslint-config-prettier
      dependency-type: direct:development
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    * Update .eslintrc.json
    
    * Bump eslint-config-prettier from 6.15.0 to 8.3.0
    
    Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 6.15.0 to 8.3.0.
    - [Release notes](https://github.com/prettier/eslint-config-prettier/releases)
    - [Changelog](https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md)
    - [Commits](prettier/eslint-config-prettier@v6.15.0...v8.3.0)
    
    ---
    updated-dependencies:
    - dependency-name: eslint-config-prettier
      dependency-type: direct:development
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    Co-authored-by: Felix Böhm <188768+fb55@users.noreply.github.com>
    dependabot[bot] and fb55 authored Sep 16, 2021
    Copy the full SHA
    ff63f1d View commit details
  3. 2.0.1

    fb55 committed Sep 16, 2021
    Copy the full SHA
    65e40b0 View commit details
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
coverage/
lib/
62 changes: 62 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"extends": ["eslint:recommended", "prettier"],
"env": {
"node": true,
"es6": true
},
"rules": {
"eqeqeq": [2, "smart"],
"no-caller": 2,
"dot-notation": 2,
"no-var": 2,
"prefer-const": 2,
"prefer-arrow-callback": [2, { "allowNamedFunctions": true }],
"arrow-body-style": [2, "as-needed"],
"object-shorthand": 2,
"prefer-template": 2,
"one-var": [2, "never"],
"prefer-destructuring": [2, { "object": true }],
"capitalized-comments": 2,
"multiline-comment-style": [2, "starred-block"],
"spaced-comment": 2,
"yoda": [2, "never"],
"curly": [2, "multi-line"],
"no-else-return": 2
},
"overrides": [
{
"files": "*.ts",
"extends": [
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"parserOptions": {
"sourceType": "module",
"project": "./tsconfig.eslint.json"
},
"rules": {
"@typescript-eslint/prefer-for-of": 0,
"@typescript-eslint/member-ordering": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/no-unused-vars": 0,
"@typescript-eslint/no-use-before-define": [
2,
{ "functions": false }
],
"@typescript-eslint/consistent-type-definitions": [
2,
"interface"
],
"@typescript-eslint/prefer-function-type": 2,
"@typescript-eslint/no-unnecessary-type-arguments": 2,
"@typescript-eslint/prefer-string-starts-ends-with": 2,
"@typescript-eslint/prefer-readonly": 2,
"@typescript-eslint/prefer-includes": 2,
"@typescript-eslint/no-unnecessary-condition": 2,
"@typescript-eslint/switch-exhaustiveness-check": 2,
"@typescript-eslint/prefer-nullish-coalescing": 2
}
}
]
}
2 changes: 2 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github: [fb55]
tidelift: "npm/nth-check"
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
versioning-strategy: increase
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: daily
52 changes: 52 additions & 0 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: "Code scanning - action"

on:
push:
branches: [master]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
schedule:
- cron: "0 7 * * 0"

jobs:
CodeQL-Build:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2

# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
28 changes: 28 additions & 0 deletions .github/workflows/dependabot-automerge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Based on https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/automating-dependabot-with-github-actions#enable-auto-merge-on-a-pull-request
name: Dependabot auto-merge
on: pull_request_target

permissions:
pull-requests: write
contents: write

jobs:
dependabot:
runs-on: ubuntu-latest
if: ${{ github.actor == 'dependabot[bot]' }}
steps:
- name: Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v1.1.1
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
- name: Enable auto-merge for Dependabot PRs
# Automatically merge semver-patch and semver-minor PRs
if: "${{ steps.metadata.outputs.update-type ==
'version-update:semver-minor' ||
steps.metadata.outputs.update-type ==
'version-update:semver-patch' }}"
run: gh pr merge --auto --squash "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
57 changes: 57 additions & 0 deletions .github/workflows/nodejs-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Node.js CI

on: [push, pull_request]

env:
CI: true
FORCE_COLOR: 2
NODE_COV: 16 # The Node.js version to run coveralls on

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 16
cache: npm
- run: npm ci
- run: npm run lint

test:
name: Node ${{ matrix.node }}
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
node:
- 10
- 12
- 14
- 16

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
cache: npm
- run: npm ci
- run: npm run build --if-present

- name: Run Jest
run: npm run test:jest
if: matrix.node != env.NODE_COV

- name: Run Jest with coverage
run: npm run test:jest -- --coverage
if: matrix.node == env.NODE_COV

- name: Run Coveralls
uses: coverallsapp/github-action@master
if: matrix.node == env.NODE_COV
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.vscode/
node_modules/
coverage/
lib/
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
coverage/
lib/
5 changes: 0 additions & 5 deletions .travis.yml

This file was deleted.

11 changes: 11 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Copyright (c) Felix Böhm
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
77 changes: 53 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,80 @@
#nth-check [![Build Status](https://travis-ci.org/fb55/nth-check.png)](https://travis-ci.org/fb55/nth-check)
# nth-check [![Build Status](https://travis-ci.org/fb55/nth-check.svg)](https://travis-ci.org/fb55/nth-check)

A performant nth-check parser & compiler.
Parses and compiles CSS nth-checks to highly optimized functions.

###About
### About

This module can be used to parse & compile nth-checks, as they are found in CSS 3's `nth-child()` and `nth-last-of-type()`.

`nth-check` focusses on speed, providing optimized functions for different kinds of nth-child formulas, while still following the [spec](http://www.w3.org/TR/css3-selectors/#nth-child-pseudo).

###API
### API

```js
var nthCheck = require("nth-check");
import nthCheck, { parse, compile } from "nth-check";
```

#####`nthCheck(formula)`
##### `nthCheck(formula)`

First parses, then compiles the formula.
Parses and compiles a formula to a highly optimized function. Combination of `parse` and `compile`.

#####`nthCheck.parse(formula)`
If the formula doesn't match any elements, it returns [`boolbase`](https://github.com/fb55/boolbase)'s `falseFunc`. Otherwise, a function accepting an _index_ is returned, which returns whether or not the passed _index_ matches the formula.

Parses the expression, throws a `SyntaxError` if it fails, otherwise returns an array containing two elements.
**Note**: The nth-rule starts counting at `1`, the returned function at `0`.

__Example:__
**Example:**

```js
nthCheck.parse("2n+3") //[2, 3]
const check = nthCheck("2n+3");

check(0); // `false`
check(1); // `false`
check(2); // `true`
check(3); // `false`
check(4); // `true`
check(5); // `false`
check(6); // `true`
```

#####`nthCheck.compile([a, b])`
##### `parse(formula)`

Parses the expression, throws an `Error` if it fails. Otherwise, returns an array containing the integer step size and the integer offset of the nth rule.

**Example:**

```js
parse("2n+3"); // [2, 3]
```

##### `compile([a, b])`

Takes an array with two elements (as returned by `.parse`) and returns a highly optimized function.

If the formula doesn't match any elements, it returns [`boolbase`](https://github.com/fb55/boolbase)'s `falseFunc`, otherwise, a function accepting an _index_ is returned, which returns whether or not a passed _index_ matches the formula. (Note: The spec starts counting at `1`, the returned function at `0`).
**Example:**

__Example:__
```js
var check = nthCheck.compile([2, 3]);

check(0) //false
check(1) //false
check(2) //true
check(3) //false
check(4) //true
check(5) //false
check(6) //true
const check = compile([2, 3]);

check(0); // `false`
check(1); // `false`
check(2); // `true`
check(3); // `false`
check(4); // `true`
check(5); // `false`
check(6); // `true`
```

---
License: BSD

License: BSD-2-Clause

## Security contact information

To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure.

## `nth-check` for enterprise

Available as part of the Tidelift Subscription

The maintainers of `nth-check` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-nth-check?utm_source=npm-nth-check&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
40 changes: 0 additions & 40 deletions compile.js

This file was deleted.

9 changes: 0 additions & 9 deletions index.js

This file was deleted.

9,089 changes: 9,089 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

90 changes: 65 additions & 25 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,67 @@
{
"name": "nth-check",
"version": "1.0.1",
"description": "performant nth-check parser & compiler",
"main": "index.js",
"scripts": {
"test": "node test"
},
"repository": {
"type": "git",
"url": "https://github.com/fb55/nth-check"
},
"keywords": [
"nth-child",
"nth",
"css"
],
"author": "Felix Boehm <me@feedic.com>",
"license": "BSD",
"bugs": {
"url": "https://github.com/fb55/nth-check/issues"
},
"homepage": "https://github.com/fb55/nth-check",
"dependencies": {
"boolbase": "~1.0.0"
}
"name": "nth-check",
"version": "2.0.1",
"description": "Parses and compiles CSS nth-checks to highly optimized functions.",
"author": "Felix Boehm <me@feedic.com>",
"license": "BSD-2-Clause",
"sideEffects": false,
"funding": {
"url": "https://github.com/fb55/nth-check?sponsor=1"
},
"directories": {
"lib": "lib/"
},
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib/**/*"
],
"scripts": {
"test": "npm run test:jest && npm run lint",
"test:jest": "jest",
"lint": "npm run lint:es && npm run lint:prettier",
"lint:es": "eslint .",
"lint:prettier": "npm run prettier -- --check",
"format": "npm run format:es && npm run format:prettier",
"format:es": "npm run lint:es -- --fix",
"format:prettier": "npm run prettier -- --write",
"prettier": "prettier '**/*.{ts,md,json,yml}'",
"build": "tsc",
"prepare": "npm run build"
},
"repository": {
"type": "git",
"url": "https://github.com/fb55/nth-check"
},
"keywords": [
"nth-child",
"nth",
"css"
],
"bugs": {
"url": "https://github.com/fb55/nth-check/issues"
},
"homepage": "https://github.com/fb55/nth-check",
"dependencies": {
"boolbase": "^1.0.0"
},
"devDependencies": {
"@types/jest": "^27.0.1",
"@types/node": "^16.9.1",
"@typescript-eslint/eslint-plugin": "^4.31.1",
"@typescript-eslint/parser": "^4.31.1",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"jest": "^27.2.0",
"prettier": "^2.4.1",
"ts-jest": "^27.0.5",
"typescript": "^4.4.3"
},
"jest": {
"preset": "ts-jest",
"testEnvironment": "node"
},
"prettier": {
"tabWidth": 4
}
}
40 changes: 0 additions & 40 deletions parse.js

This file was deleted.

49 changes: 49 additions & 0 deletions src/__fixtures__/rules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
export const valid: [string, [number, number]][] = [
["1", [0, 1]],
["2", [0, 2]],
["3", [0, 3]],
["5", [0, 5]],
[" 1 ", [0, 1]],
[" 5 ", [0, 5]],
["+2n + 1", [2, 1]],
["-1", [0, -1]],
["-1n + 3", [-1, 3]],
["-1n+3", [-1, 3]],
["-n+2", [-1, 2]],
["-n+3", [-1, 3]],
["0n+3", [0, 3]],
["1n", [1, 0]],
["1n+0", [1, 0]],
["2n", [2, 0]],
["2n + 1", [2, 1]],
["2n+1", [2, 1]],
["3n", [3, 0]],
["3n+0", [3, 0]],
["3n+1", [3, 1]],
["3n+2", [3, 2]],
["3n+3", [3, 3]],
["3n-1", [3, -1]],
["3n-2", [3, -2]],
["3n-3", [3, -3]],
["even", [2, 0]],
["n", [1, 0]],
["n+2", [1, 2]],
["odd", [2, 1]],

// Surprisingly, neither sizzle, qwery or nwmatcher cover these cases
["-4n+13", [-4, 13]],
["-2n + 12", [-2, 12]],
];

export const invalid = [
"-",
"- 1n",
"-1 n",
"2+0",
"2n+-0",
"an+b",
"asdf",
"b",
"expr",
"odd|even|x",
];
39 changes: 39 additions & 0 deletions src/compile.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import nthCheck, { compile } from ".";
import { valid } from "./__fixtures__/rules";

const valArray = new Array(...Array(2e3)).map((_, i) => i);

/**
* Iterate through all possible values. This is adapted from qwery,
* and uses a more intuitive way to process all elements.
*/
function slowNth([a, b]: [number, number]): number[] {
if (a === 0 && b > 0) return [b - 1];

return valArray.filter((val) => {
for (let i = b; a > 0 ? i <= valArray.length : i >= 1; i += a) {
if (val === valArray[i - 1]) return true;
}
return false;
});
}

describe("parse", () => {
it("compile & run all valid", () => {
for (const [_, parsed] of valid) {
const filtered = valArray.filter(compile(parsed));
const iterated = slowNth(parsed);

expect(filtered).toStrictEqual(iterated);
}
});

it("parse, compile & run all valid", () => {
for (const [rule, parsed] of valid) {
const filtered = valArray.filter(nthCheck(rule));
const iterated = slowNth(parsed);

expect([filtered, rule]).toStrictEqual([iterated, rule]);
}
});
});
54 changes: 54 additions & 0 deletions src/compile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { trueFunc, falseFunc } from "boolbase";

/**
* Returns a function that checks if an elements index matches the given rule
* highly optimized to return the fastest solution.
*
* @param parsed A tuple [a, b], as returned by `parse`.
* @returns A highly optimized function that returns whether an index matches the nth-check.
* @example
* const check = nthCheck.compile([2, 3]);
*
* check(0); // `false`
* check(1); // `false`
* check(2); // `true`
* check(3); // `false`
* check(4); // `true`
* check(5); // `false`
* check(6); // `true`
*/
export function compile(
parsed: [a: number, b: number]
): (index: number) => boolean {
const a = parsed[0];
// Subtract 1 from `b`, to convert from one- to zero-indexed.
const b = parsed[1] - 1;

/*
* When `b <= 0`, `a * n` won't be lead to any matches for `a < 0`.
* Besides, the specification states that no elements are
* matched when `a` and `b` are 0.
*
* `b < 0` here as we subtracted 1 from `b` above.
*/
if (b < 0 && a <= 0) return falseFunc;

// When `a` is in the range -1..1, it matches any element (so only `b` is checked).
if (a === -1) return (index) => index <= b;
if (a === 0) return (index) => index === b;
// When `b <= 0` and `a === 1`, they match any element.
if (a === 1) return b < 0 ? trueFunc : (index) => index >= b;

/*
* Otherwise, modulo can be used to check if there is a match.
*
* Modulo doesn't care about the sign, so let's use `a`s absolute value.
*/
const absA = Math.abs(a);
// Get `b mod a`, + a if this is negative.
const bMod = ((b % absA) + absA) % absA;

return a > 1
? (index) => index >= b && index % absA === bMod
: (index) => index <= b && index % absA === bMod;
}
4 changes: 4 additions & 0 deletions src/declarations/boolbase.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module "boolbase" {
export function trueFunc(...args: unknown[]): true;
export function falseFunc(...args: unknown[]): false;
}
31 changes: 31 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { parse } from "./parse";
import { compile } from "./compile";

export { parse, compile };

/**
* Parses and compiles a formula to a highly optimized function.
* Combination of `parse` and `compile`.
*
* If the formula doesn't match any elements,
* it returns [`boolbase`](https://github.com/fb55/boolbase)'s `falseFunc`.
* Otherwise, a function accepting an _index_ is returned, which returns
* whether or not the passed _index_ matches the formula.
*
* Note: The nth-rule starts counting at `1`, the returned function at `0`.
*
* @param formula The formula to compile.
* @example
* const check = nthCheck("2n+3");
*
* check(0); // `false`
* check(1); // `false`
* check(2); // `true`
* check(3); // `false`
* check(4); // `true`
* check(5); // `false`
* check(6); // `true`
*/
export default function nthCheck(formula: string): (index: number) => boolean {
return compile(parse(formula));
}
16 changes: 16 additions & 0 deletions src/parse.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { parse } from "./parse";
import { valid, invalid } from "./__fixtures__/rules";

describe("parse", () => {
it("parse invalid", () => {
for (const formula of invalid) {
expect(() => parse(formula)).toThrowError(Error);
}
});

it("parse valid", () => {
for (const [formula, result] of valid) {
expect(parse(formula)).toStrictEqual(result);
}
});
});
92 changes: 92 additions & 0 deletions src/parse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Following http://www.w3.org/TR/css3-selectors/#nth-child-pseudo

// Whitespace as per https://www.w3.org/TR/selectors-3/#lex is " \t\r\n\f"
const whitespace = new Set([9, 10, 12, 13, 32]);
const ZERO = "0".charCodeAt(0);
const NINE = "9".charCodeAt(0);

/**
* Parses an expression.
*
* @throws An `Error` if parsing fails.
* @returns An array containing the integer step size and the integer offset of the nth rule.
* @example nthCheck.parse("2n+3"); // returns [2, 3]
*/
export function parse(formula: string): [a: number, b: number] {
formula = formula.trim().toLowerCase();

if (formula === "even") {
return [2, 0];
} else if (formula === "odd") {
return [2, 1];
}

// Parse [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]?

let idx = 0;

let a = 0;
let sign = readSign();
let number = readNumber();

if (idx < formula.length && formula.charAt(idx) === "n") {
idx++;
a = sign * (number ?? 1);

skipWhitespace();

if (idx < formula.length) {
sign = readSign();
skipWhitespace();
number = readNumber();
} else {
sign = number = 0;
}
}

// Throw if there is anything else
if (number === null || idx < formula.length) {
throw new Error(`n-th rule couldn't be parsed ('${formula}')`);
}

return [a, sign * number];

function readSign() {
if (formula.charAt(idx) === "-") {
idx++;
return -1;
}

if (formula.charAt(idx) === "+") {
idx++;
}

return 1;
}

function readNumber() {
const start = idx;
let value = 0;

while (
idx < formula.length &&
formula.charCodeAt(idx) >= ZERO &&
formula.charCodeAt(idx) <= NINE
) {
value = value * 10 + (formula.charCodeAt(idx) - ZERO);
idx++;
}

// Return `null` if we didn't read anything.
return idx === start ? null : value;
}

function skipWhitespace() {
while (
idx < formula.length &&
whitespace.has(formula.charCodeAt(idx))
) {
idx++;
}
}
}
102 changes: 0 additions & 102 deletions test.js

This file was deleted.

5 changes: 5 additions & 0 deletions tsconfig.eslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": "./tsconfig.json",
"include": ["src", "test"],
"exclude": []
}
38 changes: 38 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"compilerOptions": {
/* Basic Options */
"target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
// "lib": [], /* Specify library files to be included in the compilation. */
"declaration": true /* Generates corresponding '.d.ts' file. */,
"declarationMap": true /* Generates a sourcemap for each corresponding '.d.ts' file. */,
// "sourceMap": true, /* Generates corresponding '.map' file. */
"outDir": "lib" /* Redirect output structure to the directory. */,
// "importHelpers": true, /* Import emit helpers from 'tslib'. */

/* Strict Type-Checking Options */
"strict": true /* Enable all strict type-checking options. */,

/* Additional Checks */
"noUnusedLocals": true /* Report errors on unused locals. */,
"noUnusedParameters": true /* Report errors on unused parameters. */,
"noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,

/* Module Resolution Options */
"baseUrl": "./" /* Base directory to resolve non-absolute module names. */,
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
"resolveJsonModule": true,

"paths": {
"*": ["src/declarations/*", "*"]
}
},
"include": ["src"],
"exclude": [
"**/*.spec.ts",
"**/__fixtures__/*",
"**/__tests__/*",
"**/__snapshots__/*"
]
}