diff --git a/.changeset/gentle-cobras-wash.md b/.changeset/gentle-cobras-wash.md new file mode 100644 index 0000000000..1a9245524a --- /dev/null +++ b/.changeset/gentle-cobras-wash.md @@ -0,0 +1,17 @@ +--- +'astro': minor +--- + +Adds the `astro preferences` command to manage user preferences. User preferences are specific to individual Astro users, unlike the `astro.config.mjs` file which changes behavior for everyone working on a project. + +User preferences are scoped to the current project by default, stored in a local `.astro/settings.json` file. Using the `--global` flag, user preferences can also be applied to every Astro project on the current machine. Global user preferences are stored in an operating system-specific location. + +```sh +# Disable the dev overlay for the current user in the current project +npm run astro preferences disable devOverlay +# Disable the dev overlay for the current user in all Astro projects on this machine +npm run astro preferences --global disable devOverlay + +# Check if the dev overlay is enabled for the current user +npm run astro preferences list devOverlay +``` diff --git a/packages/astro/package.json b/packages/astro/package.json index 6b076fc7da..ee0ac59bae 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -134,11 +134,14 @@ "deterministic-object-hash": "^2.0.1", "devalue": "^4.3.2", "diff": "^5.1.0", + "dlv": "^1.1.3", + "dset": "^3.1.3", "es-module-lexer": "^1.4.1", "esbuild": "^0.19.6", "estree-walker": "^3.0.3", "execa": "^8.0.1", "fast-glob": "^3.3.2", + "flattie": "^1.1.0", "github-slugger": "^2.0.0", "gray-matter": "^4.0.3", "html-escaper": "^3.0.3", @@ -185,6 +188,7 @@ "@types/cookie": "^0.5.4", "@types/debug": "^4.1.12", "@types/diff": "^5.0.8", + "@types/dlv": "^1.1.4", "@types/dom-view-transitions": "^1.0.4", "@types/estree": "^1.0.5", "@types/hast": "^3.0.3", diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 24b7b195f9..0acea76e4a 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -35,6 +35,7 @@ import type { import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server/index.js'; import type { OmitIndexSignature, Simplify } from '../type-utils.js'; import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js'; +import type { AstroPreferences } from '../preferences/index.js'; export { type AstroIntegrationLogger }; @@ -1678,6 +1679,7 @@ export interface AstroAdapterFeatures { export interface AstroSettings { config: AstroConfig; adapter: AstroAdapter | undefined; + preferences: AstroPreferences; injectedRoutes: InjectedRoute[]; resolvedInjectedRoutes: ResolvedInjectedRoute[]; pageExtensions: string[]; diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts index 0421258a51..83dd960c63 100644 --- a/packages/astro/src/cli/index.ts +++ b/packages/astro/src/cli/index.ts @@ -14,6 +14,7 @@ type CLICommand = | 'sync' | 'check' | 'info' + | 'preferences' | 'telemetry'; /** Display --help flag */ @@ -33,6 +34,7 @@ async function printAstroHelp() { ['info', 'List info about your current Astro setup.'], ['preview', 'Preview your build locally.'], ['sync', 'Generate content collection types.'], + ['preferences', 'Configure user preferences.'], ['telemetry', 'Configure telemetry settings.'], ], 'Global Flags': [ @@ -64,6 +66,7 @@ function resolveCommand(flags: yargs.Arguments): CLICommand { 'add', 'sync', 'telemetry', + 'preferences', 'dev', 'build', 'preview', @@ -114,6 +117,12 @@ async function runCommand(cmd: string, flags: yargs.Arguments) { const exitCode = await sync({ flags }); return process.exit(exitCode); } + case 'preferences': { + const { preferences } = await import('./preferences/index.js'); + const [subcommand, key, value] = flags._.slice(3).map(v => v.toString()); + const exitCode = await preferences(subcommand, key, value, { flags }); + return process.exit(exitCode); + } } // In verbose/debug mode, we log the debug logs asap before any potential errors could appear @@ -177,7 +186,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) { /** The primary CLI action */ export async function cli(args: string[]) { - const flags = yargs(args); + const flags = yargs(args, { boolean: ['global'], alias: { g: 'global' } }); const cmd = resolveCommand(flags); try { await runCommand(cmd, flags); diff --git a/packages/astro/src/cli/preferences/index.ts b/packages/astro/src/cli/preferences/index.ts new file mode 100644 index 0000000000..2a01bbae2c --- /dev/null +++ b/packages/astro/src/cli/preferences/index.ts @@ -0,0 +1,227 @@ +/* eslint-disable no-console */ +import type yargs from 'yargs-parser'; +import type { AstroSettings } from '../../@types/astro.js'; + +import { bold } from 'kleur/colors'; +import { fileURLToPath } from 'node:url'; + +import * as msg from '../../core/messages.js'; +import { createLoggerFromFlags, flagsToAstroInlineConfig } from '../flags.js'; +import { resolveConfig } from '../../core/config/config.js'; +import { createSettings } from '../../core/config/settings.js'; +import { coerce, isValidKey, type PreferenceKey } from '../../preferences/index.js'; +import { DEFAULT_PREFERENCES } from '../../preferences/defaults.js'; +import dlv from 'dlv'; +// @ts-expect-error flattie types are mispackaged +import { flattie } from 'flattie'; +import { formatWithOptions } from 'node:util'; +import { collectErrorMetadata } from '../../core/errors/dev/utils.js'; + +interface PreferencesOptions { + flags: yargs.Arguments; +} + +const PREFERENCES_SUBCOMMANDS = ['get', 'set', 'enable', 'disable', 'delete', 'reset', 'list'] as const; +export type Subcommand = typeof PREFERENCES_SUBCOMMANDS[number]; + +function isValidSubcommand(subcommand: string): subcommand is Subcommand { + return PREFERENCES_SUBCOMMANDS.includes(subcommand as Subcommand); +} + +export async function preferences(subcommand: string, key: string, value: string | undefined, { flags }: PreferencesOptions): Promise { + if (!isValidSubcommand(subcommand) || flags?.help || flags?.h) { + msg.printHelp({ + commandName: 'astro preferences', + usage: '[command]', + tables: { + Commands: [ + ['list', 'Pretty print all current preferences'], + ['list --json', 'Log all current preferences as a JSON object'], + ['get [key]', 'Log current preference value'], + ['set [key] [value]', 'Update preference value'], + ['reset [key]', 'Reset preference value to default'], + ['enable [key]', 'Set a boolean preference to true'], + ['disable [key]', 'Set a boolean preference to false'], + ], + Flags: [ + ['--global', 'Scope command to global preferences (all Astro projects) rather than the current project'], + ], + }, + }); + return 0; + } + + const inlineConfig = flagsToAstroInlineConfig(flags); + const logger = createLoggerFromFlags(flags); + const { astroConfig } = await resolveConfig(inlineConfig ?? {}, 'dev'); + const settings = await createSettings(astroConfig, fileURLToPath(astroConfig.root)); + const opts: SubcommandOptions = { + location: flags.global ? 'global' : undefined, + json: flags.json + } + + if (subcommand === 'list') { + return listPreferences(settings, opts); + } + + if (subcommand === 'enable' || subcommand === 'disable') { + key = `${key}.enabled` as PreferenceKey; + } + + if (!isValidKey(key)) { + logger.error('preferences', `Unknown preference "${key}"\n`); + return 1; + } + + if (subcommand === 'set' && value === undefined) { + const type = typeof dlv(DEFAULT_PREFERENCES, key); + console.error(msg.formatErrorMessage(collectErrorMetadata(new Error(`Please provide a ${type} value for "${key}"`)), true)); + return 1; + } + + switch (subcommand) { + case 'get': return getPreference(settings, key, opts); + case 'set': return setPreference(settings, key, value, opts); + case 'reset': + case 'delete': return resetPreference(settings, key, opts); + case 'enable': return enablePreference(settings, key, opts); + case 'disable': return disablePreference(settings, key, opts); + } +} + +interface SubcommandOptions { + location?: 'global' | 'project'; + json?: boolean; +} + +// Default `location` to "project" to avoid reading default preferencesa +async function getPreference(settings: AstroSettings, key: PreferenceKey, { location = 'project' }: SubcommandOptions) { + try { + let value = await settings.preferences.get(key, { location }); + if (value && typeof value === 'object' && !Array.isArray(value)) { + if (Object.keys(value).length === 0) { + value = dlv(DEFAULT_PREFERENCES, key); + console.log(msg.preferenceDefaultIntro(key)); + } + prettyPrint({ [key]: value }); + return 0; + } + if (value === undefined) { + const defaultValue = await settings.preferences.get(key); + console.log(msg.preferenceDefault(key, defaultValue)); + return 0; + } + console.log(msg.preferenceGet(key, value)); + return 0; + } catch {} + return 1; +} + +async function setPreference(settings: AstroSettings, key: PreferenceKey, value: unknown, { location }: SubcommandOptions) { + try { + const defaultType = typeof dlv(DEFAULT_PREFERENCES, key); + if (typeof coerce(key, value) !== defaultType) { + throw new Error(`${key} expects a "${defaultType}" value!`) + } + + await settings.preferences.set(key, coerce(key, value), { location }); + console.log(msg.preferenceSet(key, value)) + return 0; + } catch (e) { + if (e instanceof Error) { + console.error(msg.formatErrorMessage(collectErrorMetadata(e), true)); + return 1; + } + throw e; + } +} + +async function enablePreference(settings: AstroSettings, key: PreferenceKey, { location }: SubcommandOptions) { + try { + await settings.preferences.set(key, true, { location }); + console.log(msg.preferenceEnabled(key.replace('.enabled', ''))) + return 0; + } catch {} + return 1; +} + +async function disablePreference(settings: AstroSettings, key: PreferenceKey, { location }: SubcommandOptions) { + try { + await settings.preferences.set(key, false, { location }); + console.log(msg.preferenceDisabled(key.replace('.enabled', ''))) + return 0; + } catch {} + return 1; +} + +async function resetPreference(settings: AstroSettings, key: PreferenceKey, { location }: SubcommandOptions) { + try { + await settings.preferences.set(key, undefined as any, { location }); + console.log(msg.preferenceReset(key)) + return 0; + } catch {} + return 1; +} + + +async function listPreferences(settings: AstroSettings, { location, json }: SubcommandOptions) { + const store = await settings.preferences.getAll({ location }); + if (json) { + console.log(JSON.stringify(store, null, 2)); + return 0; + } + prettyPrint(store); + return 0; +} + +function prettyPrint(value: Record) { + const flattened = flattie(value); + const table = formatTable(flattened, ['Preference', 'Value']); + console.log(table); +} + +const chars = { + h: '─', + hThick: '━', + hThickCross: '┿', + v: '│', + vRight: '├', + vRightThick: '┝', + vLeft: '┤', + vLeftThick: '┥', + hTop: '┴', + hBottom: '┬', + topLeft: '╭', + topRight: '╮', + bottomLeft: '╰', + bottomRight: '╯', +} + +function formatTable(object: Record, columnLabels: [string, string]) { + const [colA, colB] = columnLabels; + const colALength = [colA, ...Object.keys(object)].reduce(longest, 0) + 3; + const colBLength = [colB, ...Object.values(object)].reduce(longest, 0) + 3; + function formatRow(i: number, a: string, b: string | number | boolean, style: (value: string | number | boolean) => string = (v) => v.toString()): string { + return `${chars.v} ${style(a)} ${space(colALength - a.length - 2)} ${chars.v} ${style(b)} ${space(colBLength - b.toString().length - 3)} ${chars.v}` + } + const top = `${chars.topLeft}${chars.h.repeat(colALength + 1)}${chars.hBottom}${chars.h.repeat(colBLength)}${chars.topRight}` + const bottom = `${chars.bottomLeft}${chars.h.repeat(colALength + 1)}${chars.hTop}${chars.h.repeat(colBLength)}${chars.bottomRight}` + const divider = `${chars.vRightThick}${chars.hThick.repeat(colALength + 1)}${chars.hThickCross}${chars.hThick.repeat(colBLength)}${chars.vLeftThick}` + const rows: string[] = [top, formatRow(-1, colA, colB, bold), divider]; + let i = 0; + for (const [key, value] of Object.entries(object)) { + rows.push(formatRow(i, key, value, (v) => formatWithOptions({ colors: true }, v))); + i++; + } + rows.push(bottom); + return rows.join('\n'); +} + +function space(len: number) { + return ' '.repeat(len); +} + +const longest = (a: number, b: string | number | boolean) => { + const { length: len } = b.toString(); + return a > len ? a : len; +}; diff --git a/packages/astro/src/core/config/settings.ts b/packages/astro/src/core/config/settings.ts index fca392c976..29df00eafc 100644 --- a/packages/astro/src/core/config/settings.ts +++ b/packages/astro/src/core/config/settings.ts @@ -10,11 +10,14 @@ import { formatYAMLException, isYAMLException } from '../errors/utils.js'; import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../constants.js'; import { AstroTimer } from './timer.js'; import { loadTSConfig } from './tsconfig.js'; +import createPreferences from '../../preferences/index.js'; export function createBaseSettings(config: AstroConfig): AstroSettings { const { contentDir } = getContentPaths(config); + const preferences = createPreferences(config); return { config, + preferences, tsConfig: undefined, tsConfigPath: undefined, adapter: undefined, diff --git a/packages/astro/src/core/dev/restart.ts b/packages/astro/src/core/dev/restart.ts index 16c1b1b2ce..49cd185d8a 100644 --- a/packages/astro/src/core/dev/restart.ts +++ b/packages/astro/src/core/dev/restart.ts @@ -29,6 +29,9 @@ async function createRestartedContainer( return newContainer; } +const configRE = new RegExp(`.*astro\.config\.((mjs)|(cjs)|(js)|(ts))$`); +const preferencesRE = new RegExp(`.*\.astro\/settings\.json$`); + export function shouldRestartContainer( { settings, inlineConfig, restartInFlight }: Container, changedFile: string @@ -43,9 +46,9 @@ export function shouldRestartContainer( } // Otherwise, watch for any astro.config.* file changes in project root else { - const exp = new RegExp(`.*astro\.config\.((mjs)|(cjs)|(js)|(ts))$`); const normalizedChangedFile = vite.normalizePath(changedFile); - shouldRestart = exp.test(normalizedChangedFile); + shouldRestart = configRE.test(normalizedChangedFile) || preferencesRE.test(normalizedChangedFile); + } if (!shouldRestart && settings.watchFiles.length > 0) { diff --git a/packages/astro/src/core/logger/core.ts b/packages/astro/src/core/logger/core.ts index 2c26a55a0d..5dab122135 100644 --- a/packages/astro/src/core/logger/core.ts +++ b/packages/astro/src/core/logger/core.ts @@ -25,6 +25,7 @@ export type LoggerLabel = | 'vite' | 'watch' | 'middleware' + | 'preferences' // SKIP_FORMAT: A special label that tells the logger not to apply any formatting. // Useful for messages that are already formatted, like the server start message. | 'SKIP_FORMAT'; diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts index 1c37909622..935ed1bdc4 100644 --- a/packages/astro/src/core/messages.ts +++ b/packages/astro/src/core/messages.ts @@ -3,6 +3,7 @@ import { bgRed, bgWhite, bgYellow, + bgCyan, black, blue, bold, @@ -110,6 +111,34 @@ export function telemetryEnabled() { ].join('\n'); } +export function preferenceEnabled(name: string) { + return `${green('◉')} ${name} is now ${bgGreen(black(' enabled '))}\n`; +} + +export function preferenceSet(name: string, value: any) { + return `${green('◉')} ${name} has been set to ${bgGreen(black(` ${JSON.stringify(value)} `))}\n`; +} + +export function preferenceGet(name: string, value: any) { + return `${green('◉')} ${name} is set to ${bgGreen(black(` ${JSON.stringify(value)} `))}\n`; +} + +export function preferenceDefaultIntro(name: string) { + return `${yellow('◯')} ${name} has not been set. It defaults to\n`; +} + +export function preferenceDefault(name: string, value: any) { + return `${yellow('◯')} ${name} has not been set. It defaults to ${bgYellow(black(` ${JSON.stringify(value)} `))}\n`; +} + +export function preferenceDisabled(name: string) { + return `${yellow('◯')} ${name} is now ${bgYellow(black(' disabled '))}\n`; +} + +export function preferenceReset(name: string) { + return `${cyan('◆')} ${name} has been ${bgCyan(black(' reset '))}\n`; +} + export function telemetryDisabled() { return [ green('▶ Anonymous telemetry ') + bgGreen(' disabled '), diff --git a/packages/astro/src/preferences/README.md b/packages/astro/src/preferences/README.md new file mode 100644 index 0000000000..4234ebac1b --- /dev/null +++ b/packages/astro/src/preferences/README.md @@ -0,0 +1,33 @@ +# Preferences + +The preferences module implements global and local user preferences for controlling certain Astro behavior. Whereas the `astro.config.mjs` file controls project-specific behavior for every user of a project, preferences are user-specific. + +The design of Preferences is inspired by [Git](https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration) and [Visual Studio Code](https://code.visualstudio.com/docs/getstarted/settings). Both systems implement similar layering approaches with project-specific and global settings. + +## `AstroPreferences` + +The `AstroPreferences` interface exposes both a `get` and `set` function. + +### Reading a preference + +`preferences.get("dot.separated.value")` will read a preference value from multiple sources if needed. Local project preferences are read from `.astro/settings.json`, if it exists. Next, global user preferences are read from `//astro/settings.json`. If neither of those are found, the default preferences defined in [`./defaults.ts`](./defaults.ts) will apply. + +In order to read a preference from a specific location, you can pass the `location: "global" | "project"` option. + +```js +await preferences.get('dot.separated.value', { location: 'global' }); +``` + +### Writing a preference + +`preferences.set("dot.separated.value", true)` will store a preference value. By default, preferences are stored locally in a project. + +In order to set a global user preference, you can pass the `location: "global"` option. + +```js +await preferences.set('dot.separated.value', 'value', { location: 'global' }); +``` + +## Relation to Telemetry + +This module evolved from the existing `@astrojs/telemetry` package, but has been generalized for user-facing `astro` preferences. At some point, we'll need to merge the logic in `@astrojs/telemetry` and the logic in this module so that all preferences are stored in the same location. diff --git a/packages/astro/src/preferences/defaults.ts b/packages/astro/src/preferences/defaults.ts new file mode 100644 index 0000000000..74ae7b2dc6 --- /dev/null +++ b/packages/astro/src/preferences/defaults.ts @@ -0,0 +1,8 @@ +export const DEFAULT_PREFERENCES = { + devOverlay: { + /** Specifies whether the user has the Dev Overlay enabled */ + enabled: true, + }, +} + +export type Preferences = typeof DEFAULT_PREFERENCES; diff --git a/packages/astro/src/preferences/index.ts b/packages/astro/src/preferences/index.ts new file mode 100644 index 0000000000..86faf1cc85 --- /dev/null +++ b/packages/astro/src/preferences/index.ts @@ -0,0 +1,91 @@ +import type { AstroConfig } from '../@types/astro.js'; + +import { fileURLToPath } from 'node:url'; +import os from 'node:os'; +import process from 'node:process'; +import path from 'node:path'; + +import dget from 'dlv'; +import { DEFAULT_PREFERENCES, type Preferences } from './defaults.js'; +import { PreferenceStore } from './store.js'; + +type DotKeys = T extends object ? { [K in keyof T]: + `${Exclude}${DotKeys extends never ? "" : `.${DotKeys}`}` +}[keyof T] : never + +export type GetDotKey< + T extends Record, + K extends string +> = K extends `${infer U}.${infer Rest}` ? GetDotKey : T[K] + +export interface PreferenceOptions { + location?: 'global' | 'project'; +} + +export type PreferenceKey = DotKeys; + +export interface AstroPreferences { + get(key: Key, opts?: PreferenceOptions): Promise>; + set(key: Key, value: GetDotKey, opts?: PreferenceOptions): Promise; + getAll(opts?: PreferenceOptions): Promise>; +} + +export function isValidKey(key: string): key is PreferenceKey { + return dget(DEFAULT_PREFERENCES, key) !== undefined; +} +export function coerce(key: string, value: unknown) { + const type = typeof dget(DEFAULT_PREFERENCES, key); + switch (type) { + case 'string': return value; + case 'number': return Number(value); + case 'boolean': { + if (value === 'true' || value === 1) return true; + if (value === 'false' || value === 0) return false; + } + } + return value as any; +} + +export default function createPreferences(config: AstroConfig): AstroPreferences { + const global = new PreferenceStore(getGlobalPreferenceDir()); + const project = new PreferenceStore(fileURLToPath(new URL('./.astro/', config.root))); + const stores = { global, project }; + + return { + async get(key, { location } = {}) { + if (!location) return project.get(key) ?? global.get(key) ?? dget(DEFAULT_PREFERENCES, key); + return stores[location].get(key); + }, + async set(key, value, { location = 'project' } = {}) { + stores[location].set(key, value); + }, + async getAll({ location } = {}) { + if (!location) return Object.assign({}, stores['global'].getAll(), stores['project'].getAll()); + return stores[location].getAll(); + }, + } +} + + +// Adapted from https://github.com/sindresorhus/env-paths +export function getGlobalPreferenceDir() { + const name = 'astro'; + const homedir = os.homedir(); + const macos = () => path.join(homedir, 'Library', 'Preferences', name); + const win = () => { + const { APPDATA = path.join(homedir, 'AppData', 'Roaming') } = process.env; + return path.join(APPDATA, name, 'Config'); + }; + const linux = () => { + const { XDG_CONFIG_HOME = path.join(homedir, '.config') } = process.env; + return path.join(XDG_CONFIG_HOME, name); + }; + switch (process.platform) { + case 'darwin': + return macos(); + case 'win32': + return win(); + default: + return linux(); + } +} diff --git a/packages/astro/src/preferences/store.ts b/packages/astro/src/preferences/store.ts new file mode 100644 index 0000000000..4dabbba1ce --- /dev/null +++ b/packages/astro/src/preferences/store.ts @@ -0,0 +1,59 @@ +import dget from 'dlv'; +import { dset } from 'dset'; +import fs from 'node:fs'; +import path from 'node:path'; + +export class PreferenceStore { + private file: string; + + constructor(private dir: string, filename = 'settings.json') { + this.file = path.join(this.dir, filename); + } + + private _store?: Record; + private get store(): Record { + if (this._store) return this._store; + if (fs.existsSync(this.file)) { + try { + this._store = JSON.parse(fs.readFileSync(this.file).toString()); + } catch {} + } + if (!this._store) { + this._store = {}; + this.write(); + } + return this._store; + } + private set store(value: Record) { + this._store = value; + this.write(); + } + write() { + if (!this._store || Object.keys(this._store).length === 0) return; + fs.mkdirSync(this.dir, { recursive: true }); + fs.writeFileSync(this.file, JSON.stringify(this.store, null, '\t')); + } + clear(): void { + this.store = {}; + fs.rmSync(this.file, { recursive: true }); + } + delete(key: string): boolean { + dset(this.store, key, undefined); + this.write(); + return true; + } + get(key: string): any { + return dget(this.store, key); + } + has(key: string): boolean { + return typeof this.get(key) !== 'undefined'; + } + set(key: string, value: any): void { + if (this.get(key) === value) return; + dset(this.store, key, value); + this.write(); + } + getAll(): Record { + return this.store; + } +} diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index a58f38a02b..a8f9efa049 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -384,7 +384,7 @@ async function getScriptsAndStyles({ pipeline, filePath }: GetScriptsAndStylesPa children: '', }); - if (settings.config.devOverlay.enabled) { + if (settings.config.devOverlay.enabled && await settings.preferences.get('devOverlay.enabled')) { scripts.add({ props: { type: 'module', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ede4937053..214bf4b33f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -550,6 +550,12 @@ importers: diff: specifier: ^5.1.0 version: 5.1.0 + dlv: + specifier: ^1.1.3 + version: 1.1.3 + dset: + specifier: ^3.1.3 + version: 3.1.3 es-module-lexer: specifier: ^1.4.1 version: 1.4.1 @@ -565,6 +571,9 @@ importers: fast-glob: specifier: ^3.3.2 version: 3.3.2 + flattie: + specifier: ^1.1.0 + version: 1.1.0 github-slugger: specifier: ^2.0.0 version: 2.0.0 @@ -693,6 +702,9 @@ importers: '@types/diff': specifier: ^5.0.8 version: 5.0.8 + '@types/dlv': + specifier: ^1.1.4 + version: 1.1.4 '@types/dom-view-transitions': specifier: ^1.0.4 version: 1.0.4 @@ -12217,6 +12229,11 @@ packages: resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} dev: true + /flattie@1.1.0: + resolution: {integrity: sha512-xU99gDEnciIwJdGcBmNHnzTJ/w5AT+VFJOu6sTB6WM8diOYNA3Sa+K1DiEBQ7XH4QikQq3iFW1U+jRVcotQnBw==} + engines: {node: '>=8'} + dev: false + /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: