Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement jq like selectors per ucan delegation policy notation #344

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"devDependencies": {
"mocha": "^10.1.0",
"prettier": "2.8.8",
"typescript": "^5.0.4"
"typescript": "^5.0.4",
"entail": "^2.1.2"
},
"prettier": {
"trailingComma": "es5",
Expand Down
4 changes: 3 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"test:web": "playwright-test test/*.spec.js --cov && nyc report",
"test:node": "c8 --check-coverage --branches 100 --functions 100 --lines 100 mocha test/*.spec.js",
"test": "c8 --check-coverage --branches 100 --functions 100 --lines 100 mocha --bail test/*.spec.js",
"test:policy": "c8 --check-coverage --branches 100 --functions 100 --lines 100 entail test/policy/*.spec.js",
"coverage": "c8 --reporter=html mocha test/*.spec.js && npm_config_yes=true npx st -d coverage -p 8080",
"check": "tsc --build",
"build": "tsc --build"
Expand All @@ -44,7 +45,8 @@
"mocha": "^10.1.0",
"nyc": "^15.1.0",
"playwright-test": "^8.2.0",
"typescript": "^5.0.4"
"typescript": "^5.0.4",
"entail": "^2.1.2"
},
"type": "module",
"main": "src/lib.js",
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export * as DID from '@ipld/dag-ucan/did'
export * as Signature from '@ipld/dag-ucan/signature'
export * from './result.js'
export * as Schema from './schema.js'
export * as Selector from './policy/selector.js'
1 change: 1 addition & 0 deletions packages/core/src/policy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as Selector from './policy/selector.js'
1 change: 1 addition & 0 deletions packages/core/src/policy/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {}
102 changes: 102 additions & 0 deletions packages/core/src/policy/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import type { Variant, Result, Phantom } from '@ucanto/interface'

export type { Variant, Result }

export type SelectorParseResult = Result<SelectorPath, ParseError>

export interface ParseError extends Error {
readonly name: 'ParseError'
}

export interface ResolutionError extends Error {
readonly name: 'ResolutionError'
}

/**
* Selector use [jq](https://devdocs.io/jq/) notation.
*/
export type Selector = `.${string}` & Phantom<{ Selector: SelectorPath }>
export type SelectorPath = [{ Identity: {} }, ...SelectorSegment[]]

export type SelectionResult = Variant<{
one: Data
many: Data[]
error: ParseError | ResolutionError
}>

export type ResolutionResult = Variant<{
one: Data
many: Data[]
error: ResolutionError
}>

export type SelectorSegment = Variant<{
Identity: {}
Iterator: { optional: boolean }
Index: { optional: boolean; index: number }
Key: { optional: boolean; key: string }
Slice: {
optional?: boolean
range: [undefined, number] | [number, undefined] | [number, number]
}
}>

export type Data =
| number
| string
| boolean
| null
| Uint8Array
| ListData
| Dictionary

export interface ListData extends Array<Data> {}
export interface Dictionary {
[key: string]: Data
}

/**
* Represents an identity selector per jq.
* @see https://devdocs.io/jq/index#identity
*
* @example
* ```js
* assert.deepEqual(
* select('.', {x: 1}),
* { one: { x: 1 } }
* )
* ```
*/
export type IdentitySegment = '.' & Phantom<{ Identity: '.' }>

/**
* Selector that returns all elements of an array. Selecting `.[]` from
* `[1,2,3]` will produce selection containing those numbers. The form `.foo.[]`
* is identical to `.foo[]`.
*
* You can also use the `[]` on the object, and it will return all the values of
* the object.
*
* @example
* ```js
* assert.deepEqual(
* select('.[]', [
* {"name":"JSON", "good":true},
* {"name":"XML", "good":false}
* ]),
* {
* many: [
* {"name":"JSON", "good":true},
* {"name":"XML", "good":false}
* ]
* }
* )
* ```
*/
export type IteratorSegment = '[]' & Phantom<{ Iterator: '[]' }>

export type IndexSegment = number & Phantom<{ Index: number }>

export type KeySegment = string & Phantom<{ Key: string }>

export type SliceSegment = [start?: number, end?: number]
Loading
Loading