diff --git a/.github/workflows/cli-test.yml b/.github/workflows/cli-test.yml index 2b4a0b87a84..4f4fb9562ef 100644 --- a/.github/workflows/cli-test.yml +++ b/.github/workflows/cli-test.yml @@ -73,7 +73,7 @@ jobs: run: | node -v npm -v - pnpm test -- --silent --selectProjects=@sanity/cli + pnpm test:jest --silent --selectProjects=@sanity/cli env: # Update token in github and change below to ${{ secrets.SANITY_CI_CLI_AUTH_TOKEN }} after merge to next SANITY_CI_CLI_AUTH_TOKEN_STAGING: ${{ secrets.SANITY_CI_CLI_AUTH_TOKEN_STAGING }} diff --git a/.github/workflows/jest.yml b/.github/workflows/jest.yml new file mode 100644 index 00000000000..f83b0bb4b16 --- /dev/null +++ b/.github/workflows/jest.yml @@ -0,0 +1,77 @@ +name: Unit tests + +on: + # Build on pushes branches that have a PR (including drafts) + pull_request: + # Build on commits pushed to branches without a PR if it's in the allowlist + push: + branches: [next] + +jobs: + test: + timeout-minutes: 60 + name: Jest tests (${{ matrix.os }} / node ${{ matrix.node }}) + runs-on: ${{ matrix.os }} + env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: ${{ vars.TURBO_TEAM }} + continue-on-error: ${{ matrix.experimental }} + + strategy: + # we want to know if a test fails on a specific node version + fail-fast: false + matrix: + os: [ubuntu-latest] + node: [18, 20] + experimental: [false] + shardIndex: [1, 2, 3, 4] + shardTotal: [4] + # include: + # - os: windows-latest + # node: 16 + # experimental: true + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + + - uses: pnpm/action-setup@v4 + name: Install pnpm + id: pnpm-install + with: + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Cache node modules + id: cache-node-modules + uses: actions/cache@v4 + env: + cache-name: cache-node-modules + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ env.cache-name }}-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + v1-${{ runner.os }}-pnpm-store-${{ env.cache-name }}- + v1-${{ runner.os }}-pnpm-store- + v1-${{ runner.os }}- + + - name: Install project dependencies + run: pnpm install + + - name: Test + id: test + run: | + node -v + pnpm test:jest --silent --shard=${{ matrix.shardIndex}}/${{ matrix.shardTotal }} --ignoreProjects=@sanity/cli + env: + GITHUB_SHARD_IDENTIFIER: ${{ matrix.shardIndex }}-${{ matrix.shardTotal }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6d09a691824..d11d975026f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -72,7 +72,4 @@ jobs: id: test run: | node -v - npm -v - pnpm test -- --silent --shard=${{ matrix.shardIndex}}/${{ matrix.shardTotal }} --ignoreProjects=@sanity/cli - env: - GITHUB_SHARD_IDENTIFIER: ${{ matrix.shardIndex }}-${{ matrix.shardTotal }} + pnpm test:vitest diff --git a/dev/aliases.cjs b/dev/aliases.cjs deleted file mode 100644 index 15f0782ae48..00000000000 --- a/dev/aliases.cjs +++ /dev/null @@ -1,32 +0,0 @@ -'use strict' - -/* eslint-disable tsdoc/syntax */ - -/** - * The path mappings/aliases used by various tools in the monorepo to map imported modules to - * source files in order to speed up rebuilding and avoid having a separate watcher process to build - * from `src` to `lib`. - * - * This file is currently read by: - * - Vite when running the dev server (only when running in this monorepo) - * - jest when running test suite - * - * @type Record - */ -const devAliases = { - // NOTE: do not use regex in the module expressions, - // because they will be escaped by the jest config - '@sanity/block-tools': './packages/@sanity/block-tools/src', - '@sanity/diff': './packages/@sanity/diff/src', - '@sanity/cli': './packages/@sanity/cli/src', - '@sanity/mutator': './packages/@sanity/mutator/src', - '@sanity/schema': './packages/@sanity/schema/src/_exports', - '@sanity/migrate': './packages/@sanity/migrate/src/_exports', - '@sanity/types': './packages/@sanity/types/src', - '@sanity/util': './packages/@sanity/util/src/_exports', - '@sanity/vision': './packages/@sanity/vision/src', - 'sanity': './packages/sanity/src/_exports', - 'groq': './packages/groq/src/_exports.mts', -} - -module.exports = devAliases diff --git a/dev/depcheck-test/package.json b/dev/depcheck-test/package.json index 7ba8dc2aabc..b49bf540949 100644 --- a/dev/depcheck-test/package.json +++ b/dev/depcheck-test/package.json @@ -1,6 +1,6 @@ { "name": "depcheck-test", - "version": "3.57.4", + "version": "3.58.0", "private": true, "license": "MIT", "author": "Sanity.io " diff --git a/dev/design-studio/package.json b/dev/design-studio/package.json index d88a91deb6e..1396f9d9b29 100644 --- a/dev/design-studio/package.json +++ b/dev/design-studio/package.json @@ -1,6 +1,6 @@ { "name": "design-studio", - "version": "3.57.4", + "version": "3.58.0", "private": true, "description": "Sanity Design Studio", "keywords": [ diff --git a/dev/embedded-studio/package.json b/dev/embedded-studio/package.json index 7eda557b851..ed92725bfab 100644 --- a/dev/embedded-studio/package.json +++ b/dev/embedded-studio/package.json @@ -1,6 +1,6 @@ { "name": "embedded-studio", - "version": "3.57.4", + "version": "3.58.0", "private": true, "scripts": { "build": "tsc && vite build && sanity manifest extract", diff --git a/dev/page-building-studio/package.json b/dev/page-building-studio/package.json index 1ae554f9298..88f92340244 100644 --- a/dev/page-building-studio/package.json +++ b/dev/page-building-studio/package.json @@ -1,6 +1,6 @@ { "name": "sanity-page-building-studio", - "version": "3.57.4", + "version": "3.58.0", "private": true, "license": "MIT", "author": "Sanity.io ", diff --git a/dev/starter-next-studio/package.json b/dev/starter-next-studio/package.json index 83210a2deaa..39a497657dc 100644 --- a/dev/starter-next-studio/package.json +++ b/dev/starter-next-studio/package.json @@ -1,6 +1,6 @@ { "name": "sanity-starter-next-studio", - "version": "3.57.4", + "version": "3.58.0", "private": true, "license": "MIT", "author": "Sanity.io ", diff --git a/dev/starter-studio/package.json b/dev/starter-studio/package.json index 22e6a388fe3..f61069fbbae 100644 --- a/dev/starter-studio/package.json +++ b/dev/starter-studio/package.json @@ -1,6 +1,6 @@ { "name": "sanity-starter-studio", - "version": "3.57.4", + "version": "3.58.0", "private": true, "license": "MIT", "author": "Sanity.io ", diff --git a/dev/strict-studio/package.json b/dev/strict-studio/package.json index 01b5296659a..2019ec131e3 100644 --- a/dev/strict-studio/package.json +++ b/dev/strict-studio/package.json @@ -1,6 +1,6 @@ { "name": "sanity-strict-studio", - "version": "3.57.4", + "version": "3.58.0", "private": true, "license": "MIT", "author": "Sanity.io ", diff --git a/dev/studio-e2e-testing/package.json b/dev/studio-e2e-testing/package.json index 7a26f074ccb..9d199b01d10 100644 --- a/dev/studio-e2e-testing/package.json +++ b/dev/studio-e2e-testing/package.json @@ -1,6 +1,6 @@ { "name": "studio-e2e-testing", - "version": "3.57.4", + "version": "3.58.0", "private": true, "keywords": [ "sanity" @@ -18,7 +18,7 @@ "@sanity/google-maps-input": "^4.0.0", "@sanity/icons": "^3.4.0", "@sanity/ui": "^2.8.9", - "@sanity/vision": "3.57.4", + "@sanity/vision": "3.58.0", "react": "^18.3.1", "react-dom": "^18.3.1", "sanity": "workspace:*", diff --git a/dev/test-next-studio/package.json b/dev/test-next-studio/package.json index 15a760a06a1..10f40590bd3 100644 --- a/dev/test-next-studio/package.json +++ b/dev/test-next-studio/package.json @@ -1,6 +1,6 @@ { "name": "sanity-test-next-studio", - "version": "3.57.4", + "version": "3.58.0", "private": true, "license": "MIT", "author": "Sanity.io ", diff --git a/dev/test-studio/package.json b/dev/test-studio/package.json index fc208efa26b..64c4cb82320 100644 --- a/dev/test-studio/package.json +++ b/dev/test-studio/package.json @@ -1,6 +1,6 @@ { "name": "sanity-test-studio", - "version": "3.57.4", + "version": "3.58.0", "private": true, "license": "MIT", "author": "Sanity.io ", @@ -19,7 +19,7 @@ "@portabletext/editor": "^1.1.0", "@portabletext/react": "^3.0.0", "@sanity/assist": "^3.0.2", - "@sanity/block-tools": "3.57.4", + "@sanity/block-tools": "3.58.0", "@sanity/client": "^6.21.3", "@sanity/color": "^3.0.0", "@sanity/google-maps-input": "^4.0.0", diff --git a/examples/blog-studio/package.json b/examples/blog-studio/package.json index 08cba373652..b5c551898ac 100644 --- a/examples/blog-studio/package.json +++ b/examples/blog-studio/package.json @@ -1,6 +1,6 @@ { "name": "blog-studio", - "version": "3.57.4", + "version": "3.58.0", "private": true, "description": "Content studio running with schema from the blog init template", "keywords": [ diff --git a/examples/clean-studio/package.json b/examples/clean-studio/package.json index acfd8084219..7790dde1a83 100644 --- a/examples/clean-studio/package.json +++ b/examples/clean-studio/package.json @@ -1,6 +1,6 @@ { "name": "clean-studio", - "version": "3.57.4", + "version": "3.58.0", "private": true, "description": "Content studio running with schema from the clean template", "keywords": [ diff --git a/examples/ecommerce-studio/package.json b/examples/ecommerce-studio/package.json index 01a5b630412..ce6b5aaa36a 100644 --- a/examples/ecommerce-studio/package.json +++ b/examples/ecommerce-studio/package.json @@ -1,6 +1,6 @@ { "name": "ecommerce-studio", - "version": "3.57.4", + "version": "3.58.0", "private": true, "description": "", "keywords": [ @@ -29,7 +29,7 @@ "start": "sanity dev --port 3337" }, "dependencies": { - "@sanity/cli": "3.57.4", + "@sanity/cli": "3.58.0", "@sanity/ui": "^2.8.9", "react": "^18.3.1", "react-barcode": "^1.4.1", diff --git a/examples/movies-studio/package.json b/examples/movies-studio/package.json index 935a10fa084..826255b5596 100644 --- a/examples/movies-studio/package.json +++ b/examples/movies-studio/package.json @@ -1,6 +1,6 @@ { "name": "movies-studio", - "version": "3.57.4", + "version": "3.58.0", "private": true, "description": "Content studio running with schema from the moviedb init template", "keywords": [ diff --git a/jest.config.cjs b/jest.config.cjs deleted file mode 100644 index b743bdef019..00000000000 --- a/jest.config.cjs +++ /dev/null @@ -1,20 +0,0 @@ -/* eslint-disable tsdoc/syntax */ - -const path = require('node:path') -const globby = require('globby') - -const jestConfigFiles = globby.sync('**/*/jest.config.cjs', { - ignore: ['**/node_modules'], -}) - -const IGNORE_PROJECTS = [] - -/** @type {import("jest").Config} */ -module.exports = { - projects: jestConfigFiles - .map((file) => path.relative(__dirname, path.dirname(file))) - .filter((projectPath) => !IGNORE_PROJECTS.includes(projectPath)) - .map((projectPath) => `/${projectPath}`), - // Ignore e2e tests - modulePathIgnorePatterns: ['/test/'], -} diff --git a/jest.config.mjs b/jest.config.mjs new file mode 100644 index 00000000000..d0d52948177 --- /dev/null +++ b/jest.config.mjs @@ -0,0 +1,17 @@ +/** + * This tells jest which projects exists + */ +import path from 'node:path' +import globby from 'globby' +import {resolveDirName} from '@repo/test-config/jest' + +const jestConfigFiles = globby.sync('*/**/jest.config.mjs', {ignore: ['**/node_modules']}) + +/** @type {import("jest").Config} */ +export default { + projects: jestConfigFiles + .map((file) => path.relative(resolveDirName(import.meta.url), path.dirname(file))) + .map((projectPath) => `/${projectPath}`), + // Ignore e2e tests + modulePathIgnorePatterns: ['/test/'], +} diff --git a/lerna.json b/lerna.json index ff354a1d261..e686fd70252 100644 --- a/lerna.json +++ b/lerna.json @@ -12,5 +12,5 @@ "packages/groq", "packages/sanity" ], - "version": "3.57.4" + "version": "3.58.0" } diff --git a/package.json b/package.json index 923d3610000..90b1b6822ee 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,9 @@ "release:rc": "pnpm build && lerna publish --force-publish --dist-tag=dev-preview --preid=rc --exact", "release:tag": "RELEASE_TAG=\"${RELEASE_TAG:-canary}\"; pnpm build && lerna publish --canary --force-publish --no-git-tag-version --dist-tag=$RELEASE_TAG --preid=$RELEASE_TAG --exact", "start": "run-s dev", - "test": "jest --forceExit", + "test": "run-s test:vitest test:jest", + "test:jest": "jest --forceExit", + "test:vitest": "vitest --run", "test:e2e": "playwright test", "test:exports": "turbo run test --filter=@repo/test-exports", "tsdoc:dev": "sanity-tsdoc dev", @@ -97,14 +99,14 @@ }, "prettier": "@sanity/prettier-config", "devDependencies": { - "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/preset-env": "^7.24.7", "@babel/preset-react": "^7.24.7", "@babel/preset-typescript": "^7.24.7", "@google-cloud/storage": "^7.11.0", - "@jest/globals": "^29.7.0", "@playwright/test": "1.44.1", + "@repo/dev-aliases": "workspace:*", "@repo/package.config": "workspace:*", + "@repo/test-config": "workspace:*", "@repo/tsconfig": "workspace:*", "@sanity/client": "^6.21.3", "@sanity/eslint-config-i18n": "1.0.0", @@ -152,7 +154,6 @@ "globby": "^10.0.0", "husky": "^9.0.11", "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", "js-yaml": "^4.1.0", "lerna": "^8.1.8", "lint-staged": "^12.1.2", @@ -169,6 +170,7 @@ "typescript": "5.6.2", "vite": "^4.5.3", "vite-tsconfig-paths": "^4.3.2", + "vitest": "^2.1.1", "yargs": "^17.3.0" }, "optionalDependencies": { diff --git a/packages/@repo/dev-aliases/dev-aliases.cjs b/packages/@repo/dev-aliases/dev-aliases.cjs new file mode 100644 index 00000000000..51d3a925e5a --- /dev/null +++ b/packages/@repo/dev-aliases/dev-aliases.cjs @@ -0,0 +1,33 @@ +/* eslint-disable tsdoc/syntax */ + +// NOTE: THIS FILE NEEDS TO REMAIN COMMONJS +// It can be converted to ESM/TS when we either not use jest anymore, or node/jest runner natively supports ESM (including with import.meta etc). + +/** + * The path mappings/aliases used by various tools in the monorepo to map imported modules to + * source files in order to speed up rebuilding and avoid having a separate watcher process to build + * from `src` to `lib`. + * + * This file is currently read by: + * - Vite when running the dev server (only when running in this monorepo) + * - jest when running test suite + * + * @type Record + */ +const devAliases = { + // NOTE: do not use regex in the module expressions, + // because they will be escaped by the jest config + '@sanity/block-tools': '@sanity/block-tools/src', + '@sanity/diff': '@sanity/diff/src', + '@sanity/cli': '@sanity/cli/src', + '@sanity/mutator': '@sanity/mutator/src', + '@sanity/schema': '@sanity/schema/src/_exports', + '@sanity/migrate': '@sanity/migrate/src/_exports', + '@sanity/types': '@sanity/types/src', + '@sanity/util': '@sanity/util/src/_exports', + '@sanity/vision': '@sanity/vision/src', + 'sanity': 'sanity/src/_exports', + 'groq': 'groq/src/_exports.mts', +} + +module.exports = devAliases diff --git a/packages/@repo/dev-aliases/package.json b/packages/@repo/dev-aliases/package.json new file mode 100644 index 00000000000..7661b47ff5b --- /dev/null +++ b/packages/@repo/dev-aliases/package.json @@ -0,0 +1,12 @@ +{ + "name": "@repo/dev-aliases", + "version": "3.57.4", + "private": true, + "description": "Dev aliases for the sanity monorepo", + "type": "module", + "exports": { + ".": "./dev-aliases.cjs", + "./vite": "./vite.mjs" + }, + "main": "./dev-aliases.cjs" +} diff --git a/packages/@repo/dev-aliases/vite.mjs b/packages/@repo/dev-aliases/vite.mjs new file mode 100644 index 00000000000..a1712f6eee4 --- /dev/null +++ b/packages/@repo/dev-aliases/vite.mjs @@ -0,0 +1,18 @@ +import devAliases from './dev-aliases.cjs' + +import {dirname, resolve} from 'node:path' + +const PACKAGES_PATH = resolve(getDirname(import.meta.url), '..', '..') + +function getDirname(importMetaUrl) { + return dirname(importMetaUrl.replace('file://', '')) +} + +export function getViteAliases() { + return Object.fromEntries( + Object.entries(devAliases).map(([packageName, aliasPath]) => [ + packageName, + resolve(PACKAGES_PATH, aliasPath), + ]), + ) +} diff --git a/packages/@repo/dev-aliases/vitest.mjs b/packages/@repo/dev-aliases/vitest.mjs new file mode 100644 index 00000000000..a1712f6eee4 --- /dev/null +++ b/packages/@repo/dev-aliases/vitest.mjs @@ -0,0 +1,18 @@ +import devAliases from './dev-aliases.cjs' + +import {dirname, resolve} from 'node:path' + +const PACKAGES_PATH = resolve(getDirname(import.meta.url), '..', '..') + +function getDirname(importMetaUrl) { + return dirname(importMetaUrl.replace('file://', '')) +} + +export function getViteAliases() { + return Object.fromEntries( + Object.entries(devAliases).map(([packageName, aliasPath]) => [ + packageName, + resolve(PACKAGES_PATH, aliasPath), + ]), + ) +} diff --git a/packages/@repo/package.bundle/.eslintrc.cjs b/packages/@repo/package.bundle/.eslintrc.cjs index bdf9cc4c1b9..c9a446c5adf 100644 --- a/packages/@repo/package.bundle/.eslintrc.cjs +++ b/packages/@repo/package.bundle/.eslintrc.cjs @@ -1,4 +1,4 @@ -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../../..') diff --git a/packages/@repo/package.bundle/package.json b/packages/@repo/package.bundle/package.json index 344bc9aa684..60f4c92f10d 100644 --- a/packages/@repo/package.bundle/package.json +++ b/packages/@repo/package.bundle/package.json @@ -1,6 +1,6 @@ { "name": "@repo/package.bundle", - "version": "3.57.4", + "version": "3.58.0", "private": true, "description": "Shared package bundle configuration", "main": "./src/package.bundle.ts", diff --git a/packages/@repo/package.bundle/src/package.bundle.ts b/packages/@repo/package.bundle/src/package.bundle.ts index 764ac5f344c..b2279926495 100644 --- a/packages/@repo/package.bundle/src/package.bundle.ts +++ b/packages/@repo/package.bundle/src/package.bundle.ts @@ -15,6 +15,7 @@ export const defaultConfig: UserConfig = { plugins: [react(), tsconfigPaths()], build: { emptyOutDir: true, + sourcemap: true, lib: { entry: {}, formats: ['es'], diff --git a/packages/@repo/package.config/.eslintrc.cjs b/packages/@repo/package.config/.eslintrc.cjs index 99fd6c69224..c9a446c5adf 100644 --- a/packages/@repo/package.config/.eslintrc.cjs +++ b/packages/@repo/package.config/.eslintrc.cjs @@ -1,6 +1,4 @@ -'use strict' - -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../../..') diff --git a/packages/@repo/package.config/package.json b/packages/@repo/package.config/package.json index 058ed8878d4..a846a2f289e 100644 --- a/packages/@repo/package.config/package.json +++ b/packages/@repo/package.config/package.json @@ -1,6 +1,6 @@ { "name": "@repo/package.config", - "version": "3.57.4", + "version": "3.58.0", "private": true, "description": "Shared @sanity/pkg-utils configuration", "main": "./src/package.config.ts", diff --git a/test/config.cjs b/packages/@repo/test-config/jest/createJestConfig.mjs similarity index 81% rename from test/config.cjs rename to packages/@repo/test-config/jest/createJestConfig.mjs index e6aef82601e..174738b1f3d 100644 --- a/test/config.cjs +++ b/packages/@repo/test-config/jest/createJestConfig.mjs @@ -1,18 +1,29 @@ /* eslint-disable tsdoc/syntax */ -const path = require('node:path') -const {escapeRegExp, omit} = require('lodash') -const devAliases = require('../dev/aliases.cjs') +import devAliases from '@repo/dev-aliases' + +import path from 'node:path' +import {escapeRegExp, omit} from 'lodash-es' +import {resolveDirName} from './resolveDirName.mjs' + +const dirname = resolveDirName(import.meta.url) /** Regex for matching file extensions. */ const RE_EXT = /\.[0-9a-z]+$/i /** Path to the root of the Sanity monorepo. */ -const ROOT_PATH = path.resolve(__dirname, '..') +const ROOT_PATH = path.resolve(dirname, '..', '..', '..', '..') + +const jestAliases = Object.fromEntries( + Object.entries(devAliases).map(([packageName, aliasPath]) => [ + packageName, + path.join('./packages', aliasPath), + ]), +) /** The default module name mapper (aka. aliases) for jest tests in the Sanity monorepo. */ const defaultModuleNameMapper = resolveAliasPaths({ - ...aliasesToModuleNameWrapper(devAliases), + ...aliasesToModuleNameWrapper(jestAliases), '.*\\.module\\.css$': './test/mocks/emptyObject', '.*\\.css$': './test/mocks/undefined', }) @@ -23,7 +34,7 @@ const defaultModuleNameMapper = resolveAliasPaths({ * @param {import('jest').Config} config - Initial Jest configuration options. * @returns {import('jest').Config} The resulting Jest configuration options. */ -exports.createJestConfig = function createJestConfig(config = {}) { +export function createJestConfig(config = {}) { const { testMatch = [], setupFiles = [], @@ -57,9 +68,9 @@ exports.createJestConfig = function createJestConfig(config = {}) { '/coverage/', '/lib/', ], - resolver: path.resolve(__dirname, './resolver.cjs'), - testEnvironment: path.resolve(__dirname, './jsdom.jest.env.ts'), - setupFiles: [...setupFiles, path.resolve(__dirname, './setup.ts')], + resolver: path.resolve(dirname, './resolver.cjs'), + testEnvironment: path.resolve(dirname, './jsdom.jest.env.ts'), + setupFiles: [...setupFiles, path.resolve(dirname, './setup.ts')], // testEnvironment: 'jsdom', testEnvironmentOptions: { url: 'http://localhost:3333', @@ -81,18 +92,17 @@ exports.createJestConfig = function createJestConfig(config = {}) { '@babel/preset-env', { targets: { - node: '14', - chrome: '61', - safari: '11.3', - firefox: '60', - edge: '79', + node: '18', + safari: '16', + chrome: '110', + firefox: '110', + edge: '110', }, }, ], '@babel/preset-typescript', ['@babel/preset-react', {runtime: 'automatic'}], ], - plugins: ['@babel/plugin-proposal-class-properties'], }, ], }, diff --git a/packages/@repo/test-config/jest/index.mjs b/packages/@repo/test-config/jest/index.mjs new file mode 100644 index 00000000000..007465687d4 --- /dev/null +++ b/packages/@repo/test-config/jest/index.mjs @@ -0,0 +1,3 @@ +export {createJestConfig} from './createJestConfig.mjs' +export {resolveDirName} from './resolveDirName.mjs' +export {readPackageName} from './readPackageName.mjs' diff --git a/test/jsdom.jest.env.ts b/packages/@repo/test-config/jest/jsdom.jest.env.ts similarity index 85% rename from test/jsdom.jest.env.ts rename to packages/@repo/test-config/jest/jsdom.jest.env.ts index 45bccf3c443..f4144a0f2a8 100644 --- a/test/jsdom.jest.env.ts +++ b/packages/@repo/test-config/jest/jsdom.jest.env.ts @@ -4,7 +4,7 @@ export default class JSDOMEnvironmentWithDomRange extends JSDOMEnvironment { public async setup(): Promise { await super.setup() if (typeof this.global.TextEncoder === 'undefined') { - const {TextEncoder, TextDecoder} = require('util') + const {TextEncoder, TextDecoder} = require('node:util') this.global.TextEncoder = TextEncoder this.global.TextDecoder = TextDecoder } diff --git a/packages/@repo/test-config/jest/readPackageName.mjs b/packages/@repo/test-config/jest/readPackageName.mjs new file mode 100644 index 00000000000..bb6af5b9290 --- /dev/null +++ b/packages/@repo/test-config/jest/readPackageName.mjs @@ -0,0 +1,8 @@ +import fs from 'node:fs' +import path from 'node:path' +import {resolveDirName} from './resolveDirName.mjs' + +export function readPackageName(dirNameUrl) { + return JSON.parse(fs.readFileSync(path.join(resolveDirName(dirNameUrl), 'package.json'), 'utf-8')) + .name +} diff --git a/packages/@repo/test-config/jest/resolveDirName.mjs b/packages/@repo/test-config/jest/resolveDirName.mjs new file mode 100644 index 00000000000..f2e9a10a893 --- /dev/null +++ b/packages/@repo/test-config/jest/resolveDirName.mjs @@ -0,0 +1,5 @@ +import {dirname} from 'node:path' + +export function resolveDirName(importMetaUrl) { + return dirname(importMetaUrl.replace('file://', '')) +} diff --git a/test/resolver.cjs b/packages/@repo/test-config/jest/resolver.cjs similarity index 100% rename from test/resolver.cjs rename to packages/@repo/test-config/jest/resolver.cjs diff --git a/test/setup.ts b/packages/@repo/test-config/jest/setup.ts similarity index 100% rename from test/setup.ts rename to packages/@repo/test-config/jest/setup.ts diff --git a/packages/@repo/test-config/package.json b/packages/@repo/test-config/package.json new file mode 100644 index 00000000000..8c8c09da1e3 --- /dev/null +++ b/packages/@repo/test-config/package.json @@ -0,0 +1,19 @@ +{ + "name": "@repo/test-config", + "version": "3.57.4", + "private": true, + "description": "Test (as in unit test) config shared across packages in the sanity monorepo", + "type": "module", + "exports": { + "./jest": "./jest/index.mjs", + "./vitest": "./vitest/index.mjs" + }, + "devDependencies": { + "@jest/globals": "^29.7.0", + "@repo/dev-aliases": "workspace:*", + "dotenv": "^16.4.5", + "jest-environment-jsdom": "^29.7.0", + "lodash-es": "^4.17.21", + "vitest": "^2.1.1" + } +} diff --git a/packages/@repo/test-config/vitest/index.mjs b/packages/@repo/test-config/vitest/index.mjs new file mode 100644 index 00000000000..3cd2d23085c --- /dev/null +++ b/packages/@repo/test-config/vitest/index.mjs @@ -0,0 +1,28 @@ +import * as vitest from 'vitest/config' +import {getViteAliases} from '@repo/dev-aliases/vite' +import {configDefaults} from 'vitest/config' + +/** + * + * @param [config] {vitest.UserConfig} + * @return {vitest.UserConfig} + */ +export function defineConfig(config) { + return vitest.defineConfig({ + ...config, + test: { + ...config?.test, + alias: {...config?.test?.alias, ...getViteAliases()}, + typecheck: { + ...config?.test?.typecheck, + exclude: [ + ...(configDefaults.typecheck?.exclude || []), + '.tmp/**', + './lib/**', + ...(config?.test?.typecheck?.exclude || []), + ], + }, + exclude: [...configDefaults.exclude, '.tmp/**', './lib/**', ...(config?.test?.exclude || [])], + }, + }) +} diff --git a/packages/@repo/test-exports/package.json b/packages/@repo/test-exports/package.json index 65662eb0a0e..aa0e295e40e 100644 --- a/packages/@repo/test-exports/package.json +++ b/packages/@repo/test-exports/package.json @@ -1,6 +1,6 @@ { "name": "@repo/test-exports", - "version": "3.57.4", + "version": "3.58.0", "private": true, "description": "Ensures that all the monorepo packages that are published works in native node ESM and CJS runtimes", "exports": { diff --git a/packages/@repo/tsconfig/package.json b/packages/@repo/tsconfig/package.json index efee35f18a3..aafa8a7e82e 100644 --- a/packages/@repo/tsconfig/package.json +++ b/packages/@repo/tsconfig/package.json @@ -1,5 +1,5 @@ { "name": "@repo/tsconfig", - "version": "3.57.4", + "version": "3.58.0", "private": true } diff --git a/packages/@sanity/block-tools/.depcheckrc.json b/packages/@sanity/block-tools/.depcheckrc.json index 02c1502f7d2..4599f605fef 100644 --- a/packages/@sanity/block-tools/.depcheckrc.json +++ b/packages/@sanity/block-tools/.depcheckrc.json @@ -1,3 +1,3 @@ { - "ignores": ["@repo/tsconfig", "@sanity/pkg-utils", "react"] + "ignores": ["@repo/tsconfig", "@sanity/pkg-utils", "react", "@vitest/coverage-v8"] } diff --git a/packages/@sanity/block-tools/.eslintrc.cjs b/packages/@sanity/block-tools/.eslintrc.cjs index 99fd6c69224..c9a446c5adf 100644 --- a/packages/@sanity/block-tools/.eslintrc.cjs +++ b/packages/@sanity/block-tools/.eslintrc.cjs @@ -1,6 +1,4 @@ -'use strict' - -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../../..') diff --git a/packages/@sanity/block-tools/jest.config.cjs b/packages/@sanity/block-tools/jest.config.cjs deleted file mode 100644 index 69385d6e759..00000000000 --- a/packages/@sanity/block-tools/jest.config.cjs +++ /dev/null @@ -1,10 +0,0 @@ -'use strict' - -const {createJestConfig} = require('../../../test/config.cjs') - -module.exports = createJestConfig({ - displayName: require('./package.json').name, - testEnvironment: 'node', - rootDir: __dirname, - setupFilesAfterEnv: ['./test/setup.ts'], -}) diff --git a/packages/@sanity/block-tools/package.json b/packages/@sanity/block-tools/package.json index 383e05e232e..f1c8c556a17 100644 --- a/packages/@sanity/block-tools/package.json +++ b/packages/@sanity/block-tools/package.json @@ -1,6 +1,6 @@ { "name": "@sanity/block-tools", - "version": "3.57.4", + "version": "3.58.0", "description": "Can format HTML, Slate JSON or Sanity block array into any other format.", "keywords": [ "sanity", @@ -42,26 +42,28 @@ "build": "pkg-utils build --strict --check --clean", "check:types": "tsc --project tsconfig.lib.json", "clean": "rimraf lib", - "coverage": "NODE_ENV=test jest --coverage", + "coverage": "NODE_ENV=test vitest --coverage", "lint": "eslint .", "prepublishOnly": "turbo run build", - "test": "NODE_ENV=test jest", + "test": "vitest run", "watch": "pkg-utils watch" }, "dependencies": { - "@sanity/types": "3.57.4", + "@sanity/types": "3.58.0", "@types/react": "^18.3.5", "get-random-values-esm": "1.0.2", "lodash": "^4.17.21" }, "devDependencies": { - "@jest/globals": "^29.7.0", "@repo/package.config": "workspace:*", - "@sanity/schema": "3.57.4", + "@repo/test-config": "workspace:*", + "@sanity/schema": "3.58.0", "@types/jsdom": "^20.0.0", "@types/lodash": "^4.17.7", "@vercel/stega": "0.1.2", - "jsdom": "^23.0.1" + "@vitest/coverage-v8": "^2.1.1", + "jsdom": "^23.0.1", + "vitest": "^2.1.1" }, "publishConfig": { "access": "public" diff --git a/packages/@sanity/block-tools/test/setup.ts b/packages/@sanity/block-tools/test/setup.ts index 0ec684b6250..00ca9304e74 100644 --- a/packages/@sanity/block-tools/test/setup.ts +++ b/packages/@sanity/block-tools/test/setup.ts @@ -1,12 +1,10 @@ -import {beforeEach, jest} from '@jest/globals' - -export {} +import {beforeEach, vi} from 'vitest' let mockTestKey = 0 -jest.mock('../src/util/randomKey', () => { +vi.mock('../src/util/randomKey', () => { return { - randomKey: jest.fn().mockImplementation(() => { + randomKey: vi.fn().mockImplementation(() => { return `randomKey${mockTestKey++}` }), } diff --git a/packages/@sanity/block-tools/test/tests/HtmlDeserializer/index.test.ts b/packages/@sanity/block-tools/test/tests/HtmlDeserializer/index.test.ts index bacd549e2ca..65d9d6dab7d 100644 --- a/packages/@sanity/block-tools/test/tests/HtmlDeserializer/index.test.ts +++ b/packages/@sanity/block-tools/test/tests/HtmlDeserializer/index.test.ts @@ -2,8 +2,8 @@ import assert from 'node:assert' import fs from 'node:fs' import path from 'node:path' -import {describe, it} from '@jest/globals' import {JSDOM} from 'jsdom' +import {describe, it} from 'vitest' import * as blockTools from '../../../src' import {type BlockTestFn} from './types' @@ -14,12 +14,12 @@ describe('HtmlDeserializer', () => { if (test[0] === '.' || path.extname(test).length > 0) { return } - it(test, () => { + it(test, async () => { const dir = path.resolve(__dirname, test) const input = fs.readFileSync(path.resolve(dir, 'input.html')).toString() const expected = JSON.parse(fs.readFileSync(path.resolve(dir, 'output.json'), 'utf-8')) // eslint-disable-next-line import/no-dynamic-require - const fn = require(path.resolve(dir)).default as BlockTestFn + const fn = (await import(path.resolve(dir))).default as BlockTestFn const commonOptions = { parseHtml: (html: string) => new JSDOM(html).window.document, } diff --git a/packages/@sanity/block-tools/test/tests/util/__snapshots__/blockContentTypeFeatures.test.ts.snap b/packages/@sanity/block-tools/test/tests/util/__snapshots__/blockContentTypeFeatures.test.ts.snap index 64957f8d273..b12612a1ea5 100644 --- a/packages/@sanity/block-tools/test/tests/util/__snapshots__/blockContentTypeFeatures.test.ts.snap +++ b/packages/@sanity/block-tools/test/tests/util/__snapshots__/blockContentTypeFeatures.test.ts.snap @@ -1,26 +1,26 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`blockContentTypeFeatures will give a sane feature set for the default schema 1`] = ` -Object { - "annotations": Array [ - Object { +exports[`blockContentTypeFeatures > will give a sane feature set for the default schema 1`] = ` +{ + "annotations": [ + { "icon": undefined, "title": "Link", - "type": Object { - "fields": Array [ - Object { + "type": { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "href", - "type": Object { + "type": { "description": "A valid web, email, phone, or relative link.", "jsonType": "string", "name": "url", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Link", - "type": Object { + "type": { "jsonType": "string", "name": "url", "title": "Url", @@ -30,21 +30,21 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "href", - "type": Object { + "type": { "description": "A valid web, email, phone, or relative link.", "jsonType": "string", "name": "url", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Link", - "type": Object { + "type": { "jsonType": "string", "name": "url", "title": "Url", @@ -56,24 +56,24 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "i18nTitleKey": "inputs.portable-text.annotation.link", "jsonType": "object", "name": "link", - "options": Object { - "modal": Object { + "options": { + "modal": { "type": "popover", }, }, - "orderings": Array [], - "preview": Object { + "orderings": [], + "preview": { "prepare": [Function], - "select": Object { + "select": { "href": "href", }, }, "title": "Link", - "type": Object { + "type": { "jsonType": "object", "name": "object", "title": "Object", @@ -83,117 +83,117 @@ Object { "value": "link", }, ], - "decorators": Array [ - Object { + "decorators": [ + { "i18nTitleKey": "inputs.portable-text.decorator.strong", "title": "Strong", "value": "strong", }, - Object { + { "i18nTitleKey": "inputs.portable-text.decorator.emphasis", "title": "Italic", "value": "em", }, - Object { + { "i18nTitleKey": "inputs.portable-text.decorator.code", "title": "Code", "value": "code", }, - Object { + { "i18nTitleKey": "inputs.portable-text.decorator.underline", "title": "Underline", "value": "underline", }, - Object { + { "i18nTitleKey": "inputs.portable-text.decorator.strike-through", "title": "Strike", "value": "strike-through", }, ], - "lists": Array [ - Object { + "lists": [ + { "i18nTitleKey": "inputs.portable-text.list-type.bullet", "title": "Bulleted list", "value": "bullet", }, - Object { + { "i18nTitleKey": "inputs.portable-text.list-type.number", "title": "Numbered list", "value": "number", }, ], - "styles": Array [ - Object { + "styles": [ + { "i18nTitleKey": "inputs.portable-text.style.normal", "title": "Normal", "value": "normal", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.h1", "title": "Heading 1", "value": "h1", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.h2", "title": "Heading 2", "value": "h2", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.h3", "title": "Heading 3", "value": "h3", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.h4", "title": "Heading 4", "value": "h4", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.h5", "title": "Heading 5", "value": "h5", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.h6", "title": "Heading 6", "value": "h6", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.quote", "title": "Quote", "value": "blockquote", }, ], - "types": Object { - "block": Object { + "types": { + "block": { "jsonType": "array", "name": "array", - "of": Array [ - Object { - "fields": Array [ - Object { + "of": [ + { + "fields": [ + { "name": "children", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { - "annotations": Array [ - Object { - "fields": Array [ - Object { + "of": [ + { + "annotations": [ + { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "href", - "type": Object { + "type": { "description": "A valid web, email, phone, or relative link.", "jsonType": "string", "name": "url", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Link", - "type": Object { + "type": { "jsonType": "string", "name": "url", "title": "Url", @@ -203,21 +203,21 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "href", - "type": Object { + "type": { "description": "A valid web, email, phone, or relative link.", "jsonType": "string", "name": "url", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Link", - "type": Object { + "type": { "jsonType": "string", "name": "url", "title": "Url", @@ -229,24 +229,24 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "i18nTitleKey": "inputs.portable-text.annotation.link", "jsonType": "object", "name": "link", - "options": Object { - "modal": Object { + "options": { + "modal": { "type": "popover", }, }, - "orderings": Array [], - "preview": Object { + "orderings": [], + "preview": { "prepare": [Function], - "select": Object { + "select": { "href": "href", }, }, "title": "Link", - "type": Object { + "type": { "jsonType": "object", "name": "object", "title": "Object", @@ -254,48 +254,48 @@ Object { }, }, ], - "decorators": Array [ - Object { + "decorators": [ + { "i18nTitleKey": "inputs.portable-text.decorator.strong", "title": "Strong", "value": "strong", }, - Object { + { "i18nTitleKey": "inputs.portable-text.decorator.emphasis", "title": "Italic", "value": "em", }, - Object { + { "i18nTitleKey": "inputs.portable-text.decorator.code", "title": "Code", "value": "code", }, - Object { + { "i18nTitleKey": "inputs.portable-text.decorator.underline", "title": "Underline", "value": "underline", }, - Object { + { "i18nTitleKey": "inputs.portable-text.decorator.strike-through", "title": "Strike", "value": "strike-through", }, ], - "fields": Array [ - Object { + "fields": [ + { "name": "marks", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { + "of": [ + { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "String", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -304,24 +304,24 @@ Object { }, ], "title": "Marks", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, - Object { + { "name": "text", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Text", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -331,18 +331,18 @@ Object { }, ], "jsonType": "object", - "marks": Array [], + "marks": [], "name": "span", - "options": Object {}, - "preview": Object { + "options": {}, + "preview": { "prepare": [Function], - "select": Object { + "select": { "marks": "marks", "text": "text", }, }, "title": "Span", - "type": Object { + "type": { "jsonType": "object", "name": "span", "title": "Span", @@ -351,68 +351,68 @@ Object { }, ], "title": "Content", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, - Object { + { "name": "style", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "options": Object { - "list": Array [ - Object { + "options": { + "list": [ + { "i18nTitleKey": "inputs.portable-text.style.normal", "title": "Normal", "value": "normal", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.h1", "title": "Heading 1", "value": "h1", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.h2", "title": "Heading 2", "value": "h2", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.h3", "title": "Heading 3", "value": "h3", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.h4", "title": "Heading 4", "value": "h4", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.h5", "title": "Heading 5", "value": "h5", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.h6", "title": "Heading 6", "value": "h6", }, - Object { + { "i18nTitleKey": "inputs.portable-text.style.quote", "title": "Quote", "value": "blockquote", }, ], }, - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Style", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -420,30 +420,30 @@ Object { }, }, }, - Object { + { "name": "listItem", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "options": Object { - "list": Array [ - Object { + "options": { + "list": [ + { "i18nTitleKey": "inputs.portable-text.list-type.bullet", "title": "Bulleted list", "value": "bullet", }, - Object { + { "i18nTitleKey": "inputs.portable-text.list-type.number", "title": "Numbered list", "value": "number", }, ], }, - "preview": Object { + "preview": { "prepare": [Function], }, "title": "List type", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -451,27 +451,27 @@ Object { }, }, }, - Object { + { "name": "markDefs", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { - "fields": Array [ - Object { + "of": [ + { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "href", - "type": Object { + "type": { "description": "A valid web, email, phone, or relative link.", "jsonType": "string", "name": "url", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Link", - "type": Object { + "type": { "jsonType": "string", "name": "url", "title": "Url", @@ -481,21 +481,21 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "href", - "type": Object { + "type": { "description": "A valid web, email, phone, or relative link.", "jsonType": "string", "name": "url", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Link", - "type": Object { + "type": { "jsonType": "string", "name": "url", "title": "Url", @@ -507,24 +507,24 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "i18nTitleKey": "inputs.portable-text.annotation.link", "jsonType": "object", "name": "link", - "options": Object { - "modal": Object { + "options": { + "modal": { "type": "popover", }, }, - "orderings": Array [], - "preview": Object { + "orderings": [], + "preview": { "prepare": [Function], - "select": Object { + "select": { "href": "href", }, }, "title": "Link", - "type": Object { + "type": { "jsonType": "object", "name": "object", "title": "Object", @@ -533,24 +533,24 @@ Object { }, ], "title": "Mark definitions", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, - Object { + { "name": "level", - "type": Object { + "type": { "jsonType": "number", "name": "number", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Indentation", - "type": Object { + "type": { "jsonType": "number", "name": "number", "title": "Number", @@ -561,33 +561,33 @@ Object { ], "jsonType": "object", "name": "block", - "options": Object {}, - "preview": Object { + "options": {}, + "preview": { "prepare": [Function], - "select": Object {}, + "select": {}, }, "title": "Block", - "type": Object { + "type": { "jsonType": "object", "name": "block", "title": "Block", "type": null, }, }, - Object { - "fields": Array [ - Object { + { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "code", - "type": Object { + "type": { "jsonType": "string", "name": "text", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Code", - "type": Object { + "type": { "jsonType": "string", "name": "text", "title": "Text", @@ -595,18 +595,18 @@ Object { }, }, }, - Object { + { "fieldset": undefined, "group": undefined, "name": "language", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Language", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -614,22 +614,22 @@ Object { }, }, }, - Object { + { "fieldset": undefined, "group": undefined, "name": "highlightedLines", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { + "of": [ + { "jsonType": "number", "name": "number", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Highlighted line", - "type": Object { + "type": { "jsonType": "number", "name": "number", "title": "Number", @@ -638,29 +638,29 @@ Object { }, ], "title": "Highlighted lines", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "code", - "type": Object { + "type": { "jsonType": "string", "name": "text", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Code", - "type": Object { + "type": { "jsonType": "string", "name": "text", "title": "Text", @@ -670,19 +670,19 @@ Object { }, "single": true, }, - Object { - "field": Object { + { + "field": { "fieldset": undefined, "group": undefined, "name": "language", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Language", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -692,23 +692,23 @@ Object { }, "single": true, }, - Object { - "field": Object { + { + "field": { "fieldset": undefined, "group": undefined, "name": "highlightedLines", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { + "of": [ + { "jsonType": "number", "name": "number", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Highlighted line", - "type": Object { + "type": { "jsonType": "number", "name": "number", "title": "Number", @@ -717,10 +717,10 @@ Object { }, ], "title": "Highlighted lines", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, @@ -728,20 +728,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "code", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "language", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.language", "ns": "studio", }, @@ -750,13 +750,13 @@ Object { "title": "Language", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "language", }, }, "title": "Code", - "type": Object { + "type": { "jsonType": "object", "name": "object", "title": "Object", @@ -765,28 +765,28 @@ Object { }, ], "title": "Body", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, - "blockObjects": Array [ - Object { - "fields": Array [ - Object { + "blockObjects": [ + { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "code", - "type": Object { + "type": { "jsonType": "string", "name": "text", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Code", - "type": Object { + "type": { "jsonType": "string", "name": "text", "title": "Text", @@ -794,18 +794,18 @@ Object { }, }, }, - Object { + { "fieldset": undefined, "group": undefined, "name": "language", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Language", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -813,22 +813,22 @@ Object { }, }, }, - Object { + { "fieldset": undefined, "group": undefined, "name": "highlightedLines", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { + "of": [ + { "jsonType": "number", "name": "number", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Highlighted line", - "type": Object { + "type": { "jsonType": "number", "name": "number", "title": "Number", @@ -837,29 +837,29 @@ Object { }, ], "title": "Highlighted lines", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "code", - "type": Object { + "type": { "jsonType": "string", "name": "text", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Code", - "type": Object { + "type": { "jsonType": "string", "name": "text", "title": "Text", @@ -869,19 +869,19 @@ Object { }, "single": true, }, - Object { - "field": Object { + { + "field": { "fieldset": undefined, "group": undefined, "name": "language", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Language", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -891,23 +891,23 @@ Object { }, "single": true, }, - Object { - "field": Object { + { + "field": { "fieldset": undefined, "group": undefined, "name": "highlightedLines", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { + "of": [ + { "jsonType": "number", "name": "number", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Highlighted line", - "type": Object { + "type": { "jsonType": "number", "name": "number", "title": "Number", @@ -916,10 +916,10 @@ Object { }, ], "title": "Highlighted lines", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, @@ -927,20 +927,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "code", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "language", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.language", "ns": "studio", }, @@ -949,13 +949,13 @@ Object { "title": "Language", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "language", }, }, "title": "Code", - "type": Object { + "type": { "jsonType": "object", "name": "object", "title": "Object", @@ -963,24 +963,24 @@ Object { }, }, ], - "inlineObjects": Array [], - "span": Object { - "annotations": Array [ - Object { - "fields": Array [ - Object { + "inlineObjects": [], + "span": { + "annotations": [ + { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "href", - "type": Object { + "type": { "description": "A valid web, email, phone, or relative link.", "jsonType": "string", "name": "url", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Link", - "type": Object { + "type": { "jsonType": "string", "name": "url", "title": "Url", @@ -990,21 +990,21 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "href", - "type": Object { + "type": { "description": "A valid web, email, phone, or relative link.", "jsonType": "string", "name": "url", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Link", - "type": Object { + "type": { "jsonType": "string", "name": "url", "title": "Url", @@ -1016,24 +1016,24 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "i18nTitleKey": "inputs.portable-text.annotation.link", "jsonType": "object", "name": "link", - "options": Object { - "modal": Object { + "options": { + "modal": { "type": "popover", }, }, - "orderings": Array [], - "preview": Object { + "orderings": [], + "preview": { "prepare": [Function], - "select": Object { + "select": { "href": "href", }, }, "title": "Link", - "type": Object { + "type": { "jsonType": "object", "name": "object", "title": "Object", @@ -1041,48 +1041,48 @@ Object { }, }, ], - "decorators": Array [ - Object { + "decorators": [ + { "i18nTitleKey": "inputs.portable-text.decorator.strong", "title": "Strong", "value": "strong", }, - Object { + { "i18nTitleKey": "inputs.portable-text.decorator.emphasis", "title": "Italic", "value": "em", }, - Object { + { "i18nTitleKey": "inputs.portable-text.decorator.code", "title": "Code", "value": "code", }, - Object { + { "i18nTitleKey": "inputs.portable-text.decorator.underline", "title": "Underline", "value": "underline", }, - Object { + { "i18nTitleKey": "inputs.portable-text.decorator.strike-through", "title": "Strike", "value": "strike-through", }, ], - "fields": Array [ - Object { + "fields": [ + { "name": "marks", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { + "of": [ + { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "String", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1091,24 +1091,24 @@ Object { }, ], "title": "Marks", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, - Object { + { "name": "text", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Text", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1118,18 +1118,18 @@ Object { }, ], "jsonType": "object", - "marks": Array [], + "marks": [], "name": "span", - "options": Object {}, - "preview": Object { + "options": {}, + "preview": { "prepare": [Function], - "select": Object { + "select": { "marks": "marks", "text": "text", }, }, "title": "Span", - "type": Object { + "type": { "jsonType": "object", "name": "span", "title": "Span", @@ -1140,24 +1140,24 @@ Object { } `; -exports[`blockContentTypeFeatures will give spesific features for a custom schema 1`] = ` -Object { - "annotations": Array [ - Object { +exports[`blockContentTypeFeatures > will give spesific features for a custom schema 1`] = ` +{ + "annotations": [ + { "icon": undefined, "title": "Author", - "type": Object { - "fields": Array [ - Object { + "type": { + "fields": [ + { "name": "_ref", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Referenced document ID", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1165,16 +1165,16 @@ Object { }, }, }, - Object { + { "name": "_weak", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Weak reference", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", "title": "Boolean", @@ -1183,18 +1183,18 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "name": "_ref", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Referenced document ID", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1204,17 +1204,17 @@ Object { }, "single": true, }, - Object { - "field": Object { + { + "field": { "name": "_weak", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Weak reference", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", "title": "Boolean", @@ -1228,41 +1228,41 @@ Object { "jsonType": "object", "name": "author", "title": "Author", - "to": Array [ - Object { - "__experimental_search": Array [ - Object { - "path": Array [ + "to": [ + { + "__experimental_search": [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, }, ], - "fields": Array [ - Object { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1271,20 +1271,20 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1295,20 +1295,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "author", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "name", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.name", "ns": "studio", }, @@ -1317,26 +1317,26 @@ Object { "title": "Name", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "name", }, }, "title": "Author", - "type": Object { - "fields": Array [ - Object { + "type": { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1345,20 +1345,20 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1369,20 +1369,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "author", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "name", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.name", "ns": "studio", }, @@ -1391,33 +1391,33 @@ Object { "title": "Name", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "name", }, }, "title": "Author", - "type": Object { + "type": { "jsonType": "object", "name": "document", "title": "Document", "type": null, }, - Symbol(__cachedStringFields_4): Array [ - Object { - "path": Array [ + Symbol(__cachedStringFields_4): [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, @@ -1426,7 +1426,7 @@ Object { }, }, ], - "type": Object { + "type": { "jsonType": "object", "name": "reference", "title": "Reference", @@ -1436,95 +1436,95 @@ Object { "value": "author", }, ], - "decorators": Array [ - Object { + "decorators": [ + { "title": "Strong", "value": "strong", }, - Object { + { "title": "Emphasis", "value": "em", }, - Object { + { "title": "Code", "value": "code", }, - Object { + { "title": "Strike through", "value": "strike-through", }, - Object { + { "title": "Highlight", "value": "highlight", }, - Object { + { "title": "Subscript", "value": "sub", }, - Object { + { "title": "Superscript", "value": "sup", }, - Object { + { "title": "Mark", "value": "mark", }, - Object { + { "title": "Inserted", "value": "ins", }, - Object { + { "title": "Small", "value": "small", }, ], - "lists": Array [ - Object { + "lists": [ + { "title": "Numbered", "value": "number", }, ], - "styles": Array [ - Object { + "styles": [ + { "title": "Normal", "value": "normal", }, - Object { + { "title": "H1", "value": "h1", }, - Object { + { "title": "H2", "value": "h2", }, ], - "types": Object { - "block": Object { + "types": { + "block": { "jsonType": "array", "name": "array", - "of": Array [ - Object { - "fields": Array [ - Object { + "of": [ + { + "fields": [ + { "name": "children", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { - "annotations": Array [ - Object { - "fields": Array [ - Object { + "of": [ + { + "annotations": [ + { + "fields": [ + { "name": "_ref", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Referenced document ID", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1532,16 +1532,16 @@ Object { }, }, }, - Object { + { "name": "_weak", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Weak reference", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", "title": "Boolean", @@ -1550,18 +1550,18 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "name": "_ref", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Referenced document ID", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1571,17 +1571,17 @@ Object { }, "single": true, }, - Object { - "field": Object { + { + "field": { "name": "_weak", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Weak reference", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", "title": "Boolean", @@ -1595,41 +1595,41 @@ Object { "jsonType": "object", "name": "author", "title": "Author", - "to": Array [ - Object { - "__experimental_search": Array [ - Object { - "path": Array [ + "to": [ + { + "__experimental_search": [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, }, ], - "fields": Array [ - Object { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1638,20 +1638,20 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1662,20 +1662,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "author", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "name", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.name", "ns": "studio", }, @@ -1684,26 +1684,26 @@ Object { "title": "Name", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "name", }, }, "title": "Author", - "type": Object { - "fields": Array [ - Object { + "type": { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1712,20 +1712,20 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1736,20 +1736,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "author", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "name", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.name", "ns": "studio", }, @@ -1758,33 +1758,33 @@ Object { "title": "Name", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "name", }, }, "title": "Author", - "type": Object { + "type": { "jsonType": "object", "name": "document", "title": "Document", "type": null, }, - Symbol(__cachedStringFields_4): Array [ - Object { - "path": Array [ + Symbol(__cachedStringFields_4): [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, @@ -1793,7 +1793,7 @@ Object { }, }, ], - "type": Object { + "type": { "jsonType": "object", "name": "reference", "title": "Reference", @@ -1801,63 +1801,63 @@ Object { }, }, ], - "decorators": Array [ - Object { + "decorators": [ + { "title": "Strong", "value": "strong", }, - Object { + { "title": "Emphasis", "value": "em", }, - Object { + { "title": "Code", "value": "code", }, - Object { + { "title": "Strike through", "value": "strike-through", }, - Object { + { "title": "Highlight", "value": "highlight", }, - Object { + { "title": "Subscript", "value": "sub", }, - Object { + { "title": "Superscript", "value": "sup", }, - Object { + { "title": "Mark", "value": "mark", }, - Object { + { "title": "Inserted", "value": "ins", }, - Object { + { "title": "Small", "value": "small", }, ], - "fields": Array [ - Object { + "fields": [ + { "name": "marks", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { + "of": [ + { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "String", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1866,24 +1866,24 @@ Object { }, ], "title": "Marks", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, - Object { + { "name": "text", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Text", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1893,18 +1893,18 @@ Object { }, ], "jsonType": "object", - "marks": Array [], + "marks": [], "name": "span", - "options": Object {}, - "preview": Object { + "options": {}, + "preview": { "prepare": [Function], - "select": Object { + "select": { "marks": "marks", "text": "text", }, }, "title": "Span", - "type": Object { + "type": { "jsonType": "object", "name": "span", "title": "Span", @@ -1913,40 +1913,40 @@ Object { }, ], "title": "Content", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, - Object { + { "name": "style", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "options": Object { - "list": Array [ - Object { + "options": { + "list": [ + { "title": "Normal", "value": "normal", }, - Object { + { "title": "H1", "value": "h1", }, - Object { + { "title": "H2", "value": "h2", }, ], }, - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Style", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1954,24 +1954,24 @@ Object { }, }, }, - Object { + { "name": "listItem", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "options": Object { - "list": Array [ - Object { + "options": { + "list": [ + { "title": "Numbered", "value": "number", }, ], }, - "preview": Object { + "preview": { "prepare": [Function], }, "title": "List type", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -1979,24 +1979,24 @@ Object { }, }, }, - Object { + { "name": "markDefs", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { - "fields": Array [ - Object { + "of": [ + { + "fields": [ + { "name": "_ref", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Referenced document ID", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2004,16 +2004,16 @@ Object { }, }, }, - Object { + { "name": "_weak", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Weak reference", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", "title": "Boolean", @@ -2022,18 +2022,18 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "name": "_ref", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Referenced document ID", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2043,17 +2043,17 @@ Object { }, "single": true, }, - Object { - "field": Object { + { + "field": { "name": "_weak", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Weak reference", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", "title": "Boolean", @@ -2067,41 +2067,41 @@ Object { "jsonType": "object", "name": "author", "title": "Author", - "to": Array [ - Object { - "__experimental_search": Array [ - Object { - "path": Array [ + "to": [ + { + "__experimental_search": [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, }, ], - "fields": Array [ - Object { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2110,20 +2110,20 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2134,20 +2134,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "author", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "name", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.name", "ns": "studio", }, @@ -2156,26 +2156,26 @@ Object { "title": "Name", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "name", }, }, "title": "Author", - "type": Object { - "fields": Array [ - Object { + "type": { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2184,20 +2184,20 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2208,20 +2208,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "author", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "name", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.name", "ns": "studio", }, @@ -2230,54 +2230,54 @@ Object { "title": "Name", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "name", }, }, "title": "Author", - "type": Object { + "type": { "jsonType": "object", "name": "document", "title": "Document", "type": null, }, - Symbol(__cachedStringFields_4): Array [ - Object { - "path": Array [ + Symbol(__cachedStringFields_4): [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, }, ], }, - Symbol(__cachedStringFields_4): Array [ - Object { - "path": Array [ + Symbol(__cachedStringFields_4): [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, @@ -2285,7 +2285,7 @@ Object { ], }, ], - "type": Object { + "type": { "jsonType": "object", "name": "reference", "title": "Reference", @@ -2294,24 +2294,24 @@ Object { }, ], "title": "Mark definitions", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, - Object { + { "name": "level", - "type": Object { + "type": { "jsonType": "number", "name": "number", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Indentation", - "type": Object { + "type": { "jsonType": "number", "name": "number", "title": "Number", @@ -2322,34 +2322,34 @@ Object { ], "jsonType": "object", "name": "customBlock", - "options": Object {}, - "preview": Object { + "options": {}, + "preview": { "prepare": [Function], - "select": Object {}, + "select": {}, }, "title": "Block", - "type": Object { - "fields": Array [ - Object { + "type": { + "fields": [ + { "name": "children", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { - "annotations": Array [ - Object { - "fields": Array [ - Object { + "of": [ + { + "annotations": [ + { + "fields": [ + { "name": "_ref", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Referenced document ID", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2357,16 +2357,16 @@ Object { }, }, }, - Object { + { "name": "_weak", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Weak reference", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", "title": "Boolean", @@ -2375,18 +2375,18 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "name": "_ref", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Referenced document ID", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2396,17 +2396,17 @@ Object { }, "single": true, }, - Object { - "field": Object { + { + "field": { "name": "_weak", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Weak reference", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", "title": "Boolean", @@ -2420,41 +2420,41 @@ Object { "jsonType": "object", "name": "author", "title": "Author", - "to": Array [ - Object { - "__experimental_search": Array [ - Object { - "path": Array [ + "to": [ + { + "__experimental_search": [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, }, ], - "fields": Array [ - Object { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2463,20 +2463,20 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2487,20 +2487,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "author", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "name", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.name", "ns": "studio", }, @@ -2509,26 +2509,26 @@ Object { "title": "Name", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "name", }, }, "title": "Author", - "type": Object { - "fields": Array [ - Object { + "type": { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2537,20 +2537,20 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2561,20 +2561,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "author", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "name", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.name", "ns": "studio", }, @@ -2583,33 +2583,33 @@ Object { "title": "Name", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "name", }, }, "title": "Author", - "type": Object { + "type": { "jsonType": "object", "name": "document", "title": "Document", "type": null, }, - Symbol(__cachedStringFields_4): Array [ - Object { - "path": Array [ + Symbol(__cachedStringFields_4): [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, @@ -2618,7 +2618,7 @@ Object { }, }, ], - "type": Object { + "type": { "jsonType": "object", "name": "reference", "title": "Reference", @@ -2626,63 +2626,63 @@ Object { }, }, ], - "decorators": Array [ - Object { + "decorators": [ + { "title": "Strong", "value": "strong", }, - Object { + { "title": "Emphasis", "value": "em", }, - Object { + { "title": "Code", "value": "code", }, - Object { + { "title": "Strike through", "value": "strike-through", }, - Object { + { "title": "Highlight", "value": "highlight", }, - Object { + { "title": "Subscript", "value": "sub", }, - Object { + { "title": "Superscript", "value": "sup", }, - Object { + { "title": "Mark", "value": "mark", }, - Object { + { "title": "Inserted", "value": "ins", }, - Object { + { "title": "Small", "value": "small", }, ], - "fields": Array [ - Object { + "fields": [ + { "name": "marks", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { + "of": [ + { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "String", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2691,24 +2691,24 @@ Object { }, ], "title": "Marks", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, - Object { + { "name": "text", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Text", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2718,18 +2718,18 @@ Object { }, ], "jsonType": "object", - "marks": Array [], + "marks": [], "name": "span", - "options": Object {}, - "preview": Object { + "options": {}, + "preview": { "prepare": [Function], - "select": Object { + "select": { "marks": "marks", "text": "text", }, }, "title": "Span", - "type": Object { + "type": { "jsonType": "object", "name": "span", "title": "Span", @@ -2738,40 +2738,40 @@ Object { }, ], "title": "Content", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, - Object { + { "name": "style", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "options": Object { - "list": Array [ - Object { + "options": { + "list": [ + { "title": "Normal", "value": "normal", }, - Object { + { "title": "H1", "value": "h1", }, - Object { + { "title": "H2", "value": "h2", }, ], }, - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Style", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2779,24 +2779,24 @@ Object { }, }, }, - Object { + { "name": "listItem", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "options": Object { - "list": Array [ - Object { + "options": { + "list": [ + { "title": "Numbered", "value": "number", }, ], }, - "preview": Object { + "preview": { "prepare": [Function], }, "title": "List type", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2804,24 +2804,24 @@ Object { }, }, }, - Object { + { "name": "markDefs", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { - "fields": Array [ - Object { + "of": [ + { + "fields": [ + { "name": "_ref", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Referenced document ID", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2829,16 +2829,16 @@ Object { }, }, }, - Object { + { "name": "_weak", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Weak reference", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", "title": "Boolean", @@ -2847,18 +2847,18 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "name": "_ref", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Referenced document ID", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2868,17 +2868,17 @@ Object { }, "single": true, }, - Object { - "field": Object { + { + "field": { "name": "_weak", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Weak reference", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", "title": "Boolean", @@ -2892,41 +2892,41 @@ Object { "jsonType": "object", "name": "author", "title": "Author", - "to": Array [ - Object { - "__experimental_search": Array [ - Object { - "path": Array [ + "to": [ + { + "__experimental_search": [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, }, ], - "fields": Array [ - Object { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2935,20 +2935,20 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -2959,20 +2959,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "author", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "name", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.name", "ns": "studio", }, @@ -2981,26 +2981,26 @@ Object { "title": "Name", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "name", }, }, "title": "Author", - "type": Object { - "fields": Array [ - Object { + "type": { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -3009,20 +3009,20 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -3033,20 +3033,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "author", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "name", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.name", "ns": "studio", }, @@ -3055,54 +3055,54 @@ Object { "title": "Name", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "name", }, }, "title": "Author", - "type": Object { + "type": { "jsonType": "object", "name": "document", "title": "Document", "type": null, }, - Symbol(__cachedStringFields_4): Array [ - Object { - "path": Array [ + Symbol(__cachedStringFields_4): [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, }, ], }, - Symbol(__cachedStringFields_4): Array [ - Object { - "path": Array [ + Symbol(__cachedStringFields_4): [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, @@ -3110,7 +3110,7 @@ Object { ], }, ], - "type": Object { + "type": { "jsonType": "object", "name": "reference", "title": "Reference", @@ -3119,24 +3119,24 @@ Object { }, ], "title": "Mark definitions", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, - Object { + { "name": "level", - "type": Object { + "type": { "jsonType": "number", "name": "number", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Indentation", - "type": Object { + "type": { "jsonType": "number", "name": "number", "title": "Number", @@ -3147,13 +3147,13 @@ Object { ], "jsonType": "object", "name": "customBlock", - "options": Object {}, - "preview": Object { + "options": {}, + "preview": { "prepare": [Function], - "select": Object {}, + "select": {}, }, "title": "Block", - "type": Object { + "type": { "jsonType": "object", "name": "block", "title": "Block", @@ -3163,29 +3163,29 @@ Object { }, ], "title": "Body", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, - "blockObjects": Array [], - "inlineObjects": Array [], - "span": Object { - "annotations": Array [ - Object { - "fields": Array [ - Object { + "blockObjects": [], + "inlineObjects": [], + "span": { + "annotations": [ + { + "fields": [ + { "name": "_ref", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Referenced document ID", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -3193,16 +3193,16 @@ Object { }, }, }, - Object { + { "name": "_weak", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Weak reference", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", "title": "Boolean", @@ -3211,18 +3211,18 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "name": "_ref", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Referenced document ID", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -3232,17 +3232,17 @@ Object { }, "single": true, }, - Object { - "field": Object { + { + "field": { "name": "_weak", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Weak reference", - "type": Object { + "type": { "jsonType": "boolean", "name": "boolean", "title": "Boolean", @@ -3256,41 +3256,41 @@ Object { "jsonType": "object", "name": "author", "title": "Author", - "to": Array [ - Object { - "__experimental_search": Array [ - Object { - "path": Array [ + "to": [ + { + "__experimental_search": [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, }, ], - "fields": Array [ - Object { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -3299,20 +3299,20 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -3323,20 +3323,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "author", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "name", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.name", "ns": "studio", }, @@ -3345,26 +3345,26 @@ Object { "title": "Name", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "name", }, }, "title": "Author", - "type": Object { - "fields": Array [ - Object { + "type": { + "fields": [ + { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -3373,20 +3373,20 @@ Object { }, }, ], - "fieldsets": Array [ - Object { - "field": Object { + "fieldsets": [ + { + "field": { "fieldset": undefined, "group": undefined, "name": "name", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Name", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -3397,20 +3397,20 @@ Object { "single": true, }, ], - "groups": Array [], + "groups": [], "jsonType": "object", "name": "author", - "options": Object {}, - "orderings": Array [ - Object { - "by": Array [ - Object { + "options": {}, + "orderings": [ + { + "by": [ + { "direction": "asc", "field": "name", }, ], - "i18n": Object { - "title": Object { + "i18n": { + "title": { "key": "default-orderings.name", "ns": "studio", }, @@ -3419,33 +3419,33 @@ Object { "title": "Name", }, ], - "preview": Object { - "select": Object { + "preview": { + "select": { "title": "name", }, }, "title": "Author", - "type": Object { + "type": { "jsonType": "object", "name": "document", "title": "Document", "type": null, }, - Symbol(__cachedStringFields_4): Array [ - Object { - "path": Array [ + Symbol(__cachedStringFields_4): [ + { + "path": [ "_id", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "_type", ], "weight": 1, }, - Object { - "path": Array [ + { + "path": [ "name", ], "weight": 10, @@ -3454,7 +3454,7 @@ Object { }, }, ], - "type": Object { + "type": { "jsonType": "object", "name": "reference", "title": "Reference", @@ -3462,63 +3462,63 @@ Object { }, }, ], - "decorators": Array [ - Object { + "decorators": [ + { "title": "Strong", "value": "strong", }, - Object { + { "title": "Emphasis", "value": "em", }, - Object { + { "title": "Code", "value": "code", }, - Object { + { "title": "Strike through", "value": "strike-through", }, - Object { + { "title": "Highlight", "value": "highlight", }, - Object { + { "title": "Subscript", "value": "sub", }, - Object { + { "title": "Superscript", "value": "sup", }, - Object { + { "title": "Mark", "value": "mark", }, - Object { + { "title": "Inserted", "value": "ins", }, - Object { + { "title": "Small", "value": "small", }, ], - "fields": Array [ - Object { + "fields": [ + { "name": "marks", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [ - Object { + "of": [ + { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "String", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -3527,24 +3527,24 @@ Object { }, ], "title": "Marks", - "type": Object { + "type": { "jsonType": "array", "name": "array", - "of": Array [], + "of": [], "type": null, }, }, }, - Object { + { "name": "text", - "type": Object { + "type": { "jsonType": "string", "name": "string", - "preview": Object { + "preview": { "prepare": [Function], }, "title": "Text", - "type": Object { + "type": { "jsonType": "string", "name": "string", "title": "String", @@ -3554,18 +3554,18 @@ Object { }, ], "jsonType": "object", - "marks": Array [], + "marks": [], "name": "span", - "options": Object {}, - "preview": Object { + "options": {}, + "preview": { "prepare": [Function], - "select": Object { + "select": { "marks": "marks", "text": "text", }, }, "title": "Span", - "type": Object { + "type": { "jsonType": "object", "name": "span", "title": "Span", diff --git a/packages/@sanity/block-tools/test/tests/util/blockContentTypeFeatures.test.ts b/packages/@sanity/block-tools/test/tests/util/blockContentTypeFeatures.test.ts index 2df70279822..bad0ef8f691 100644 --- a/packages/@sanity/block-tools/test/tests/util/blockContentTypeFeatures.test.ts +++ b/packages/@sanity/block-tools/test/tests/util/blockContentTypeFeatures.test.ts @@ -1,5 +1,5 @@ -import {describe, expect, it} from '@jest/globals' import {type ObjectSchemaType} from '@sanity/types' +import {describe, expect, it} from 'vitest' import blockContentTypeFeatures from '../../../src/util/blockContentTypeFeatures' import customSchema from '../../fixtures/customSchema' diff --git a/packages/@sanity/block-tools/test/tests/util/normalizeBlock.test.ts b/packages/@sanity/block-tools/test/tests/util/normalizeBlock.test.ts index 030624b1c5e..954b47e9bc5 100644 --- a/packages/@sanity/block-tools/test/tests/util/normalizeBlock.test.ts +++ b/packages/@sanity/block-tools/test/tests/util/normalizeBlock.test.ts @@ -1,6 +1,6 @@ import assert from 'node:assert' -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' import {normalizeBlock} from '../../../src/util/normalizeBlock' @@ -22,7 +22,7 @@ describe('normalizeBlock', () => { }, ], } - assert.deepEqual(normalizeBlock(block), { + assert.deepStrictEqual(normalizeBlock(block), { _key: 'randomKey0', _type: 'block', children: [ diff --git a/packages/@sanity/block-tools/vitest.config.mts b/packages/@sanity/block-tools/vitest.config.mts new file mode 100644 index 00000000000..38b35dc7aec --- /dev/null +++ b/packages/@sanity/block-tools/vitest.config.mts @@ -0,0 +1,8 @@ +import {defineConfig} from '@repo/test-config/vitest' + +export default defineConfig({ + test: { + environment: 'node', + setupFiles: ['./test/setup.ts'], + }, +}) diff --git a/packages/@sanity/cli/.eslintrc.cjs b/packages/@sanity/cli/.eslintrc.cjs index 0b17a2291bd..2b6c3ecb066 100644 --- a/packages/@sanity/cli/.eslintrc.cjs +++ b/packages/@sanity/cli/.eslintrc.cjs @@ -1,6 +1,4 @@ -'use strict' - -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../../..') diff --git a/packages/@sanity/cli/jest.config.cjs b/packages/@sanity/cli/jest.config.mjs similarity index 52% rename from packages/@sanity/cli/jest.config.cjs rename to packages/@sanity/cli/jest.config.mjs index 4fc83258bb1..297fd47b744 100644 --- a/packages/@sanity/cli/jest.config.cjs +++ b/packages/@sanity/cli/jest.config.mjs @@ -1,14 +1,11 @@ -'use strict' +import {createJestConfig, readPackageName, resolveDirName} from '@repo/test-config/jest' -const {createJestConfig} = require('../../../test/config.cjs') - -module.exports = createJestConfig({ - displayName: require('./package.json').name, +export default createJestConfig({ + displayName: readPackageName(import.meta.url), globalSetup: '/test/shared/globalSetup.ts', globalTeardown: '/test/shared/globalTeardown.ts', - rootDir: __dirname, + rootDir: resolveDirName(import.meta.url), setupFilesAfterEnv: ['/test/shared/setupAfterEnv.ts'], slowTestThreshold: 60000, testEnvironment: 'node', - testTimeout: 30000, }) diff --git a/packages/@sanity/cli/package.json b/packages/@sanity/cli/package.json index 25575ccdb60..ca6ea391a99 100644 --- a/packages/@sanity/cli/package.json +++ b/packages/@sanity/cli/package.json @@ -1,6 +1,6 @@ { "name": "@sanity/cli", - "version": "3.57.4", + "version": "3.58.0", "description": "Sanity CLI tool for managing Sanity installations, managing plugins, schemas and datasets", "keywords": [ "sanity", @@ -58,9 +58,9 @@ "dependencies": { "@babel/traverse": "^7.23.5", "@sanity/client": "^6.21.3", - "@sanity/codegen": "3.57.4", + "@sanity/codegen": "3.58.0", "@sanity/telemetry": "^0.7.7", - "@sanity/util": "3.57.4", + "@sanity/util": "3.58.0", "chalk": "^4.1.2", "debug": "^4.3.4", "decompress": "^4.2.0", @@ -68,7 +68,6 @@ "esbuild-register": "^3.5.0", "get-it": "^8.6.5", "groq-js": "^1.13.0", - "node-machine-id": "^1.1.12", "pkg-dir": "^5.0.0", "prettier": "^3.3.0", "semver": "^7.3.5", @@ -78,6 +77,7 @@ "devDependencies": { "@jest/globals": "^29.7.0", "@repo/package.config": "workspace:*", + "@repo/test-config": "workspace:*", "@rexxars/gitconfiglocal": "^3.0.1", "@rollup/plugin-node-resolve": "^15.2.3", "@sanity/eslint-config-studio": "^4.0.0", diff --git a/packages/@sanity/cli/src/cli.ts b/packages/@sanity/cli/src/cli.ts index abca613da93..67bc4f130d0 100755 --- a/packages/@sanity/cli/src/cli.ts +++ b/packages/@sanity/cli/src/cli.ts @@ -5,7 +5,6 @@ import path from 'node:path' import chalk from 'chalk' import dotenv from 'dotenv' -import {machineId} from 'node-machine-id' import resolveFrom from 'resolve-from' import {CliCommand} from './__telemetry__/cli.telemetry' @@ -85,7 +84,6 @@ export async function runCli(cliRoot: string, {cliVersion}: {cliVersion: string} ) telemetry.updateUserProperties({ - deviceId: await machineId(), runtimeVersion: process.version, runtime: detectRuntime(), cliVersion: pkg.version, diff --git a/packages/@sanity/cli/src/types.ts b/packages/@sanity/cli/src/types.ts index ac85b2d5666..46705876634 100644 --- a/packages/@sanity/cli/src/types.ts +++ b/packages/@sanity/cli/src/types.ts @@ -94,7 +94,6 @@ export interface CliBaseCommandContext { } export interface TelemetryUserProperties { - deviceId: string runtime: string runtimeVersion: string cliVersion: string diff --git a/packages/@sanity/codegen/.eslintrc.cjs b/packages/@sanity/codegen/.eslintrc.cjs index 99fd6c69224..c9a446c5adf 100644 --- a/packages/@sanity/codegen/.eslintrc.cjs +++ b/packages/@sanity/codegen/.eslintrc.cjs @@ -1,6 +1,4 @@ -'use strict' - -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../../..') diff --git a/packages/@sanity/codegen/jest.config.cjs b/packages/@sanity/codegen/jest.config.cjs deleted file mode 100644 index 51ecfb62217..00000000000 --- a/packages/@sanity/codegen/jest.config.cjs +++ /dev/null @@ -1,8 +0,0 @@ -'use strict' - -const {createJestConfig} = require('../../../test/config.cjs') - -module.exports = createJestConfig({ - displayName: require('./package.json').name, - testEnvironment: 'node', -}) diff --git a/packages/@sanity/codegen/jest.config.mjs b/packages/@sanity/codegen/jest.config.mjs new file mode 100644 index 00000000000..fc29f9a54e1 --- /dev/null +++ b/packages/@sanity/codegen/jest.config.mjs @@ -0,0 +1,6 @@ +import {createJestConfig, readPackageName} from '@repo/test-config/jest' + +export default createJestConfig({ + displayName: readPackageName(import.meta.url), + testEnvironment: 'node', +}) diff --git a/packages/@sanity/codegen/package.json b/packages/@sanity/codegen/package.json index f184a269ddf..8d27200bcd8 100644 --- a/packages/@sanity/codegen/package.json +++ b/packages/@sanity/codegen/package.json @@ -1,6 +1,6 @@ { "name": "@sanity/codegen", - "version": "3.57.4", + "version": "3.58.0", "description": "Codegen toolkit for Sanity.io", "keywords": [ "sanity", @@ -69,6 +69,7 @@ "devDependencies": { "@jest/globals": "^29.7.0", "@repo/package.config": "workspace:*", + "@repo/test-config": "workspace:*", "@types/babel__core": "^7.20.5", "@types/babel__generator": "^7.6.8", "@types/babel__register": "^7.17.3", diff --git a/packages/@sanity/diff/.eslintrc.cjs b/packages/@sanity/diff/.eslintrc.cjs index 6c8797ce99a..2ecdef408ba 100644 --- a/packages/@sanity/diff/.eslintrc.cjs +++ b/packages/@sanity/diff/.eslintrc.cjs @@ -1,6 +1,4 @@ -'use strict' - -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../../..') diff --git a/packages/@sanity/diff/package.json b/packages/@sanity/diff/package.json index 57d33680ab8..30d99316d17 100644 --- a/packages/@sanity/diff/package.json +++ b/packages/@sanity/diff/package.json @@ -1,6 +1,6 @@ { "name": "@sanity/diff", - "version": "3.57.4", + "version": "3.58.0", "description": "Generates diffs between documents and primitive types", "keywords": [ "sanity", diff --git a/packages/@sanity/migrate/.eslintrc.cjs b/packages/@sanity/migrate/.eslintrc.cjs index 99fd6c69224..c9a446c5adf 100644 --- a/packages/@sanity/migrate/.eslintrc.cjs +++ b/packages/@sanity/migrate/.eslintrc.cjs @@ -1,6 +1,4 @@ -'use strict' - -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../../..') diff --git a/packages/@sanity/migrate/jest.config.cjs b/packages/@sanity/migrate/jest.config.cjs deleted file mode 100644 index 073a08fcc23..00000000000 --- a/packages/@sanity/migrate/jest.config.cjs +++ /dev/null @@ -1,9 +0,0 @@ -'use strict' - -const {createJestConfig} = require('../../../test/config.cjs') - -module.exports = createJestConfig({ - displayName: require('./package.json').name, - testEnvironment: 'node', - transformIgnorePatterns: ['node_modules/(?!(uint8array-extras)/)'], -}) diff --git a/packages/@sanity/migrate/package.json b/packages/@sanity/migrate/package.json index 33c4f74d323..8b0b9efa497 100644 --- a/packages/@sanity/migrate/package.json +++ b/packages/@sanity/migrate/package.json @@ -1,6 +1,6 @@ { "name": "@sanity/migrate", - "version": "3.57.4", + "version": "3.58.0", "description": "Tooling for running data migrations on Sanity.io projects", "keywords": [ "sanity", @@ -46,14 +46,14 @@ "clean": "rimraf lib coverage", "lint": "eslint .", "prepublishOnly": "turbo run build", - "test": "jest", + "test": "vitest", "watch": "pkg-utils watch" }, "dependencies": { "@sanity/client": "^6.21.3", "@sanity/mutate": "^0.10.0", - "@sanity/types": "3.57.4", - "@sanity/util": "3.57.4", + "@sanity/types": "3.58.0", + "@sanity/util": "3.58.0", "arrify": "^2.0.1", "debug": "^4.3.4", "fast-fifo": "^1.3.2", @@ -61,11 +61,12 @@ "p-map": "^7.0.1" }, "devDependencies": { - "@jest/globals": "^29.7.0", "@repo/package.config": "workspace:*", + "@repo/test-config": "workspace:*", "@types/arrify": "^2.0.1", "@types/debug": "^4.1.12", - "rimraf": "^3.0.2" + "rimraf": "^3.0.2", + "vitest": "^2.1.1" }, "engines": { "node": ">=18" diff --git a/packages/@sanity/migrate/src/fetch-utils/__test__/assert2xx.test.ts b/packages/@sanity/migrate/src/fetch-utils/__test__/assert2xx.test.ts index 8397f2cd1ab..804a5998ddb 100644 --- a/packages/@sanity/migrate/src/fetch-utils/__test__/assert2xx.test.ts +++ b/packages/@sanity/migrate/src/fetch-utils/__test__/assert2xx.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {assert2xx} from '../fetchStream' @@ -25,10 +25,12 @@ test('server responds with 4xx and error response', () => { message: 'More details', }), } - expect(assert2xx(mockResponse as unknown as Response)).rejects.toThrowError({ - statusCode: 400, - message: 'Error message: More details', - }) + expect(assert2xx(mockResponse as unknown as Response)).rejects.toThrowError( + expect.objectContaining({ + statusCode: 400, + message: 'Error message: More details', + }), + ) }) test('server responds with 5xx and no json response', () => { @@ -37,10 +39,12 @@ test('server responds with 5xx and no json response', () => { statusText: 'Internal Server Error', json: () => Promise.reject(new Error('Failed to parse JSON')), } - expect(assert2xx(mockResponse as unknown as Response)).rejects.toThrowError({ - statusCode: 500, - message: 'HTTP Error 500: Internal Server Error', - }) + expect(assert2xx(mockResponse as unknown as Response)).rejects.toThrowError( + expect.objectContaining({ + statusCode: 500, + message: 'HTTP Error 500: Internal Server Error', + }), + ) }) test('server responds with 5xx and json response', () => { @@ -56,8 +60,10 @@ test('server responds with 5xx and json response', () => { status: 500, }), } - expect(assert2xx(mockResponse as unknown as Response)).rejects.toThrowError({ - statusCode: 500, - message: 'validationError: Document is not of valid type', - }) + expect(assert2xx(mockResponse as unknown as Response)).rejects.toThrowError( + expect.objectContaining({ + statusCode: 500, + message: 'validationError: Document is not of valid type', + }), + ) }) diff --git a/packages/@sanity/migrate/src/fs-webstream/__test__/bufferThroughFile.test.ts b/packages/@sanity/migrate/src/fs-webstream/__test__/bufferThroughFile.test.ts index c5f7f55cbe2..9838e380f30 100644 --- a/packages/@sanity/migrate/src/fs-webstream/__test__/bufferThroughFile.test.ts +++ b/packages/@sanity/migrate/src/fs-webstream/__test__/bufferThroughFile.test.ts @@ -2,7 +2,7 @@ import {stat} from 'node:fs/promises' import path from 'node:path' -import {describe, expect, test} from '@jest/globals' +import {describe, expect, test} from 'vitest' import {decodeText, parse} from '../../it-utils' import {firstValueFrom} from '../../it-utils/firstValueFrom' @@ -200,7 +200,7 @@ describe('using secondary stream', () => { await expect(() => lastValueFrom(parse(decodeText(streamToAsyncIterator(createReader())))), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Cannot create new buffered readers on aborted stream"`, + `[Error: Cannot create new buffered readers on aborted stream]`, ) }) }) diff --git a/packages/@sanity/migrate/src/it-utils/__test__/decodeText.test.ts b/packages/@sanity/migrate/src/it-utils/__test__/decodeText.test.ts index 2e02bddd375..637ae8373fa 100644 --- a/packages/@sanity/migrate/src/it-utils/__test__/decodeText.test.ts +++ b/packages/@sanity/migrate/src/it-utils/__test__/decodeText.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {decodeText} from '../decodeText' import {toArray} from '../toArray' diff --git a/packages/@sanity/migrate/src/it-utils/__test__/json.test.ts b/packages/@sanity/migrate/src/it-utils/__test__/json.test.ts index 27ce4edab92..0a18c3830fc 100644 --- a/packages/@sanity/migrate/src/it-utils/__test__/json.test.ts +++ b/packages/@sanity/migrate/src/it-utils/__test__/json.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {parseJSON} from '../json' diff --git a/packages/@sanity/migrate/src/it-utils/__test__/split.test.ts b/packages/@sanity/migrate/src/it-utils/__test__/split.test.ts index 275882c0fb8..aa970d00e18 100644 --- a/packages/@sanity/migrate/src/it-utils/__test__/split.test.ts +++ b/packages/@sanity/migrate/src/it-utils/__test__/split.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {split} from '../split' diff --git a/packages/@sanity/migrate/src/mutations/__tests__/mutate.test.ts b/packages/@sanity/migrate/src/mutations/__tests__/mutate.test.ts index d760638ceb4..5f583aa9a55 100644 --- a/packages/@sanity/migrate/src/mutations/__tests__/mutate.test.ts +++ b/packages/@sanity/migrate/src/mutations/__tests__/mutate.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {at, create, createIfNotExists, createOrReplace, del, patch} from '../creators' import {inc, insert, set, setIfMissing, unset} from '../operations/creators' diff --git a/packages/@sanity/migrate/src/runner/__tests__/normalizeMigrationDefinition.test.ts b/packages/@sanity/migrate/src/runner/__tests__/normalizeMigrationDefinition.test.ts index 15578ab1c82..90a38dcac17 100644 --- a/packages/@sanity/migrate/src/runner/__tests__/normalizeMigrationDefinition.test.ts +++ b/packages/@sanity/migrate/src/runner/__tests__/normalizeMigrationDefinition.test.ts @@ -1,13 +1,8 @@ -import {describe, expect, it, jest} from '@jest/globals' import {type SanityDocument} from '@sanity/types' +import {describe, expect, it, vitest} from 'vitest' import {createIfNotExists} from '../../mutations' -import { - type DocumentMigrationReturnValue, - type Migration, - type MigrationContext, - type NodeMigration, -} from '../../types' +import {type Migration, type MigrationContext, type NodeMigration} from '../../types' import { createAsyncIterableMutation, normalizeMigrateDefinition, @@ -43,7 +38,7 @@ describe('#normalizeMigrateDefinition', () => { const result = normalizeMigrateDefinition(mockMigration) const res = [] - for await (const item of result(jest.fn() as any, {} as any)) { + for await (const item of result(vitest.fn(), {} as any)) { res.push(item) } @@ -96,7 +91,7 @@ describe('#normalizeMigrateDefinition', () => { describe('#createAsyncIterableMutation', () => { it('should return an async iterable', async () => { const mockMigration: NodeMigration = { - document: jest.fn<() => DocumentMigrationReturnValue>(), + document: vitest.fn(), } const iterable = createAsyncIterableMutation(mockMigration, {documentTypes: ['foo']}) diff --git a/packages/@sanity/migrate/src/runner/utils/__tests__/batchMutations.test.ts b/packages/@sanity/migrate/src/runner/utils/__tests__/batchMutations.test.ts index fe3f62f14e5..50cd8a6a751 100644 --- a/packages/@sanity/migrate/src/runner/utils/__tests__/batchMutations.test.ts +++ b/packages/@sanity/migrate/src/runner/utils/__tests__/batchMutations.test.ts @@ -1,4 +1,4 @@ -import {describe, expect, test} from '@jest/globals' +import {describe, expect, test} from 'vitest' import {toArray} from '../../../it-utils' import {batchMutations} from '../batchMutations' diff --git a/packages/@sanity/migrate/src/runner/utils/__tests__/toSanityMutations.test.ts b/packages/@sanity/migrate/src/runner/utils/__tests__/toSanityMutations.test.ts index 6ed39b0bd1c..e47edc17c88 100644 --- a/packages/@sanity/migrate/src/runner/utils/__tests__/toSanityMutations.test.ts +++ b/packages/@sanity/migrate/src/runner/utils/__tests__/toSanityMutations.test.ts @@ -1,6 +1,6 @@ /* eslint-disable simple-import-sort/imports */ // Note: for some reason, this needs to be imported before the mocked module -import {afterEach, describe, expect, it, jest} from '@jest/globals' +import {afterEach, describe, expect, it, vitest} from 'vitest' /* eslint-enable simple-import-sort/imports */ import {SanityEncoder} from '@sanity/mutate' @@ -8,22 +8,20 @@ import {SanityEncoder} from '@sanity/mutate' import {type Mutation, type Transaction} from '../../../mutations' import {toSanityMutations, type TransactionPayload} from '../toSanityMutations' -jest.mock('@sanity/mutate', () => { +vitest.mock('@sanity/mutate', async () => { // eslint-disable-next-line @typescript-eslint/consistent-type-imports - const actual = jest.requireActual('@sanity/mutate') + const actual = await vitest.importActual('@sanity/mutate') return { ...actual, SanityEncoder: { ...actual.SanityEncoder, - encodeAll: jest - .fn() - .mockImplementation(actual.SanityEncoder.encodeAll), + encodeAll: vitest.fn().mockImplementation(actual.SanityEncoder.encodeAll), }, } }) afterEach(() => { - jest.clearAllMocks() + vitest.clearAllMocks() }) describe('#toSanityMutations', () => { diff --git a/packages/@sanity/migrate/src/sources/__test__/fromExportArchive.test.ts b/packages/@sanity/migrate/src/sources/__test__/fromExportArchive.test.ts index a87c3b6878c..fbdbfc11778 100644 --- a/packages/@sanity/migrate/src/sources/__test__/fromExportArchive.test.ts +++ b/packages/@sanity/migrate/src/sources/__test__/fromExportArchive.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {decodeText, parse, toArray} from '../../it-utils' import {fromExportArchive} from '../fromExportArchive' diff --git a/packages/@sanity/migrate/src/tar-webstream/__test__/invalid.test.ts b/packages/@sanity/migrate/src/tar-webstream/__test__/invalid.test.ts index dc725addbff..0b637779447 100644 --- a/packages/@sanity/migrate/src/tar-webstream/__test__/invalid.test.ts +++ b/packages/@sanity/migrate/src/tar-webstream/__test__/invalid.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {readFileAsWebStream} from '../../fs-webstream/readFileAsWebStream' import {streamToAsyncIterator} from '../../utils/streamToAsyncIterator' @@ -19,7 +19,7 @@ test('untar an empty tar file', async () => { } } }).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unexpected end of tar file. Expected 512 bytes of headers."`, + `[Error: Unexpected end of tar file. Expected 512 bytes of headers.]`, ) }) @@ -31,7 +31,7 @@ test('untar an invalid tar file of > 512b', async () => { } } }).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?"`, + `[Error: Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?]`, ) }) @@ -43,6 +43,6 @@ test('untar a corrupted tar file', async () => { } } }).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?"`, + `[Error: Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?]`, ) }) diff --git a/packages/@sanity/migrate/src/tar-webstream/__test__/movies.test.ts b/packages/@sanity/migrate/src/tar-webstream/__test__/movies.test.ts index bc20a535f4a..27e0a83f400 100644 --- a/packages/@sanity/migrate/src/tar-webstream/__test__/movies.test.ts +++ b/packages/@sanity/migrate/src/tar-webstream/__test__/movies.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {readFileAsWebStream} from '../../fs-webstream/readFileAsWebStream' import {toArray} from '../../it-utils/toArray' diff --git a/packages/@sanity/migrate/src/tar-webstream/__test__/small.test.ts b/packages/@sanity/migrate/src/tar-webstream/__test__/small.test.ts index fa91f9f2a50..d3cf40e40eb 100644 --- a/packages/@sanity/migrate/src/tar-webstream/__test__/small.test.ts +++ b/packages/@sanity/migrate/src/tar-webstream/__test__/small.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {readFileAsWebStream} from '../../fs-webstream/readFileAsWebStream' import {decodeText} from '../../it-utils/decodeText' diff --git a/packages/@sanity/migrate/vitest.config.mts b/packages/@sanity/migrate/vitest.config.mts new file mode 100644 index 00000000000..ed51d314e07 --- /dev/null +++ b/packages/@sanity/migrate/vitest.config.mts @@ -0,0 +1,7 @@ +import {defineConfig} from '@repo/test-config/vitest' + +export default defineConfig({ + test: { + includeSource: ['./src/**/*.ts'], + }, +}) diff --git a/packages/@sanity/mutator/.eslintrc.cjs b/packages/@sanity/mutator/.eslintrc.cjs index 99fd6c69224..c9a446c5adf 100644 --- a/packages/@sanity/mutator/.eslintrc.cjs +++ b/packages/@sanity/mutator/.eslintrc.cjs @@ -1,6 +1,4 @@ -'use strict' - -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../../..') diff --git a/packages/@sanity/mutator/jest.config.cjs b/packages/@sanity/mutator/jest.config.cjs deleted file mode 100644 index 644f91ee308..00000000000 --- a/packages/@sanity/mutator/jest.config.cjs +++ /dev/null @@ -1,7 +0,0 @@ -'use strict' - -const {createJestConfig} = require('../../../test/config.cjs') - -module.exports = createJestConfig({ - displayName: require('./package.json').name, -}) diff --git a/packages/@sanity/mutator/package.json b/packages/@sanity/mutator/package.json index 42866e0c531..a687f4326a5 100644 --- a/packages/@sanity/mutator/package.json +++ b/packages/@sanity/mutator/package.json @@ -1,6 +1,6 @@ { "name": "@sanity/mutator", - "version": "3.57.4", + "version": "3.58.0", "description": "A set of models to make it easier to utilize the powerful real time collaborative features of Sanity", "keywords": [ "sanity", @@ -45,21 +45,22 @@ "lint": "eslint .", "perf": "node ./perf/run.js", "prepublishOnly": "turbo run build", - "test": "jest", + "test": "vitest run", "watch": "pkg-utils watch" }, "dependencies": { "@sanity/diff-match-patch": "^3.1.1", - "@sanity/types": "3.57.4", + "@sanity/types": "3.58.0", "@sanity/uuid": "^3.0.1", "debug": "^4.3.4", "lodash": "^4.17.21" }, "devDependencies": { - "@jest/globals": "^29.7.0", "@repo/package.config": "workspace:*", + "@repo/test-config": "workspace:*", "@types/debug": "^4.1.5", "@types/lodash": "^4.17.7", - "rimraf": "^3.0.2" + "rimraf": "^3.0.2", + "vitest": "^2.1.1" } } diff --git a/packages/@sanity/mutator/test/BufferedDocument.test.ts b/packages/@sanity/mutator/test/BufferedDocument.test.ts index a6599347572..bbee2fcbb9d 100644 --- a/packages/@sanity/mutator/test/BufferedDocument.test.ts +++ b/packages/@sanity/mutator/test/BufferedDocument.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {BufferedDocumentTester} from './util/BufferedDocumentTester' diff --git a/packages/@sanity/mutator/test/Descender.test.ts b/packages/@sanity/mutator/test/Descender.test.ts index 71111b87435..2db08a37dae 100644 --- a/packages/@sanity/mutator/test/Descender.test.ts +++ b/packages/@sanity/mutator/test/Descender.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {Descender} from '../src/jsonpath/Descender' import {Expression} from '../src/jsonpath/Expression' diff --git a/packages/@sanity/mutator/test/Document.test.ts b/packages/@sanity/mutator/test/Document.test.ts index a6120b2461c..27a202bf919 100644 --- a/packages/@sanity/mutator/test/Document.test.ts +++ b/packages/@sanity/mutator/test/Document.test.ts @@ -1,4 +1,4 @@ -import {test} from '@jest/globals' +import {test} from 'vitest' import {DocumentTester} from './util/DocumentTester' diff --git a/packages/@sanity/mutator/test/Expression.test.ts b/packages/@sanity/mutator/test/Expression.test.ts index 637ad83dcc9..1f24e461406 100644 --- a/packages/@sanity/mutator/test/Expression.test.ts +++ b/packages/@sanity/mutator/test/Expression.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {Expression} from '../src/jsonpath/Expression' import {parseJsonPath} from '../src/jsonpath/parse' diff --git a/packages/@sanity/mutator/test/Matcher.test.ts b/packages/@sanity/mutator/test/Matcher.test.ts index 3b129077dc3..0bed1e96971 100644 --- a/packages/@sanity/mutator/test/Matcher.test.ts +++ b/packages/@sanity/mutator/test/Matcher.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {Matcher} from '../src/jsonpath/Matcher' import {PlainProbe} from '../src/jsonpath/PlainProbe' diff --git a/packages/@sanity/mutator/test/Mutation.test.ts b/packages/@sanity/mutator/test/Mutation.test.ts index 0dd20aa08d7..920490f6408 100644 --- a/packages/@sanity/mutator/test/Mutation.test.ts +++ b/packages/@sanity/mutator/test/Mutation.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {Mutation} from '../src/document/Mutation' diff --git a/packages/@sanity/mutator/test/SquashingBuffer.test.ts b/packages/@sanity/mutator/test/SquashingBuffer.test.ts index 6544bddf769..d44d81caad9 100644 --- a/packages/@sanity/mutator/test/SquashingBuffer.test.ts +++ b/packages/@sanity/mutator/test/SquashingBuffer.test.ts @@ -1,5 +1,5 @@ -import {expect, jest, test} from '@jest/globals' import {type PatchMutationOperation} from '@sanity/types' +import {expect, test, vi} from 'vitest' import {Mutation} from '../src/document/Mutation' import {SquashingBuffer} from '../src/document/SquashingBuffer' @@ -113,7 +113,7 @@ test.each(['create', 'createIfNotExists', 'createOrReplace'])( '%s defaults to current created at time', (createFnc) => { const globalMockDate = new Date('2020-01-01T12:34:55.000Z') - const globalDateSpy = jest.spyOn(global, 'Date').mockReturnValue(globalMockDate) + const globalDateSpy = vi.spyOn(global, 'Date').mockReturnValue(globalMockDate) const sb = new SquashingBuffer(null) @@ -140,7 +140,7 @@ test.each(['create', 'createIfNotExists', 'createOrReplace'])( test('de-duplicate create respects deletes', () => { const globalMockDate = new Date('2020-01-01T12:34:55.000Z') - const globalDateSpy = jest.spyOn(global, 'Date').mockReturnValue(globalMockDate) + const globalDateSpy = vi.spyOn(global, 'Date').mockReturnValue(globalMockDate) const initial = {_id: '1', _type: 'test', a: 'A string value', c: 'Some value'} const sb = new SquashingBuffer(initial) diff --git a/packages/@sanity/mutator/test/arrayToJSONMatchPath.test.ts b/packages/@sanity/mutator/test/arrayToJSONMatchPath.test.ts index 348e48b2045..bdfa2956288 100644 --- a/packages/@sanity/mutator/test/arrayToJSONMatchPath.test.ts +++ b/packages/@sanity/mutator/test/arrayToJSONMatchPath.test.ts @@ -1,4 +1,4 @@ -import {describe, expect, test} from '@jest/globals' +import {describe, expect, test} from 'vitest' // Converts an array of simple values (strings, numbers only) to a jsonmatch path string. import {arrayToJSONMatchPath} from '../src/jsonpath/arrayToJSONMatchPath' diff --git a/packages/@sanity/mutator/test/descend.test.ts b/packages/@sanity/mutator/test/descend.test.ts index 50c7f024c67..98ef64068db 100644 --- a/packages/@sanity/mutator/test/descend.test.ts +++ b/packages/@sanity/mutator/test/descend.test.ts @@ -1,4 +1,4 @@ -import {describe, expect, test} from '@jest/globals' +import {describe, expect, test} from 'vitest' import {descend} from '../src/jsonpath/descend' import {parseJsonPath} from '../src/jsonpath/parse' diff --git a/packages/@sanity/mutator/test/extract.test.ts b/packages/@sanity/mutator/test/extract.test.ts index 4c8dced0dae..af8e09dfb40 100644 --- a/packages/@sanity/mutator/test/extract.test.ts +++ b/packages/@sanity/mutator/test/extract.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {extract} from '../src/jsonpath' diff --git a/packages/@sanity/mutator/test/extractWithPath.test.ts b/packages/@sanity/mutator/test/extractWithPath.test.ts index b657ace151e..9c1784f02a8 100644 --- a/packages/@sanity/mutator/test/extractWithPath.test.ts +++ b/packages/@sanity/mutator/test/extractWithPath.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {extractWithPath} from '../src/jsonpath' diff --git a/packages/@sanity/mutator/test/parse.test.ts b/packages/@sanity/mutator/test/parse.test.ts index 6a8a4f37d70..87822d3b690 100644 --- a/packages/@sanity/mutator/test/parse.test.ts +++ b/packages/@sanity/mutator/test/parse.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {parseJsonPath} from '../src/jsonpath/parse' diff --git a/packages/@sanity/mutator/test/patch.test.ts b/packages/@sanity/mutator/test/patch.test.ts index 6634a338a3a..01576d656fb 100644 --- a/packages/@sanity/mutator/test/patch.test.ts +++ b/packages/@sanity/mutator/test/patch.test.ts @@ -1,5 +1,5 @@ -import {expect, test} from '@jest/globals' import {cloneDeep} from 'lodash' +import {expect, test} from 'vitest' import {type Doc} from '../src/document/types' import {Patcher} from '../src/patch' diff --git a/packages/@sanity/mutator/test/toPath.test.ts b/packages/@sanity/mutator/test/toPath.test.ts index b4f552a93cb..ccea4f6cb05 100644 --- a/packages/@sanity/mutator/test/toPath.test.ts +++ b/packages/@sanity/mutator/test/toPath.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {parseJsonPath} from '../src/jsonpath/parse' import {toPath} from '../src/jsonpath/toPath' diff --git a/packages/@sanity/mutator/test/tokenize.test.ts b/packages/@sanity/mutator/test/tokenize.test.ts index e0651bd8919..1ee3467c501 100644 --- a/packages/@sanity/mutator/test/tokenize.test.ts +++ b/packages/@sanity/mutator/test/tokenize.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {tokenize} from '../src/jsonpath/tokenize' diff --git a/packages/@sanity/mutator/test/util/BufferedDocumentTester.ts b/packages/@sanity/mutator/test/util/BufferedDocumentTester.ts index 18dd5004cbd..c51a5f4fc72 100644 --- a/packages/@sanity/mutator/test/util/BufferedDocumentTester.ts +++ b/packages/@sanity/mutator/test/util/BufferedDocumentTester.ts @@ -1,7 +1,7 @@ -import {expect} from '@jest/globals' // A test jig for the BufferedDocument model import {type PatchMutationOperation} from '@sanity/types' import debugLogger from 'debug' +import {expect} from 'vitest' import {BufferedDocument, Mutation} from '../../src/document' import {type CommitHandlerMessage} from '../../src/document/BufferedDocument' diff --git a/packages/@sanity/mutator/test/util/DocumentTester.ts b/packages/@sanity/mutator/test/util/DocumentTester.ts index bc462bf995e..c27ce31d620 100644 --- a/packages/@sanity/mutator/test/util/DocumentTester.ts +++ b/packages/@sanity/mutator/test/util/DocumentTester.ts @@ -1,6 +1,6 @@ -import {expect} from '@jest/globals' // A test jig for the Document model import {type PatchMutationOperation} from '@sanity/types' +import {expect} from 'vitest' import {Document, Mutation} from '../../src/document' import {type SubmissionResponder} from '../../src/document/Document' diff --git a/packages/@sanity/mutator/vitest.config.mts b/packages/@sanity/mutator/vitest.config.mts new file mode 100644 index 00000000000..c70678156c4 --- /dev/null +++ b/packages/@sanity/mutator/vitest.config.mts @@ -0,0 +1,3 @@ +import {defineConfig} from '@repo/test-config/vitest' + +export default defineConfig() diff --git a/packages/@sanity/schema/.eslintrc.cjs b/packages/@sanity/schema/.eslintrc.cjs index 99fd6c69224..c9a446c5adf 100644 --- a/packages/@sanity/schema/.eslintrc.cjs +++ b/packages/@sanity/schema/.eslintrc.cjs @@ -1,6 +1,4 @@ -'use strict' - -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../../..') diff --git a/packages/@sanity/schema/jest.config.cjs b/packages/@sanity/schema/jest.config.cjs deleted file mode 100644 index 51ecfb62217..00000000000 --- a/packages/@sanity/schema/jest.config.cjs +++ /dev/null @@ -1,8 +0,0 @@ -'use strict' - -const {createJestConfig} = require('../../../test/config.cjs') - -module.exports = createJestConfig({ - displayName: require('./package.json').name, - testEnvironment: 'node', -}) diff --git a/packages/@sanity/schema/package.json b/packages/@sanity/schema/package.json index 8745f5f794f..4ae35e8f331 100644 --- a/packages/@sanity/schema/package.json +++ b/packages/@sanity/schema/package.json @@ -1,6 +1,6 @@ { "name": "@sanity/schema", - "version": "3.57.4", + "version": "3.58.0", "description": "", "keywords": [ "sanity", @@ -58,13 +58,13 @@ "clean": "rimraf _internal.js lib", "lint": "eslint .", "prepublishOnly": "turbo run build", - "test": "jest", - "test:watch": "jest --watchAll", + "test": "vitest run", + "test:watch": "vitest watch", "watch": "pkg-utils watch" }, "dependencies": { "@sanity/generate-help-url": "^3.0.0", - "@sanity/types": "3.57.4", + "@sanity/types": "3.58.0", "arrify": "^1.0.1", "groq-js": "^1.13.0", "humanize-list": "^1.0.1", @@ -73,12 +73,14 @@ "object-inspect": "^1.13.1" }, "devDependencies": { - "@jest/globals": "^29.7.0", "@repo/package.config": "workspace:*", + "@repo/test-config": "workspace:*", "@sanity/icons": "^3.4.0", "@types/arrify": "^1.0.4", + "@types/lodash": "^4.17.7", "@types/object-inspect": "^1.13.0", "@types/react": "^18.3.5", - "rimraf": "^3.0.2" + "rimraf": "^3.0.2", + "vitest": "^2.1.1" } } diff --git a/packages/@sanity/schema/src/legacy/searchConfig/resolve.test.ts b/packages/@sanity/schema/src/legacy/searchConfig/resolve.test.ts index 3b9a86ad7bc..83cabef70c5 100644 --- a/packages/@sanity/schema/src/legacy/searchConfig/resolve.test.ts +++ b/packages/@sanity/schema/src/legacy/searchConfig/resolve.test.ts @@ -1,5 +1,5 @@ -import {describe, expect, test} from '@jest/globals' import {defineField, defineType, type Schema} from '@sanity/types' +import {describe, expect, test} from 'vitest' import {Schema as SchemaBuilder} from '../Schema' import {resolveSearchConfig, resolveSearchConfigForBaseFieldPaths} from './resolve' diff --git a/packages/@sanity/schema/test/extractSchema/__snapshots__/extractSchema.test.ts.snap b/packages/@sanity/schema/test/extractSchema/__snapshots__/extractSchema.test.ts.snap index 30e7c989fc1..cf35610d583 100644 --- a/packages/@sanity/schema/test/extractSchema/__snapshots__/extractSchema.test.ts.snap +++ b/packages/@sanity/schema/test/extractSchema/__snapshots__/extractSchema.test.ts.snap @@ -1,56 +1,56 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Extract schema test Can extract inline documents 1`] = ` -Array [ - Object { - "attributes": Object { - "_createdAt": Object { +exports[`Extract schema test > Can extract inline documents 1`] = ` +[ + { + "attributes": { + "_createdAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_id": Object { + "_id": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_rev": Object { + "_rev": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "validDocument", }, }, - "_updatedAt": Object { + "_updatedAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "inlineAuthor": Object { + "inlineAuthor": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "author", }, }, - "name": Object { + "name": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -58,32 +58,32 @@ Array [ "type": "object", }, }, - "inlineAuthors": Object { + "inlineAuthors": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "author", }, }, - "name": Object { + "name": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -95,28 +95,28 @@ Array [ "type": "array", }, }, - "referenceAuthor": Object { + "referenceAuthor": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -125,39 +125,39 @@ Array [ "type": "object", }, }, - "referenceAuthors": Object { + "referenceAuthors": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_ref": Object { + "value": { + "of": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, }, "dereferencesTo": "author", - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -173,43 +173,43 @@ Array [ "name": "validDocument", "type": "document", }, - Object { - "attributes": Object { - "_createdAt": Object { + { + "attributes": { + "_createdAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_id": Object { + "_id": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_rev": Object { + "_rev": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "author", }, }, - "_updatedAt": Object { + "_updatedAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "name": Object { + "name": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -220,45 +220,45 @@ Array [ ] `; -exports[`Extract schema test Extracts schema general 1`] = ` -Array [ - Object { +exports[`Extract schema test > Extracts schema general 1`] = ` +[ + { "name": "sanity.imagePaletteSwatch", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "sanity.imagePaletteSwatch", }, }, - "background": Object { + "background": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "foreground": Object { + "foreground": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "population": Object { + "population": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "title": Object { + "title": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -266,70 +266,70 @@ Array [ "type": "object", }, }, - Object { + { "name": "sanity.imagePalette", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "sanity.imagePalette", }, }, - "darkMuted": Object { + "darkMuted": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imagePaletteSwatch", "type": "inline", }, }, - "darkVibrant": Object { + "darkVibrant": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imagePaletteSwatch", "type": "inline", }, }, - "dominant": Object { + "dominant": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imagePaletteSwatch", "type": "inline", }, }, - "lightMuted": Object { + "lightMuted": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imagePaletteSwatch", "type": "inline", }, }, - "lightVibrant": Object { + "lightVibrant": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imagePaletteSwatch", "type": "inline", }, }, - "muted": Object { + "muted": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imagePaletteSwatch", "type": "inline", }, }, - "vibrant": Object { + "vibrant": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imagePaletteSwatch", "type": "inline", }, @@ -338,36 +338,36 @@ Array [ "type": "object", }, }, - Object { + { "name": "sanity.imageDimensions", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "sanity.imageDimensions", }, }, - "aspectRatio": Object { + "aspectRatio": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "height": Object { + "height": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "width": Object { + "width": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, @@ -375,36 +375,36 @@ Array [ "type": "object", }, }, - Object { + { "name": "geopoint", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "geopoint", }, }, - "alt": Object { + "alt": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "lat": Object { + "lat": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "lng": Object { + "lng": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, @@ -412,29 +412,29 @@ Array [ "type": "object", }, }, - Object { + { "name": "slug", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "slug", }, }, - "current": Object { + "current": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "source": Object { + "source": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -442,142 +442,142 @@ Array [ "type": "object", }, }, - Object { + { "name": "someTextType", "type": "type", - "value": Object { + "value": { "type": "string", }, }, - Object { - "attributes": Object { - "_createdAt": Object { + { + "attributes": { + "_createdAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_id": Object { + "_id": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_rev": Object { + "_rev": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "sanity.fileAsset", }, }, - "_updatedAt": Object { + "_updatedAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "altText": Object { + "altText": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "assetId": Object { + "assetId": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "description": Object { + "description": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "extension": Object { + "extension": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "label": Object { + "label": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "mimeType": Object { + "mimeType": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "originalFilename": Object { + "originalFilename": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "path": Object { + "path": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "sha1hash": Object { + "sha1hash": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "size": Object { + "size": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "source": Object { + "source": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.assetSourceData", "type": "inline", }, }, - "title": Object { + "title": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "uploadId": Object { + "uploadId": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "url": Object { + "url": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -585,22 +585,22 @@ Array [ "name": "sanity.fileAsset", "type": "document", }, - Object { + { "name": "code", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "code", }, }, - "thecode": Object { + "thecode": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -608,39 +608,39 @@ Array [ "type": "object", }, }, - Object { + { "name": "customStringType", "type": "type", - "value": Object { + "value": { "type": "string", }, }, - Object { + { "name": "blocksTest", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "blocksTest", }, }, - "arrayOfArticles": Object { + "arrayOfArticles": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_key": Object { + "value": { + "of": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { + "rest": { "name": "blocksTest", "type": "inline", }, @@ -649,57 +649,57 @@ Array [ "type": "array", }, }, - "blockInBlock": Object { + "blockInBlock": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "block", }, }, - "children": Object { + "children": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "of": Array [ - Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "of": [ + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "span", }, }, - "marks": Object { + "marks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { + "value": { + "of": { "type": "string", }, "type": "array", }, }, - "text": Object { + "text": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -708,64 +708,64 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "footnote", }, }, - "footnote": Object { + "footnote": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "block", }, }, - "children": Object { + "children": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "span", }, }, - "marks": Object { + "marks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { + "value": { + "of": { "type": "string", }, "type": "array", }, }, - "text": Object { + "text": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -777,34 +777,34 @@ Array [ "type": "array", }, }, - "level": Object { + "level": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "listItem": Object { + "listItem": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [], + "value": { + "of": [], "type": "union", }, }, - "markDefs": Object { + "markDefs": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "null", }, }, - "style": Object { + "style": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "normal", }, @@ -813,11 +813,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -830,11 +830,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -849,23 +849,23 @@ Array [ "type": "array", }, }, - "level": Object { + "level": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "listItem": Object { + "listItem": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "bullet", }, - Object { + { "type": "string", "value": "number", }, @@ -873,32 +873,32 @@ Array [ "type": "union", }, }, - "markDefs": Object { + "markDefs": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "link", }, }, - "href": Object { + "href": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -910,40 +910,40 @@ Array [ "type": "array", }, }, - "style": Object { + "style": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "normal", }, - Object { + { "type": "string", "value": "h1", }, - Object { + { "type": "string", "value": "h2", }, - Object { + { "type": "string", "value": "h3", }, - Object { + { "type": "string", "value": "h4", }, - Object { + { "type": "string", "value": "h5", }, - Object { + { "type": "string", "value": "h6", }, - Object { + { "type": "string", "value": "blockquote", }, @@ -952,11 +952,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -968,68 +968,68 @@ Array [ "type": "array", }, }, - "blockList": Object { + "blockList": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "blockListEntry", }, }, - "blocks": Object { + "blocks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "block", }, }, - "children": Object { + "children": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "span", }, }, - "marks": Object { + "marks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { + "value": { + "of": { "type": "string", }, "type": "array", }, }, - "text": Object { + "text": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1041,23 +1041,23 @@ Array [ "type": "array", }, }, - "level": Object { + "level": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "listItem": Object { + "listItem": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "bullet", }, - Object { + { "type": "string", "value": "number", }, @@ -1065,32 +1065,32 @@ Array [ "type": "union", }, }, - "markDefs": Object { + "markDefs": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "link", }, }, - "href": Object { + "href": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1102,40 +1102,40 @@ Array [ "type": "array", }, }, - "style": Object { + "style": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "normal", }, - Object { + { "type": "string", "value": "h1", }, - Object { + { "type": "string", "value": "h2", }, - Object { + { "type": "string", "value": "h3", }, - Object { + { "type": "string", "value": "h4", }, - Object { + { "type": "string", "value": "h5", }, - Object { + { "type": "string", "value": "h6", }, - Object { + { "type": "string", "value": "blockquote", }, @@ -1144,11 +1144,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1160,19 +1160,19 @@ Array [ "type": "array", }, }, - "title": Object { + "title": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1184,62 +1184,62 @@ Array [ "type": "array", }, }, - "customized": Object { + "customized": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "of": Array [ - Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "of": [ + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "author", }, }, - "name": Object { + "name": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "profilePicture": Object { + "profilePicture": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "image", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -1248,32 +1248,32 @@ Array [ "type": "object", }, }, - "attribution": Object { + "attribution": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "caption": Object { + "caption": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "crop": Object { + "crop": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageCrop", "type": "inline", }, }, - "hotspot": Object { + "hotspot": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageHotspot", "type": "inline", }, @@ -1283,11 +1283,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1296,53 +1296,53 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "block", }, }, - "children": Object { + "children": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "of": Array [ - Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "of": [ + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "span", }, }, - "marks": Object { + "marks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { + "value": { + "of": { "type": "string", }, "type": "array", }, }, - "text": Object { + "text": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1351,37 +1351,37 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "image", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -1390,60 +1390,60 @@ Array [ "type": "object", }, }, - "authors": Object { + "authors": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "author", }, }, - "name": Object { + "name": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "profilePicture": Object { + "profilePicture": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "image", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -1452,32 +1452,32 @@ Array [ "type": "object", }, }, - "attribution": Object { + "attribution": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "caption": Object { + "caption": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "crop": Object { + "crop": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageCrop", "type": "inline", }, }, - "hotspot": Object { + "hotspot": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageHotspot", "type": "inline", }, @@ -1487,11 +1487,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1503,35 +1503,35 @@ Array [ "type": "array", }, }, - "caption": Object { + "caption": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "crop": Object { + "crop": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageCrop", "type": "inline", }, }, - "hotspot": Object { + "hotspot": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageHotspot", "type": "inline", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1546,23 +1546,23 @@ Array [ "type": "array", }, }, - "level": Object { + "level": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "listItem": Object { + "listItem": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "bullet", }, - Object { + { "type": "string", "value": "number", }, @@ -1570,41 +1570,41 @@ Array [ "type": "union", }, }, - "markDefs": Object { + "markDefs": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "of": Array [ - Object { - "attributes": Object { - "_ref": Object { + "value": { + "of": { + "of": [ + { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, }, "dereferencesTo": "author", - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1613,28 +1613,28 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "test", }, }, - "testString": Object { + "testString": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1649,24 +1649,24 @@ Array [ "type": "array", }, }, - "style": Object { + "style": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "normal", }, - Object { + { "type": "string", "value": "h1", }, - Object { + { "type": "string", "value": "h2", }, - Object { + { "type": "string", "value": "blockquote", }, @@ -1675,11 +1675,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1694,48 +1694,48 @@ Array [ "type": "array", }, }, - "deep": Object { + "deep": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "blocks": Object { + "value": { + "attributes": { + "blocks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "of": Array [ - Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "of": [ + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "image", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -1744,28 +1744,28 @@ Array [ "type": "object", }, }, - "crop": Object { + "crop": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageCrop", "type": "inline", }, }, - "hotspot": Object { + "hotspot": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageHotspot", "type": "inline", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1774,56 +1774,56 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "author", }, }, - "name": Object { + "name": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "profilePicture": Object { + "profilePicture": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "image", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -1832,32 +1832,32 @@ Array [ "type": "object", }, }, - "attribution": Object { + "attribution": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "caption": Object { + "caption": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "crop": Object { + "crop": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageCrop", "type": "inline", }, }, - "hotspot": Object { + "hotspot": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageHotspot", "type": "inline", }, @@ -1867,11 +1867,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1880,51 +1880,51 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "block", }, }, - "children": Object { + "children": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "span", }, }, - "marks": Object { + "marks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { + "value": { + "of": { "type": "string", }, "type": "array", }, }, - "text": Object { + "text": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -1936,23 +1936,23 @@ Array [ "type": "array", }, }, - "level": Object { + "level": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "listItem": Object { + "listItem": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "bullet", }, - Object { + { "type": "string", "value": "number", }, @@ -1960,39 +1960,39 @@ Array [ "type": "union", }, }, - "markDefs": Object { + "markDefs": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_ref": Object { + "value": { + "of": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, }, "dereferencesTo": "author", - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2004,24 +2004,24 @@ Array [ "type": "array", }, }, - "style": Object { + "style": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "normal", }, - Object { + { "type": "string", "value": "h1", }, - Object { + { "type": "string", "value": "h2", }, - Object { + { "type": "string", "value": "blockquote", }, @@ -2030,11 +2030,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2049,10 +2049,10 @@ Array [ "type": "array", }, }, - "something": Object { + "something": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2060,43 +2060,43 @@ Array [ "type": "object", }, }, - "defaults": Object { + "defaults": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "of": Array [ - Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "of": [ + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "image", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -2105,28 +2105,28 @@ Array [ "type": "object", }, }, - "crop": Object { + "crop": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageCrop", "type": "inline", }, }, - "hotspot": Object { + "hotspot": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageHotspot", "type": "inline", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2135,35 +2135,35 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_ref": Object { + { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, }, "dereferencesTo": "author", - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2172,35 +2172,35 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_ref": Object { + { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, }, "dereferencesTo": "book", - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2209,43 +2209,43 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "objectWithNestedArray", }, }, - "array": Object { + "array": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "author": Object { + "value": { + "of": { + "attributes": { + "author": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -2254,19 +2254,19 @@ Array [ "type": "object", }, }, - "title": Object { + "title": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2278,19 +2278,19 @@ Array [ "type": "array", }, }, - "title": Object { + "title": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2299,56 +2299,56 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "author", }, }, - "name": Object { + "name": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "profilePicture": Object { + "profilePicture": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "image", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -2357,32 +2357,32 @@ Array [ "type": "object", }, }, - "attribution": Object { + "attribution": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "caption": Object { + "caption": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "crop": Object { + "crop": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageCrop", "type": "inline", }, }, - "hotspot": Object { + "hotspot": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageHotspot", "type": "inline", }, @@ -2392,11 +2392,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2405,63 +2405,63 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_key": Object { + { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { + "rest": { "name": "code", "type": "inline", }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "otherTestObject", }, }, - "field1": Object { + "field1": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "field3": Object { + "field3": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "aNumber": Object { + "value": { + "of": { + "attributes": { + "aNumber": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "aString": Object { + "aString": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2474,11 +2474,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2493,55 +2493,55 @@ Array [ "type": "array", }, }, - "first": Object { + "first": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "block", }, }, - "children": Object { + "children": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "span", }, }, - "marks": Object { + "marks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { + "value": { + "of": { "type": "string", }, "type": "array", }, }, - "text": Object { + "text": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2553,23 +2553,23 @@ Array [ "type": "array", }, }, - "level": Object { + "level": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "listItem": Object { + "listItem": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "bullet", }, - Object { + { "type": "string", "value": "number", }, @@ -2577,32 +2577,32 @@ Array [ "type": "union", }, }, - "markDefs": Object { + "markDefs": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "link", }, }, - "href": Object { + "href": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2614,40 +2614,40 @@ Array [ "type": "array", }, }, - "style": Object { + "style": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "normal", }, - Object { + { "type": "string", "value": "h1", }, - Object { + { "type": "string", "value": "h2", }, - Object { + { "type": "string", "value": "h3", }, - Object { + { "type": "string", "value": "h4", }, - Object { + { "type": "string", "value": "h5", }, - Object { + { "type": "string", "value": "h6", }, - Object { + { "type": "string", "value": "blockquote", }, @@ -2656,11 +2656,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2672,55 +2672,55 @@ Array [ "type": "array", }, }, - "minimal": Object { + "minimal": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "block", }, }, - "children": Object { + "children": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "span", }, }, - "marks": Object { + "marks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { + "value": { + "of": { "type": "string", }, "type": "array", }, }, - "text": Object { + "text": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2732,34 +2732,34 @@ Array [ "type": "array", }, }, - "level": Object { + "level": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "listItem": Object { + "listItem": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [], + "value": { + "of": [], "type": "union", }, }, - "markDefs": Object { + "markDefs": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "null", }, }, - "style": Object { + "style": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "normal", }, @@ -2768,11 +2768,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2784,43 +2784,43 @@ Array [ "type": "array", }, }, - "readOnlyWithDefaults": Object { + "readOnlyWithDefaults": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "of": Array [ - Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "of": [ + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "image", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -2829,28 +2829,28 @@ Array [ "type": "object", }, }, - "crop": Object { + "crop": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageCrop", "type": "inline", }, }, - "hotspot": Object { + "hotspot": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageHotspot", "type": "inline", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2859,35 +2859,35 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_ref": Object { + { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, }, "dereferencesTo": "author", - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2896,35 +2896,35 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_ref": Object { + { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, }, "dereferencesTo": "book", - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -2933,56 +2933,56 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "author", }, }, - "name": Object { + "name": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "profilePicture": Object { + "profilePicture": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "image", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -2991,32 +2991,32 @@ Array [ "type": "object", }, }, - "attribution": Object { + "attribution": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "caption": Object { + "caption": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "crop": Object { + "crop": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageCrop", "type": "inline", }, }, - "hotspot": Object { + "hotspot": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageHotspot", "type": "inline", }, @@ -3026,11 +3026,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3039,43 +3039,43 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_key": Object { + { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { + "rest": { "name": "code", "type": "inline", }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "testObject", }, }, - "field1": Object { + "field1": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3084,48 +3084,48 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "otherTestObject", }, }, - "field1": Object { + "field1": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "field3": Object { + "field3": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "aNumber": Object { + "value": { + "of": { + "attributes": { + "aNumber": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "aString": Object { + "aString": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3138,11 +3138,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3157,62 +3157,62 @@ Array [ "type": "array", }, }, - "recursive": Object { + "recursive": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "blocks": Object { + "value": { + "attributes": { + "blocks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "of": Array [ - Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "of": [ + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "block", }, }, - "children": Object { + "children": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "span", }, }, - "marks": Object { + "marks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { + "value": { + "of": { "type": "string", }, "type": "array", }, }, - "text": Object { + "text": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3224,34 +3224,34 @@ Array [ "type": "array", }, }, - "level": Object { + "level": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "listItem": Object { + "listItem": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [], + "value": { + "of": [], "type": "union", }, }, - "markDefs": Object { + "markDefs": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "null", }, }, - "style": Object { + "style": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "normal", }, @@ -3260,11 +3260,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3273,16 +3273,16 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_key": Object { + { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { + "rest": { "name": "blocksTest", "type": "inline", }, @@ -3298,57 +3298,57 @@ Array [ "type": "object", }, }, - "reproCH9436": Object { + "reproCH9436": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "of": Array [ - Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "of": [ + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "block", }, }, - "children": Object { + "children": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "span", }, }, - "marks": Object { + "marks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { + "value": { + "of": { "type": "string", }, "type": "array", }, }, - "text": Object { + "text": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3360,23 +3360,23 @@ Array [ "type": "array", }, }, - "level": Object { + "level": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "listItem": Object { + "listItem": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "bullet", }, - Object { + { "type": "string", "value": "number", }, @@ -3384,32 +3384,32 @@ Array [ "type": "union", }, }, - "markDefs": Object { + "markDefs": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "link", }, }, - "href": Object { + "href": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3421,40 +3421,40 @@ Array [ "type": "array", }, }, - "style": Object { + "style": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "normal", }, - Object { + { "type": "string", "value": "h1", }, - Object { + { "type": "string", "value": "h2", }, - Object { + { "type": "string", "value": "h3", }, - Object { + { "type": "string", "value": "h4", }, - Object { + { "type": "string", "value": "h5", }, - Object { + { "type": "string", "value": "h6", }, - Object { + { "type": "string", "value": "blockquote", }, @@ -3463,11 +3463,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3476,37 +3476,37 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_type": Object { + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "imageWithPortableTextCaption", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -3515,55 +3515,55 @@ Array [ "type": "object", }, }, - "caption": Object { + "caption": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "block", }, }, - "children": Object { + "children": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "span", }, }, - "marks": Object { + "marks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { + "value": { + "of": { "type": "string", }, "type": "array", }, }, - "text": Object { + "text": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3575,23 +3575,23 @@ Array [ "type": "array", }, }, - "level": Object { + "level": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "listItem": Object { + "listItem": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "bullet", }, - Object { + { "type": "string", "value": "number", }, @@ -3599,32 +3599,32 @@ Array [ "type": "union", }, }, - "markDefs": Object { + "markDefs": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "link", }, }, - "href": Object { + "href": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3636,40 +3636,40 @@ Array [ "type": "array", }, }, - "style": Object { + "style": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "normal", }, - Object { + { "type": "string", "value": "h1", }, - Object { + { "type": "string", "value": "h2", }, - Object { + { "type": "string", "value": "h3", }, - Object { + { "type": "string", "value": "h4", }, - Object { + { "type": "string", "value": "h5", }, - Object { + { "type": "string", "value": "h6", }, - Object { + { "type": "string", "value": "blockquote", }, @@ -3678,11 +3678,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3694,28 +3694,28 @@ Array [ "type": "array", }, }, - "crop": Object { + "crop": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageCrop", "type": "inline", }, }, - "hotspot": Object { + "hotspot": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageHotspot", "type": "inline", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3730,64 +3730,64 @@ Array [ "type": "array", }, }, - "title": Object { + "title": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "withGeopoint": Object { + "withGeopoint": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "of": Array [ - Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "of": [ + { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "block", }, }, - "children": Object { + "children": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "span", }, }, - "marks": Object { + "marks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { + "value": { + "of": { "type": "string", }, "type": "array", }, }, - "text": Object { + "text": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3799,23 +3799,23 @@ Array [ "type": "array", }, }, - "level": Object { + "level": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "listItem": Object { + "listItem": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "bullet", }, - Object { + { "type": "string", "value": "number", }, @@ -3823,32 +3823,32 @@ Array [ "type": "union", }, }, - "markDefs": Object { + "markDefs": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "link", }, }, - "href": Object { + "href": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3860,40 +3860,40 @@ Array [ "type": "array", }, }, - "style": Object { + "style": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "normal", }, - Object { + { "type": "string", "value": "h1", }, - Object { + { "type": "string", "value": "h2", }, - Object { + { "type": "string", "value": "h3", }, - Object { + { "type": "string", "value": "h4", }, - Object { + { "type": "string", "value": "h5", }, - Object { + { "type": "string", "value": "h6", }, - Object { + { "type": "string", "value": "blockquote", }, @@ -3902,11 +3902,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3915,16 +3915,16 @@ Array [ }, "type": "object", }, - Object { - "attributes": Object { - "_key": Object { + { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { + "rest": { "name": "geopoint", "type": "inline", }, @@ -3940,43 +3940,43 @@ Array [ "type": "object", }, }, - Object { - "attributes": Object { - "_createdAt": Object { + { + "attributes": { + "_createdAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_id": Object { + "_id": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_rev": Object { + "_rev": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "book", }, }, - "_updatedAt": Object { + "_updatedAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "name": Object { + "name": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -3984,80 +3984,80 @@ Array [ "name": "book", "type": "document", }, - Object { - "attributes": Object { - "_createdAt": Object { + { + "attributes": { + "_createdAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_id": Object { + "_id": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_rev": Object { + "_rev": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "author", }, }, - "_updatedAt": Object { + "_updatedAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "name": Object { + "name": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "profilePicture": Object { + "profilePicture": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "image", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -4066,32 +4066,32 @@ Array [ "type": "object", }, }, - "attribution": Object { + "attribution": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "caption": Object { + "caption": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "crop": Object { + "crop": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageCrop", "type": "inline", }, }, - "hotspot": Object { + "hotspot": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageHotspot", "type": "inline", }, @@ -4104,43 +4104,43 @@ Array [ "name": "author", "type": "document", }, - Object { + { "name": "sanity.imageCrop", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "sanity.imageCrop", }, }, - "bottom": Object { + "bottom": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "left": Object { + "left": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "right": Object { + "right": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "top": Object { + "top": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, @@ -4148,43 +4148,43 @@ Array [ "type": "object", }, }, - Object { + { "name": "sanity.imageHotspot", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "sanity.imageHotspot", }, }, - "height": Object { + "height": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "width": Object { + "width": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "x": Object { + "x": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "y": Object { + "y": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, @@ -4192,143 +4192,143 @@ Array [ "type": "object", }, }, - Object { - "attributes": Object { - "_createdAt": Object { + { + "attributes": { + "_createdAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_id": Object { + "_id": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_rev": Object { + "_rev": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "sanity.imageAsset", }, }, - "_updatedAt": Object { + "_updatedAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "altText": Object { + "altText": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "assetId": Object { + "assetId": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "description": Object { + "description": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "extension": Object { + "extension": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "label": Object { + "label": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "metadata": Object { + "metadata": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageMetadata", "type": "inline", }, }, - "mimeType": Object { + "mimeType": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "originalFilename": Object { + "originalFilename": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "path": Object { + "path": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "sha1hash": Object { + "sha1hash": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "size": Object { + "size": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "source": Object { + "source": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.assetSourceData", "type": "inline", }, }, - "title": Object { + "title": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "uploadId": Object { + "uploadId": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "url": Object { + "url": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -4336,36 +4336,36 @@ Array [ "name": "sanity.imageAsset", "type": "document", }, - Object { + { "name": "sanity.assetSourceData", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "sanity.assetSourceData", }, }, - "id": Object { + "id": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "name": Object { + "name": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "url": Object { + "url": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -4373,66 +4373,66 @@ Array [ "type": "object", }, }, - Object { + { "name": "sanity.imageMetadata", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "sanity.imageMetadata", }, }, - "blurHash": Object { + "blurHash": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "dimensions": Object { + "dimensions": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imageDimensions", "type": "inline", }, }, - "hasAlpha": Object { + "hasAlpha": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, - "isOpaque": Object { + "isOpaque": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, - "location": Object { + "location": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "geopoint", "type": "inline", }, }, - "lqip": Object { + "lqip": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "palette": Object { + "palette": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "sanity.imagePalette", "type": "inline", }, @@ -4441,88 +4441,88 @@ Array [ "type": "object", }, }, - Object { - "attributes": Object { - "_createdAt": Object { + { + "attributes": { + "_createdAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_id": Object { + "_id": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_rev": Object { + "_rev": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "validDocument", }, }, - "_updatedAt": Object { + "_updatedAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "blocks": Object { + "blocks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "block", }, }, - "children": Object { + "children": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "span", }, }, - "marks": Object { + "marks": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { + "value": { + "of": { "type": "string", }, "type": "array", }, }, - "text": Object { + "text": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -4534,23 +4534,23 @@ Array [ "type": "array", }, }, - "level": Object { + "level": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "listItem": Object { + "listItem": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "bullet", }, - Object { + { "type": "string", "value": "number", }, @@ -4558,32 +4558,32 @@ Array [ "type": "union", }, }, - "markDefs": Object { + "markDefs": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Object { - "attributes": Object { - "_type": Object { + "value": { + "of": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "link", }, }, - "href": Object { + "href": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -4595,40 +4595,40 @@ Array [ "type": "array", }, }, - "style": Object { + "style": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "normal", }, - Object { + { "type": "string", "value": "h1", }, - Object { + { "type": "string", "value": "h2", }, - Object { + { "type": "string", "value": "h3", }, - Object { + { "type": "string", "value": "h4", }, - Object { + { "type": "string", "value": "h5", }, - Object { + { "type": "string", "value": "h6", }, - Object { + { "type": "string", "value": "blockquote", }, @@ -4637,11 +4637,11 @@ Array [ }, }, }, - "rest": Object { - "attributes": Object { - "_key": Object { + "rest": { + "attributes": { + "_key": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -4653,28 +4653,28 @@ Array [ "type": "array", }, }, - "customStringType": Object { + "customStringType": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "customStringType", "type": "inline", }, }, - "list": Object { + "list": { "optional": true, "type": "objectAttribute", - "value": Object { - "of": Array [ - Object { + "value": { + "of": [ + { "type": "string", "value": "a", }, - Object { + { "type": "string", "value": "b", }, - Object { + { "type": "string", "value": "c", }, @@ -4682,40 +4682,40 @@ Array [ "type": "union", }, }, - "manuscript": Object { + "manuscript": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "manuscript", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -4724,28 +4724,28 @@ Array [ "type": "object", }, }, - "author": Object { + "author": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -4754,10 +4754,10 @@ Array [ "type": "object", }, }, - "description": Object { + "description": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -4765,35 +4765,35 @@ Array [ "type": "object", }, }, - "number": Object { + "number": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, - "other": Object { + "other": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -4802,28 +4802,28 @@ Array [ "type": "object", }, }, - "others": Object { + "others": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -4832,26 +4832,26 @@ Array [ "type": "object", }, }, - "someInlinedObject": Object { + "someInlinedObject": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "obj", "type": "inline", }, }, - "someTextType": Object { + "someTextType": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "name": "someTextType", "type": "inline", }, }, - "title": Object { + "title": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -4859,43 +4859,43 @@ Array [ "name": "validDocument", "type": "document", }, - Object { - "attributes": Object { - "_createdAt": Object { + { + "attributes": { + "_createdAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_id": Object { + "_id": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_rev": Object { + "_rev": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "otherValidDocument", }, }, - "_updatedAt": Object { + "_updatedAt": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "title": Object { + "title": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -4903,40 +4903,40 @@ Array [ "name": "otherValidDocument", "type": "document", }, - Object { + { "name": "manuscript", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "manuscript", }, }, - "asset": Object { + "asset": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -4945,28 +4945,28 @@ Array [ "type": "object", }, }, - "author": Object { + "author": { "optional": true, "type": "objectAttribute", - "value": Object { - "attributes": Object { - "_ref": Object { + "value": { + "attributes": { + "_ref": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "_type": Object { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "reference", }, }, - "_weak": Object { + "_weak": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "boolean", }, }, @@ -4975,10 +4975,10 @@ Array [ "type": "object", }, }, - "description": Object { + "description": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, @@ -4986,29 +4986,29 @@ Array [ "type": "object", }, }, - Object { + { "name": "obj", "type": "type", - "value": Object { - "attributes": Object { - "_type": Object { + "value": { + "attributes": { + "_type": { "type": "objectAttribute", - "value": Object { + "value": { "type": "string", "value": "obj", }, }, - "field1": Object { + "field1": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "string", }, }, - "field2": Object { + "field2": { "optional": true, "type": "objectAttribute", - "value": Object { + "value": { "type": "number", }, }, diff --git a/packages/@sanity/schema/test/extractSchema/extractSchema.test.ts b/packages/@sanity/schema/test/extractSchema/extractSchema.test.ts index 8ca796f3b44..fabf7e47fd4 100644 --- a/packages/@sanity/schema/test/extractSchema/extractSchema.test.ts +++ b/packages/@sanity/schema/test/extractSchema/extractSchema.test.ts @@ -1,8 +1,8 @@ import assert, {strictEqual} from 'node:assert' -import {describe, expect, test} from '@jest/globals' import {defineField, defineType} from '@sanity/types' import {type DocumentSchemaType} from 'groq-js' +import {describe, expect, test} from 'vitest' import {Schema} from '../../src/legacy/Schema' import {extractSchema} from '../../src/sanity/extractSchema' @@ -521,7 +521,7 @@ describe('Extract schema test', () => { expect(book.attributes.assetRequiredFileRuleSpec.value.attributes.asset.optional).toBe(false) // with assetRequired defined in _rules, it should be required }) - describe('can handle `list` option that is not an array', () => { + test('can handle `list` option that is not an array', () => { const schema = createSchema(schemaFixtures.listObjectOption) const extracted = extractSchema(schema) diff --git a/packages/@sanity/schema/test/legacy/schemas.test.ts b/packages/@sanity/schema/test/legacy/schemas.test.ts index 91890351bb2..72aa404f4e1 100644 --- a/packages/@sanity/schema/test/legacy/schemas.test.ts +++ b/packages/@sanity/schema/test/legacy/schemas.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {Schema} from '../../src/legacy/Schema' import rawSchemas from './fixtures/schemas' diff --git a/packages/@sanity/schema/test/validation/validation.test.ts b/packages/@sanity/schema/test/validation/validation.test.ts index b2053aca52d..0284ed88bc2 100644 --- a/packages/@sanity/schema/test/validation/validation.test.ts +++ b/packages/@sanity/schema/test/validation/validation.test.ts @@ -1,6 +1,6 @@ -import {describe, expect, test} from '@jest/globals' import {SquareIcon} from '@sanity/icons' import {flatten} from 'lodash' +import {describe, expect, test} from 'vitest' import {validateSchema} from '../../src/sanity/validateSchema' diff --git a/packages/@sanity/schema/vitest.config.mts b/packages/@sanity/schema/vitest.config.mts new file mode 100644 index 00000000000..c70678156c4 --- /dev/null +++ b/packages/@sanity/schema/vitest.config.mts @@ -0,0 +1,3 @@ +import {defineConfig} from '@repo/test-config/vitest' + +export default defineConfig() diff --git a/packages/@sanity/types/.eslintrc.cjs b/packages/@sanity/types/.eslintrc.cjs index 99fd6c69224..c9a446c5adf 100644 --- a/packages/@sanity/types/.eslintrc.cjs +++ b/packages/@sanity/types/.eslintrc.cjs @@ -1,6 +1,4 @@ -'use strict' - -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../../..') diff --git a/packages/@sanity/types/jest.config.cjs b/packages/@sanity/types/jest.config.cjs deleted file mode 100644 index 51ecfb62217..00000000000 --- a/packages/@sanity/types/jest.config.cjs +++ /dev/null @@ -1,8 +0,0 @@ -'use strict' - -const {createJestConfig} = require('../../../test/config.cjs') - -module.exports = createJestConfig({ - displayName: require('./package.json').name, - testEnvironment: 'node', -}) diff --git a/packages/@sanity/types/package.json b/packages/@sanity/types/package.json index 2450cd67916..543a4207186 100644 --- a/packages/@sanity/types/package.json +++ b/packages/@sanity/types/package.json @@ -1,6 +1,6 @@ { "name": "@sanity/types", - "version": "3.57.4", + "version": "3.58.0", "description": "Type definitions for common Sanity data structures", "keywords": [ "sanity", @@ -44,8 +44,8 @@ "check:types": "tsc --project tsconfig.lib.json", "clean": "rimraf lib", "prepublishOnly": "turbo run build", - "test": "jest", - "test:watch": "jest --watchAll", + "test": "vitest run", + "test:watch": "vitest watch", "watch": "pkg-utils watch" }, "dependencies": { @@ -53,9 +53,12 @@ "@types/react": "^18.3.5" }, "devDependencies": { - "@jest/globals": "^29.7.0", "@repo/package.config": "workspace:*", + "@repo/test-config": "workspace:*", "@sanity/insert-menu": "1.0.9", - "rimraf": "^3.0.2" + "@vitejs/plugin-react": "^4.3.1", + "react": "^18.3.1", + "rimraf": "^3.0.2", + "vitest": "^2.1.1" } } diff --git a/packages/@sanity/types/src/transactionLog/types.ts b/packages/@sanity/types/src/transactionLog/types.ts index 5a003eba75f..bea66a05033 100644 --- a/packages/@sanity/types/src/transactionLog/types.ts +++ b/packages/@sanity/types/src/transactionLog/types.ts @@ -51,7 +51,7 @@ export interface TransactionLogEventWithEffects extends TransactionLogEvent { */ export interface TransactionLogEventWithMutations extends TransactionLogEvent { /** - * Array of mutations that occured in this transaction. Note that the transaction + * Array of mutations that occurred in this transaction. Note that the transaction * log has an additional mutation type not typically seen in other APIs; * `createSquashed` ({@link CreateSquashedMutation}). */ @@ -83,7 +83,7 @@ export interface CreateSquashedMutation { createdAt: string /** - * The document as it exists after squashing has occured + * The document as it exists after squashing has occurred */ document: { _id: string diff --git a/packages/@sanity/types/test/alias.test.ts b/packages/@sanity/types/test/alias.test.ts index 3717de4d5e1..1b8e622afda 100644 --- a/packages/@sanity/types/test/alias.test.ts +++ b/packages/@sanity/types/test/alias.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/array.test.ts b/packages/@sanity/types/test/array.test.ts index 0931a4aaf00..79424f0ca36 100644 --- a/packages/@sanity/types/test/array.test.ts +++ b/packages/@sanity/types/test/array.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/block.test.ts b/packages/@sanity/types/test/block.test.ts index ef03e058f88..412383439f6 100644 --- a/packages/@sanity/types/test/block.test.ts +++ b/packages/@sanity/types/test/block.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/boolean.test.ts b/packages/@sanity/types/test/boolean.test.ts index c5148ea9f96..1ba1a92abc8 100644 --- a/packages/@sanity/types/test/boolean.test.ts +++ b/packages/@sanity/types/test/boolean.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/date.test.ts b/packages/@sanity/types/test/date.test.ts index f1fe123a44f..bdf09667d74 100644 --- a/packages/@sanity/types/test/date.test.ts +++ b/packages/@sanity/types/test/date.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/datetime.test.ts b/packages/@sanity/types/test/datetime.test.ts index 8ccb21b633c..d3c1202473c 100644 --- a/packages/@sanity/types/test/datetime.test.ts +++ b/packages/@sanity/types/test/datetime.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/document.test.ts b/packages/@sanity/types/test/document.test.ts index c7f6c9ce682..bd032be8e19 100644 --- a/packages/@sanity/types/test/document.test.ts +++ b/packages/@sanity/types/test/document.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/email.test.ts b/packages/@sanity/types/test/email.test.ts index 0e58d2c96e1..c8f1d85eb66 100644 --- a/packages/@sanity/types/test/email.test.ts +++ b/packages/@sanity/types/test/email.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ import {type BooleanDefinition, type EmailDefinition} from '../src/schema/definition' diff --git a/packages/@sanity/types/test/file.test.ts b/packages/@sanity/types/test/file.test.ts index c24ddfcd783..4ab5c464c2a 100644 --- a/packages/@sanity/types/test/file.test.ts +++ b/packages/@sanity/types/test/file.test.ts @@ -1,10 +1,10 @@ -import {describe, it} from '@jest/globals' /* eslint-disable @typescript-eslint/no-unused-vars */ /** * Some of these tests have no expect statement; * use of ts-expect-error serves the same purpose - TypeScript is the testrunner here */ import {type FileDefinition, type StringDefinition} from '@sanity/types' +import {describe, it} from 'vitest' import {defineField, defineType} from '../src/schema/types' diff --git a/packages/@sanity/types/test/generic.test.tsx b/packages/@sanity/types/test/generic.test.tsx index 22cd671e50c..efe75979197 100644 --- a/packages/@sanity/types/test/generic.test.tsx +++ b/packages/@sanity/types/test/generic.test.tsx @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/geopoint.test.ts b/packages/@sanity/types/test/geopoint.test.ts index 6356e1a9bf2..e6341edcf8d 100644 --- a/packages/@sanity/types/test/geopoint.test.ts +++ b/packages/@sanity/types/test/geopoint.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/image.test.ts b/packages/@sanity/types/test/image.test.ts index 4fa41524de8..4221adfc380 100644 --- a/packages/@sanity/types/test/image.test.ts +++ b/packages/@sanity/types/test/image.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/number.test.ts b/packages/@sanity/types/test/number.test.ts index 8b890c5bb93..b9c6935dac0 100644 --- a/packages/@sanity/types/test/number.test.ts +++ b/packages/@sanity/types/test/number.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/object.test.ts b/packages/@sanity/types/test/object.test.ts index 39d891d9ed0..dd25798c244 100644 --- a/packages/@sanity/types/test/object.test.ts +++ b/packages/@sanity/types/test/object.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/reference.test.ts b/packages/@sanity/types/test/reference.test.ts index 8d428d68648..60539411682 100644 --- a/packages/@sanity/types/test/reference.test.ts +++ b/packages/@sanity/types/test/reference.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/slug.test.ts b/packages/@sanity/types/test/slug.test.ts index 0b3cd8f5af7..59b99325669 100644 --- a/packages/@sanity/types/test/slug.test.ts +++ b/packages/@sanity/types/test/slug.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/string.test.ts b/packages/@sanity/types/test/string.test.ts index 843defd403b..f311508e481 100644 --- a/packages/@sanity/types/test/string.test.ts +++ b/packages/@sanity/types/test/string.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/text.test.ts b/packages/@sanity/types/test/text.test.ts index 9dc7c9dc2a1..9e07d2eea9e 100644 --- a/packages/@sanity/types/test/text.test.ts +++ b/packages/@sanity/types/test/text.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/test/typeMerge.test.ts b/packages/@sanity/types/test/typeMerge.test.ts index 6b457a8e344..366ed8bbca6 100644 --- a/packages/@sanity/types/test/typeMerge.test.ts +++ b/packages/@sanity/types/test/typeMerge.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' import {type ExtensionTypeExampleDef, type ObjectDefinition} from '../src/schema/definition' import {defineType} from '../src/schema/types' diff --git a/packages/@sanity/types/test/url.test.ts b/packages/@sanity/types/test/url.test.ts index 2eab9bd0d49..ced13927718 100644 --- a/packages/@sanity/types/test/url.test.ts +++ b/packages/@sanity/types/test/url.test.ts @@ -1,4 +1,4 @@ -import {describe, it} from '@jest/globals' +import {describe, it} from 'vitest' /* eslint-disable @typescript-eslint/no-unused-vars */ /** diff --git a/packages/@sanity/types/vitest.config.mts b/packages/@sanity/types/vitest.config.mts new file mode 100644 index 00000000000..c38d69d9c06 --- /dev/null +++ b/packages/@sanity/types/vitest.config.mts @@ -0,0 +1,6 @@ +import {defineConfig} from '@repo/test-config/vitest' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +}) diff --git a/packages/@sanity/util/.eslintrc.cjs b/packages/@sanity/util/.eslintrc.cjs index 99fd6c69224..c9a446c5adf 100644 --- a/packages/@sanity/util/.eslintrc.cjs +++ b/packages/@sanity/util/.eslintrc.cjs @@ -1,6 +1,4 @@ -'use strict' - -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../../..') diff --git a/packages/@sanity/util/jest.config.cjs b/packages/@sanity/util/jest.config.cjs deleted file mode 100644 index 644f91ee308..00000000000 --- a/packages/@sanity/util/jest.config.cjs +++ /dev/null @@ -1,7 +0,0 @@ -'use strict' - -const {createJestConfig} = require('../../../test/config.cjs') - -module.exports = createJestConfig({ - displayName: require('./package.json').name, -}) diff --git a/packages/@sanity/util/package.json b/packages/@sanity/util/package.json index 5a3c2672654..e22dc339f90 100644 --- a/packages/@sanity/util/package.json +++ b/packages/@sanity/util/package.json @@ -1,6 +1,6 @@ { "name": "@sanity/util", - "version": "3.57.4", + "version": "3.58.0", "description": "Utilities shared across projects of Sanity", "keywords": [ "sanity", @@ -117,21 +117,22 @@ "check:types": "tsc --project tsconfig.lib.json", "clean": "rimraf client.js concurrency-limiter.js content.js createSafeJsonParser.js fs.js legacyDateFormat.js lib paths.js", "prepublishOnly": "turbo run build", - "test": "jest", + "test": "vitest run", "watch": "pkg-utils watch" }, "dependencies": { "@sanity/client": "^6.21.3", - "@sanity/types": "3.57.4", + "@sanity/types": "3.58.0", "get-random-values-esm": "1.0.2", "moment": "^2.29.4", "rxjs": "^7.8.1" }, "devDependencies": { - "@jest/globals": "^29.7.0", "@repo/package.config": "workspace:*", + "@repo/test-config": "workspace:*", "@types/moment": "^2.13.0", - "rimraf": "^3.0.2" + "rimraf": "^3.0.2", + "vitest": "^2.1.1" }, "engines": { "node": ">=18" diff --git a/packages/@sanity/util/src/client/concurrency-limiter/__test__/createClientConcurrencyLimiter.test.ts b/packages/@sanity/util/src/client/concurrency-limiter/__test__/createClientConcurrencyLimiter.test.ts index 9fb285b07f7..c6dddeecf1c 100644 --- a/packages/@sanity/util/src/client/concurrency-limiter/__test__/createClientConcurrencyLimiter.test.ts +++ b/packages/@sanity/util/src/client/concurrency-limiter/__test__/createClientConcurrencyLimiter.test.ts @@ -1,8 +1,8 @@ import {types} from 'node:util' -import {describe, expect, it, jest} from '@jest/globals' import {createClient, type SanityClient} from '@sanity/client' import {firstValueFrom, from} from 'rxjs' +import {describe, expect, it, vi} from 'vitest' import {createClientConcurrencyLimiter} from '../createClientConcurrencyLimiter' @@ -17,7 +17,7 @@ describe('createConcurrencyLimitedClient', () => { })() const mockClient = { - fetch: jest.fn(() => deferredPromise), + fetch: vi.fn(() => deferredPromise), } as unknown as SanityClient const limitConcurrency = createClientConcurrencyLimiter(1) @@ -45,7 +45,7 @@ describe('createConcurrencyLimitedClient', () => { const mockClient = { observable: { - fetch: jest.fn(() => from(deferredPromise)), + fetch: vi.fn(() => from(deferredPromise)), }, } as unknown as SanityClient diff --git a/packages/@sanity/util/src/content/__test__/isDeepEmpty.test.ts b/packages/@sanity/util/src/content/__test__/isDeepEmpty.test.ts index 3f0f6e41324..1088acd7cd3 100644 --- a/packages/@sanity/util/src/content/__test__/isDeepEmpty.test.ts +++ b/packages/@sanity/util/src/content/__test__/isDeepEmpty.test.ts @@ -1,4 +1,5 @@ -import {it, expect} from '@jest/globals' +import {expect, it} from 'vitest' + import {isDeepEmpty} from '../isDeepEmpty' it('returns true for undefined', () => { diff --git a/packages/@sanity/util/test/ConcurrencyLimiter.test.ts b/packages/@sanity/util/test/ConcurrencyLimiter.test.ts index cbca6b83ca1..fcf99d1e69f 100644 --- a/packages/@sanity/util/test/ConcurrencyLimiter.test.ts +++ b/packages/@sanity/util/test/ConcurrencyLimiter.test.ts @@ -1,4 +1,4 @@ -import {describe, expect, it, jest} from '@jest/globals' +import {describe, expect, it, vi} from 'vitest' import {ConcurrencyLimiter} from '../src/concurrency-limiter' @@ -8,10 +8,10 @@ describe('ConcurrencyLimiter', () => { it('keeps track of inflight operations and prevents more than the max concurrency at a time', async () => { const limiter = new ConcurrencyLimiter(2) - const promise1Cb = jest.fn() - const promise2Cb = jest.fn() - const promise3Cb = jest.fn() - const promise4Cb = jest.fn() + const promise1Cb = vi.fn() + const promise2Cb = vi.fn() + const promise3Cb = vi.fn() + const promise4Cb = vi.fn() const allDone = Promise.all([ limiter.ready().then(promise1Cb), diff --git a/packages/@sanity/util/test/PathUtils.test.ts b/packages/@sanity/util/test/PathUtils.test.ts index 63cb3b26589..18fa162a1fc 100644 --- a/packages/@sanity/util/test/PathUtils.test.ts +++ b/packages/@sanity/util/test/PathUtils.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' /* eslint-disable max-nested-callbacks, @typescript-eslint/ban-ts-comment */ import {fromString, get, resolveKeyedPath, toString} from '../src/paths' diff --git a/packages/@sanity/util/test/createSafeJsonParser.test.ts b/packages/@sanity/util/test/createSafeJsonParser.test.ts index 8aec5d9e14b..91f08e26e57 100644 --- a/packages/@sanity/util/test/createSafeJsonParser.test.ts +++ b/packages/@sanity/util/test/createSafeJsonParser.test.ts @@ -1,4 +1,4 @@ -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {createSafeJsonParser} from '../src/createSafeJsonParser' @@ -14,9 +14,9 @@ test('parse JSON', () => { test('parse JSON with interrupting error', () => { expect(() => parse('{"someString": "str{"error":{"description":"Some error"}}')) .toThrowErrorMatchingInlineSnapshot(` -"Error parsing JSON: Some error + [Error: Error parsing JSON: Some error -{\\"error\\":{\\"description\\":\\"Some error\\"}} -" -`) + {"error":{"description":"Some error"}} + ] + `) }) diff --git a/packages/@sanity/util/test/util.test.ts b/packages/@sanity/util/test/util.test.ts index 4b7a48f0f2a..7e6c33450ae 100644 --- a/packages/@sanity/util/test/util.test.ts +++ b/packages/@sanity/util/test/util.test.ts @@ -3,7 +3,7 @@ import * as fs from 'node:fs' import * as os from 'node:os' import * as path from 'node:path' -import {expect, test} from '@jest/globals' +import {expect, test} from 'vitest' import {absolutify, expandHome, pathIsEmpty} from '../src/fsTools' diff --git a/packages/@sanity/util/vitest.config.mts b/packages/@sanity/util/vitest.config.mts new file mode 100644 index 00000000000..c70678156c4 --- /dev/null +++ b/packages/@sanity/util/vitest.config.mts @@ -0,0 +1,3 @@ +import {defineConfig} from '@repo/test-config/vitest' + +export default defineConfig() diff --git a/packages/@sanity/vision/.eslintrc.cjs b/packages/@sanity/vision/.eslintrc.cjs index 99fd6c69224..c9a446c5adf 100644 --- a/packages/@sanity/vision/.eslintrc.cjs +++ b/packages/@sanity/vision/.eslintrc.cjs @@ -1,6 +1,4 @@ -'use strict' - -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../../..') diff --git a/packages/@sanity/vision/package.json b/packages/@sanity/vision/package.json index 43dd29c3a39..4b6f863a2bb 100644 --- a/packages/@sanity/vision/package.json +++ b/packages/@sanity/vision/package.json @@ -1,6 +1,6 @@ { "name": "@sanity/vision", - "version": "3.57.4", + "version": "3.58.0", "description": "Sanity plugin for running/debugging GROQ-queries against Sanity datasets", "keywords": [ "sanity", diff --git a/packages/@sanity/vision/src/containers/VisionErrorBoundary.tsx b/packages/@sanity/vision/src/containers/VisionErrorBoundary.tsx index a82ae4bf7ab..383be049414 100644 --- a/packages/@sanity/vision/src/containers/VisionErrorBoundary.tsx +++ b/packages/@sanity/vision/src/containers/VisionErrorBoundary.tsx @@ -69,7 +69,7 @@ export class VisionErrorBoundary extends Component< /> - An error occured + An error occurred diff --git a/packages/create-sanity/index.js b/packages/create-sanity/index.js index c303d6ca371..b7c9beee290 100755 --- a/packages/create-sanity/index.js +++ b/packages/create-sanity/index.js @@ -1,6 +1,6 @@ #!/usr/bin/env node -const childProcess = require('child_process') -const path = require('path') +const childProcess = require('node:child_process') +const path = require('node:path') const resolvePkg = require('resolve-pkg') const args = process.argv.slice(2) diff --git a/packages/create-sanity/package.json b/packages/create-sanity/package.json index f7392caeb35..0bbb241f87f 100644 --- a/packages/create-sanity/package.json +++ b/packages/create-sanity/package.json @@ -1,6 +1,6 @@ { "name": "create-sanity", - "version": "3.57.4", + "version": "3.58.0", "description": "Initialize a new Sanity project", "keywords": [ "sanity", @@ -26,7 +26,7 @@ "index.js" ], "dependencies": { - "@sanity/cli": "3.57.4", + "@sanity/cli": "3.58.0", "resolve-pkg": "^2.0.0" }, "engines": { diff --git a/packages/groq/.eslintrc.cjs b/packages/groq/.eslintrc.cjs index 4b3a2aaccdc..1ab5fa45ba9 100644 --- a/packages/groq/.eslintrc.cjs +++ b/packages/groq/.eslintrc.cjs @@ -1,6 +1,4 @@ -'use strict' - -const path = require('path') +const path = require('node:path') const ROOT_PATH = path.resolve(__dirname, '../..') diff --git a/packages/groq/package.json b/packages/groq/package.json index 27a900ad7fa..b49534e9267 100644 --- a/packages/groq/package.json +++ b/packages/groq/package.json @@ -1,6 +1,6 @@ { "name": "groq", - "version": "3.57.4", + "version": "3.58.0", "description": "Tagged template literal for Sanity.io GROQ-queries", "keywords": [ "sanity", diff --git a/packages/groq/test/define.test.cjs b/packages/groq/test/define.test.cjs index 71d2652b145..09fed2a9a8a 100644 --- a/packages/groq/test/define.test.cjs +++ b/packages/groq/test/define.test.cjs @@ -1,4 +1,3 @@ -'use strict' // Integration test for the Node.js CJS runtime const {strict: assert} = require('node:assert') diff --git a/packages/groq/test/groq.test.cjs b/packages/groq/test/groq.test.cjs index 1b4cbb6e6ff..a63d41b1171 100644 --- a/packages/groq/test/groq.test.cjs +++ b/packages/groq/test/groq.test.cjs @@ -1,4 +1,3 @@ -'use strict' // Integration test for the Node.js CJS runtime const {strict: assert} = require('node:assert') diff --git a/packages/sanity/jest.config.cjs b/packages/sanity/jest.config.cjs deleted file mode 100644 index fbe5b921f05..00000000000 --- a/packages/sanity/jest.config.cjs +++ /dev/null @@ -1,19 +0,0 @@ -const path = require('node:path') -const {createJestConfig} = require('../../test/config.cjs') - -const cliPath = path.resolve(__dirname, './src/_internal/cli') - -module.exports = createJestConfig({ - displayName: require('./package.json').name, - globalSetup: '/test/setup/global.ts', - setupFiles: ['/test/setup/environment.ts'], - setupFilesAfterEnv: ['/test/setup/afterEnv.ts'], - modulePathIgnorePatterns: [ - '/playwright-ct', - cliPath, // the CLI has its own jest config - ], - projects: [ - __dirname, // self - cliPath, // cli - ], -}) diff --git a/packages/sanity/jest.config.mjs b/packages/sanity/jest.config.mjs new file mode 100644 index 00000000000..5a3590d1488 --- /dev/null +++ b/packages/sanity/jest.config.mjs @@ -0,0 +1,15 @@ +import path from 'node:path' +import {createJestConfig, readPackageName, resolveDirName} from '@repo/test-config/jest' + +const cliPath = path.resolve(resolveDirName(import.meta.url), './src/_internal/cli') + +export default createJestConfig({ + displayName: readPackageName(import.meta.url), + globalSetup: '/test/setup/global.ts', + setupFiles: ['/test/setup/environment.ts'], + setupFilesAfterEnv: ['/test/setup/afterEnv.ts'], + modulePathIgnorePatterns: [ + '/playwright-ct', + cliPath, // the CLI has its own jest config + ], +}) diff --git a/packages/sanity/package.json b/packages/sanity/package.json index e8145a8812a..5aded12c020 100644 --- a/packages/sanity/package.json +++ b/packages/sanity/package.json @@ -1,6 +1,6 @@ { "name": "sanity", - "version": "3.57.4", + "version": "3.58.0", "description": "Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches", "keywords": [ "sanity", @@ -158,11 +158,11 @@ "@rexxars/react-json-inspector": "^8.0.1", "@sanity/asset-utils": "^1.2.5", "@sanity/bifur-client": "^0.4.1", - "@sanity/block-tools": "3.57.4", - "@sanity/cli": "3.57.4", + "@sanity/block-tools": "3.58.0", + "@sanity/cli": "3.58.0", "@sanity/client": "^6.21.3", "@sanity/color": "^3.0.0", - "@sanity/diff": "3.57.4", + "@sanity/diff": "3.58.0", "@sanity/diff-match-patch": "^3.1.1", "@sanity/eventsource": "^5.0.0", "@sanity/export": "^3.41.0", @@ -171,14 +171,14 @@ "@sanity/import": "^3.37.3", "@sanity/insert-menu": "1.0.9", "@sanity/logos": "^2.1.4", - "@sanity/migrate": "3.57.4", - "@sanity/mutator": "3.57.4", + "@sanity/migrate": "3.58.0", + "@sanity/mutator": "3.58.0", "@sanity/presentation": "1.16.5", - "@sanity/schema": "3.57.4", + "@sanity/schema": "3.58.0", "@sanity/telemetry": "^0.7.7", - "@sanity/types": "3.57.4", + "@sanity/types": "3.58.0", "@sanity/ui": "^2.8.9", - "@sanity/util": "3.57.4", + "@sanity/util": "3.58.0", "@sanity/uuid": "^3.0.1", "@sentry/react": "^8.7.0", "@tanstack/react-table": "^8.16.0", @@ -270,8 +270,10 @@ "@jest/globals": "^29.7.0", "@playwright/experimental-ct-react": "1.44.1", "@playwright/test": "1.44.1", + "@repo/dev-aliases": "workspace:*", "@repo/package.config": "workspace:*", - "@sanity/codegen": "3.57.4", + "@repo/test-config": "workspace:*", + "@sanity/codegen": "3.58.0", "@sanity/generate-help-url": "^3.0.0", "@sanity/pkg-utils": "6.11.2", "@sanity/tsdoc": "1.0.105", diff --git a/packages/sanity/src/_internal/cli/jest.config.cjs b/packages/sanity/src/_internal/cli/jest.config.cjs deleted file mode 100644 index 25196fe02b2..00000000000 --- a/packages/sanity/src/_internal/cli/jest.config.cjs +++ /dev/null @@ -1,7 +0,0 @@ -const {createJestConfig} = require('../../../../../test/config.cjs') -const path = require('node:path') - -module.exports = createJestConfig({ - displayName: `${require('../../../package.json').name}/${path.basename(__dirname)}`, - testEnvironment: 'node', -}) diff --git a/packages/sanity/src/_internal/cli/jest.config.mjs b/packages/sanity/src/_internal/cli/jest.config.mjs new file mode 100644 index 00000000000..a5403040555 --- /dev/null +++ b/packages/sanity/src/_internal/cli/jest.config.mjs @@ -0,0 +1,6 @@ +import {createJestConfig} from '@repo/test-config/jest' + +export default createJestConfig({ + displayName: 'sanity/cli', + testEnvironment: 'node', +}) diff --git a/packages/sanity/src/_internal/cli/server/__tests__/aliases.test.ts b/packages/sanity/src/_internal/cli/server/__tests__/aliases.test.ts index a45e6f7c84d..c5b67c84555 100644 --- a/packages/sanity/src/_internal/cli/server/__tests__/aliases.test.ts +++ b/packages/sanity/src/_internal/cli/server/__tests__/aliases.test.ts @@ -5,7 +5,11 @@ import {escapeRegExp} from 'lodash' import resolve from 'resolve.exports' import {type Alias} from 'vite' -import {browserCompatibleSanityPackageSpecifiers, getAliases} from '../aliases' +import { + browserCompatibleSanityPackageSpecifiers, + getSanityPkgExportAliases, +} from '../getBrowserAliases' +import {getMonorepoAliases} from '../sanityMonorepo' const sanityPkgPath = path.resolve(__dirname, '../../../../../package.json') // eslint-disable-next-line import/no-dynamic-require @@ -57,7 +61,7 @@ describe('getAliases', () => { // > esbuild in this environment because esbuild relies on this invariant. This // > is not a problem with esbuild. You need to fix your environment instead. it('returns the correct aliases for normal builds', () => { - const aliases = getAliases({sanityPkgPath}) + const aliases = getSanityPkgExportAliases(sanityPkgPath) // Prepare expected aliases const dirname = path.dirname(sanityPkgPath) @@ -80,31 +84,24 @@ describe('getAliases', () => { expect(aliases).toEqual(expectedAliases) }) - it('returns the correct aliases for the monorepo', () => { - const monorepoPath = path.resolve(__dirname, '../../../../../monorepo') + it('returns the correct aliases for the monorepo', async () => { + const monorepoPath = '/path/to/monorepo' const devAliases = { - 'sanity/_singletons': 'packages/sanity/src/_singletons.ts', - 'sanity/desk': 'packages/sanity/src/desk.ts', - 'sanity/presentation': 'packages/sanity/src/presentation.ts', + 'sanity/_singletons': 'sanity/src/_singletons.ts', + 'sanity/desk': 'sanity/src/desk.ts', + 'sanity/presentation': 'sanity/src/presentation.ts', } - jest.doMock(path.resolve(monorepoPath, 'dev/aliases.cjs'), () => devAliases, {virtual: true}) - const aliases = getAliases({ - monorepo: {path: monorepoPath}, - }) - - const expectedAliases = Object.fromEntries( - Object.entries(devAliases).map(([key, modulePath]) => { - return [key, path.resolve(monorepoPath, modulePath)] - }), - ) + const expectedAliases = { + 'sanity/_singletons': '/path/to/monorepo/packages/sanity/src/_singletons.ts', + 'sanity/desk': '/path/to/monorepo/packages/sanity/src/desk.ts', + 'sanity/presentation': '/path/to/monorepo/packages/sanity/src/presentation.ts', + } - expect(aliases).toMatchObject(expectedAliases) - }) + jest.doMock('@repo/dev-aliases', () => devAliases, {virtual: true}) - it('returns an empty object if no conditions are met', () => { - const aliases = getAliases({}) + const aliases = await getMonorepoAliases(monorepoPath) - expect(aliases).toEqual({}) + expect(aliases).toMatchObject(expectedAliases) }) }) diff --git a/packages/sanity/src/_internal/cli/server/aliases.ts b/packages/sanity/src/_internal/cli/server/aliases.ts index 4d8fb8639fb..39cea623361 100644 --- a/packages/sanity/src/_internal/cli/server/aliases.ts +++ b/packages/sanity/src/_internal/cli/server/aliases.ts @@ -1,51 +1,18 @@ -import path from 'node:path' +import {type AliasOptions} from 'vite' -import {escapeRegExp} from 'lodash' -import resolve from 'resolve.exports' -import {type Alias, type AliasOptions} from 'vite' - -import {type SanityMonorepo} from './sanityMonorepo' +import {getSanityPkgExportAliases} from './getBrowserAliases' +import {getMonorepoAliases} from './sanityMonorepo' /** * @internal */ export interface GetAliasesOptions { - /** An optional monorepo configuration object. */ - monorepo?: SanityMonorepo + /** An optional monorepo path. */ + monorepoPath?: string /** The path to the sanity package.json file. */ - sanityPkgPath?: string + sanityPkgPath: string } -/** - * The following are the specifiers that are expected/allowed to be used within - * a built Sanity studio in the browser. These are used in combination with - * `resolve.exports` to determine the final entry point locations for each allowed specifier. - * - * There is also a corresponding test for this file that expects these to be - * included in the `sanity` package.json. That test is meant to keep this list - * in sync in the event we add another package subpath. - * - * @internal - */ -export const browserCompatibleSanityPackageSpecifiers = [ - 'sanity', - 'sanity/_createContext', - 'sanity/_singletons', - 'sanity/desk', - 'sanity/presentation', - 'sanity/router', - 'sanity/structure', - 'sanity/package.json', -] - -/** - * These conditions should align with the conditions present in the - * `package.json` of the `'sanity'` module. they are given to `resolve.exports` - * in order to determine the correct entrypoint for the browser-compatible - * package specifiers listed above. - */ -const conditions = ['import', 'browser', 'default'] - /** * Returns an object of aliases for Vite to use. * @@ -55,61 +22,13 @@ const conditions = ['import', 'browser', 'default'] * * If the project is within the monorepo, it uses the source files directly for a better * development experience. Otherwise, it uses the `sanityPkgPath` and `conditions` to locate - * the entry points for each subpath the Sanity module exports. + * the entry points for each subpath of the Sanity module exports. * * @internal */ -export function getAliases({monorepo, sanityPkgPath}: GetAliasesOptions): AliasOptions { - // If the current Studio is located within the Sanity monorepo - if (monorepo?.path) { - // Load monorepo aliases. This ensures that the Vite server uses the source files - // instead of the compiled output, allowing for a better development experience. - const aliasesPath = path.resolve(monorepo.path, 'dev/aliases.cjs') - - // Import the development aliases configuration - // eslint-disable-next-line import/no-dynamic-require - const devAliases: Record = require(aliasesPath) - - // Resolve each alias path relative to the monorepo path - const monorepoAliases = Object.fromEntries( - Object.entries(devAliases).map(([key, modulePath]) => { - return [key, path.resolve(monorepo.path, modulePath)] - }), - ) - - // Return the aliases configuration for monorepo - return monorepoAliases - } - - // If not in the monorepo, use the `sanityPkgPath` - // to locate the entry points for each subpath the Sanity module exports - if (sanityPkgPath) { - // Load the package.json of the Sanity package - // eslint-disable-next-line import/no-dynamic-require - const pkg = require(sanityPkgPath) - const dirname = path.dirname(sanityPkgPath) - - // Resolve the entry points for each allowed specifier - const unifiedSanityAliases = browserCompatibleSanityPackageSpecifiers.reduce( - (acc, next) => { - // Resolve the export path for the specifier using resolve.exports - const dest = resolve.exports(pkg, next, {browser: true, conditions})?.[0] - if (!dest) return acc - - // Map the specifier to its resolved path - acc.push({ - find: new RegExp(`^${escapeRegExp(next)}$`), - replacement: path.resolve(dirname, dest), - }) - return acc - }, - [], - ) - - // Return the aliases configuration for external projects - return unifiedSanityAliases - } - - // Return an empty aliases configuration if no conditions are met - return {} +export async function getAliases({ + monorepoPath, + sanityPkgPath, +}: GetAliasesOptions): Promise { + return monorepoPath ? getMonorepoAliases(monorepoPath) : getSanityPkgExportAliases(sanityPkgPath) } diff --git a/packages/sanity/src/_internal/cli/server/getBrowserAliases.ts b/packages/sanity/src/_internal/cli/server/getBrowserAliases.ts new file mode 100644 index 00000000000..91ca70d22d7 --- /dev/null +++ b/packages/sanity/src/_internal/cli/server/getBrowserAliases.ts @@ -0,0 +1,63 @@ +import path from 'node:path' + +import {escapeRegExp} from 'lodash' +import resolve from 'resolve.exports' +import {type Alias} from 'vite' + +/** + * The following are the specifiers that are expected/allowed to be used within + * a built Sanity studio in the browser. These are used in combination with + * `resolve.exports` to determine the final entry point locations for each allowed specifier. + * + * There is also a corresponding test for this file that expects these to be + * included in the `sanity` package.json. That test is meant to keep this list + * in sync in the event we add another package subpath. + * + * @internal + */ +export const browserCompatibleSanityPackageSpecifiers = [ + 'sanity', + 'sanity/_createContext', + 'sanity/_singletons', + 'sanity/desk', + 'sanity/presentation', + 'sanity/router', + 'sanity/structure', + 'sanity/package.json', +] + +/** + * These conditions should align with the conditions present in the + * `package.json` of the `'sanity'` module. they are given to `resolve.exports` + * in order to determine the correct entrypoint for the browser-compatible + * package specifiers listed above. + */ +const conditions = ['import', 'browser', 'default'] + +// locate the entry points for each subpath the Sanity module exports +export function getSanityPkgExportAliases(sanityPkgPath: string) { + // Load the package.json of the Sanity package + // eslint-disable-next-line import/no-dynamic-require + const pkg = require(sanityPkgPath) + const dirname = path.dirname(sanityPkgPath) + + // Resolve the entry points for each allowed specifier + const unifiedSanityAliases = browserCompatibleSanityPackageSpecifiers.reduce( + (acc, next) => { + // Resolve the export path for the specifier using resolve.exports + const dest = resolve.exports(pkg, next, {browser: true, conditions})?.[0] + if (!dest) return acc + + // Map the specifier to its resolved path + acc.push({ + find: new RegExp(`^${escapeRegExp(next)}$`), + replacement: path.resolve(dirname, dest), + }) + return acc + }, + [], + ) + + // Return the aliases configuration for external projects + return unifiedSanityAliases +} diff --git a/packages/sanity/src/_internal/cli/server/getViteConfig.ts b/packages/sanity/src/_internal/cli/server/getViteConfig.ts index 3e27aaa03b6..0acd60bf48c 100644 --- a/packages/sanity/src/_internal/cli/server/getViteConfig.ts +++ b/packages/sanity/src/_internal/cli/server/getViteConfig.ts @@ -6,11 +6,11 @@ import debug from 'debug' import readPkgUp from 'read-pkg-up' import {type ConfigEnv, type InlineConfig, mergeConfig} from 'vite' -import {getAliases} from './aliases' import {createExternalFromImportMap} from './createExternalFromImportMap' +import {getSanityPkgExportAliases} from './getBrowserAliases' import {getStudioEnvironmentVariables} from './getStudioEnvironmentVariables' import {normalizeBasePath} from './helpers' -import {loadSanityMonorepo} from './sanityMonorepo' +import {getMonorepoAliases, loadSanityMonorepo} from './sanityMonorepo' import {sanityBuildEntries} from './vite/plugin-sanity-build-entries' import {sanityDotWorkaroundPlugin} from './vite/plugin-sanity-dot-workaround' import {sanityFaviconsPlugin} from './vite/plugin-sanity-favicons' @@ -113,7 +113,9 @@ export async function getViteConfig(options: ViteOptions): Promise envPrefix: 'SANITY_STUDIO_', logLevel: mode === 'production' ? 'silent' : 'info', resolve: { - alias: getAliases({monorepo, sanityPkgPath}), + alias: monorepo?.path + ? await getMonorepoAliases(monorepo.path) + : getSanityPkgExportAliases(sanityPkgPath), dedupe: ['styled-components'], }, define: { diff --git a/packages/sanity/src/_internal/cli/server/renderDocument.ts b/packages/sanity/src/_internal/cli/server/renderDocument.ts index 0033e621a85..3c1a3badd96 100644 --- a/packages/sanity/src/_internal/cli/server/renderDocument.ts +++ b/packages/sanity/src/_internal/cli/server/renderDocument.ts @@ -16,10 +16,9 @@ import {parse as parseHtml} from 'node-html-parser' import {createElement} from 'react' import {renderToStaticMarkup} from 'react-dom/server' -import {getAliases} from './aliases' import {TIMESTAMPED_IMPORTMAP_INJECTOR_SCRIPT} from './constants' import {debug as serverDebug} from './debug' -import {type SanityMonorepo} from './sanityMonorepo' +import {getMonorepoAliases, type SanityMonorepo} from './sanityMonorepo' const debug = serverDebug.extend('renderDocument') @@ -173,7 +172,9 @@ function renderDocumentFromWorkerData() { // Require hook #1 // Alias monorepo modules debug('Registering potential aliases') - require('module-alias').addAliases(getAliases({monorepo})) + if (monorepo) { + require('module-alias').addAliases(getMonorepoAliases(monorepo.path)) + } // Require hook #2 // Use `esbuild` to allow JSX/TypeScript and modern JS features diff --git a/packages/sanity/src/_internal/cli/server/sanityMonorepo.ts b/packages/sanity/src/_internal/cli/server/sanityMonorepo.ts index 9837f5717e4..a41e2426212 100644 --- a/packages/sanity/src/_internal/cli/server/sanityMonorepo.ts +++ b/packages/sanity/src/_internal/cli/server/sanityMonorepo.ts @@ -9,6 +9,15 @@ export interface SanityMonorepo { path: string } +export async function getMonorepoAliases(monorepoPath: string) { + const {default: aliases} = await import('@repo/dev-aliases') + return Object.fromEntries( + Object.entries(aliases).map(([pkgName, pkgPath]) => { + return [pkgName, path.resolve(monorepoPath, path.join('packages', pkgPath))] + }), + ) +} + /** * Load information about the `sanity-io/sanity` monorepo (if applicable) * diff --git a/packages/sanity/src/_internal/cli/threads/__tests__/validateDocuments.test.ts b/packages/sanity/src/_internal/cli/threads/__tests__/validateDocuments.test.ts index df9018b56fd..dcfac4c9950 100644 --- a/packages/sanity/src/_internal/cli/threads/__tests__/validateDocuments.test.ts +++ b/packages/sanity/src/_internal/cli/threads/__tests__/validateDocuments.test.ts @@ -6,7 +6,7 @@ import {afterAll, beforeAll, describe, expect, it, jest} from '@jest/globals' import {type SanityDocument, type SanityProject} from '@sanity/client' import {evaluate, parse} from 'groq-js' -import {getAliases} from '../../server/aliases' +import {getMonorepoAliases} from '../../server/sanityMonorepo' import {createReceiver, type WorkerChannelReceiver} from '../../util/workerChannels' import {type ValidateDocumentsWorkerData, type ValidationWorkerChannel} from '../validateDocuments' @@ -204,7 +204,7 @@ describe('validateDocuments', () => { const moduleAlias = require('module-alias') const { register } = require('esbuild-register/dist/node') - moduleAlias.addAliases(${JSON.stringify(getAliases({monorepo: {path: path.resolve(__dirname, '../../../../../../..')}}))}) + moduleAlias.addAliases(${JSON.stringify(await getMonorepoAliases(path.resolve(__dirname, '../../../../../../..')))}) const { unregister } = register({ target: 'node18', diff --git a/packages/sanity/src/_singletons/context/StudioAnnouncementsContext.ts b/packages/sanity/src/_singletons/context/StudioAnnouncementsContext.ts new file mode 100644 index 00000000000..702cb3c9f7a --- /dev/null +++ b/packages/sanity/src/_singletons/context/StudioAnnouncementsContext.ts @@ -0,0 +1,11 @@ +import {createContext} from 'sanity/_createContext' + +import type {StudioAnnouncementsContextValue} from '../../core/studio/studioAnnouncements/types' + +/** + * @internal + */ +export const StudioAnnouncementContext = createContext( + 'sanity/_singletons/context/studioAnnouncements', + undefined, +) diff --git a/packages/sanity/src/_singletons/index.ts b/packages/sanity/src/_singletons/index.ts index ca77d8f8c1d..05761b9609f 100644 --- a/packages/sanity/src/_singletons/index.ts +++ b/packages/sanity/src/_singletons/index.ts @@ -55,6 +55,7 @@ export * from './context/SearchContext' export * from './context/SortableItemIdContext' export * from './context/SourceContext' export * from './context/StructureToolContext' +export * from './context/StudioAnnouncementsContext' export * from './context/TasksContext' export * from './context/TasksEnabledContext' export * from './context/TasksNavigationContext' diff --git a/packages/sanity/src/core/components/errorActions/ErrorActions.tsx b/packages/sanity/src/core/components/errorActions/ErrorActions.tsx new file mode 100644 index 00000000000..60b0593f5e8 --- /dev/null +++ b/packages/sanity/src/core/components/errorActions/ErrorActions.tsx @@ -0,0 +1,47 @@ +import {CopyIcon, SyncIcon} from '@sanity/icons' +import {Inline} from '@sanity/ui' +import {type ComponentProps, type ComponentType} from 'react' + +import {Button, Tooltip} from '../../../ui-components' +import {strings} from './strings' +import {useCopyErrorDetails} from './useCopyErrorDetails' + +/** + * @internal + */ +export interface ErrorActionsProps extends Pick, 'size'> { + error: unknown + eventId: string | null + onRetry?: () => void +} + +/** + * @internal + */ +export const ErrorActions: ComponentType = ({error, eventId, onRetry, size}) => { + const copyErrorDetails = useCopyErrorDetails(error, eventId) + + return ( + + {onRetry && ( + + ) + } + + const {queryByText, getByRole} = render(, {wrapper}) + + expect(queryByText("What's new")).toBeInTheDocument() + expect(queryByText(mockAnnouncements[1].title)).toBeInTheDocument() + + const openDialogButton = getByRole('button', {name: 'Open dialog'}) + fireEvent.click(openDialogButton) + + // The card closes even if we open it from somewhere else + await waitFor(() => { + expect(queryByText("What's new")).toBeNull() + }) + // The first announcement is seen, it's rendered because it's showing all + expect(queryByText(mockAnnouncements[0].title)).toBeInTheDocument() + // The second announcement is unseen, so it's rendered + expect(queryByText(mockAnnouncements[1].title)).toBeInTheDocument() + }) + }) + describe('tests audiences - studio version is 3.57.0', () => { + beforeEach(() => { + jest.clearAllMocks() + // It doesn't show the first element + seenAnnouncementsMock.mockReturnValue([ + of({value: [], error: null, loading: false}), + jest.fn(), + ]) + }) + + test('if the audience is everyone, it shows the announcement regardless the version', () => { + const announcements: StudioAnnouncementDocument[] = [ + { + ...mockAnnouncements[1], + audience: 'everyone', + }, + ] + mockClient(announcements) + + const {result} = renderHook(() => useStudioAnnouncements(), { + wrapper, + }) + + expect(result.current.unseenAnnouncements).toEqual(announcements) + expect(result.current.studioAnnouncements).toEqual(announcements) + }) + test('if the audience is greater-than-or-equal-version and studio version is not above', () => { + const announcements: StudioAnnouncementDocument[] = [ + { + ...mockAnnouncements[1], + audience: 'greater-than-or-equal-version', + studioVersion: '3.58.0', + }, + ] + mockClient(announcements) + + const {result} = renderHook(() => useStudioAnnouncements(), { + wrapper, + }) + + expect(result.current.unseenAnnouncements).toEqual([]) + expect(result.current.studioAnnouncements).toEqual([]) + }) + test('if the audience is greater-than-or-equal-version and studio version is above', () => { + const announcements: StudioAnnouncementDocument[] = [ + { + ...mockAnnouncements[1], + audience: 'greater-than-or-equal-version', + studioVersion: '3.56.0', + }, + ] + mockClient(announcements) + + const {result} = renderHook(() => useStudioAnnouncements(), { + wrapper, + }) + + expect(result.current.unseenAnnouncements).toEqual(announcements) + expect(result.current.studioAnnouncements).toEqual(announcements) + }) + test('if the audience is above-equal.version and studio version is equal', () => { + const announcements: StudioAnnouncementDocument[] = [ + { + ...mockAnnouncements[1], + audience: 'greater-than-or-equal-version', + studioVersion: '3.57.0', + }, + ] + mockClient(announcements) + + const {result} = renderHook(() => useStudioAnnouncements(), { + wrapper, + }) + + expect(result.current.unseenAnnouncements).toEqual(announcements) + expect(result.current.studioAnnouncements).toEqual(announcements) + }) + test('if the audience is specific-version and studio matches', () => { + const announcements: StudioAnnouncementDocument[] = [ + { + ...mockAnnouncements[1], + audience: 'specific-version', + studioVersion: '3.57.0', + }, + ] + mockClient(announcements) + + const {result} = renderHook(() => useStudioAnnouncements(), { + wrapper, + }) + + expect(result.current.unseenAnnouncements).toEqual(announcements) + expect(result.current.studioAnnouncements).toEqual(announcements) + }) + test("if the audience is specific-version and studio doesn't match ", () => { + const announcements: StudioAnnouncementDocument[] = [ + { + ...mockAnnouncements[1], + audience: 'specific-version', + studioVersion: '3.56.0', + }, + ] + mockClient(announcements) + + const {result} = renderHook(() => useStudioAnnouncements(), { + wrapper, + }) + + expect(result.current.unseenAnnouncements).toEqual([]) + expect(result.current.studioAnnouncements).toEqual([]) + }) + test('if the audience is less-than-or-equal-version and studio is above', () => { + const announcements: StudioAnnouncementDocument[] = [ + { + ...mockAnnouncements[1], + audience: 'less-than-or-equal-version', + studioVersion: '3.56.0', + }, + ] + mockClient(announcements) + + const {result} = renderHook(() => useStudioAnnouncements(), { + wrapper, + }) + + expect(result.current.unseenAnnouncements).toEqual([]) + expect(result.current.studioAnnouncements).toEqual([]) + }) + test('if the audience is less-than-or-equal-version and studio is below', () => { + const announcements: StudioAnnouncementDocument[] = [ + { + ...mockAnnouncements[1], + audience: 'less-than-or-equal-version', + studioVersion: '3.58.0', + }, + ] + mockClient(announcements) + + const {result} = renderHook(() => useStudioAnnouncements(), { + wrapper, + }) + + expect(result.current.unseenAnnouncements).toEqual(announcements) + expect(result.current.studioAnnouncements).toEqual(announcements) + }) + test('if the audience is less-than-or-equal-version and studio is equal', () => { + const announcements: StudioAnnouncementDocument[] = [ + { + ...mockAnnouncements[1], + audience: 'less-than-or-equal-version', + studioVersion: '3.57.0', + }, + ] + mockClient(announcements) + + const {result} = renderHook(() => useStudioAnnouncements(), { + wrapper, + }) + + expect(result.current.unseenAnnouncements).toEqual(announcements) + expect(result.current.studioAnnouncements).toEqual(announcements) + }) + test("if the audienceRole is fixed and user doesn't have the role", () => { + // mocked workspace roles is [ { name: 'administrator', title: 'Administrator' } ] + const announcements: StudioAnnouncementDocument[] = [ + { + ...mockAnnouncements[1], + audienceRole: ['developer'], + audience: 'everyone', + }, + ] + mockClient(announcements) + + const {result} = renderHook(() => useStudioAnnouncements(), { + wrapper, + }) + + expect(result.current.unseenAnnouncements).toEqual([]) + expect(result.current.studioAnnouncements).toEqual([]) + }) + test('if the audienceRole is fixed and user has the role', () => { + // mocked workspace roles is [ { name: 'administrator', title: 'Administrator' } ] + const announcements: StudioAnnouncementDocument[] = [ + { + ...mockAnnouncements[1], + audienceRole: ['administrator'], + audience: 'everyone', + }, + ] + mockClient(announcements) + + const {result} = renderHook(() => useStudioAnnouncements(), { + wrapper, + }) + + expect(result.current.unseenAnnouncements).toEqual(announcements) + expect(result.current.studioAnnouncements).toEqual(announcements) + }) + }) + describe('storing seen announcements', () => { + beforeEach(() => { + jest.clearAllMocks() + }) + test('when the card is dismissed, and only 1 announcement received', () => { + const saveSeenAnnouncementsMock = jest.fn() + seenAnnouncementsMock.mockReturnValue([ + of({value: [], error: null, loading: false}), + saveSeenAnnouncementsMock, + ]) + mockClient([mockAnnouncements[0]]) + + const {getByLabelText} = render(null, {wrapper}) + + const closeButton = getByLabelText('Dismiss announcements') + fireEvent.click(closeButton) + expect(saveSeenAnnouncementsMock).toHaveBeenCalledWith([mockAnnouncements[0]._id]) + }) + test('when the card is dismissed, and 2 announcements are received', () => { + const saveSeenAnnouncementsMock = jest.fn() + seenAnnouncementsMock.mockReturnValue([ + of({value: [], error: null, loading: false}), + saveSeenAnnouncementsMock, + ]) + mockClient(mockAnnouncements) + + const {getByLabelText} = render(null, {wrapper}) + + const closeButton = getByLabelText('Dismiss announcements') + fireEvent.click(closeButton) + expect(saveSeenAnnouncementsMock).toHaveBeenCalledWith(mockAnnouncements.map((d) => d._id)) + }) + test("when the card is dismissed, doesn't persist previous stored values", () => { + const saveSeenAnnouncementsMock = jest.fn() + // The id received here is not present anymore in the mock announcements, this id won't be stored in next save. + seenAnnouncementsMock.mockReturnValue([ + of({value: ['not-to-be-persisted'], error: null, loading: false}), + saveSeenAnnouncementsMock, + ]) + mockClient(mockAnnouncements) + const {getByLabelText} = render(null, {wrapper}) + + const closeButton = getByLabelText('Dismiss announcements') + fireEvent.click(closeButton) + expect(saveSeenAnnouncementsMock).toHaveBeenCalledWith(mockAnnouncements.map((d) => d._id)) + }) + test('when the card is dismissed, persist previous stored values', () => { + const saveSeenAnnouncementsMock = jest.fn() + // The id received here is present in the mock announcements, this id will be persisted in next save. + seenAnnouncementsMock.mockReturnValue([ + of({value: [mockAnnouncements[0]._id], error: null, loading: false}), + saveSeenAnnouncementsMock, + ]) + mockClient(mockAnnouncements) + + const {getByLabelText} = render(null, {wrapper}) + + const closeButton = getByLabelText('Dismiss announcements') + fireEvent.click(closeButton) + expect(saveSeenAnnouncementsMock).toHaveBeenCalledWith(mockAnnouncements.map((d) => d._id)) + }) + test('when the dialog is closed', () => { + const saveSeenAnnouncementsMock = jest.fn() + seenAnnouncementsMock.mockReturnValue([ + of({value: [], error: null, loading: false}), + saveSeenAnnouncementsMock, + ]) + mockClient(mockAnnouncements) + + const {getByLabelText} = render(null, {wrapper}) + + const openButton = getByLabelText('Open announcements') + fireEvent.click(openButton) + // Dialog renders and we close it + const closeButton = getByLabelText('Close dialog') + fireEvent.click(closeButton) + expect(saveSeenAnnouncementsMock).toHaveBeenCalledWith(mockAnnouncements.map((d) => d._id)) + }) + }) +}) diff --git a/packages/sanity/src/core/studio/studioAnnouncements/__tests__/useSeenAnnouncements.test.tsx b/packages/sanity/src/core/studio/studioAnnouncements/__tests__/useSeenAnnouncements.test.tsx new file mode 100644 index 00000000000..ba610997ad2 --- /dev/null +++ b/packages/sanity/src/core/studio/studioAnnouncements/__tests__/useSeenAnnouncements.test.tsx @@ -0,0 +1,148 @@ +import {beforeEach, describe, expect, jest, test} from '@jest/globals' +import {act, renderHook, waitFor} from '@testing-library/react' +import {of, Subject} from 'rxjs' +import {useRouter} from 'sanity/router' + +import {useKeyValueStore} from '../../../store/_legacy/datastores' +import {type SeenAnnouncementsState, useSeenAnnouncements} from '../useSeenAnnouncements' + +jest.mock('../../../store/_legacy/datastores', () => ({ + useKeyValueStore: jest.fn(), +})) + +const useKeyValueStoreMock = useKeyValueStore as jest.Mock +jest.mock('sanity/router', () => ({ + useRouter: jest.fn().mockReturnValue({state: {}}), +})) +const useRouterMock = useRouter as jest.Mock + +describe('useSeenAnnouncements', () => { + beforeEach(() => { + jest.clearAllMocks() + }) + test('should return "loading" initially and update when observable emits', async () => { + const observable = new Subject() + const getKeyMock = jest.fn().mockReturnValue(observable) + const setKeyMock = jest.fn() + useKeyValueStoreMock.mockReturnValue({getKey: getKeyMock, setKey: setKeyMock}) + + const {result} = renderHook(() => useSeenAnnouncements()) + const seenAnnouncements$ = result.current[0] + const seenAnnouncements = ['announcement1', 'announcement2'] + + const expectedStates: SeenAnnouncementsState[] = [ + {value: null, error: null, loading: true}, + {value: seenAnnouncements, error: null, loading: false}, + ] + const emissions: SeenAnnouncementsState[] = [] + + seenAnnouncements$.subscribe((state) => { + emissions.push(state) + }) + + act(() => { + observable.next(seenAnnouncements) + }) + expect(emissions).toEqual(expectedStates) + }) + test('should handle errors on the keyValueStore', async () => { + const observable = new Subject() + const getKeyMock = jest.fn().mockReturnValue(observable) + const setKeyMock = jest.fn() + + useKeyValueStoreMock.mockReturnValue({getKey: getKeyMock, setKey: setKeyMock}) + + const {result} = renderHook(() => useSeenAnnouncements()) + const seenAnnouncements$ = result.current[0] + + const emissions: SeenAnnouncementsState[] = [] + + seenAnnouncements$.subscribe((state) => { + emissions.push(state) + }) + + const error = new Error('An error occurred') + act(() => { + observable.error(error) + }) + const expectedStates: SeenAnnouncementsState[] = [ + {value: null, error: null, loading: true}, + {value: null, error: error, loading: false}, + ] + expect(emissions).toEqual(expectedStates) + }) + + test('should call the getKey function with the correct key when the hook is called', () => { + const observable = new Subject() + const getKeyMock = jest.fn().mockImplementation(() => observable) + + const setKeyMock = jest.fn().mockReturnValue(of([])) + + useKeyValueStoreMock.mockReturnValue({getKey: getKeyMock, setKey: setKeyMock}) + + renderHook(() => useSeenAnnouncements()) + + expect(getKeyMock).toHaveBeenCalledWith('studio.announcement.seen') + }) + + test('should call setKey with the correct arguments when setSeenAnnouncements is called', () => { + const newSeenAnnouncements = ['announcement1', 'announcement2'] + const getKeyMock = jest.fn().mockImplementation(() => of([])) + const setKeyMock = jest.fn().mockReturnValue(of([])) + + useKeyValueStoreMock.mockReturnValue({getKey: getKeyMock, setKey: setKeyMock}) + const {result} = renderHook(() => useSeenAnnouncements()) + const [_, setSeenAnnouncements] = result.current + + act(() => { + setSeenAnnouncements(newSeenAnnouncements) + }) + + expect(setKeyMock).toHaveBeenCalledWith('studio.announcement.seen', newSeenAnnouncements) + }) + describe('should reset states when the param is provided', () => { + test('when a reset value is provided', async () => { + useRouterMock.mockReturnValue({ + state: {_searchParams: [['reset-announcements', 'foo,bar']]}, + }) + const getKeyMock = jest.fn().mockImplementation(() => of([])) + const setKeyMock = jest.fn().mockReturnValue(of([])) + + useKeyValueStoreMock.mockReturnValue({getKey: getKeyMock, setKey: setKeyMock}) + renderHook(() => useSeenAnnouncements()) + + await waitFor(() => { + expect(setKeyMock).toHaveBeenCalledWith('studio.announcement.seen', ['foo', 'bar']) + }) + }) + test('when no reset value is provided', async () => { + useRouterMock.mockReturnValue({ + state: {_searchParams: [['reset-announcements', '']]}, + }) + const getKeyMock = jest.fn().mockImplementation(() => of([])) + const setKeyMock = jest.fn().mockReturnValue(of([])) + + useKeyValueStoreMock.mockReturnValue({getKey: getKeyMock, setKey: setKeyMock}) + renderHook(() => useSeenAnnouncements()) + + await waitFor(() => { + expect(setKeyMock).toHaveBeenCalledWith('studio.announcement.seen', []) + }) + }) + + test('when the reset key is not provided', async () => { + useRouterMock.mockReturnValue({ + state: {_searchParams: []}, + }) + const getKeyMock = jest.fn().mockImplementation(() => of([])) + const setKeyMock = jest.fn().mockReturnValue(of([])) + + useKeyValueStoreMock.mockReturnValue({getKey: getKeyMock, setKey: setKeyMock}) + renderHook(() => useSeenAnnouncements()) + + await waitFor(() => { + expect(setKeyMock).not.toHaveBeenCalled() + }) + }) + }) +}) diff --git a/packages/sanity/src/core/studio/studioAnnouncements/__tests__/utils.test.ts b/packages/sanity/src/core/studio/studioAnnouncements/__tests__/utils.test.ts new file mode 100644 index 00000000000..823a80a5de6 --- /dev/null +++ b/packages/sanity/src/core/studio/studioAnnouncements/__tests__/utils.test.ts @@ -0,0 +1,96 @@ +import {describe, expect, test} from '@jest/globals' + +import {isValidAnnouncementAudience, isValidAnnouncementRole} from '../utils' + +describe('isValidAnnouncementRole', () => { + const userRoles = [ + {name: 'developer', title: 'Developer'}, + {name: 'administrator', title: 'Administrator'}, + ] + + test('returns true when audienceRole is undefined', () => { + expect(isValidAnnouncementRole(undefined, userRoles)).toBe(true) + }) + test('returns true when user is undefined', () => { + expect(isValidAnnouncementRole(['administrator'], undefined)).toBe(false) + expect(isValidAnnouncementRole(['administrator'], [])).toBe(false) + }) + test("returns true if the user's role is in the audienceRole", () => { + expect(isValidAnnouncementRole(['administrator'], userRoles)).toBe(true) + }) + test("returns true if the user's role is in the audienceRole", () => { + expect(isValidAnnouncementRole(['developer', 'custom'], userRoles)).toBe(true) + }) + test("returns false if the user's role is not in the audienceRole", () => { + expect(isValidAnnouncementRole(['editor'], userRoles)).toBe(false) + }) + test("returns false if the user's role is not in the audienceRole", () => { + expect(isValidAnnouncementRole(['editor'], [{name: 'foo', title: 'Custom foo role'}])).toBe( + false, + ) + }) + test('returns false if the user has a custom role and we aim custom roles', () => { + expect( + isValidAnnouncementRole( + ['custom'], + [...userRoles, {name: 'foo', title: 'A custom foo role'}], + ), + ).toBe(true) + }) +}) + +describe('isValidAnnouncementAudience', () => { + test('should return true when audience is "everyone"', () => { + const announcement = {audience: 'everyone', studioVersion: undefined} as const + const sanityVersion = '3.55.0' + expect(isValidAnnouncementAudience(announcement, sanityVersion)).toBe(true) + }) + + describe('when audience is "specific-version"', () => { + const document = {audience: 'specific-version', studioVersion: '3.55.0'} as const + test('should return true when versions match', () => { + const sanityVersion = '3.55.0' + expect(isValidAnnouncementAudience(document, sanityVersion)).toBe(true) + }) + + test('should return false when versions do not match', () => { + const sanityVersion = '3.56.0' + expect(isValidAnnouncementAudience(document, sanityVersion)).toBe(false) + }) + }) + + describe('when audience is "above-version"', () => { + const document = {audience: 'greater-than-or-equal-version', studioVersion: '3.55.0'} as const + test('should return true when sanityVersion is above document.studioVersion', () => { + const sanityVersion = '3.56.0' + expect(isValidAnnouncementAudience(document, sanityVersion)).toBe(true) + }) + + test('should return true when sanityVersion is equal to document.studioVersion', () => { + const sanityVersion = '3.55.0' + expect(isValidAnnouncementAudience(document, sanityVersion)).toBe(true) + }) + + test('should return false when sanityVersion is below document.studioVersion', () => { + const sanityVersion = '3.54.0' + expect(isValidAnnouncementAudience(document, sanityVersion)).toBe(false) + }) + }) + describe('when audience is "below-version"', () => { + const document = {audience: 'less-than-or-equal-version', studioVersion: '3.55.0'} as const + test('should return false when sanityVersion is above document.studioVersion', () => { + const sanityVersion = '3.56.0' + expect(isValidAnnouncementAudience(document, sanityVersion)).toBe(false) + }) + + test('should return true when sanityVersion is equal to document.studioVersion', () => { + const sanityVersion = '3.55.0' + expect(isValidAnnouncementAudience(document, sanityVersion)).toBe(true) + }) + + test('should return true when sanityVersion is below document.studioVersion', () => { + const sanityVersion = '3.54.0' + expect(isValidAnnouncementAudience(document, sanityVersion)).toBe(true) + }) + }) +}) diff --git a/packages/sanity/src/core/studio/studioAnnouncements/index.ts b/packages/sanity/src/core/studio/studioAnnouncements/index.ts new file mode 100644 index 00000000000..4b6679f6f82 --- /dev/null +++ b/packages/sanity/src/core/studio/studioAnnouncements/index.ts @@ -0,0 +1,4 @@ +// This exports are internal but consumed in the product-announcements studio to generate the in-studio previews. +export * from './StudioAnnouncementsCard' +export * from './StudioAnnouncementsDialog' +export * from './utils' diff --git a/packages/sanity/src/core/studio/studioAnnouncements/types.ts b/packages/sanity/src/core/studio/studioAnnouncements/types.ts new file mode 100644 index 00000000000..0e841435be9 --- /dev/null +++ b/packages/sanity/src/core/studio/studioAnnouncements/types.ts @@ -0,0 +1,43 @@ +import {type PortableTextBlock} from 'sanity' + +export const audienceRoles = [ + 'administrator', + 'editor', + 'viewer', + 'contributor', + 'developer', + 'custom', +] as const + +export type AudienceRole = (typeof audienceRoles)[number] + +export interface StudioAnnouncementDocument { + _id: string + _type: 'productAnnouncement' + _rev: string + _createdAt: string + _updatedAt: string + title: string + name: string + body: PortableTextBlock[] + announcementType: 'whats-new' + publishedDate: string + expiryDate?: string + audience: + | 'everyone' + | 'specific-version' + | 'greater-than-or-equal-version' + | 'less-than-or-equal-version' + audienceRole?: AudienceRole[] | undefined + studioVersion?: string + preHeader: string +} + +export interface StudioAnnouncementsContextValue { + studioAnnouncements: StudioAnnouncementDocument[] + unseenAnnouncements: StudioAnnouncementDocument[] + onDialogOpen: (mode: DialogMode) => void +} + +// Decides weather to show all the announcements or only the unseen ones +export type DialogMode = 'card' | 'help_menu' diff --git a/packages/sanity/src/core/studio/studioAnnouncements/useSeenAnnouncements.ts b/packages/sanity/src/core/studio/studioAnnouncements/useSeenAnnouncements.ts new file mode 100644 index 00000000000..5cb23844f86 --- /dev/null +++ b/packages/sanity/src/core/studio/studioAnnouncements/useSeenAnnouncements.ts @@ -0,0 +1,57 @@ +import {useCallback, useEffect, useMemo} from 'react' +import {catchError, map, type Observable, of, startWith} from 'rxjs' +import {useRouter} from 'sanity/router' + +import {useKeyValueStore} from '../../store/_legacy/datastores' + +const KEY = 'studio.announcement.seen' +const RESET_PARAM = 'reset-announcements' + +export interface SeenAnnouncementsState { + value: string[] | null + error: Error | null + loading: boolean +} +const INITIAL_STATE: SeenAnnouncementsState = { + value: null, + error: null, + loading: true, +} + +export function useSeenAnnouncements(): [ + Observable, + (seen: string[]) => void, +] { + const router = useRouter() + const keyValueStore = useKeyValueStore() + const seenAnnouncements$: Observable = useMemo( + () => + keyValueStore.getKey(KEY).pipe( + map((value) => ({value: value as string[] | null, error: null, loading: false})), + startWith(INITIAL_STATE), + catchError((error) => of({value: null, error: error, loading: false})), + ), + [keyValueStore], + ) + + const setSeenAnnouncements = useCallback( + (seen: string[]) => { + keyValueStore.setKey(KEY, seen) + }, + [keyValueStore], + ) + const params = new URLSearchParams(router.state._searchParams) + const resetAnnouncementsParams = params?.get(RESET_PARAM) + + useEffect(() => { + // For testing purposes, reset the seen params. + // e.g. /structure?reset-announcements=foo,bar + // Will reset the values of the seen announcement to: ['foo', 'bar'] + if (resetAnnouncementsParams !== null) { + const resetValue = resetAnnouncementsParams ? resetAnnouncementsParams.split(',') : [] + setSeenAnnouncements(resetValue) + } + }, [resetAnnouncementsParams, setSeenAnnouncements]) + + return [seenAnnouncements$, setSeenAnnouncements] +} diff --git a/packages/sanity/src/core/studio/studioAnnouncements/useStudioAnnouncements.tsx b/packages/sanity/src/core/studio/studioAnnouncements/useStudioAnnouncements.tsx new file mode 100644 index 00000000000..2ff5fba557f --- /dev/null +++ b/packages/sanity/src/core/studio/studioAnnouncements/useStudioAnnouncements.tsx @@ -0,0 +1,13 @@ +import {useContext} from 'react' +import {StudioAnnouncementContext} from 'sanity/_singletons' + +import {type StudioAnnouncementsContextValue} from './types' + +export function useStudioAnnouncements(): StudioAnnouncementsContextValue { + const context = useContext(StudioAnnouncementContext) + if (!context) { + throw new Error('useStudioAnnouncements: missing context value') + } + + return context +} diff --git a/packages/sanity/src/core/studio/studioAnnouncements/utils.ts b/packages/sanity/src/core/studio/studioAnnouncements/utils.ts new file mode 100644 index 00000000000..b2142ce83c6 --- /dev/null +++ b/packages/sanity/src/core/studio/studioAnnouncements/utils.ts @@ -0,0 +1,55 @@ +import {type Role} from 'sanity' +import {satisfies} from 'semver' + +import {type AudienceRole, audienceRoles, type StudioAnnouncementDocument} from './types' + +/** + * @internal + * @hidden + */ +export function isValidAnnouncementAudience( + document: { + audience: StudioAnnouncementDocument['audience'] + studioVersion: StudioAnnouncementDocument['studioVersion'] + }, + sanityVersion: string, +): boolean { + switch (document.audience) { + case 'everyone': + return true + case 'specific-version': + return satisfies(sanityVersion, `= ${document.studioVersion}`, { + includePrerelease: true, + }) + case 'greater-than-or-equal-version': + return satisfies(sanityVersion, `>= ${document.studioVersion}`, { + includePrerelease: true, + }) + case 'less-than-or-equal-version': + return satisfies(sanityVersion, `<= ${document.studioVersion}`, { + includePrerelease: true, + }) + default: + return true + } +} + +/** + * @internal + * @hidden + */ +export function isValidAnnouncementRole( + audience: StudioAnnouncementDocument['audienceRole'] | undefined, + userRoles: Role[] | undefined, +): boolean { + if (!audience || !audience.length) return true + if (!userRoles || !userRoles.length) return false + + if (userRoles.some((role) => audience.includes(role.name as AudienceRole))) return true + + // Check if the user has a custom role + if (userRoles.some((role) => !audienceRoles.includes(role.name as AudienceRole))) { + return audience.includes('custom') + } + return false +} diff --git a/packages/sanity/src/core/studio/upsell/upsellDescriptionSerializer/UpsellDescriptionSerializer.tsx b/packages/sanity/src/core/studio/upsell/upsellDescriptionSerializer/UpsellDescriptionSerializer.tsx index d4a3757a703..b0269be8e9e 100644 --- a/packages/sanity/src/core/studio/upsell/upsellDescriptionSerializer/UpsellDescriptionSerializer.tsx +++ b/packages/sanity/src/core/studio/upsell/upsellDescriptionSerializer/UpsellDescriptionSerializer.tsx @@ -1,7 +1,13 @@ -import {PortableText, type PortableTextComponents} from '@portabletext/react' +import { + PortableText, + type PortableTextComponents, + type PortableTextTypeComponentProps, +} from '@portabletext/react' import {Icon, LinkIcon} from '@sanity/icons' import {type PortableTextBlock} from '@sanity/types' import {Box, Card, Flex, Heading, Text} from '@sanity/ui' +// eslint-disable-next-line camelcase +import {getTheme_v2} from '@sanity/ui/theme' import {type ReactNode, useEffect, useMemo, useState} from 'react' import {css, styled} from 'styled-components' @@ -62,16 +68,22 @@ const InlineIcon = styled(Icon)` } ` -const Link = styled.a<{useTextColor: boolean}>` +const Link = styled.a<{$useTextColor: boolean}>` font-weight: 600; - color: ${(props) => (props.useTextColor ? 'var(--card-muted-fg-color) !important' : '')}; + color: ${(props) => (props.$useTextColor ? 'var(--card-muted-fg-color) !important' : '')}; ` -const DynamicIconContainer = styled.span` +const DynamicIconContainer = styled.span<{$inline: boolean}>` + display: ${({$inline}) => ($inline ? 'inline-block' : 'inline')}; + font-size: calc(21 / 16 * 1rem) !important; + min-width: calc(21 / 16 * 1rem - 0.375rem); + line-height: 0; > svg { + height: 1em; + width: 1em; display: inline; - font-size: calc(21 / 16 * 1rem) !important; - margin: -0.375rem 0 !important; + font-size: 1em !important; + margin: -0.375rem !important; *[stroke] { stroke: currentColor; } @@ -80,7 +92,7 @@ const DynamicIconContainer = styled.span` const accentSpanWrapper = (children: ReactNode) => {children} -const DynamicIcon = (props: {icon: {url: string}}) => { +const DynamicIcon = (props: {icon: {url: string}; inline?: boolean}) => { const [__html, setHtml] = useState('') useEffect(() => { const controller = new AbortController() @@ -105,7 +117,7 @@ const DynamicIcon = (props: {icon: {url: string}}) => { } }, [props.icon.url]) - return + return } function NormalBlock(props: {children: ReactNode}) { @@ -120,7 +132,7 @@ function NormalBlock(props: {children: ReactNode}) { ) } -function HeadingBlock(props: {children: ReactNode}) { +function H2Block(props: {children: ReactNode}) { const {children} = props return ( @@ -131,20 +143,78 @@ function HeadingBlock(props: {children: ReactNode}) { ) } -const components: PortableTextComponents = { +function H3Block(props: {children: ReactNode}) { + const {children} = props + return ( + + + {children} + + + ) +} + +const Image = styled.img((props) => { + const theme = getTheme_v2(props.theme) + + return css` + object-fit: cover; + width: 100%; + border-radius: ${theme.radius[3]}px; + ` +}) + +function ImageBlock( + props: PortableTextTypeComponentProps<{ + image?: {url: string} + }>, +) { + return ( + + + + ) +} + +const createComponents = ({ + onLinkClick, +}: { + onLinkClick?: ({url, linkTitle}: {url: string; linkTitle: string}) => void +}): PortableTextComponents => ({ block: { normal: ({children}) => {children}, - h2: ({children}) => {children}, + h2: ({children}) => {children}, + h3: ({children}) => {children}, }, list: { - bullet: ({children}) => children, - number: ({children}) => <>{children}, + bullet: ({children}) =>
    {children}
, + number: ({children}) =>
    {children}
, checkmarks: ({children}) => <>{children}, }, listItem: { - bullet: ({children}) => {children}, - number: ({children}) => {children}, - checkmarks: ({children}) => {children}, + bullet: ({children}) => ( + + {children} + + ), + number: ({children}) => ( + + {children} + + ), + checkmarks: ({children}) => {children}, }, marks: { @@ -155,7 +225,17 @@ const components: PortableTextComponents = { href={props.value.href} rel="noopener noreferrer" target="_blank" - useTextColor={props.value.useTextColor} + $useTextColor={props.value.useTextColor} + // eslint-disable-next-line react/jsx-no-bind + onClick={ + onLinkClick + ? () => + onLinkClick({ + url: props.value.href, + linkTitle: props.text, + }) + : undefined + } > {props.children} {props.value.showIcon && } @@ -174,7 +254,7 @@ const components: PortableTextComponents = { $hasTextRight={props.value.hasTextRight} /> ) : ( - + <>{props.value.icon?.url && } )} ) @@ -193,7 +273,7 @@ const components: PortableTextComponents = { {props.value.sanityIcon ? ( ) : ( - + <>{props.value.icon?.url && } )} @@ -206,11 +286,13 @@ const components: PortableTextComponents = { ), + imageBlock: (props) => , }, -} +}) interface DescriptionSerializerProps { blocks: PortableTextBlock[] + onLinkClick?: ({url, linkTitle}: {url: string; linkTitle: string}) => void } /** @@ -219,7 +301,11 @@ interface DescriptionSerializerProps { * @internal */ export function UpsellDescriptionSerializer(props: DescriptionSerializerProps) { - const value = useMemo(() => transformBlocks(props.blocks), [props.blocks]) + const {blocks, onLinkClick} = props + + const value = useMemo(() => transformBlocks(blocks), [blocks]) + const components = useMemo(() => createComponents({onLinkClick: onLinkClick}), [onLinkClick]) + return ( diff --git a/packages/sanity/src/core/tasks/components/form/fields/assignee/AssigneeSelectionMenu.tsx b/packages/sanity/src/core/tasks/components/form/fields/assignee/AssigneeSelectionMenu.tsx index 4d072c8bb8b..2c3714be450 100644 --- a/packages/sanity/src/core/tasks/components/form/fields/assignee/AssigneeSelectionMenu.tsx +++ b/packages/sanity/src/core/tasks/components/form/fields/assignee/AssigneeSelectionMenu.tsx @@ -9,6 +9,7 @@ import { MenuItem, Text, TextInput, + VirtualList, } from '@sanity/ui' import {deburr} from 'lodash' import {type ChangeEvent, type KeyboardEvent, useCallback, useMemo, useRef, useState} from 'react' @@ -172,7 +173,7 @@ function MentionsMenu({onSelect, value = ''}: {onSelect: SelectItemHandler; valu
) : ( - filteredOptions.map(renderItem) + )} diff --git a/packages/sanity/src/structure/i18n/resources.ts b/packages/sanity/src/structure/i18n/resources.ts index 800fda3727d..6001d69fc54 100644 --- a/packages/sanity/src/structure/i18n/resources.ts +++ b/packages/sanity/src/structure/i18n/resources.ts @@ -95,6 +95,13 @@ const structureLocaleStrings = defineLocalesResources('structure', { 'banners.deleted-document-banner.text': 'This document has been deleted.', /** The text content for the deprecated document type banner */ 'banners.deprecated-document-type-banner.text': 'This document type has been deprecated.', + /** The text for publish action for discarding the version */ + 'banners.live-edit-draft-banner.discard.tooltip': 'Discard draft', + /** The text for publish action for the draft banner */ + 'banners.live-edit-draft-banner.publish.tooltip': 'Publish to continue editing', + /** The text content for the live edit document when it's a draft */ + 'banners.live-edit-draft-banner.text': + 'The type {{schemaType}} has liveEdit enabled, but a draft version of this document exists. Publish or discard the draft in order to continue live editing it.', /** The text for the permission check banner if the user only has one role, and it does not allow updating this document */ 'banners.permission-check-banner.missing-permission_create_one': 'Your role does not have permissions to create this document.', @@ -320,8 +327,6 @@ const structureLocaleStrings = defineLocalesResources('structure', { 'panes.document-header-title.new.text': 'New {{schemaType}}', /** The text used in the document header title if no other title can be determined */ 'panes.document-header-title.untitled.text': 'Untitled', - /** The text for the retry button on the document list pane */ - 'panes.document-list-pane.error.retry-button.text': 'Retry', /** The error text on the document list pane */ 'panes.document-list-pane.error.text': 'Error: {{error}}', /** The error title on the document list pane */ diff --git a/packages/sanity/src/structure/panes/document/DocumentPaneProvider.tsx b/packages/sanity/src/structure/panes/document/DocumentPaneProvider.tsx index f15f16fffcf..dc43f0902da 100644 --- a/packages/sanity/src/structure/panes/document/DocumentPaneProvider.tsx +++ b/packages/sanity/src/structure/panes/document/DocumentPaneProvider.tsx @@ -8,7 +8,7 @@ import { type SanityDocumentLike, } from '@sanity/types' import {useToast} from '@sanity/ui' -import {fromString as pathFromString, resolveKeyedPath} from '@sanity/util/paths' +import {fromString as pathFromString, pathFor, resolveKeyedPath} from '@sanity/util/paths' import {omit, throttle} from 'lodash' import {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react' import deepEquals from 'react-fast-compare' @@ -517,6 +517,9 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { const createActionDisabled = isNonExistent && !isActionEnabled(schemaType!, 'create') const reconnecting = connectionState === 'reconnecting' const isLocked = editState.transactionSyncLock?.enabled + // in cases where the document has drafts but the schema is live edit, + // there is a risk of data loss, so we disable editing in this case + const isLiveEditAndDraft = Boolean(liveEdit && editState.draft) return ( !ready || @@ -527,19 +530,22 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { reconnecting || isLocked || isDeleting || - isDeleted + isDeleted || + isLiveEditAndDraft ) }, [ - connectionState, - editState.transactionSyncLock, - isNonExistent, - isDeleted, - isDeleting, isPermissionsLoading, permissions?.granted, + schemaType, + isNonExistent, + connectionState, + editState.transactionSyncLock?.enabled, + editState.draft, + liveEdit, ready, revTime, - schemaType, + isDeleting, + isDeleted, ]) const formState = useFormState({ @@ -609,10 +615,11 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { ) const handleFocus = useCallback( - (nextFocusPath: Path, payload?: OnPathFocusPayload) => { - setFocusPath(nextFocusPath) - if (!deepEquals(focusPathRef.current, nextFocusPath)) { - setOpenPath(nextFocusPath.slice(0, -1)) + (_nextFocusPath: Path, payload?: OnPathFocusPayload) => { + const nextFocusPath = pathFor(_nextFocusPath) + if (nextFocusPath !== focusPathRef.current) { + setFocusPath(pathFor(nextFocusPath)) + setOpenPath(pathFor(nextFocusPath.slice(0, -1))) focusPathRef.current = nextFocusPath onFocusPath?.(nextFocusPath) } @@ -741,12 +748,18 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { ) useEffect(() => { + let timeout: ReturnType if (connectionState === 'reconnecting') { - pushToast({ - id: 'sanity/structure/reconnecting', - status: 'warning', - title: t('panes.document-pane-provider.reconnecting.title'), - }) + timeout = setTimeout(() => { + pushToast({ + id: 'sanity/structure/reconnecting', + status: 'warning', + title: t('panes.document-pane-provider.reconnecting.title'), + }) + }, 2000) // 2 seconds, we can iterate on the value + } + return () => { + if (timeout) clearTimeout(timeout) } }, [connectionState, pushToast, t]) diff --git a/packages/sanity/src/structure/panes/document/documentPanel/DocumentPanel.tsx b/packages/sanity/src/structure/panes/document/documentPanel/DocumentPanel.tsx index ebc889cf801..dac52251855 100644 --- a/packages/sanity/src/structure/panes/document/documentPanel/DocumentPanel.tsx +++ b/packages/sanity/src/structure/panes/document/documentPanel/DocumentPanel.tsx @@ -4,6 +4,7 @@ import {ScrollContainer, useTimelineSelector, VirtualizerScrollInstanceProvider} import {css, styled} from 'styled-components' import {PaneContent, usePane, usePaneLayout} from '../../../components' +import {isLiveEditEnabled} from '../../../components/paneItem/helpers' import {useStructureTool} from '../../../useStructureTool' import {DocumentInspectorPanel} from '../documentInspector' import {InspectDialog} from '../inspectDialog' @@ -14,6 +15,7 @@ import { PermissionCheckBanner, ReferenceChangedBanner, } from './banners' +import {DraftLiveEditBanner} from './banners/DraftLiveEditBanner' import {FormView} from './documentViews' interface DocumentPanelProps { @@ -117,6 +119,8 @@ export const DocumentPanel = function DocumentPanel(props: DocumentPanelProps) { (state) => state.lastNonDeletedRevId, ) + const isLiveEdit = isLiveEditEnabled(schemaType) + // Scroll to top as `documentId` changes useEffect(() => { if (!documentScrollElement?.scrollTo) return @@ -150,6 +154,14 @@ export const DocumentPanel = function DocumentPanel(props: DocumentPanelProps) { scrollElement={documentScrollElement} containerElement={formContainerElement} > + {activeView.type === 'form' && isLiveEdit && ready && ( + + )} + {activeView.type === 'form' && !isPermissionsLoading && ready && ( <> | null + documentId: string + schemaType: ObjectSchemaType +} + +export function DraftLiveEditBanner({ + displayed, + documentId, + schemaType, +}: DraftLiveEditBannerProps): JSX.Element | null { + const {t} = useTranslation(structureLocaleNamespace) + const [isPublishing, setPublishing] = useState(false) + const [isDiscarding, setDiscarding] = useState(false) + const telemetry = useTelemetry() + + const {publish, discardChanges} = useDocumentOperation(documentId, displayed?._type || '') + + const handlePublish = useCallback(() => { + publish.execute() + setPublishing(true) + telemetry.log(ResolvedLiveEdit, {liveEditResolveType: 'publish'}) + }, [publish, telemetry]) + + const handleDiscard = useCallback(() => { + discardChanges.execute() + setDiscarding(true) + telemetry.log(ResolvedLiveEdit, {liveEditResolveType: 'discard'}) + }, [discardChanges, telemetry]) + + useEffect(() => { + return () => { + setPublishing(false) + setDiscarding(false) + } + }) + + if (displayed && displayed._id && !isDraftId(displayed._id)) { + return null + } + + return ( + + + + +