Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

groq-js

Package Overview
Dependencies
Maintainers
45
Versions
72
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

groq-js - npm Package Compare versions

Comparing version 1.5.0-canary.1 to 1.5.0-canary.2

4

API.md
# API
GROQ-JS exposes two functions:
GROQ-JS exposes three functions:
```typescript
import {parse, evaluate} from 'groq-js'
import {parse, evaluate, typeEvaluate} from 'groq-js'
```

@@ -8,0 +8,0 @@

@@ -45,4 +45,7 @@ export declare interface AccessAttributeNode extends BaseNode {

/** Describes a type node for array values. */
export declare interface ArrayTypeNode<T extends TypeNode = TypeNode> {
/** can be used to identify the type of the node, in this case it's always 'array' */
type: 'array'
/** the type of the array elements */
of: T

@@ -63,4 +66,7 @@ }

/** Describes a type node for boolean values, optionally including a value. If a value is provided it will always be the given boolean value. */
export declare interface BooleanTypeNode {
/** can be used to identify the type of the node, in this case it's always 'boolean' */
type: 'boolean'
/** an optional value of the boolean, if provided it will always be the given boolean value */
value?: boolean

@@ -133,5 +139,9 @@ }

/** Represents a document structure with a fixed type 'document', a name, and a collection of attributes.*/
export declare interface DocumentSchemaType {
/** can be used to identify the type of the node, in this case it's always 'document' */
type: 'document'
/** the name of the document */
name: string
/** ttributes is defined by a key-value pair where the key is a string and the value is an ObjectAttribute. */
attributes: Record<string, ObjectAttribute>

@@ -257,4 +267,7 @@ }

/** Describes a type node for inline values, including a name that references another type. */
export declare interface InlineTypeNode {
/** can be used to identify the type of the node, in this case it's always 'inline' */
type: 'inline'
/** the name of the referenced type */
name: string

@@ -287,3 +300,5 @@ }

/** Describes a type node for null values, always being the null value. */
export declare interface NullTypeNode {
/** can be used to identify the type of the node, in this case it's always 'null' */
type: 'null'

@@ -294,4 +309,7 @@ }

/** Describes a type node for number values, optionally including a value. If a value is provided it will always be the given numeric value.*/
export declare interface NumberTypeNode {
/** can be used to identify the type of the node, in this case it's always 'number' */
type: 'number'
/** an optional value of the number, if provided it will always be the given numeric value */
value?: number

@@ -302,5 +320,9 @@ }

/** Describes a type node for object attributes, including a type and an optional flag for being optional. */
export declare interface ObjectAttribute<T extends TypeNode = TypeNode> {
/** can be used to identify the type of the node, in this case it's always 'objectAttribute' */
type: 'objectAttribute'
/** the type of the attribute */
value: T
/** an optional flag if the attribute is optional set on the object */
optional?: boolean

@@ -336,5 +358,15 @@ }

/**
* Describes a type node for object values, including a collection of attributes and an optional rest value.
* The rest value can be another ObjectTypeNode, an UnknownTypeNode, or an InlineTypeNode.
* If the rest value is an ObjectTypeNode, it means that the object can have additional attributes.
* If the rest value is an UnknownTypeNode, the entire object is unknown.
* If the rest value is an InlineTypeNode, it means that the object has additional attributes from the referenced type.
*/
export declare interface ObjectTypeNode<T extends TypeNode = TypeNode> {
/** can be used to identify the type of the node, in this case it's always 'object' */
type: 'object'
/** a collection of attributes */
attributes: Record<string, ObjectAttribute<T>>
/** an optional rest value */
rest?: ObjectTypeNode | UnknownTypeNode | InlineTypeNode

@@ -419,2 +451,3 @@ dereferencesTo?: string

/** Union of any primitive type nodes. */
export declare type PrimitiveTypeNode = StringTypeNode | NumberTypeNode | BooleanTypeNode

@@ -428,2 +461,3 @@

/** A schema consisting of a list of Document or TypeDeclaration items, allowing for complex type definitions. */
export declare type SchemaType = (DocumentSchemaType | TypeDeclarationSchemaType)[]

@@ -495,4 +529,7 @@

/** Describes a type node for string values, optionally including a value. If a value is provided it will always be the given string value. */
export declare interface StringTypeNode {
/** can be used to identify the type of the node, in this case it's always 'string' */
type: 'string'
/** an optional value of the string, if provided it will always be the given string value */
value?: string

@@ -519,5 +556,9 @@ }

/** Defines a type declaration with a specific name and a value that describes the structure of the type using a TypeNode. */
export declare interface TypeDeclarationSchemaType {
/** can be used to identify the type of the node, in this case it's always 'type' */
type: 'type'
/** the name of the type */
name: string
/** the value that describes the structure of the type */
value: TypeNode

@@ -536,2 +577,3 @@ }

/** All possible type nodes. */
export declare type TypeNode =

@@ -548,8 +590,13 @@ | ObjectTypeNode

/** Describes a type node for union values. */
export declare interface UnionTypeNode<T extends TypeNode = TypeNode> {
/** can be used to identify the type of the node, in this case it's always 'union' */
type: 'union'
/** a collection of types */
of: T[]
}
/** Describes a type node for unknown value. */
export declare type UnknownTypeNode = {
/** can be used to identify the type of the node, in this case it's always 'unknown' */
type: 'unknown'

@@ -556,0 +603,0 @@ }

{
"name": "groq-js",
"version": "1.5.0-canary.1",
"version": "1.5.0-canary.2",
"keywords": [

@@ -83,8 +83,8 @@ "sanity",

"devDependencies": {
"@sanity/pkg-utils": "^4.3.1",
"@sanity/pkg-utils": "^5.0.0",
"@sanity/semantic-release-preset": "^4.1.7",
"@types/debug": "^4.1.12",
"@types/tap": "^15.0.11",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
"eslint": "^8.57.0",

@@ -102,3 +102,3 @@ "eslint-config-prettier": "^9.1.0",

"tsx": "^4.7.1",
"typescript": "^5.3.3"
"typescript": "^5.4.2"
},

@@ -105,0 +105,0 @@ "engines": {

@@ -27,2 +27,3 @@ import debug from 'debug'

SelectNode,
SliceNode,
ValueNode,

@@ -48,2 +49,3 @@ } from '../nodeTypes'

} from './types'
import {nullUnion} from './typeHelpers'

@@ -53,3 +55,3 @@ const $trace = debug('typeEvaluator:evaluate:trace')

// log to stdout
const $debug = debug('typeEvaluator:evaluate::debug')
const $debug = debug('typeEvaluator:evaluate:debug')
// log to stdout

@@ -68,2 +70,3 @@ $debug.log = console.log.bind(console) // eslint-disable-line no-console

export function typeEvaluate(ast: ExprNode, schema: Schema): TypeNode {
$debug('evaluateQueryType.ast %O', ast)
const parsed = walk({

@@ -76,3 +79,3 @@ node: ast,

const optimized = optimizeUnions(parsed)
$trace('evaluateQueryType.optimized %O', optimized)
$debug('evaluateQueryType.optimized %O', optimized)

@@ -140,3 +143,3 @@ return optimized

if (attr.type === 'ObjectAttributeValue') {
const field = optimizeUnions(walk({node: attr.value, scope}))
const field = walk({node: attr.value, scope})
attributes[attr.name] = {

@@ -185,157 +188,162 @@ type: 'objectAttribute',

// eslint-disable-next-line complexity, max-statements
// eslint-disable-next-line max-statements
function handleOpCallNode(node: OpCallNode, scope: Scope): TypeNode {
const left = walk({node: node.left, scope})
const right = walk({node: node.right, scope})
$trace('opCallNode "%s" %O', node.op, {left, right})
if (left.type === 'unknown' || right.type === 'unknown') {
return {type: 'unknown'} satisfies UnknownTypeNode
}
switch (node.op) {
case '==':
case '!=': {
return {
type: 'boolean',
value: resolveCondition(node, scope),
} satisfies BooleanTypeNode
}
case '>':
case '>=':
case '<':
case '<=': {
if (left.type !== right.type) {
return {type: 'null'}
const lhs = walk({node: node.left, scope})
const rhs = walk({node: node.right, scope})
return mapUnion(lhs, (left) =>
// eslint-disable-next-line complexity
mapUnion(rhs, (right) => {
$trace('opCallNode "%s" %O', node.op, {left, right})
if (left.type === 'unknown' || right.type === 'unknown') {
return {type: 'unknown'} satisfies UnknownTypeNode
}
if (isPrimitiveTypeNode(left)) {
const resolved = resolveCondition(node, scope)
return {
type: 'boolean',
value: resolved,
} satisfies BooleanTypeNode
}
return {type: 'null'}
}
case 'in': {
if (right.type === 'array') {
const resolved = resolveCondition(node, scope)
return {
type: 'boolean',
value: resolved,
} satisfies BooleanTypeNode
}
return {type: 'null'}
}
case 'match': {
const resolved = resolveCondition(node, scope)
switch (node.op) {
case '==':
case '!=': {
return {
type: 'boolean',
value: resolveCondition(node, scope),
} satisfies BooleanTypeNode
}
case '>':
case '>=':
case '<':
case '<=': {
if (left.type !== right.type) {
return {type: 'null'}
}
if (isPrimitiveTypeNode(left)) {
const resolved = resolveCondition(node, scope)
return {
type: 'boolean',
value: resolved,
} satisfies BooleanTypeNode
}
return {
type: 'boolean',
value: resolved,
} satisfies BooleanTypeNode
}
case '+': {
if (left.type === 'string' && right.type === 'string') {
return {
type: 'string',
value:
left.value !== undefined && right.value !== undefined
? left.value + right.value
: undefined,
return {type: 'null'}
}
}
case 'in': {
if (right.type === 'array') {
const resolved = resolveCondition(node, scope)
return {
type: 'boolean',
value: resolved,
} satisfies BooleanTypeNode
}
return {type: 'null'}
}
case 'match': {
const resolved = resolveCondition(node, scope)
if (left.type === 'number' && right.type === 'number') {
return {
type: 'number',
value:
left.value !== undefined && right.value !== undefined
? left.value + right.value
: undefined,
return {
type: 'boolean',
value: resolved,
} satisfies BooleanTypeNode
}
}
if (left.type === 'array' && right.type === 'array') {
return {
type: 'array',
of: {
type: 'union',
of: [left.of, right.of],
},
} satisfies ArrayTypeNode
}
if (left.type === 'object' && right.type === 'object') {
return {
type: 'object',
attributes: {...left.attributes, ...right.attributes},
} satisfies ObjectTypeNode
}
return {type: 'null'}
}
case '-': {
if (left.type === 'number' && right.type === 'number') {
return {
type: 'number',
value:
left.value !== undefined && right.value !== undefined
? left.value - right.value
: undefined,
case '+': {
if (left.type === 'string' && right.type === 'string') {
return {
type: 'string',
value:
left.value !== undefined && right.value !== undefined
? left.value + right.value
: undefined,
}
}
if (left.type === 'number' && right.type === 'number') {
return {
type: 'number',
value:
left.value !== undefined && right.value !== undefined
? left.value + right.value
: undefined,
}
}
if (left.type === 'array' && right.type === 'array') {
return {
type: 'array',
of: {
type: 'union',
of: [left.of, right.of],
},
} satisfies ArrayTypeNode
}
if (left.type === 'object' && right.type === 'object') {
return {
type: 'object',
attributes: {...left.attributes, ...right.attributes},
} satisfies ObjectTypeNode
}
return {type: 'null'}
}
}
return {type: 'null'}
}
case '*': {
if (left.type === 'number' && right.type === 'number') {
return {
type: 'number',
value:
left.value !== undefined && right.value !== undefined
? left.value * right.value
: undefined,
case '-': {
if (left.type === 'number' && right.type === 'number') {
return {
type: 'number',
value:
left.value !== undefined && right.value !== undefined
? left.value - right.value
: undefined,
}
}
return {type: 'null'}
}
}
return {type: 'null'}
}
case '/': {
if (left.type === 'number' && right.type === 'number') {
return {
type: 'number',
value:
left.value !== undefined && right.value !== undefined
? left.value / right.value
: undefined,
case '*': {
if (left.type === 'number' && right.type === 'number') {
return {
type: 'number',
value:
left.value !== undefined && right.value !== undefined
? left.value * right.value
: undefined,
}
}
return {type: 'null'}
}
}
return {type: 'null'}
}
case '**': {
if (left.type === 'number' && right.type === 'number') {
return {
type: 'number',
value:
left.value !== undefined && right.value !== undefined
? left.value ** right.value
: undefined,
case '/': {
if (left.type === 'number' && right.type === 'number') {
return {
type: 'number',
value:
left.value !== undefined && right.value !== undefined
? left.value / right.value
: undefined,
}
}
return {type: 'null'}
}
}
return {type: 'null'}
}
case '%': {
if (left.type === 'number' && right.type === 'number') {
return {
type: 'number',
value:
left.value !== undefined && right.value !== undefined
? left.value % right.value
: undefined,
case '**': {
if (left.type === 'number' && right.type === 'number') {
return {
type: 'number',
value:
left.value !== undefined && right.value !== undefined
? left.value ** right.value
: undefined,
}
}
return {type: 'null'}
}
case '%': {
if (left.type === 'number' && right.type === 'number') {
return {
type: 'number',
value:
left.value !== undefined && right.value !== undefined
? left.value % right.value
: undefined,
}
}
return {type: 'null'}
}
default: {
return {
type: 'unknown',
} satisfies UnknownTypeNode
}
}
return {type: 'null'}
}
default: {
return {
type: 'unknown',
} satisfies UnknownTypeNode
}
}
}),
)
}

@@ -397,13 +405,25 @@

if (base.of.type === 'union') {
const value = walk({node: node.expr, scope: scope.createHidden(base.of.of)}) // re use the current parent, this is a "sub" scope
$trace('map.expr %O', value)
// if this is an inline type we resolve it since we want to map over the actual value.
return maybeResolveInline(base.of, scope, (base) => {
if (base.type === 'union') {
const value = walk({node: node.expr, scope: scope.createHidden(base.of)}) // re use the current parent, this is a "sub" scope
$trace('map.expr %O', value)
return {
type: 'array',
of: value,
} satisfies ArrayTypeNode
}
return {
type: 'array',
of: value,
} satisfies ArrayTypeNode
}
if (base.type === 'object') {
const value = walk({node: node.expr, scope: scope.createHidden([base])}) // re use the current parent, this is a "sub" scope
$trace('map.expr %O', value)
return base
return {
type: 'array',
of: value,
} satisfies ArrayTypeNode
}
return {type: 'unknown'} satisfies UnknownTypeNode
})
})

@@ -438,3 +458,2 @@ }

$trace('projection.base %O', base)
$trace('projection.scope %O', scope.value)

@@ -544,2 +563,6 @@ if (base.type === 'unknown' || base.type === 'null') {

$debug(`accessAttribute.attribute found ${node.name} %O`, attribute)
if (attribute.optional) {
return nullUnion(attribute.value)
}
return attribute.value

@@ -639,2 +662,15 @@ }

function handleSlice(node: SliceNode, scope: Scope): TypeNode {
$trace('slice.node %O', node)
const base = walk({node: node.base, scope})
return mapUnion(base, (base) => {
if (base.type !== 'array') {
return {type: 'null'} satisfies NullTypeNode
}
return base
})
}
function handleParentNode({n}: ParentNode, scope: Scope): TypeNode {

@@ -791,2 +827,5 @@ let current: Scope = scope

case 'Slice': {
return handleSlice(node, scope)
}
// everything else

@@ -1119,1 +1158,13 @@ case 'Asc':

}
function maybeResolveInline(
node: TypeNode,
scope: Scope,
mapper: (node: TypeNode) => TypeNode,
): TypeNode {
if (node.type === 'inline') {
const resolvedInline = scope.context.lookupTypeDeclaration(node)
return mapper(resolvedInline)
}
return mapper(node)
}

@@ -1,2 +0,2 @@

import {ObjectAttribute, ObjectTypeNode} from './types'
import type {ObjectAttribute, ObjectTypeNode, TypeNode, UnionTypeNode} from './types'

@@ -50,1 +50,15 @@ /**

}
export function nullUnion(node: TypeNode): UnionTypeNode {
if (node.type === 'union') {
return {
type: 'union',
of: [...node.of, {type: 'null'}],
} satisfies UnionTypeNode
}
return {
type: 'union',
of: [node, {type: 'null'}],
} satisfies UnionTypeNode
}

@@ -0,65 +1,116 @@

/** Represents a document structure with a fixed type 'document', a name, and a collection of attributes.*/
export interface Document {
/** can be used to identify the type of the node, in this case it's always 'document' */
type: 'document'
/** the name of the document */
name: string
/** ttributes is defined by a key-value pair where the key is a string and the value is an ObjectAttribute. */
attributes: Record<string, ObjectAttribute>
}
/** Defines a type declaration with a specific name and a value that describes the structure of the type using a TypeNode. */
export interface TypeDeclaration {
/** can be used to identify the type of the node, in this case it's always 'type' */
type: 'type'
/** the name of the type */
name: string
/** the value that describes the structure of the type */
value: TypeNode
}
/** A schema consisting of a list of Document or TypeDeclaration items, allowing for complex type definitions. */
export type Schema = (Document | TypeDeclaration)[]
/** Describes a type node for string values, optionally including a value. If a value is provided it will always be the given string value. */
export interface StringTypeNode {
/** can be used to identify the type of the node, in this case it's always 'string' */
type: 'string'
/** an optional value of the string, if provided it will always be the given string value */
value?: string
}
/** Describes a type node for number values, optionally including a value. If a value is provided it will always be the given numeric value.*/
export interface NumberTypeNode {
/** can be used to identify the type of the node, in this case it's always 'number' */
type: 'number'
/** an optional value of the number, if provided it will always be the given numeric value */
value?: number
}
/** Describes a type node for boolean values, optionally including a value. If a value is provided it will always be the given boolean value. */
export interface BooleanTypeNode {
/** can be used to identify the type of the node, in this case it's always 'boolean' */
type: 'boolean'
/** an optional value of the boolean, if provided it will always be the given boolean value */
value?: boolean
}
/** Union of any primitive type nodes. */
export type PrimitiveTypeNode = StringTypeNode | NumberTypeNode | BooleanTypeNode
/** Describes a type node for null values, always being the null value. */
export interface NullTypeNode {
/** can be used to identify the type of the node, in this case it's always 'null' */
type: 'null'
}
// InlineTypeNode inlines a type from a type declaration
/** Describes a type node for inline values, including a name that references another type. */
export interface InlineTypeNode {
/** can be used to identify the type of the node, in this case it's always 'inline' */
type: 'inline'
/** the name of the referenced type */
name: string
}
/**
* Describes a type node for object values, including a collection of attributes and an optional rest value.
* The rest value can be another ObjectTypeNode, an UnknownTypeNode, or an InlineTypeNode.
* If the rest value is an ObjectTypeNode, it means that the object can have additional attributes.
* If the rest value is an UnknownTypeNode, the entire object is unknown.
* If the rest value is an InlineTypeNode, it means that the object has additional attributes from the referenced type.
*/
export interface ObjectTypeNode<T extends TypeNode = TypeNode> {
/** can be used to identify the type of the node, in this case it's always 'object' */
type: 'object'
/** a collection of attributes */
attributes: Record<string, ObjectAttribute<T>>
/** an optional rest value */
rest?: ObjectTypeNode | UnknownTypeNode | InlineTypeNode
dereferencesTo?: string // the name of the document this object dereferences to
/* an optional reference to the document this object dereferences to */
dereferencesTo?: string
}
/** Describes a type node for object attributes, including a type and an optional flag for being optional. */
export interface ObjectAttribute<T extends TypeNode = TypeNode> {
/** can be used to identify the type of the node, in this case it's always 'objectAttribute' */
type: 'objectAttribute'
/** the type of the attribute */
value: T
/** an optional flag if the attribute is optional set on the object */
optional?: boolean
}
/** Describes a type node for union values. */
export interface UnionTypeNode<T extends TypeNode = TypeNode> {
/** can be used to identify the type of the node, in this case it's always 'union' */
type: 'union'
/** a collection of types */
of: T[]
}
/** Describes a type node for array values. */
export interface ArrayTypeNode<T extends TypeNode = TypeNode> {
/** can be used to identify the type of the node, in this case it's always 'array' */
type: 'array'
/** the type of the array elements */
of: T
}
export type UnknownTypeNode = {type: 'unknown'}
/** Describes a type node for unknown value. */
export type UnknownTypeNode = {
/** can be used to identify the type of the node, in this case it's always 'unknown' */
type: 'unknown'
}
/** All possible type nodes. */
export type TypeNode =

@@ -66,0 +117,0 @@ | ObjectTypeNode

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 not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc