From 7addeefdac1d5702d3d971272dca1eede570fce2 Mon Sep 17 00:00:00 2001 From: Sindre Gulseth Date: Tue, 19 Mar 2024 16:04:44 +0100 Subject: [PATCH] feat(codegen): add groq finder methods. (#5980) Adds methods that parses a js/ts source file and returns all groq queries. Co-authored-by: Tonina Zhelyazkova --- packages/@sanity/codegen/babel.config.json | 12 + packages/@sanity/codegen/package.json | 18 +- .../@sanity/codegen/src/_exports/index.ts | 4 +- .../__tests__/findQueriesInSource.test.ts | 113 +++++ .../__tests__/fixtures/exportStar.ts | 1 + .../__tests__/fixtures/exportVar.ts | 1 + .../typescript/__tests__/fixtures/source1.ts | 3 + .../typescript/__tests__/fixtures/source2.ts | 3 + .../src/typescript/expressionResolvers.ts | 427 ++++++++++++++++++ .../src/typescript/findQueriesInSource.ts | 64 +++ .../codegen/src/typescript/moduleResolver.ts | 41 ++ .../codegen/src/typescript/parseSource.ts | 20 + .../codegen/src/typescript/registerBabel.ts | 17 + pnpm-lock.yaml | 97 +++- 14 files changed, 804 insertions(+), 17 deletions(-) create mode 100644 packages/@sanity/codegen/babel.config.json create mode 100644 packages/@sanity/codegen/src/typescript/__tests__/findQueriesInSource.test.ts create mode 100644 packages/@sanity/codegen/src/typescript/__tests__/fixtures/exportStar.ts create mode 100644 packages/@sanity/codegen/src/typescript/__tests__/fixtures/exportVar.ts create mode 100644 packages/@sanity/codegen/src/typescript/__tests__/fixtures/source1.ts create mode 100644 packages/@sanity/codegen/src/typescript/__tests__/fixtures/source2.ts create mode 100644 packages/@sanity/codegen/src/typescript/expressionResolvers.ts create mode 100644 packages/@sanity/codegen/src/typescript/findQueriesInSource.ts create mode 100644 packages/@sanity/codegen/src/typescript/moduleResolver.ts create mode 100644 packages/@sanity/codegen/src/typescript/parseSource.ts create mode 100644 packages/@sanity/codegen/src/typescript/registerBabel.ts diff --git a/packages/@sanity/codegen/babel.config.json b/packages/@sanity/codegen/babel.config.json new file mode 100644 index 00000000000..4dd92d93f5c --- /dev/null +++ b/packages/@sanity/codegen/babel.config.json @@ -0,0 +1,12 @@ +{ + "presets": [ + ["@babel/preset-env", {"targets": "maintained node versions"}], + [ + "@babel/preset-react", + { + "runtime": "automatic" + } + ], + "@babel/preset-typescript" + ] +} diff --git a/packages/@sanity/codegen/package.json b/packages/@sanity/codegen/package.json index 17870b94217..4bdb8eb5736 100644 --- a/packages/@sanity/codegen/package.json +++ b/packages/@sanity/codegen/package.json @@ -57,8 +57,24 @@ "watch": "pkg-utils watch --tsconfig tsconfig.lib.json", "test": "jest" }, - "dependencies": {}, + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/preset-env": "^7.23.8", + "@babel/preset-react": "^7.23.3", + "@babel/preset-typescript": "^7.23.3", + "@babel/register": "^7.23.7", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.9", + "debug": "^4.3.4", + "tsconfig-paths": "^4.2.0" + }, "devDependencies": { + "@jest/globals": "^29.7.0", + "@types/babel__core": "^7.20.5", + "@types/babel__register": "^7.17.3", + "@types/babel__traverse": "^7.18.1", + "@types/debug": "^4.1.12", + "groq": "workspace:*", "rimraf": "^3.0.2" }, "engines": { diff --git a/packages/@sanity/codegen/src/_exports/index.ts b/packages/@sanity/codegen/src/_exports/index.ts index 32194a4a2f0..83a47fcd8ea 100644 --- a/packages/@sanity/codegen/src/_exports/index.ts +++ b/packages/@sanity/codegen/src/_exports/index.ts @@ -1 +1,3 @@ -export const TODO = 1 +export {findQueriesInSource} from '../typescript/findQueriesInSource' +export {getResolver} from '../typescript/moduleResolver' +export {registerBabel} from '../typescript/registerBabel' diff --git a/packages/@sanity/codegen/src/typescript/__tests__/findQueriesInSource.test.ts b/packages/@sanity/codegen/src/typescript/__tests__/findQueriesInSource.test.ts new file mode 100644 index 00000000000..1b212580005 --- /dev/null +++ b/packages/@sanity/codegen/src/typescript/__tests__/findQueriesInSource.test.ts @@ -0,0 +1,113 @@ +import path from 'node:path' + +import {describe, expect, test} from '@jest/globals' + +import {findQueriesInSource} from '../findQueriesInSource' + +describe('findQueries', () => { + describe('should find queries in source', () => { + test('plain string', () => { + const source = ` + import { groq } from "groq"; + const postQuery = groq\`*[_type == "author"]\` + const res = sanity.fetch(postQuery); + ` + + const queries = findQueriesInSource(source, 'test.ts') + const queryResult = queries[0] + + expect(queryResult?.result).toEqual('*[_type == "author"]') + }) + + test('with variables', () => { + const source = ` + import { groq } from "groq"; + const type = "author"; + const authorQuery = groq\`*[_type == "\${type}"]\` + const res = sanity.fetch(authorQuery); + ` + + const queries = findQueriesInSource(source, 'test.ts') + const queryResult = queries[0] + + expect(queryResult?.result).toEqual('*[_type == "author"]') + }) + + test('with function', () => { + const source = ` + import { groq } from "groq"; + const getType = () => () => () => "author"; + const query = groq\`*[_type == "\${getType()()()}"]\` + const res = sanity.fetch(query); + ` + + const queries = findQueriesInSource(source, 'test.ts') + + const queryResult = queries[0] + + expect(queryResult?.result).toEqual('*[_type == "author"]') + }) + + test('with block comment', () => { + const source = ` + import { groq } from "groq"; + const type = "author"; + const query = /* groq */ groq\`*[_type == "\${type}"]\`; + const res = sanity.fetch(query); + ` + + const queries = findQueriesInSource(source, 'test.ts') + const queryResult = queries[0] + + expect(queryResult?.result).toEqual('*[_type == "author"]') + }) + }) + + test('should not find inline queries in source', () => { + const source = ` + import { groq } from "groq"; + const res = sanity.fetch(groq\`*[_type == "author"]\`); + ` + + const queries = findQueriesInSource(source, 'test.ts') + + expect(queries.length).toBe(0) + }) + + test("should name queries with 'Result' at the end", () => { + const source = ` + import { groq } from "groq"; + const postQuery = groq\`*[_type == "author"]\` + const res = sanity.fetch(postQueryResult); + ` + + const queries = findQueriesInSource(source, 'test.ts') + const queryResult = queries[0] + + expect(queryResult?.name.substr(-6)).toBe('Result') + }) + + test('should import', () => { + const source = ` + import { groq } from "groq"; + import {foo} from "./fixtures/exportVar"; + const postQuery = groq\`*[_type == "\${foo}"]\` + const res = sanity.fetch(postQueryResult); + ` + + const resolver: NodeJS.RequireResolve = (id) => { + if (id === 'foo') { + return path.resolve(__dirname, 'fixtures', 'exportVar') + } + return require.resolve(id) + } + resolver.paths = (request: string): string[] | null => { + return require.resolve.paths(request) + } + + const queries = findQueriesInSource(source, 'test.ts', undefined, resolver) + const queryResult = queries[0] + + expect(queryResult?.name.substr(-6)).toBe('Result') + }) +}) diff --git a/packages/@sanity/codegen/src/typescript/__tests__/fixtures/exportStar.ts b/packages/@sanity/codegen/src/typescript/__tests__/fixtures/exportStar.ts new file mode 100644 index 00000000000..80d07c82b89 --- /dev/null +++ b/packages/@sanity/codegen/src/typescript/__tests__/fixtures/exportStar.ts @@ -0,0 +1 @@ +export * from './exportVar' diff --git a/packages/@sanity/codegen/src/typescript/__tests__/fixtures/exportVar.ts b/packages/@sanity/codegen/src/typescript/__tests__/fixtures/exportVar.ts new file mode 100644 index 00000000000..cb356468240 --- /dev/null +++ b/packages/@sanity/codegen/src/typescript/__tests__/fixtures/exportVar.ts @@ -0,0 +1 @@ +export const foo = 'foo' diff --git a/packages/@sanity/codegen/src/typescript/__tests__/fixtures/source1.ts b/packages/@sanity/codegen/src/typescript/__tests__/fixtures/source1.ts new file mode 100644 index 00000000000..c405a5aa5f1 --- /dev/null +++ b/packages/@sanity/codegen/src/typescript/__tests__/fixtures/source1.ts @@ -0,0 +1,3 @@ +import groq from 'groq' + +export const postQuery = groq`*[_type == "author"]` diff --git a/packages/@sanity/codegen/src/typescript/__tests__/fixtures/source2.ts b/packages/@sanity/codegen/src/typescript/__tests__/fixtures/source2.ts new file mode 100644 index 00000000000..f11674b9e6f --- /dev/null +++ b/packages/@sanity/codegen/src/typescript/__tests__/fixtures/source2.ts @@ -0,0 +1,3 @@ +import groq from 'groq' + +const postQuery = groq`*[_type == "author"]` diff --git a/packages/@sanity/codegen/src/typescript/expressionResolvers.ts b/packages/@sanity/codegen/src/typescript/expressionResolvers.ts new file mode 100644 index 00000000000..e2101606eea --- /dev/null +++ b/packages/@sanity/codegen/src/typescript/expressionResolvers.ts @@ -0,0 +1,427 @@ +import fs from 'node:fs' +import path from 'node:path' + +import {type TransformOptions} from '@babel/core' +import traverse, {type Scope} from '@babel/traverse' +import * as babelTypes from '@babel/types' +import createDebug from 'debug' + +import {parseSourceFile} from './parseSource' + +const debug = createDebug('sanity:codegen:findQueries:debug') + +type resolveExpressionReturnType = string + +export interface NamedQueryResult { + name: string + result: resolveExpressionReturnType +} + +const TAGGED_TEMPLATE_ALLOW_LIST = ['groq'] + +export function resolveExpression({ + node, + file, + scope, + filename, + resolver, + babelConfig, + params = [], + fnArguments = [], +}: { + node: babelTypes.Node + file: babelTypes.File + scope: Scope + filename: string + resolver: NodeJS.RequireResolve + babelConfig: TransformOptions + params?: babelTypes.Node[] + fnArguments?: babelTypes.Node[] +}): resolveExpressionReturnType { + debug( + `Resolving node ${node.type} in ${filename}:${node.loc?.start.line}:${node.loc?.start.column}`, + ) + if ( + babelTypes.isTaggedTemplateExpression(node) && + babelTypes.isIdentifier(node.tag) && + TAGGED_TEMPLATE_ALLOW_LIST.includes(node.tag.name) + ) { + return resolveExpression({ + node: node.quasi, + scope, + filename, + file, + resolver, + params, + babelConfig, + fnArguments, + }) + } + + if (babelTypes.isTemplateLiteral(node)) { + const resolvedExpressions = node.expressions.map((expression) => + resolveExpression({ + node: expression, + scope, + filename, + file, + resolver, + params, + babelConfig, + fnArguments, + }), + ) + return node.quasis + .map((quasi, idx) => { + return (quasi.value.cooked || '') + (resolvedExpressions[idx] || '') + }) + .join('') + } + + if (babelTypes.isLiteral(node)) { + if (node.type === 'NullLiteral' || node.type === 'RegExpLiteral') { + throw new Error(`Unsupported literal type: ${node.type}`) + } + + return node.value.toString() + } + + if (babelTypes.isIdentifier(node)) { + return resolveIdentifier({ + node, + scope, + filename, + file, + resolver, + fnArguments, + babelConfig, + params, + }) + } + + if (babelTypes.isVariableDeclarator(node)) { + if (!node.init) { + throw new Error(`Unsupported variable declarator`) + } + + return resolveExpression({ + node: node.init, + fnArguments, + scope, + filename, + file, + babelConfig, + resolver, + }) + } + + if (babelTypes.isCallExpression(node)) { + return resolveCallExpression({ + node, + scope, + filename, + file, + resolver, + babelConfig, + params, + fnArguments, + }) + } + + if ( + babelTypes.isArrowFunctionExpression(node) || + babelTypes.isFunctionDeclaration(node) || + babelTypes.isFunctionExpression(node) + ) { + return resolveExpression({ + node: node.body, + params: node.params, + fnArguments, + scope, + filename, + file, + babelConfig, + resolver, + }) + } + + if (babelTypes.isNewExpression(node)) { + return resolveExpression({ + node: node.callee, + scope, + filename, + file, + babelConfig, + resolver, + }) + } + + if (babelTypes.isImportDefaultSpecifier(node) || babelTypes.isImportSpecifier(node)) { + return resolveImportSpecifier({node, file, scope, filename, resolver, babelConfig}) + } + + if (babelTypes.isAssignmentPattern(node)) { + return resolveExpression({ + node: node.right, + scope, + filename, + file, + resolver, + params, + babelConfig, + fnArguments, + }) + } + + throw new Error( + `Unsupported expression type: ${node.type} in ${filename}:${node.loc?.start.line}:${node.loc?.start.column}`, + ) +} + +function resolveIdentifier({ + node, + scope, + filename, + file, + resolver, + babelConfig, + fnArguments, + params, +}: { + node: babelTypes.Identifier + file: babelTypes.File + scope: Scope + filename: string + resolver: NodeJS.RequireResolve + babelConfig: TransformOptions + fnArguments: babelTypes.Node[] + params: babelTypes.Node[] +}): resolveExpressionReturnType { + const paramIndex = params.findIndex( + (param) => + (babelTypes.isIdentifier(param) && node.name === param.name) || + (babelTypes.isAssignmentPattern(param) && + babelTypes.isIdentifier(param.left) && + node.name === param.left.name), + ) + const argument = fnArguments[paramIndex] + if (argument && babelTypes.isLiteral(argument)) { + return resolveExpression({ + node: argument, + scope, + filename, + file, + resolver, + params, + babelConfig, + fnArguments, + }) + } + const binding = scope.getBinding(node.name) + if (binding) { + if (babelTypes.isIdentifier(binding.path.node)) { + const isSame = binding.path.node.name === node.name + if (isSame) { + throw new Error( + `Could not resolve same identifier "${node.name}" in "${filename}:${node.loc?.start.line}:${node.loc?.start.column}"`, + ) + } + } + return resolveExpression({ + node: binding.path.node, + params, + fnArguments, + scope, + filename, + babelConfig, + file, + resolver, + }) + } + + throw new Error( + `Could not find binding for node "${node.name}" in ${filename}:${node.loc?.start.line}:${node.loc?.start.column}`, + ) +} + +function resolveCallExpression({ + node, + scope, + filename, + file, + resolver, + babelConfig, + params, +}: { + node: babelTypes.CallExpression + file: babelTypes.File + scope: Scope + filename: string + resolver: NodeJS.RequireResolve + babelConfig: TransformOptions + fnArguments: babelTypes.Node[] + params: babelTypes.Node[] +}): resolveExpressionReturnType { + const {callee} = node + return resolveExpression({ + node: callee, + scope, + filename, + file, + resolver, + babelConfig, + params, + fnArguments: node.arguments, + }) +} + +function resolveImportSpecifier({ + node, + file, + filename, + resolver, + babelConfig, +}: { + node: babelTypes.ImportDefaultSpecifier | babelTypes.ImportSpecifier | babelTypes.ExportSpecifier + file: babelTypes.File + scope: Scope + filename: string + resolver: NodeJS.RequireResolve + babelConfig: TransformOptions +}): resolveExpressionReturnType { + let importDeclaration: babelTypes.ImportDeclaration | undefined + traverse(file, { + ImportDeclaration(n) { + if (!babelTypes.isImportDeclaration(n.node)) { + return + } + for (const specifier of n.node.specifiers) { + if (babelTypes.isImportDefaultSpecifier(specifier)) { + if (specifier.local.loc?.identifierName === node.local.name) { + importDeclaration = n.node + break + } + } + if (specifier.local.name === node.local.name) { + importDeclaration = n.node + } + } + }, + }) + + if (!importDeclaration) { + throw new Error(`Could not find import declaration for ${node.local.name}`) + } + + const importName = node.local.name + const importFileName = importDeclaration.source.value + // const importPath = path.resolve(path.dirname(filename), importFileName); + const importPath = importName.startsWith('./') + ? path.resolve(path.dirname(filename), importFileName) + : importFileName + const resolvedFile = resolver(importPath) + const source = fs.readFileSync(resolvedFile) + const tree = parseSourceFile(source.toString(), resolvedFile, babelConfig) + + let newScope: Scope | undefined + traverse(tree, { + Program(p) { + newScope = p.scope + }, + }) + if (!newScope) { + throw new Error(`Could not find scope for ${filename}`) + } + + const binding = newScope.getBinding(importName) + if (binding) { + return resolveExpression({ + node: binding.path.node, + file: tree, + scope: newScope, + babelConfig, + filename: importFileName, + resolver, + }) + } + + // It's not a global binding, but it might be a named export + let namedExport: babelTypes.ExportNamedDeclaration | undefined + let newImportName: string | undefined + traverse(tree, { + ExportDeclaration(p) { + if (p.node.type === 'ExportNamedDeclaration') { + for (const specifier of p.node.specifiers) { + if ( + specifier.type === 'ExportSpecifier' && + specifier.exported.type === 'Identifier' && + specifier.exported.name === importName + ) { + namedExport = p.node + newImportName = specifier.exported.name + } + } + } + }, + }) + + if (namedExport && newImportName) { + return resolveExportSpecifier({ + node: namedExport, + importName: newImportName, + filename: resolvedFile, + resolver, + babelConfig, + }) + } + + throw new Error(`Could not find binding for import "${importName}" in ${importFileName}`) +} + +function resolveExportSpecifier({ + node, + importName, + filename, + babelConfig, + resolver, +}: { + node: babelTypes.ExportNamedDeclaration + importName: string + filename: string + babelConfig: TransformOptions + resolver: NodeJS.RequireResolve +}): resolveExpressionReturnType { + if (!node.source) { + throw new Error(`Could not find source for export "${importName}" in ${filename}`) + } + + const importFileName = node.source.value + const importPath = path.resolve(path.dirname(filename), importFileName) + const resolvedFile = resolver(importPath) + const source = fs.readFileSync(resolvedFile) + const tree = parseSourceFile(source.toString(), resolvedFile, babelConfig) + + let newScope: Scope | undefined + traverse(tree, { + Program(p) { + newScope = p.scope + }, + }) + if (!newScope) { + throw new Error(`Could not find scope for ${filename}`) + } + + const binding = newScope.getBinding(importName) + if (binding) { + return resolveExpression({ + node: binding.path.node, + file: tree, + scope: newScope, + filename: importFileName, + babelConfig, + resolver, + }) + } + + throw new Error(`Could not find binding for export "${importName}" in ${importFileName}`) +} diff --git a/packages/@sanity/codegen/src/typescript/findQueriesInSource.ts b/packages/@sanity/codegen/src/typescript/findQueriesInSource.ts new file mode 100644 index 00000000000..4f98c705642 --- /dev/null +++ b/packages/@sanity/codegen/src/typescript/findQueriesInSource.ts @@ -0,0 +1,64 @@ +import {createRequire} from 'node:module' +import {join} from 'node:path' + +import {type TransformOptions, traverse} from '@babel/core' +import * as babelTypes from '@babel/types' + +import {type NamedQueryResult, resolveExpression} from './expressionResolvers' +import {parseSourceFile} from './parseSource' + +const require = createRequire(__filename) + +const groqTagName = 'groq' + +const defaultBabelOptions = { + extends: join(__dirname, '..', '..', 'babel.config.json'), +} + +/** + * findQueriesInSource takes a source string and returns all GROQ queries in it. + * @param source - The source code to search for queries + * @param filename - The filename of the source code + * @param babelConfig - The babel configuration to use when parsing the source + * @param resolver - A resolver function to use when resolving module imports + * @returns + * @beta + * @internal + */ +export function findQueriesInSource( + source: string, + filename: string, + babelConfig: TransformOptions = defaultBabelOptions, + resolver: NodeJS.RequireResolve = require.resolve, +): NamedQueryResult[] { + const queries: NamedQueryResult[] = [] + const file = parseSourceFile(source, filename, babelConfig) + + traverse(file, { + // Look for variable declarations, e.g. `const myQuery = groq`... and extract the query. + // The variable name is used as the name of the query result type + VariableDeclarator({node, scope}) { + const init = node.init + // Look for tagged template expressions that are called with the `groq` tag + if ( + babelTypes.isTaggedTemplateExpression(init) && + babelTypes.isIdentifier(init.tag) && + babelTypes.isIdentifier(node.id) && + init.tag.name === groqTagName + ) { + const queryName = `${node.id.name}Result` + const queryResult = resolveExpression({ + node: init, + file, + scope, + babelConfig, + filename, + resolver, + }) + queries.push({name: queryName, result: queryResult}) + } + }, + }) + + return queries +} diff --git a/packages/@sanity/codegen/src/typescript/moduleResolver.ts b/packages/@sanity/codegen/src/typescript/moduleResolver.ts new file mode 100644 index 00000000000..3fc121839d2 --- /dev/null +++ b/packages/@sanity/codegen/src/typescript/moduleResolver.ts @@ -0,0 +1,41 @@ +import createDebug from 'debug' +import {createMatchPath, loadConfig as loadTSConfig} from 'tsconfig-paths' + +const debug = createDebug('sanity:codegen:moduleResolver') + +/** + * This is a custom implementation of require.resolve that takes into account the paths + * configuration in tsconfig.json. This is necessary if we want to resolve paths that are + * custom defined in the tsconfig.json file. + * Resolving here is best effort and might not work in all cases. + * @beta + */ +export function getResolver(cwd?: string): NodeJS.RequireResolve { + const tsConfig = loadTSConfig(cwd) + + if (tsConfig.resultType === 'failed') { + debug('Could not load tsconfig, using default resolver: %s', tsConfig.message) + return require.resolve + } + + const matchPath = createMatchPath( + tsConfig.absoluteBaseUrl, + tsConfig.paths, + tsConfig.mainFields, + tsConfig.addMatchAll, + ) + + const resolve = function (request: string, options?: {paths?: string[]}): string { + const found = matchPath(request) + if (found !== undefined) { + return require.resolve(found, options) + } + return require.resolve(request, options) + } + + // wrap the resolve.path function to make it available. + resolve.paths = (request: string): string[] | null => { + return require.resolve.paths(request) + } + return resolve +} diff --git a/packages/@sanity/codegen/src/typescript/parseSource.ts b/packages/@sanity/codegen/src/typescript/parseSource.ts new file mode 100644 index 00000000000..26085d571c6 --- /dev/null +++ b/packages/@sanity/codegen/src/typescript/parseSource.ts @@ -0,0 +1,20 @@ +import {parse, type TransformOptions} from '@babel/core' +import type * as babelTypes from '@babel/types' + +// helper function to parse a source file +export function parseSourceFile( + source: string, + filename: string, + babelOptions: TransformOptions, +): babelTypes.File { + const result = parse(source, { + ...babelOptions, + filename, + }) + + if (!result) { + throw new Error(`Failed to parse ${filename}`) + } + + return result +} diff --git a/packages/@sanity/codegen/src/typescript/registerBabel.ts b/packages/@sanity/codegen/src/typescript/registerBabel.ts new file mode 100644 index 00000000000..a47789ffc28 --- /dev/null +++ b/packages/@sanity/codegen/src/typescript/registerBabel.ts @@ -0,0 +1,17 @@ +import {join} from 'node:path' + +import {type TransformOptions} from '@babel/core' +import register from '@babel/register' + +const defaultBabelOptions = { + extends: join(__dirname, '..', '..', 'babel.config.json'), +} + +/** + * Register Babel with the given options + * @param babelOptions - The options to use when registering Babel + * @beta + */ +export function registerBabel(babelOptions: TransformOptions = defaultBabelOptions): void { + register({...babelOptions, extensions: ['.ts', '.tsx', '.js', '.jsx']}) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b6a9e6dac84..004bc0f8307 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -838,7 +838,53 @@ importers: version: 4.0.0 packages/@sanity/codegen: + dependencies: + '@babel/core': + specifier: ^7.23.9 + version: 7.24.0 + '@babel/preset-env': + specifier: ^7.23.8 + version: 7.24.0(@babel/core@7.24.0) + '@babel/preset-react': + specifier: ^7.23.3 + version: 7.23.3(@babel/core@7.24.0) + '@babel/preset-typescript': + specifier: ^7.23.3 + version: 7.23.3(@babel/core@7.24.0) + '@babel/register': + specifier: ^7.23.7 + version: 7.23.7(@babel/core@7.24.0) + '@babel/traverse': + specifier: ^7.23.5 + version: 7.24.0(supports-color@5.5.0) + '@babel/types': + specifier: ^7.23.9 + version: 7.24.0 + debug: + specifier: ^4.3.4 + version: 4.3.4(supports-color@5.5.0) + tsconfig-paths: + specifier: ^4.2.0 + version: 4.2.0 devDependencies: + '@jest/globals': + specifier: ^29.7.0 + version: 29.7.0 + '@types/babel__core': + specifier: ^7.20.5 + version: 7.20.5 + '@types/babel__register': + specifier: ^7.17.3 + version: 7.17.3 + '@types/babel__traverse': + specifier: ^7.18.1 + version: 7.20.5 + '@types/debug': + specifier: ^4.1.12 + version: 4.1.12 + groq: + specifier: workspace:* + version: link:../../groq rimraf: specifier: ^3.0.2 version: 3.0.2 @@ -2204,7 +2250,6 @@ packages: dependencies: '@babel/core': 7.24.0 '@babel/helper-plugin-utils': 7.24.0 - dev: true /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.0): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} @@ -2280,7 +2325,6 @@ packages: dependencies: '@babel/core': 7.24.0 '@babel/helper-plugin-utils': 7.24.0 - dev: true /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.0): resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} @@ -2680,7 +2724,6 @@ packages: dependencies: '@babel/core': 7.24.0 '@babel/helper-plugin-utils': 7.24.0 - dev: true /@babel/plugin-transform-react-jsx-development@7.22.5(@babel/core@7.24.0): resolution: {integrity: sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==} @@ -2690,7 +2733,6 @@ packages: dependencies: '@babel/core': 7.24.0 '@babel/plugin-transform-react-jsx': 7.23.4(@babel/core@7.24.0) - dev: true /@babel/plugin-transform-react-jsx-self@7.23.3(@babel/core@7.24.0): resolution: {integrity: sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==} @@ -2722,7 +2764,6 @@ packages: '@babel/helper-plugin-utils': 7.24.0 '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0) '@babel/types': 7.24.0 - dev: true /@babel/plugin-transform-react-pure-annotations@7.23.3(@babel/core@7.24.0): resolution: {integrity: sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==} @@ -2733,7 +2774,6 @@ packages: '@babel/core': 7.24.0 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-plugin-utils': 7.24.0 - dev: true /@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.24.0): resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==} @@ -2811,7 +2851,6 @@ packages: '@babel/helper-create-class-features-plugin': 7.23.7(@babel/core@7.24.0) '@babel/helper-plugin-utils': 7.24.0 '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.0) - dev: true /@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.24.0): resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==} @@ -2965,7 +3004,6 @@ packages: '@babel/plugin-transform-react-jsx': 7.23.4(@babel/core@7.24.0) '@babel/plugin-transform-react-jsx-development': 7.22.5(@babel/core@7.24.0) '@babel/plugin-transform-react-pure-annotations': 7.23.3(@babel/core@7.24.0) - dev: true /@babel/preset-typescript@7.23.3(@babel/core@7.24.0): resolution: {integrity: sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==} @@ -2979,7 +3017,20 @@ packages: '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0) '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0) '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.24.0) - dev: true + + /@babel/register@7.23.7(@babel/core@7.24.0): + resolution: {integrity: sha512-EjJeB6+kvpk+Y5DAkEAmbOBEFkh9OASx0huoEkqYTFxAZHzOAX2Oh5uwAUuL2rUddqfM0SA+KPXV2TbzoZ2kvQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + clone-deep: 4.0.1 + find-cache-dir: 2.1.0 + make-dir: 2.1.0 + pirates: 4.0.6 + source-map-support: 0.5.21 + dev: false /@babel/regjsgen@0.8.0: resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} @@ -6933,6 +6984,12 @@ packages: dependencies: '@babel/types': 7.24.0 + /@types/babel__register@7.17.3: + resolution: {integrity: sha512-hy9H39BUIGO0C88bLxQD5rqBvqMgjPjDnA8Mx+fjAqtOi4OG7qYaZUMlDHfLOx5G9WtBzhfchzxKl37LTsVRbA==} + dependencies: + '@types/babel__core': 7.20.5 + dev: true + /@types/babel__template@7.4.4: resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} dependencies: @@ -8971,7 +9028,6 @@ packages: is-plain-object: 2.0.4 kind-of: 6.0.3 shallow-clone: 3.0.1 - dev: true /clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} @@ -11169,6 +11225,15 @@ packages: transitivePeerDependencies: - supports-color + /find-cache-dir@2.1.0: + resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} + engines: {node: '>=6'} + dependencies: + commondir: 1.0.1 + make-dir: 2.1.0 + pkg-dir: 3.0.0 + dev: false + /find-config@1.0.0: resolution: {integrity: sha512-Z+suHH+7LSE40WfUeZPIxSxypCWvrzdVc60xAjUShZeT5eMWM0/FQUduq3HjluyfAHWvC/aOBkT1pTZktyF/jg==} engines: {node: '>= 0.12'} @@ -14204,7 +14269,6 @@ packages: dependencies: pify: 4.0.1 semver: 5.7.2 - dev: true /make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} @@ -15771,7 +15835,6 @@ packages: /pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} - dev: true /pify@5.0.0: resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} @@ -15794,6 +15857,13 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + /pkg-dir@3.0.0: + resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} + engines: {node: '>=6'} + dependencies: + find-up: 3.0.0 + dev: false + /pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -17094,7 +17164,6 @@ packages: engines: {node: '>=8'} dependencies: kind-of: 6.0.3 - dev: true /shallow-equals@1.0.0: resolution: {integrity: sha512-xd/FKcdmfmMbyYCca3QTVEJtqUOGuajNzvAX6nt8dXILwjAIEkfHc4hI8/JMGApAmb7VeULO0Q30NTxnbH/15g==} @@ -17661,7 +17730,6 @@ packages: /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - dev: true /strip-bom@4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} @@ -18186,7 +18254,6 @@ packages: json5: 2.2.3 minimist: 1.2.8 strip-bom: 3.0.0 - dev: true /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}