Comparing version 0.3.0-beta.0 to 0.3.0-beta.1
# Changelog | ||
## v0.3.0 - 2021-06-25 | ||
API changes: | ||
- Introduce `params` parameter on `parse` which is required to properly parse an expression (@judofyr) | ||
GROQ compatibility fixes: | ||
- Preserve nulls in objects (@judofyr, #36) | ||
- Add support for arrays in `length` (@judofyr) | ||
- Use stable sorting in `order` (@judofyr) | ||
- Implement `string` function (@judofyr, @israelroldan) | ||
- Add support for arrays in `references` (@judofyr) | ||
- Implement `dateTime` (@judofyr) | ||
- Implement proper array traversal (@judofyr) | ||
- Implement `score` function (@judofyr) | ||
- Implement namespaced functions (@judofyr) | ||
- Implement `lower` and `upper` (@judofyr) | ||
- Implement `pt::text` (@judofyr) | ||
- Improve `match` behavior (@judofyr) | ||
Private changes: | ||
- Simplify and restructure AST (@judofyr) | ||
- Split up `SyntaxNode` into a special `ExprNode` represent what's returned from `parse` (@judofyr) | ||
Tooling changes: | ||
- Use `tap` for running tests since Jest is too slow (@judofyr) | ||
## v0.2.0 - 2020-10-20 | ||
@@ -4,0 +34,0 @@ |
@@ -6,14 +6,15 @@ import type { ExprNode } from '../nodeTypes'; | ||
declare type GroqFunctionArg = ExprNode; | ||
declare type WithArity<T> = T & { | ||
declare type WithOptions<T> = T & { | ||
arity?: GroqFunctionArity; | ||
mode?: 'normal' | 'delta'; | ||
}; | ||
export declare type GroqFunctionArity = number | ((count: number) => boolean); | ||
export declare type GroqFunction = (args: GroqFunctionArg[], scope: Scope, execute: Executor) => PromiseLike<Value>; | ||
export declare type FunctionSet = Record<string, WithArity<GroqFunction> | undefined>; | ||
export declare type FunctionSet = Record<string, WithOptions<GroqFunction> | undefined>; | ||
export declare type NamespaceSet = Record<string, FunctionSet | undefined>; | ||
export declare type GroqPipeFunction = (base: Value, args: ExprNode[], scope: Scope, execute: Executor) => PromiseLike<Value>; | ||
export declare const pipeFunctions: { | ||
[key: string]: WithArity<GroqPipeFunction>; | ||
[key: string]: WithOptions<GroqPipeFunction>; | ||
}; | ||
export declare const namespaces: NamespaceSet; | ||
export {}; |
@@ -6,3 +6,3 @@ import { GroqFunction, GroqPipeFunction } from './evaluator/functions'; | ||
/** A node which can be evaluated into a value. */ | ||
export declare type ExprNode = AccessAttributeNode | AccessElementNode | AndNode | ArrayNode | ArrayCoerceNode | AscNode | ContextNode | DerefNode | DescNode | EverythingNode | FilterNode | FlatMapNode | FuncCallNode | GroupNode | InRangeNode | MapNode | NegNode | NotNode | ObjectNode | OpCallNode | OrNode | ParameterNode | ParentNode | PipeFuncCallNode | PosNode | ProjectionNode | SelectNode | SliceNode | ThisNode | ValueNode; | ||
export declare type ExprNode = AccessAttributeNode | AccessElementNode | AndNode | ArrayNode | ArrayCoerceNode | AscNode | ContextNode | DerefNode | DescNode | EverythingNode | FilterNode | FlatMapNode | FuncCallNode | GroupNode | InRangeNode | MapNode | NegNode | NotNode | ObjectNode | OpCallNode | OrNode | ParameterNode | ParentNode | PipeFuncCallNode | PosNode | ProjectionNode | SelectNode | SliceNode | ThisNode | TupleNode | ValueNode; | ||
export declare type OpCall = '==' | '!=' | '>' | '>=' | '<' | '<=' | '+' | '-' | '*' | '/' | '%' | '**' | 'in' | 'match'; | ||
@@ -136,2 +136,6 @@ /** The base interface for SyntaxNode. */ | ||
} | ||
export interface TupleNode extends BaseNode { | ||
type: 'Tuple'; | ||
members: Array<ExprNode>; | ||
} | ||
export interface ValueNode<P = any> { | ||
@@ -138,0 +142,0 @@ type: 'Value'; |
{ | ||
"name": "groq-js", | ||
"version": "0.3.0-beta.0", | ||
"version": "0.3.0-beta.1", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "author": "Sanity.io <hello@sanity.io>", |
@@ -323,2 +323,6 @@ import * as NodeTypes from '../nodeTypes' | ||
Tuple() { | ||
throw new Error('tuples can not be evaluated') | ||
}, | ||
async Or({left, right}, scope, execute) { | ||
@@ -325,0 +329,0 @@ const leftValue = await execute(left, scope) |
@@ -61,4 +61,5 @@ import type {ExprNode} from '../nodeTypes' | ||
type GroqFunctionArg = ExprNode | ||
type WithArity<T> = T & { | ||
type WithOptions<T> = T & { | ||
arity?: GroqFunctionArity | ||
mode?: 'normal' | 'delta' | ||
} | ||
@@ -74,3 +75,3 @@ | ||
export type FunctionSet = Record<string, WithArity<GroqFunction> | undefined> | ||
export type FunctionSet = Record<string, WithOptions<GroqFunction> | undefined> | ||
@@ -293,3 +294,3 @@ export type NamespaceSet = Record<string, FunctionSet | undefined> | ||
export const pipeFunctions: {[key: string]: WithArity<GroqPipeFunction>} = {} | ||
export const pipeFunctions: {[key: string]: WithOptions<GroqPipeFunction>} = {} | ||
@@ -389,2 +390,26 @@ pipeFunctions.order = async function order(base, args, scope, execute) { | ||
const delta: FunctionSet = {} | ||
delta.changedAny = () => { | ||
throw new Error('not implemented') | ||
} | ||
delta.changedAny.arity = 1 | ||
delta.changedAny.mode = 'delta' | ||
delta.changedOnly = () => { | ||
throw new Error('not implemented') | ||
} | ||
delta.changedOnly.arity = 1 | ||
delta.changedOnly.mode = 'delta' | ||
const diff: FunctionSet = {} | ||
diff.changedAny = () => { | ||
throw new Error('not implemented') | ||
} | ||
diff.changedAny.arity = 3 | ||
diff.changedOnly = () => { | ||
throw new Error('not implemented') | ||
} | ||
diff.changedOnly.arity = 3 | ||
export const namespaces: NamespaceSet = { | ||
@@ -394,2 +419,4 @@ global, | ||
pt, | ||
delta, | ||
diff, | ||
} |
@@ -6,25 +6,22 @@ import {NULL_VALUE, Value} from '../values' | ||
return blockText(value.data) | ||
} else if (value.isArray()) { | ||
const texts = await arrayText(value) | ||
if (texts.length > 0) { | ||
return texts.join('\n\n') | ||
} | ||
} | ||
let result = '' | ||
let first = true | ||
return null | ||
} | ||
if (value.isArray()) { | ||
for await (const block of value) { | ||
if (block.type !== 'object') continue | ||
async function arrayText(value: Value, result: string[] = []): Promise<string[]> { | ||
for await (const block of value) { | ||
if (block.type === 'object') { | ||
const text = blockText(block.data) | ||
if (text === null) continue | ||
if (!first) { | ||
result += '\n\n' | ||
} | ||
first = false | ||
result += text | ||
if (text !== null) result.push(text) | ||
} else if (block.isArray()) { | ||
await arrayText(block, result) | ||
} | ||
} | ||
// If there were no blocks => Return null. | ||
if (first) return null | ||
return result | ||
@@ -31,0 +28,0 @@ } |
@@ -42,2 +42,3 @@ import {GroqFunction, GroqPipeFunction} from './evaluator/functions' | ||
| ThisNode | ||
| TupleNode | ||
| ValueNode | ||
@@ -216,2 +217,7 @@ | ||
export interface TupleNode extends BaseNode { | ||
type: 'Tuple' | ||
members: Array<ExprNode> | ||
} | ||
export interface ValueNode<P = any> { | ||
@@ -218,0 +224,0 @@ type: 'Value' |
@@ -311,2 +311,14 @@ /* eslint-disable camelcase */ | ||
tuple(p) { | ||
const members: NodeTypes.ExprNode[] = [] | ||
while (p.getMark().name !== 'tuple_end') { | ||
members.push(p.process(EXPR_BUILDER)) | ||
} | ||
p.shift() | ||
return { | ||
type: 'Tuple', | ||
members, | ||
} | ||
}, | ||
func_call(p) { | ||
@@ -378,2 +390,6 @@ let namespace = 'global' | ||
if (func.mode !== undefined && func.mode !== p.parseOptions.mode) { | ||
throw new GroqQueryError(`Undefined function: ${name}`) | ||
} | ||
return { | ||
@@ -380,0 +396,0 @@ type: 'FuncCall', |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
2300543
20913