diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..3e3e1df --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly diff --git a/.github/workflows/deno-ci.yml b/.github/workflows/deno-ci.yml index 95f79aa..957fa8f 100644 --- a/.github/workflows/deno-ci.yml +++ b/.github/workflows/deno-ci.yml @@ -5,6 +5,9 @@ on: branches: [ main ] pull_request: {} +permissions: + contents: read + jobs: check: @@ -13,20 +16,76 @@ jobs: strategy: matrix: deno-version: - - v1.18 - - v1.20 - - v1.22 + - v1.40 + - v2.0 + - v2.1 + - v2.2 + - v2.3 + - v2.4 + - v2.5 - canary fail-fast: false # run each branch to completion steps: - name: Checkout source - uses: actions/checkout@v2 + uses: actions/checkout@v5 + + - name: Cache Deno deps + uses: actions/cache@v4 + with: + path: ~/.cache/deno + key: deno/${{ matrix.deno-version }}-${{ github.sha }} - name: Use Deno ${{ matrix.deno-version }} - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ matrix.deno-version }} + - name: 'Possibly reset lockfile' + run: deno install || rm deno.lock + - name: Run test suite - run: deno test --allow-read=test test/*.js + run: deno task test + + dry-run: + runs-on: ubuntu-latest + + steps: + - name: Checkout source + uses: actions/checkout@v5 + + - name: Use stable Deno + uses: denoland/setup-deno@v2 + + - name: Cache Deno deps + uses: actions/cache@v4 + with: + path: ~/.cache/deno + key: deno/publish-${{ github.sha }} + + - name: Check publish rules + run: time deno publish --dry-run --allow-dirty + + publish: + runs-on: ubuntu-latest + needs: check + if: github.event_name == 'push' + + permissions: + contents: read + id-token: write + + steps: + - name: Checkout source + uses: actions/checkout@v5 + + - name: Use stable Deno + uses: denoland/setup-deno@v2 + + - name: Cache Deno deps + uses: actions/cache@v4 + with: + path: ~/.cache/deno + key: deno/publish-${{ github.sha }} + - name: Publish now + run: deno publish diff --git a/README.md b/README.md index 3dfe9f5..d092a73 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,18 @@ -![Test CI](https://github.com/danopia/deno-jmespath/workflows/CI/badge.svg?branch=main) +![Test CI](https://github.com/danopia/jmespath/workflows/CI/badge.svg?branch=main) -# deno.land/x/jmespath +# JSR package `@cloudydeno/jmespath` -A jmespath-ts fork, repackaged and ported to Deno. -The `src/` directory is published to deno.land. +A jmespath-ts fork, repackaged and ported to be Deno-first. +The `src/` directory is published [to JSR](https://jsr.io/@cloudydeno/jmespath). The `test/` directory contains the upstream unit tests. + +```javascript +// deno add jsr:@cloudydeno/jmespath + +import { search, compile } from '@cloudydeno/jmespath'; +``` + This library should be useful for JSON-heavy APIs such as AWS. In the process of porting, diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..24b9597 --- /dev/null +++ b/deno.json @@ -0,0 +1,20 @@ +{ + "name": "@cloudydeno/jmespath", + "version": "1.0.0", + "license": "MPL-2.0", + "exports": "./src/index.ts", + "imports": { + "@std/assert": "jsr:@std/assert@^1", + "@std/path": "jsr:@std/path@^1" + }, + "tasks": { + "test": "deno test --allow-read=test test/*.js" + }, + "publish": { + "exclude": [ + ".editorconfig", + ".github", + "test" + ] + } +} diff --git a/deno.lock b/deno.lock new file mode 100644 index 0000000..ddf2024 --- /dev/null +++ b/deno.lock @@ -0,0 +1,31 @@ +{ + "version": "5", + "specifiers": { + "jsr:@std/assert@1": "1.0.14", + "jsr:@std/internal@^1.0.10": "1.0.10", + "jsr:@std/path@1": "1.1.2" + }, + "jsr": { + "@std/assert@1.0.14": { + "integrity": "68d0d4a43b365abc927f45a9b85c639ea18a9fab96ad92281e493e4ed84abaa4", + "dependencies": [ + "jsr:@std/internal" + ] + }, + "@std/internal@1.0.10": { + "integrity": "e3be62ce42cab0e177c27698e5d9800122f67b766a0bea6ca4867886cbde8cf7" + }, + "@std/path@1.1.2": { + "integrity": "c0b13b97dfe06546d5e16bf3966b1cadf92e1cc83e56ba5476ad8b498d9e3038", + "dependencies": [ + "jsr:@std/internal" + ] + } + }, + "workspace": { + "dependencies": [ + "jsr:@std/assert@1", + "jsr:@std/path@1" + ] + } +} diff --git a/src/README.md b/src/README.md index bb16427..ec647e2 100644 --- a/src/README.md +++ b/src/README.md @@ -14,7 +14,7 @@ given a JMESPath expression. ### `search(data: JSONValue, expression: string): JSONValue` ```javascript -import { search } from "https://deno.land/x/jmespath/index.ts"; +import { search } from "jsr:@cloudydeno/jmespath"; search({foo: {bar: {baz: [0, 1, 2, 3, 4]}}}, "foo.bar.baz[2]") @@ -31,7 +31,7 @@ The JMESPath language can do *a lot* more than select an element from a list. Here are a few more examples: ```javascript -import { search } from "https://deno.land/x/jmespath/index.ts"; +import { search } from "jsr:@cloudydeno/jmespath"; /* --- EXAMPLE 1 --- */ @@ -82,7 +82,7 @@ search(JSON_DOCUMENT, "foo[?age > `30`]"); Extend the list of built in JMESpath expressions with your own functions. ```javascript - import {search, registerFunction, TYPE_NUMBER} from "https://deno.land/x/jmespath/index.ts"; + import {search, registerFunction, TYPE_NUMBER} from "jsr:@cloudydeno/jmespath"; search({ foo: 60, bar: 10 }, 'divide(foo, bar)') @@ -109,7 +109,7 @@ function takes a JMESPath expression and returns an abstract syntax tree that can be used by the TreeInterpreter function ```javascript -import { compile, TreeInterpreter } from "https://deno.land/x/jmespath/index.ts"; +import { compile, TreeInterpreter } from "jsr:@cloudydeno/jmespath"; const ast = compile('foo.bar'); diff --git a/src/Runtime.ts b/src/Runtime.ts index b7f7844..4f05136 100644 --- a/src/Runtime.ts +++ b/src/Runtime.ts @@ -84,7 +84,7 @@ export class Runtime { private validateArgs(name: string, args: any[], signature: InputSignature[]): void { let pluralized: boolean; this.validateInputSignatures(name, signature); - const numberOfRequiredArgs = signature.filter(argSignature => !argSignature.optional ?? false).length; + const numberOfRequiredArgs = signature.filter(argSignature => !argSignature.optional).length; const lastArgIsVariadic = signature[signature.length - 1]?.variadic ?? false; const tooFewArgs = args.length < numberOfRequiredArgs; const tooManyArgs = args.length > signature.length; diff --git a/src/TreeInterpreter.ts b/src/TreeInterpreter.ts index 6bbd7a7..12f4750 100644 --- a/src/TreeInterpreter.ts +++ b/src/TreeInterpreter.ts @@ -275,5 +275,5 @@ export class TreeInterpreter { } } -export const TreeInterpreterInstance = new TreeInterpreter(); +export const TreeInterpreterInstance: TreeInterpreter = new TreeInterpreter(); export default TreeInterpreterInstance; diff --git a/src/index.ts b/src/index.ts index 3330e4b..ed34421 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,13 @@ import Parser from './Parser.ts'; import Lexer from './Lexer.ts'; import TreeInterpreterInst from './TreeInterpreter.ts'; import type { ASTNode, LexerToken } from './Lexer.ts'; -import { InputArgument, RuntimeFunction, InputSignature } from './Runtime.ts'; +import { InputArgument, type RuntimeFunction, type InputSignature } from './Runtime.ts'; + +export { + type ASTNode, + type Token, + type LexerToken, +} from './Lexer.ts'; export type { FunctionSignature, RuntimeFunction, InputSignature } from './Runtime.ts'; export type ObjectDict = Record; diff --git a/src/utils/index.ts b/src/utils/index.ts index 1783fb0..55c30c4 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -46,7 +46,7 @@ export const isFalse = (obj: unknown): boolean => { } if (isObject(obj)) { for (const key in obj) { - if (obj.hasOwnProperty(key)) { + if (Object.hasOwn(obj, key)) { return false; } } diff --git a/test/compliance.spec.js b/test/compliance.spec.js index 804e791..22916a2 100644 --- a/test/compliance.spec.js +++ b/test/compliance.spec.js @@ -2,7 +2,8 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { search } from '../src/index.ts'; -import { basename, join } from 'https://deno.land/std@0.140.0/path/mod.ts'; +import { basename } from '@std/path/basename'; +import { join } from '@std/path/join'; import { describe, it, expect, each } from './deno-shim.js'; // Compliance tests that aren't supported yet. diff --git a/test/compliance/syntax.json b/test/compliance/syntax.json index 2b1a1d2..caa295f 100644 --- a/test/compliance/syntax.json +++ b/test/compliance/syntax.json @@ -470,7 +470,7 @@ }, { "expression": "\"foo", - "error": "Unexpected end of JSON input" + "error": "Unterminated string in JSON at position 4 (line 1 column 5)" } ] }, @@ -523,7 +523,7 @@ { "comment": "Literal char not escaped", "expression": "foo[?bar==`[\"foo`bar\"]`]", - "error": "Unexpected end of JSON input" + "error": "Unterminated string in JSON at position 5 (line 1 column 6)" }, { "comment": "Literal char escaped", diff --git a/test/deno-shim.js b/test/deno-shim.js index c2d5648..cc3f6a3 100644 --- a/test/deno-shim.js +++ b/test/deno-shim.js @@ -1,7 +1,7 @@ -import { - assertEquals, assertStrictEquals, - assertThrows, assertStringIncludes, -} from "https://deno.land/std@0.140.0/testing/asserts.ts"; +import { assertEquals } from "@std/assert/equals"; +import { assertStrictEquals } from "@std/assert/strict-equals"; +import { assertThrows } from "@std/assert/throws"; +import { assertStringIncludes } from "@std/assert/string-includes"; const suiteStack = [];