diff --git a/apps/kazam/package.json b/apps/kazam/package.json index 25d240b..8a45741 100644 --- a/apps/kazam/package.json +++ b/apps/kazam/package.json @@ -10,7 +10,7 @@ }, "main": "./dist/index.cjs", "types": "./dist/index.d.ts", - "bin": "./dist/cli.cjs", + "bin": "./dist/cli.mjs", "files": [ "dist" ], @@ -26,13 +26,19 @@ "@whitebird/kaz-ast": "workspace:*", "@whitebird/kazam-parser-base": "workspace:*", "@whitebird/kazam-transformer-base": "workspace:*", + "c12": "^1.4.2", "chalk": "^4", "commander": "^10.0.1", "glob": "10.1.0", + "ink": "^4.4.1", + "ink-spinner": "^5.0.0", + "just-kebab-case": "^4.2.0", + "react": "^18.2.0", "typescript": "^5.0.0", "zod": "^3.21.4" }, "devDependencies": { + "@types/ink-spinner": "^3.0.2", "@types/node": "^18.11.9", "@vitest/coverage-v8": "^0.34.1", "@whitebird/kazam-parser-kaz": "workspace:*", diff --git a/apps/kazam/src/adapters/cli/cli.ts b/apps/kazam/src/adapters/cli/cli.ts new file mode 100644 index 0000000..00e780b --- /dev/null +++ b/apps/kazam/src/adapters/cli/cli.ts @@ -0,0 +1,10 @@ +import process from 'node:process' + +import { program } from 'commander' + +import { generateCommand } from './commands/generate' + +program + .addCommand(generateCommand) + +export const runCli = () => program.parse(process.argv) diff --git a/apps/kazam/src/adapters/cli/commands/generate.tsx b/apps/kazam/src/adapters/cli/commands/generate.tsx new file mode 100644 index 0000000..b61b412 --- /dev/null +++ b/apps/kazam/src/adapters/cli/commands/generate.tsx @@ -0,0 +1,43 @@ +import * as fs from 'node:fs' + +import { loadConfig } from 'c12' +import { Command } from 'commander' +import { type AppProps, render } from 'ink' +import React from 'react' + +import { generate } from '../../../application/usecases/generate' +import type { KazamConfig } from '../../../types/kazam-config' +import { GenerateView } from '../views/generate' + +export const generateCommand = new Command() + .command('generate') + .description('Generate code from your Kazam files') + .option('-c, --config ', 'Path to the config file', (path) => { + if (!fs.existsSync(path)) + throw new Error(`Could not find config file at ${path}`) + + return path + }) + .action(async (options) => { + let exit: AppProps['exit'] | undefined + const setExit = (_exit: AppProps['exit']) => exit = _exit + + const { config, configFile } = await loadConfig({ + name: 'kazam', + ...(options.config && { configFile: options.config }), + }) + + if (config === null || configFile === undefined) + throw new Error('Could not load config') + + const generatePromise = generate(config, configFile, fs) + + render( + , + ) + + generatePromise.finally(exit) + }) diff --git a/apps/kazam/src/adapters/cli/components/spinner.tsx b/apps/kazam/src/adapters/cli/components/spinner.tsx new file mode 100644 index 0000000..7b5b345 --- /dev/null +++ b/apps/kazam/src/adapters/cli/components/spinner.tsx @@ -0,0 +1,4 @@ +import Spinner_ from 'ink-spinner' +import React from 'react' + +export const Spinner = () => diff --git a/apps/kazam/src/adapters/cli/types/Commander.d.ts b/apps/kazam/src/adapters/cli/types/Commander.d.ts new file mode 100644 index 0000000..fef67b9 --- /dev/null +++ b/apps/kazam/src/adapters/cli/types/Commander.d.ts @@ -0,0 +1,3 @@ +// declare module 'commander' { +// export * from '@commander-js/extra-typings' +// } diff --git a/apps/kazam/src/adapters/cli/views/generate.tsx b/apps/kazam/src/adapters/cli/views/generate.tsx new file mode 100644 index 0000000..29d2365 --- /dev/null +++ b/apps/kazam/src/adapters/cli/views/generate.tsx @@ -0,0 +1,61 @@ +import path from 'node:path' + +import { type AppProps, Text, useApp } from 'ink' +import React, { useEffect, useState } from 'react' + +import type { generate } from '../../../application/usecases/generate' +import { generateEvents } from '../../../core/events/generate' +import { Spinner } from '../components/spinner' + +export const GenerateView = ( + { generatePromise, setExit }: + { generatePromise: ReturnType; setExit?: (exit: AppProps['exit']) => void }, +) => { + const { exit } = useApp() + + const [status, setStatus] = useState< + | { success: true } + | { error: string } + | { pending: true } + >({ pending: true }) + const [writtenPaths, setWrittenPaths] = useState([]) + + useEffect(() => { + setExit?.(exit) + + generatePromise + .then(() => setStatus({ success: true })) + .catch((error) => { + setStatus({ error }) + console.error('ERROR', error) + }) + + generateEvents.on('file-written', filePath => + setWrittenPaths(writtenPaths => [...writtenPaths, filePath]), + ) + }, []) + + if ('success' in status) { + return <> + Successfully generated components + {writtenPaths.map(writtenPath => + {' '}{path.normalize(writtenPath)}, + )} + + } + + if ('error' in status) { + return <> + {status.error} + + } + + return <> + + + + + {' Generating components...'} + + +} diff --git a/apps/kazam/src/adapters/lib/define-config.ts b/apps/kazam/src/adapters/lib/define-config.ts new file mode 100644 index 0000000..53137b4 --- /dev/null +++ b/apps/kazam/src/adapters/lib/define-config.ts @@ -0,0 +1,4 @@ +import { defineConfig as defineConfig_ } from '../../application/usecases/define-config' +import type { UserConfig } from '../../types/kazam-config' + +export const defineConfig = (config: UserConfig) => defineConfig_(config) diff --git a/apps/kazam/src/adapters/lib/generate.ts b/apps/kazam/src/adapters/lib/generate.ts new file mode 100644 index 0000000..b988ea8 --- /dev/null +++ b/apps/kazam/src/adapters/lib/generate.ts @@ -0,0 +1,9 @@ +import type * as fs from 'node:fs' + +import { generate as generate_ } from '../../application/usecases/generate' +import type { KazamConfig } from '../../types/kazam-config' + +export const generate = ( + { rootDir, ...config }: KazamConfig & { rootDir: string }, + fileSystem?: typeof fs | undefined, +) => generate_(config, rootDir, fileSystem) diff --git a/apps/kazam/src/adapters/lib/index.ts b/apps/kazam/src/adapters/lib/index.ts new file mode 100644 index 0000000..b718d79 --- /dev/null +++ b/apps/kazam/src/adapters/lib/index.ts @@ -0,0 +1,2 @@ +export { defineConfig } from './define-config' +export { generate } from './generate' diff --git a/apps/kazam/src/application/usecases/define-config.ts b/apps/kazam/src/application/usecases/define-config.ts new file mode 100644 index 0000000..5941e81 --- /dev/null +++ b/apps/kazam/src/application/usecases/define-config.ts @@ -0,0 +1,4 @@ +import { kazamConfigSchema } from '../../core/schemas/kazam-config' +import type { UserConfig } from '../../types/kazam-config' + +export const defineConfig = (config: UserConfig) => kazamConfigSchema.parse(config) diff --git a/apps/kazam/src/application/usecases/generate.ts b/apps/kazam/src/application/usecases/generate.ts new file mode 100644 index 0000000..a686ee9 --- /dev/null +++ b/apps/kazam/src/application/usecases/generate.ts @@ -0,0 +1,102 @@ +import type * as fs from 'node:fs' + +import type { TransformerOutput } from '@whitebird/kazam-transformer-base' +import kebabCase from 'just-kebab-case' + +import { generateEvents } from '../../core/events/generate' +import type { KazamConfig } from '../../types/kazam-config' +import type { Transformer } from '../../types/transformer' + +const writeResults = ( + files: Map, + fileSystem: typeof fs, +) => { + files.forEach((fileContents, filePath) => { + const directoryPath = filePath.split('/').slice(0, -1).join('/') + + fileSystem.mkdirSync(directoryPath, { recursive: true }) + fileSystem.writeFileSync(filePath, fileContents) + + generateEvents.emit('file-written', filePath) + }) +} + +const formatResults = ( + transformerResult: TransformerOutput<{ outputFileNameFormat: string }>, + transformer: Transformer, + config: Exclude, +): Parameters[0] => { + const formattedTransformerResult = new Map() + + const transformerDirectory = [ + config.output, + kebabCase(transformer.name.replace(/^Transformer/, '')), + ].join('/') + + transformerResult.forEach(({ filePath, content }, sourceFilePath) => { + const sourceExtension = `.${sourceFilePath.split('.').slice(-1)[0]}` ?? '' + const transformedExtension = `.${filePath.split('.').slice(-1)[0]}` ?? '' + + const outputFilePath = [ + transformerDirectory, + // The following line replaces `.kaz.tsx` with `.tsx` (for example) + filePath.replace( + new RegExp(`${sourceExtension.replace('.', '\\.')}${transformedExtension.replace('.', '\\.')}$`), + transformedExtension, + ), + ].join('/') + + formattedTransformerResult.set(outputFilePath, content) + }) + + return formattedTransformerResult +} + +const generateForConfig = async ( + config: Exclude, + configPath: string, + fileSystem?: typeof fs | undefined, +) => { + return Promise.all( + config.parsers.map(async (ParserClass) => { + const parser = new ParserClass() + + const transformerInput = await parser.loadAndParse({ + ...config, + configPath, + }) + + return config.transformers.map((TransformerClass) => { + const transformer = new TransformerClass(transformerInput, {}) + + const transformerResult = transformer.transform() + + if (fileSystem) { + writeResults( + formatResults(transformerResult, TransformerClass, config), + fileSystem, + ) + } + + return transformerResult + }) + }), + ) + .then(results => results.flat()) +} + +export const generate = async ( + config: KazamConfig, + configPath: string, + fileSystem?: typeof fs | undefined, +) => { + if (!Array.isArray(config)) + config = [config] + + const results = await Promise.all( + config.map(config => generateForConfig(config, configPath, fileSystem)), + ) + .then(results => results.flat()) + + return results +} diff --git a/apps/kazam/src/cli.ts b/apps/kazam/src/cli.ts index 2770eea..7791bf1 100644 --- a/apps/kazam/src/cli.ts +++ b/apps/kazam/src/cli.ts @@ -1,12 +1,3 @@ -#!/usr/bin/env node +import { runCli } from './adapters/cli/cli' -import process from 'node:process' - -import { program } from 'commander' - -import { generateCommand } from './commands/generate' - -program - .addCommand(generateCommand) - -program.parse(process.argv) +runCli() diff --git a/apps/kazam/src/commands/generate.ts b/apps/kazam/src/commands/generate.ts deleted file mode 100644 index dc005e6..0000000 --- a/apps/kazam/src/commands/generate.ts +++ /dev/null @@ -1,33 +0,0 @@ -import * as fs from 'node:fs' -import process from 'node:process' - -import chalk from 'chalk' -import { Command } from 'commander' - -import { generate } from '../handlers/generate.js' -import { findConfigPath } from '../utils/find-config-path.js' -import { loadConfig } from '../utils/load-config.js' - -export const generateCommand = new Command() - .command('generate') - .description('Generate code from your Kazam files') - .option('-c, --config ', 'Path to the config file', (path) => { - if (!fs.existsSync(path)) - throw new Error(`Could not find config file at ${path}`) - - return path - }) - .action(async (options) => { - const configPath = options.config ?? await findConfigPath() - const config = await loadConfig(configPath) - - await generate(config) - .then(() => { - process.stdout.write(`\r\n${chalk.green('✔')} Generated code successfully\n`) - process.exit(0) - }) - .catch((error) => { - process.stdout.write(`\r\n${chalk.red('✖')} ${error.message}\n`) - process.exit(1) - }) - }) diff --git a/apps/kazam/src/core/events/generate.ts b/apps/kazam/src/core/events/generate.ts new file mode 100644 index 0000000..18c6b10 --- /dev/null +++ b/apps/kazam/src/core/events/generate.ts @@ -0,0 +1,7 @@ +import { registerEventEmitter } from '../lib/typed-event-emitter' + +const generateEvents = registerEventEmitter<{ + 'file-written': string +}>() + +export { generateEvents } diff --git a/apps/kazam/src/core/lib/typed-event-emitter.ts b/apps/kazam/src/core/lib/typed-event-emitter.ts new file mode 100644 index 0000000..585494f --- /dev/null +++ b/apps/kazam/src/core/lib/typed-event-emitter.ts @@ -0,0 +1,23 @@ +import { EventEmitter } from 'node:events' + +class ReturnedEmitter> { + #eventEmitter = new EventEmitter() + + emit(eventName: EventName extends string ? EventName : never, data: Events[EventName]) { + return this.#eventEmitter.emit(eventName, data) + } + + on(eventName: EventName extends string ? EventName : never, listener: (data: Events[EventName]) => void): this { + this.#eventEmitter.on(eventName, listener) + return this + } + + once(eventName: EventName extends string ? EventName : never, listener: (data: Events[EventName]) => void): this { + this.#eventEmitter.once(eventName, listener) + return this + } +} + +export const registerEventEmitter = >() => { + return new ReturnedEmitter() +} diff --git a/apps/kazam/src/core/schemas/kazam-config.ts b/apps/kazam/src/core/schemas/kazam-config.ts new file mode 100644 index 0000000..55b95c0 --- /dev/null +++ b/apps/kazam/src/core/schemas/kazam-config.ts @@ -0,0 +1,28 @@ +import { ParserBase } from '@whitebird/kazam-parser-base' +import { TransformerBase } from '@whitebird/kazam-transformer-base' +import { z } from 'zod' + +import type { Parser } from '../../types/parser' +import type { Transformer } from '../../types/transformer' + +const transformerSchema = z.custom( + v => typeof v === 'function' && v.prototype instanceof TransformerBase, + { message: 'Must be an instance of TransformerBase' }, +) + +const parserSchema = z.custom( + v => typeof v === 'function' && v.prototype instanceof ParserBase, + { message: 'Must be an instance of ParserBase' }, +) + +const singleKazamConfigSchema = z.object({ + input: z.string().array(), + output: z.string(), + transformers: z.array(transformerSchema), + parsers: z.array(parserSchema), +}) + +export const kazamConfigSchema = z.union([ + singleKazamConfigSchema, + z.array(singleKazamConfigSchema), +]) diff --git a/apps/kazam/src/handlers/generate.ts b/apps/kazam/src/handlers/generate.ts deleted file mode 100644 index ab7d9ff..0000000 --- a/apps/kazam/src/handlers/generate.ts +++ /dev/null @@ -1,80 +0,0 @@ -import * as fs from 'node:fs' -import path from 'node:path' -import process from 'node:process' - -import type { KazAst } from '@whitebird/kaz-ast' - -import type { KazamConfig } from '../utils/define-config.js' - -export const generate = async (config: KazamConfig) => { - await Promise.all(config.parsers.map(async (Parser) => { - const parser = new Parser() - - const asts = await parser.parse(await parser.load(config), config) - - const transformedAsts = await transformAsts(asts, config.transformers) - - await writeOutput(transformedAsts, config) - })) -} - -async function transformAsts(asts: Record, transformers: KazamConfig['transformers']) { - return Object.fromEntries( - await Promise.all( - transformers.map(async (Transformer) => { - const transformerInstance = new Transformer( - Object.fromEntries( - Object.entries(asts).map(([fileName, ast]) => { - const fileExtension = path.extname(fileName) - - if (fileExtension.length === 0) - return [fileName, ast] - - return [fileName.slice(0, -fileExtension.length), ast] - }), - ), - {}, - ) - const output = await transformerInstance.transform() - - return [Transformer.name, output] as const - }), - ), - ) -} - -async function writeOutput(output: Awaited>, config: KazamConfig) { - const outputPath = path.isAbsolute(config.output) - ? config.output - : path.join(process.cwd(), config.output) - - fs.mkdirSync(path.dirname(outputPath), { recursive: true }) - - await Promise.all( - Object.entries(output).map(async ([transformerName, transformerOutput]) => { - const transformerOutputPath = config.transformers.length > 1 - ? path.join(outputPath, normalizeTransformerName(transformerName)) - : outputPath - - await Promise.all( - Object.entries(transformerOutput ?? {}).map(async ([fileName, file]) => { - if (file === undefined) - throw new Error(`Transformer ${transformerName} returned undefined for file ${fileName}`) - - if (!(file instanceof Blob)) - throw new Error(`Transformer ${transformerName} returned non-Blob for file ${fileName}`) - - const filePath = path.join(transformerOutputPath, file.name) - - await fs.promises.mkdir(path.dirname(filePath), { recursive: true }) - - await fs.promises.writeFile(filePath, await file.text()) - }), - ) - }), - ) -} - -function normalizeTransformerName(name: string) { - return name.replace(/^Transformer/, '').toLowerCase() -} diff --git a/apps/kazam/src/index.ts b/apps/kazam/src/index.ts index bb6a656..8b74593 100644 --- a/apps/kazam/src/index.ts +++ b/apps/kazam/src/index.ts @@ -1,3 +1 @@ -export { defineConfig, type KazamConfig, type UserConfig } from './utils/define-config' - -export { generate } from './handlers/generate' +export * from './adapters/lib' diff --git a/apps/kazam/src/types/Commander.d.ts b/apps/kazam/src/types/Commander.d.ts deleted file mode 100644 index c55a0be..0000000 --- a/apps/kazam/src/types/Commander.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -declare module 'commander' { - export * from '@commander-js/extra-typings' -} diff --git a/apps/kazam/src/types/kazam-config.ts b/apps/kazam/src/types/kazam-config.ts new file mode 100644 index 0000000..bc733c0 --- /dev/null +++ b/apps/kazam/src/types/kazam-config.ts @@ -0,0 +1,6 @@ +import type { z } from 'zod' + +import type { kazamConfigSchema } from '../core/schemas/kazam-config' + +export type KazamConfig = z.infer +export type UserConfig = z.input diff --git a/apps/kazam/src/types/parser.ts b/apps/kazam/src/types/parser.ts new file mode 100644 index 0000000..62b05d9 --- /dev/null +++ b/apps/kazam/src/types/parser.ts @@ -0,0 +1,3 @@ +import type { ParserBase } from '@whitebird/kazam-parser-base' + +export type Parser = new (...args: ConstructorParameters) => ParserBase diff --git a/apps/kazam/src/types/transformer.ts b/apps/kazam/src/types/transformer.ts new file mode 100644 index 0000000..b8171c5 --- /dev/null +++ b/apps/kazam/src/types/transformer.ts @@ -0,0 +1,3 @@ +import type { TransformerBase } from '@whitebird/kazam-transformer-base' + +export type Transformer = new (...args: ConstructorParameters) => TransformerBase<{ outputFileNameFormat: string }> diff --git a/apps/kazam/src/utils/define-config.ts b/apps/kazam/src/utils/define-config.ts deleted file mode 100644 index 27a5ecc..0000000 --- a/apps/kazam/src/utils/define-config.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { ParserBase } from '@whitebird/kazam-parser-base' -import { TransformerBase } from '@whitebird/kazam-transformer-base' -import { z } from 'zod' - -type Transformer = new (...args: ConstructorParameters) => TransformerBase -type Parser = new (...args: ConstructorParameters) => ParserBase - -const transformerSchema = z.custom( - v => typeof v === 'function' && v.prototype instanceof TransformerBase, - { message: 'Must be an instance of TransformerBase' }, -) - -const parserSchema = z.custom( - v => typeof v === 'function' && v.prototype instanceof ParserBase, - { message: 'Must be an instance of ParserBase' }, -) - -// const fsPathSchema = z.string().refine( -// v => fs.existsSync(v), -// { message: 'File does not exist' }, -// ) - -// const filePathSchema = fsPathSchema.refine( -// v => fs.statSync(v).isFile(), -// { message: 'Must be a file' }, -// ) - -// const directoryPathSchema = fsPathSchema.refine( -// v => fs.statSync(v).isDirectory(), -// { message: 'Must be a directory' }, -// ) - -const configSchema = z.object({ - input: z.string().array(), - output: z.string(), - transformers: z.array(transformerSchema).nonempty(), - parsers: z.array(parserSchema).nonempty(), - // vite: z.union([filePathSchema, z.boolean()]).default(false), -}) - -export type KazamConfig = z.infer -export type UserConfig = z.input - -export const defineConfig = (config: UserConfig) => configSchema.parse(config) - -const assertType = (_: T) => _ -assertType[0]>({}) diff --git a/apps/kazam/src/utils/find-config-path.ts b/apps/kazam/src/utils/find-config-path.ts deleted file mode 100644 index ee1e287..0000000 --- a/apps/kazam/src/utils/find-config-path.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as fs from 'node:fs' -import * as path from 'node:path' -import process from 'node:process' - -const configFiles = [ - 'kazam.config.js', - 'kazam.config.ts', -] - -export const findConfigPath = async (dirPath: string = process.cwd()) => { - for (const configFile of configFiles) { - if (fs.existsSync(path.join(dirPath, configFile))) - return path.join(dirPath, configFile) - } - - throw new Error('Could not find a config file') -} diff --git a/apps/kazam/src/utils/load-config.ts b/apps/kazam/src/utils/load-config.ts deleted file mode 100644 index d40fca8..0000000 --- a/apps/kazam/src/utils/load-config.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as fs from 'node:fs' -import * as path from 'node:path' -import process from 'node:process' -import vm from 'node:vm' - -import typescript from 'typescript' - -import { defineConfig } from './define-config.js' - -export const loadConfig = async (configPath: string) => { - if (path.extname(configPath) === '.js') { - const config = await import(configPath) - return defineConfig(config) - } - - if (path.extname(configPath) === '.ts') { - const transpiledConfigDefinition = typescript.transpileModule(fs.readFileSync(configPath, 'utf-8'), { - compilerOptions: { - module: typescript.ModuleKind.CommonJS, - }, - }).outputText - - process.env.NODE_PATH += path.delimiter + path.join(process.cwd(), 'node_modules') - const config = vm.runInThisContext(` - ((require) => { - require('module').Module._initPaths(); - var exports = {}; - ${transpiledConfigDefinition}; - return exports.default; - }) - `)(require) - - return defineConfig(config) - } - - throw new Error(`Could not load config file at ${configPath}`) -} diff --git a/apps/kazam/tests/generate.test.ts b/apps/kazam/tests/generate.test.ts index bf675e8..0db665a 100644 --- a/apps/kazam/tests/generate.test.ts +++ b/apps/kazam/tests/generate.test.ts @@ -19,14 +19,15 @@ describe('kazam', () => { fs.rmSync(baseKazamConfig.output, { recursive: true, force: true }) }) - test('should build the .kaz files', async () => { + test('should build the .kaz files in transformer specific directories', async () => { await generate({ ...baseKazamConfig, input: [path.join(__dirname, 'fixtures')], - }) + rootDir: __dirname, + }, fs) - expect(path.join(baseKazamConfig.output, 'Button.tsx')).toSatisfy(fs.existsSync) - expect(path.join(baseKazamConfig.output, 'Input.tsx')).toSatisfy(fs.existsSync) + expect(path.join(baseKazamConfig.output, 'react', 'Button.tsx')).toSatisfy(fs.existsSync) + expect(path.join(baseKazamConfig.output, 'react', 'Input.tsx')).toSatisfy(fs.existsSync) }, { timeout: 30000, // This should not take as long as 30 seconds, but in CI it is very slow }) diff --git a/apps/kazam/tsconfig.json b/apps/kazam/tsconfig.json index cff1541..fb2f679 100644 --- a/apps/kazam/tsconfig.json +++ b/apps/kazam/tsconfig.json @@ -4,7 +4,8 @@ "extends": "@whitebird/tsconfig/node.json", "compilerOptions": { "target": "es6", - "module": "commonjs", + "jsx": "react", + "module": "ESNext", "moduleResolution": "node", "sourceMap": true, "outDir": "dist", diff --git a/package.json b/package.json index ea9da78..3579bcc 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,9 @@ "pnpm": { "overrides": { "@antfu/eslint-config": "0.43.1" + }, + "patchedDependencies": { + "ink@4.4.1": "patches/ink@4.4.1.patch" } } } diff --git a/packages/parser-base/build.config.ts b/packages/parser-base/build.config.ts new file mode 100644 index 0000000..2b973fa --- /dev/null +++ b/packages/parser-base/build.config.ts @@ -0,0 +1,5 @@ +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + declaration: true, +}) diff --git a/packages/parser-base/src/index.ts b/packages/parser-base/src/index.ts index 57603db..7bdc934 100644 --- a/packages/parser-base/src/index.ts +++ b/packages/parser-base/src/index.ts @@ -1 +1,16 @@ -export * from './parser-base' +import type { TransformerInput } from '@whitebird/kazam-transformer-base' + +interface ParserConfig { + input: string[] + output: string + configPath: string +} + +export abstract class ParserBase { + abstract load(config: ParserConfig): Promise + abstract parse(loadResult: LoadResult, config: ParserConfig): Promise + + async loadAndParse(config: ParserConfig) { + return this.load(config).then(loadResult => this.parse(loadResult, config)) + } +} diff --git a/packages/parser-base/src/parser-base.ts b/packages/parser-base/src/parser-base.ts deleted file mode 100644 index 5873de4..0000000 --- a/packages/parser-base/src/parser-base.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { ITransformerInput, TransformerBase } from '@whitebird/kazam-transformer-base' - -type Transformer = new (...args: ConstructorParameters) => TransformerBase -type Parser = new (...args: ConstructorParameters) => ParserBase - -interface KazamConfig { - input: string[] - output: string - transformers: [Transformer, ...Transformer[]] - parsers: [Parser, ...Parser[]] -} - -export abstract class ParserBase { - abstract load(config: KazamConfig): unknown | Promise - - abstract parse(loadResult: Awaited>, config: KazamConfig): ITransformerInput | Promise -} diff --git a/packages/parser-kaz/build.config.ts b/packages/parser-kaz/build.config.ts new file mode 100644 index 0000000..75b6a8a --- /dev/null +++ b/packages/parser-kaz/build.config.ts @@ -0,0 +1,6 @@ +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + externals: ['@whitebird/kazam-transformer-base'], + declaration: true, +}) diff --git a/packages/parser-kaz/package.json b/packages/parser-kaz/package.json index d4bda96..ffee5ed 100644 --- a/packages/parser-kaz/package.json +++ b/packages/parser-kaz/package.json @@ -29,6 +29,7 @@ "devDependencies": { "@types/node": "^18.11.9", "@vitest/coverage-v8": "^0.34.1", + "@whitebird/kazam-transformer-base": "workspace:*", "vitest": "^0.34.1" } } diff --git a/packages/parser-kaz/src/parser-kaz.ts b/packages/parser-kaz/src/parser-kaz.ts index 7aa9334..f8b5dd5 100644 --- a/packages/parser-kaz/src/parser-kaz.ts +++ b/packages/parser-kaz/src/parser-kaz.ts @@ -1,58 +1,72 @@ import * as fs from 'node:fs' import * as path from 'node:path' -import process from 'node:process' import { parse, tokenize } from '@whitebird/kaz-ast' import { ParserBase } from '@whitebird/kazam-parser-base' +import type { TransformerInput } from '@whitebird/kazam-transformer-base' import { glob } from 'glob' import { fixAstImportPaths } from './utils/fix-ast' -export class ParserKaz extends ParserBase { - async load(config: Parameters[0]) { - const normalizedInput = config.input.map(input => path.normalize( +export class ParserKaz extends ParserBase<{ + pathRelativeToInputPath: string + inputPath: string +}[]> { + async load({ input, configPath }: Parameters['load']>[0]) { + const normalizedInput = input.map(input => path.normalize( path.isAbsolute(input) ? input - : path.join(process.cwd(), input), + : path.join(path.dirname(configPath), input), )) - const kazFiles = await Promise.all(normalizedInput.map(input => + const kazFiles = normalizedInput.map(input => ( input.endsWith('.kaz') ? [input] - : glob(path.join(input, '**/*.kaz'), { absolute: true }), - )) + : glob.sync(path.join(input, '**/*.kaz'), { absolute: true }) + ) + .map(kazFile => ({ + pathRelativeToInputPath: path.relative(input.endsWith('.kaz') ? path.dirname(input) : input, kazFile), + inputPath: input.endsWith('.kaz') ? path.dirname(input) : input, + })), + ) return kazFiles.flat() } - async parse(kazFiles: Awaited>, config: Parameters[0]) { - return Object.fromEntries( - await Promise.all(kazFiles.map(async filePath => - [ - path.relative( - (config.input.length === 1 && config.input[0]) || process.cwd(), - filePath, - ), - await (async () => { - const fileContent = fs.readFileSync(filePath, 'utf-8') - - const tokens = tokenize(fileContent) - const ast = parse(tokens) - - if (ast instanceof Error) - throw ast - - if (ast === undefined) - throw new Error(`Could not parse file ${filePath}`) - - const fixedAst = fixAstImportPaths( - ast, filePath, config, - ) - - return fixedAst - })(), - ] as const, - )), - ) + async parse( + kazFiles: { + pathRelativeToInputPath: string + inputPath: string + }[], + { input, output }: Parameters['parse']>[1], + ) { + const kazAsts: TransformerInput = {} + + for (const { inputPath, pathRelativeToInputPath } of kazFiles) { + const filePath = path.join(inputPath, pathRelativeToInputPath) + + const fileContent = fs.readFileSync(filePath, 'utf-8') + + const tokens = tokenize(fileContent) + const ast = parse(tokens) + + if (ast instanceof Error) + throw ast + + if (ast === undefined) + throw new Error(`Could not parse file ${filePath}`) + + const fixedAst = fixAstImportPaths( + ast, + { filePath, input, output }, + ) + + kazAsts[pathRelativeToInputPath] = fixedAst + } + + return kazAsts } } diff --git a/packages/parser-kaz/src/utils/fix-ast.ts b/packages/parser-kaz/src/utils/fix-ast.ts index 2a9d9e8..3ac1f9a 100644 --- a/packages/parser-kaz/src/utils/fix-ast.ts +++ b/packages/parser-kaz/src/utils/fix-ast.ts @@ -1,15 +1,17 @@ import path from 'node:path' import type { KazAst } from '@whitebird/kaz-ast' -import type { ParserBase } from '@whitebird/kazam-parser-base' -export function fixAstImportPaths(ast: KazAst, filePath: string, config: Parameters[0]) { +export function fixAstImportPaths( + ast: KazAst, + { filePath, output }: { filePath: string; input: string[]; output: string }, +) { for (const instruction of ast.instructions) { if (instruction.$type !== 'ImportInstruction') continue const fixedPath = path.relative( - config.output, + output, path.join(path.dirname(filePath), instruction.from.$value), ) diff --git a/packages/parser-kaz/tests/parser-kaz.test.ts b/packages/parser-kaz/tests/parser-kaz.test.ts index 5511c7b..ffe3758 100644 --- a/packages/parser-kaz/tests/parser-kaz.test.ts +++ b/packages/parser-kaz/tests/parser-kaz.test.ts @@ -8,37 +8,33 @@ describe('parser-kaz', () => { const config = { input: [ // test include a directory + path.join(__dirname, 'fixtures'), + // test include a subdirectory path.join(__dirname, 'fixtures', 'buttons'), // test include a file path.join(__dirname, 'fixtures', 'Input.kaz'), ], + output: 'dist', + configPath: __filename, } const parser = new ParserKaz() - describe('load', () => { - test('should return an array of file paths', async () => { - const result = await parser.load(config) - - expect(result).toEqual( - expect.arrayContaining([ - path.join(__dirname, 'fixtures', 'buttons', 'PrimaryButton.kaz'), - path.join(__dirname, 'fixtures', 'buttons', 'SecondaryButton.kaz'), - path.join(__dirname, 'fixtures', 'Input.kaz'), - ]), - ) - }) - }) - - describe('parse', () => { - test('should return an object of ASTs', async () => { - const loadResult = await parser.load(config) - - const result = await parser.parse(loadResult, config) + describe('loadAndParse', () => { + test('should return an object of ASTs with keys relative to the input path', async () => { + const result = await parser.loadAndParse(config) Object.values(result).forEach((ast) => { expect(ast.$type).toBe('Kaz') }) + + expect(result).toMatchObject({ + 'Input.kaz': expect.any(Object), + 'PrimaryButton.kaz': expect.any(Object), + 'SecondaryButton.kaz': expect.any(Object), + 'buttons/PrimaryButton.kaz': expect.any(Object), + 'buttons/SecondaryButton.kaz': expect.any(Object), + }) }) }) }) diff --git a/packages/test-web-transformer/src/types.ts b/packages/test-web-transformer/src/types.ts index f99f5a4..43ca18c 100644 --- a/packages/test-web-transformer/src/types.ts +++ b/packages/test-web-transformer/src/types.ts @@ -3,10 +3,14 @@ import type playwright from 'playwright' import type * as fixtures from './fixtures' -export type Transformer = new (...args: ConstructorParameters) => TransformerBase +export type Transformer = new (...args: ConstructorParameters) => TransformerBase<{ + outputFileNameFormat: string +}> export type RenderHtml = ( - output: Awaited> + output: Awaited['transform']>> ) => Promise export type Fixture = typeof fixtures[keyof typeof fixtures] diff --git a/packages/transformer-base/build.config.ts b/packages/transformer-base/build.config.ts new file mode 100644 index 0000000..2b973fa --- /dev/null +++ b/packages/transformer-base/build.config.ts @@ -0,0 +1,5 @@ +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + declaration: true, +}) diff --git a/packages/transformer-base/src/index.ts b/packages/transformer-base/src/index.ts index d30ecd5..5535477 100644 --- a/packages/transformer-base/src/index.ts +++ b/packages/transformer-base/src/index.ts @@ -1,12 +1,44 @@ -import { kazAstSchema } from '@whitebird/kaz-ast' -import zod from 'zod' +import type { kazAstSchema } from '@whitebird/kaz-ast' +import type zod from 'zod' -export const TransformerInput = zod.record(zod.string(), kazAstSchema) - -export function validateTransformerInput(input: unknown) { - return TransformerInput.parse(input) +export interface TransformerOptions { } -export type ITransformerInput = zod.infer +export type TransformerInput< + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _Options extends TransformerSettings = TransformerSettings, +> = Record< + string, + zod.infer +> + +export type TransformerOutput< + Settings extends TransformerSettings = TransformerSettings, +> = Map< + string, + { + filePath: Settings['outputFileNameFormat'] + content: string + } +> + +export abstract class TransformerBase< + Settings extends TransformerSettings, + Options extends Record = Record, +> { + constructor( + public readonly input: TransformerInput, + public readonly options: Options extends Record + ? TransformerOptions + : TransformerOptions & Options, + ) { + } -export * from './transformer-base' + abstract transform(): TransformerOutput +} + +interface TransformerSettings< + OutputFileNameFormat extends string = string, +> { + outputFileNameFormat: OutputFileNameFormat | null +} diff --git a/packages/transformer-base/src/transformer-base.ts b/packages/transformer-base/src/transformer-base.ts deleted file mode 100644 index f7d5b15..0000000 --- a/packages/transformer-base/src/transformer-base.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { ITransformerInput } from '.' - -// export interface ITransformerOptions { -// } -export type ITransformerOptions = Record - -export interface ITransformerOutput { - [key: string]: ITransformerOutput | (Blob & { name: string }) -} - -export abstract class TransformerBase { - constructor( - public readonly input: ITransformerInput, - public readonly options: ITransformerOptions, - ) { - } - - abstract transform(): ITransformerOutput | void -} diff --git a/packages/transformer-react/package.json b/packages/transformer-react/package.json index d810ee9..69c495a 100644 --- a/packages/transformer-react/package.json +++ b/packages/transformer-react/package.json @@ -29,7 +29,7 @@ "@whitebird/kaz-ast": "workspace:*", "@whitebird/kazam-transformer-base": "workspace:*", "@whitebird/kazam-transformer-typescript": "workspace:*", - "deepmerge": "^4.3.1", + "effect": "2.0.0-next.48", "lodash": "^4.17.21", "zod": "^3.21.4" }, @@ -40,6 +40,7 @@ "@types/react-dom": "^18.0.6", "@vitest/coverage-v8": "^0.34.1", "@whitebird/kazam-test-web-transformer": "workspace:*", + "deepmerge": "^4.3.1", "esbuild": "^0.18.2", "react": "^18.0.0", "react-dom": "^18.0.0", diff --git a/packages/transformer-react/src/handlers/computedInstruction.ts b/packages/transformer-react/src/handlers/computedInstruction.ts deleted file mode 100644 index 5d5223d..0000000 --- a/packages/transformer-react/src/handlers/computedInstruction.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleComputedInstruction: IHandler<'computedInstruction'> = (computedInstruction, { transformExpression }) => { - return `const ${computedInstruction.name.$value}` - + `${computedInstruction.type !== undefined ? `: ${computedInstruction.type.$value}` : ''}` - + ` = ${transformExpression(computedInstruction.computeValue.expression)}` -} diff --git a/packages/transformer-react/src/handlers/defaultImport.ts b/packages/transformer-react/src/handlers/defaultImport.ts deleted file mode 100644 index e98043b..0000000 --- a/packages/transformer-react/src/handlers/defaultImport.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleDefaultImport: IHandler<'defaultImport'> = (defaultImport) => { - return { name: defaultImport.name.$value } -} diff --git a/packages/transformer-react/src/handlers/importInstruction.ts b/packages/transformer-react/src/handlers/importInstruction.ts deleted file mode 100644 index bf1a2f8..0000000 --- a/packages/transformer-react/src/handlers/importInstruction.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleImportInstruction: IHandler<'importInstruction'> = (importInstructions, { handle, addImport }) => { - if (importInstructions.imports === undefined) { - addImport({ path: importInstructions.from.$value }) - } - else { - importInstructions.imports.forEach((importInstruction) => { - addImport({ - path: importInstructions.from.$value, - [importInstruction.$type === 'DefaultImport' - ? 'defaultImport' - : importInstruction.$type === 'NamedImport' - ? 'namedImports' - : 'wildcardImport']: ( - importInstruction.$type === 'NamedImport' - ? [handle(importInstruction)] - : handle(importInstruction) - ), - }) - }) - } - - return '' -} diff --git a/packages/transformer-react/src/handlers/kaz.ts b/packages/transformer-react/src/handlers/kaz.ts deleted file mode 100644 index 62367c6..0000000 --- a/packages/transformer-react/src/handlers/kaz.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as path from 'node:path' - -import type { IHandler } from '../transformer-react' - -export const handleKaz: IHandler<'ast'> = (kaz, { handle, componentMeta, addImport }) => { - addImport({ wildcardImport: { alias: 'React' }, path: 'react' }) - - const importInstructions = kaz.instructions.filter(instruction => instruction.$type === 'ImportInstruction') - const propInstructions = kaz.instructions.filter(instruction => instruction.$type === 'PropInstruction') - const otherInstructions = kaz.instructions.filter(instruction => instruction.$type !== 'ImportInstruction' && instruction.$type !== 'PropInstruction') - - importInstructions.forEach(instruction => handle(instruction)) - - const props = propInstructions.map(instruction => handle(instruction)) as { declaration: string; type: string }[] - const propsDeclaration = props.map(prop => prop.declaration).join(', ') - const propsType = props.map(prop => prop.type).join(', ') - - const componentName = path.basename(componentMeta.name, path.extname(componentMeta.name)) - - return ` - export const ${componentName} = (${props.length > 0 ? `{ ${propsDeclaration} }: { ${propsType} }` : ''}) => { - ${otherInstructions.map(instruction => handle(instruction)).join('\n')} - - return (<> - ${kaz.template.map(instruction => handle(instruction)).join('\n')} - ) - } - ` -} diff --git a/packages/transformer-react/src/handlers/namedImport.ts b/packages/transformer-react/src/handlers/namedImport.ts deleted file mode 100644 index 10431e9..0000000 --- a/packages/transformer-react/src/handlers/namedImport.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleNamedImport: IHandler<'namedImport'> = (namedImport) => { - return { name: namedImport.name.$value, alias: namedImport.alias?.$value } -} diff --git a/packages/transformer-react/src/handlers/namespaceImport.ts b/packages/transformer-react/src/handlers/namespaceImport.ts deleted file mode 100644 index e046f0a..0000000 --- a/packages/transformer-react/src/handlers/namespaceImport.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleNamespaceImport: IHandler<'namespaceImport'> = (namespaceImport) => { - return { alias: namespaceImport.name.$value } -} diff --git a/packages/transformer-react/src/handlers/propInstruction.ts b/packages/transformer-react/src/handlers/propInstruction.ts deleted file mode 100644 index 5b8a7a3..0000000 --- a/packages/transformer-react/src/handlers/propInstruction.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handlePropInstruction: IHandler<'propInstruction'> = (propInstruction, { transformExpression }) => { - return { - declaration: `${propInstruction.name.$value}` - + `${propInstruction.defaultValue !== undefined ? ` = ${transformExpression(propInstruction.defaultValue.expression)}` : ''}`, - type: `${propInstruction.name.$value}: ${propInstruction.type?.$value ?? 'any'}`, - } -} diff --git a/packages/transformer-react/src/handlers/stateInstruction.ts b/packages/transformer-react/src/handlers/stateInstruction.ts deleted file mode 100644 index 5f09bc9..0000000 --- a/packages/transformer-react/src/handlers/stateInstruction.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { IHandler } from '../transformer-react' -import { upperFirst } from '../utils/upperFirst' - -export const handleStateInstruction: IHandler<'stateInstruction'> = (stateInstruction, { addImport, transformExpression }) => { - addImport({ namedImports: [{ name: 'useState' }], path: 'react' }) - - return `const [${ - stateInstruction.name.$value - }, set${ - upperFirst(stateInstruction.name.$value) - }] = useState${ - stateInstruction.type?.$value - ? `<${stateInstruction.type.$value}>` - : '' - }(${ - stateInstruction.defaultValue !== undefined - ? transformExpression(stateInstruction.defaultValue.expression) - : '' - })` -} diff --git a/packages/transformer-react/src/handlers/templateElse.ts b/packages/transformer-react/src/handlers/templateElse.ts deleted file mode 100644 index ae75441..0000000 --- a/packages/transformer-react/src/handlers/templateElse.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleTemplateElse: IHandler<'templateElse'> = (templateElse, { handle }) => { - return templateElse.children.map(handle).join('\n') -} diff --git a/packages/transformer-react/src/handlers/templateElseIf.ts b/packages/transformer-react/src/handlers/templateElseIf.ts deleted file mode 100644 index 834926c..0000000 --- a/packages/transformer-react/src/handlers/templateElseIf.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleTemplateElseIf: IHandler<'templateElseIf'> = (templateElseIf, { handle }) => { - return (handle({ ...templateElseIf.if, $type: 'IfLogical' }) as string).slice(1, -1) -} diff --git a/packages/transformer-react/src/handlers/templateExpression.ts b/packages/transformer-react/src/handlers/templateExpression.ts deleted file mode 100644 index 15573d5..0000000 --- a/packages/transformer-react/src/handlers/templateExpression.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleTemplateExpression: IHandler<'templateExpression'> = (templateExpression, { transformExpression }) => { - return `{${transformExpression(templateExpression.expression)}}` -} diff --git a/packages/transformer-react/src/handlers/templateFor.ts b/packages/transformer-react/src/handlers/templateFor.ts deleted file mode 100644 index 4fac812..0000000 --- a/packages/transformer-react/src/handlers/templateFor.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleTemplateFor: IHandler<'templateFor'> = (templateFor, { handle, addImport }) => { - addImport({ namedImports: [{ name: 'Fragment' }], path: 'react' }) - - return `{Array.from(( - function* () { - let key = 0 - for (${templateFor.parameters.$value}) { - yield - ${templateFor.children.map(handle).join('\n')} - - } - } - )())}` -} diff --git a/packages/transformer-react/src/handlers/templateIf.ts b/packages/transformer-react/src/handlers/templateIf.ts deleted file mode 100644 index 6eb6a48..0000000 --- a/packages/transformer-react/src/handlers/templateIf.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleTemplateIf: IHandler<'templateIf'> = (templateIf, { handle }) => { - return `{ - ${templateIf.condition.$value} - ? <>${templateIf.children.map(handle).join('\n')} - : ${templateIf.else !== undefined - ? 'if' in templateIf.else - ? `${handle(templateIf.else)}` - : `<>${handle(templateIf.else)}` - : 'null' - } - }` -} diff --git a/packages/transformer-react/src/handlers/templateTag.ts b/packages/transformer-react/src/handlers/templateTag.ts deleted file mode 100644 index 3874d8e..0000000 --- a/packages/transformer-react/src/handlers/templateTag.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleTemplateTag: IHandler<'templateTag'> = (templateTag, { handle, checkIsComponent, importComponent }) => { - const isComponent = checkIsComponent(templateTag.tagName.$value) - - if (isComponent) - importComponent(templateTag.tagName.$value) - - return `<${templateTag.tagName.$value} ` - + `${(templateTag.attributes.map(attribute => handle(attribute))).join(' ')}` - + `${(templateTag.children === undefined) - ? '/>' - : `>${(templateTag.children.map(child => handle(child))).join('\n')}` - }` -} diff --git a/packages/transformer-react/src/handlers/templateTagAttribute.ts b/packages/transformer-react/src/handlers/templateTagAttribute.ts deleted file mode 100644 index 2e0bff4..0000000 --- a/packages/transformer-react/src/handlers/templateTagAttribute.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleTemplateTagAttribute: IHandler<'templateTagAttribute'> = (templateTagAttribute, { transformExpression }) => { - switch (templateTagAttribute.name.$value) { - case 'class': { - templateTagAttribute.name.$value = 'className' - } - } - - return `${templateTagAttribute.name.$value}=` - + `${(() => { - const [startChars, endChars] = ((): [string, string] => { - const isStringValue = 'value' in templateTagAttribute && typeof templateTagAttribute.value !== 'boolean' - - if (templateTagAttribute.name.$value === 'style') { - if (isStringValue) - return ['{{ cssText: "', '" }}'] - - return ['{{ cssText: ', ' }}'] - } - - if (isStringValue) - return ['"', '"'] - - return ['{', '}'] - })() - - const value = (() => { - if ('value' in templateTagAttribute) { - if (typeof templateTagAttribute.value === 'boolean') - return templateTagAttribute.value - - return templateTagAttribute.value.$value - } - - if ('expression' in templateTagAttribute) - return transformExpression(templateTagAttribute.expression) - - return 'true' - })() - - return `${startChars}${value}${endChars}` - })()}` -} diff --git a/packages/transformer-react/src/handlers/templateTagEventAttribute.ts b/packages/transformer-react/src/handlers/templateTagEventAttribute.ts deleted file mode 100644 index 0e56098..0000000 --- a/packages/transformer-react/src/handlers/templateTagEventAttribute.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { IHandler } from '../transformer-react' -import { upperFirst } from '../utils/upperFirst' - -export const handleTemplateTagEventAttribute: IHandler<'templateTagEventAttribute'> = (templateTagEventAttribute, { transformExpression }) => { - return `on${upperFirst(templateTagEventAttribute.name.$value)}={${transformExpression(templateTagEventAttribute.expression)}}` -} diff --git a/packages/transformer-react/src/handlers/templateText.ts b/packages/transformer-react/src/handlers/templateText.ts deleted file mode 100644 index 67824b2..0000000 --- a/packages/transformer-react/src/handlers/templateText.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleTemplateText: IHandler<'templateText'> = (templateText) => { - return templateText.text.$value -} diff --git a/packages/transformer-react/src/handlers/watchInstruction.ts b/packages/transformer-react/src/handlers/watchInstruction.ts deleted file mode 100644 index 0ae0c3d..0000000 --- a/packages/transformer-react/src/handlers/watchInstruction.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { IHandler } from '../transformer-react' - -export const handleWatchInstruction: IHandler<'watchInstruction'> = (watchInstruction, { addImport, transformExpression }) => { - addImport({ namedImports: [{ name: 'useEffect' }], path: 'react' }) - - return `useEffect(() => {${transformExpression(watchInstruction.callbackExpression)}}, [${watchInstruction.watchedVariables.map(variable => variable.name.$value).join(', ')}])` -} diff --git a/packages/transformer-react/src/index.ts b/packages/transformer-react/src/index.ts index 70bd91a..a63de14 100644 --- a/packages/transformer-react/src/index.ts +++ b/packages/transformer-react/src/index.ts @@ -1 +1 @@ -export { TransformerReact } from './transformer-react' +export { TransformerReact } from './transformer-react/transformer-react' diff --git a/packages/transformer-react/src/transformer-react.ts b/packages/transformer-react/src/transformer-react.ts deleted file mode 100644 index 9ce1304..0000000 --- a/packages/transformer-react/src/transformer-react.ts +++ /dev/null @@ -1,209 +0,0 @@ -import path from 'node:path' - -import * as babelParser from '@babel/parser' -import * as schemas from '@whitebird/kaz-ast' -import { type ITransformerOutput, TransformerBase } from '@whitebird/kazam-transformer-base' -import { TransformerTypescript } from '@whitebird/kazam-transformer-typescript' -import prettier from 'prettier' -import type { z } from 'zod' - -import * as handlers from './handlers' -import { type ImportInfos, importsToString, mergeImports } from './utils/imports-to-string' -import { transformExpression } from './utils/transform-expression' -import { type TUppercaseFirst, upperFirst } from './utils/upperFirst' - -interface IComponentMeta { name: string } - -type TLowercaseFirst = T extends `${infer U}${infer V}` ? `${Lowercase}${V}` : T -type TSchemaName = T extends `kaz${infer U}Schema` ? TLowercaseFirst : never - -type TypescriptAst = ReturnType -type TransformerTypescriptGenerated = Awaited>[string] - -type THandlerReturnType = unknown -type ISchemaHandlers = { - [ - key in TSchemaName as z.infer}Schema`]> extends { $type: string } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - ? typeof schemas[`kaz${TUppercaseFirst}Schema`] extends z.ZodUnion - ? never - : key - : never - ]: - (data: z.infer}Schema`]>, utils: { - handle: (input: unknown | undefined) => THandlerReturnType - addImport: (...importInfos: ImportInfos[]) => void - transformExpression: (expression: Parameters[0]) => string - checkIsComponent: (componentName: string) => boolean - importComponent: (componentName: string) => void - componentMeta: IComponentMeta - }) => THandlerReturnType -} - -export type IHandler = ISchemaHandlers[T] - -export class TransformerReact extends TransformerBase { - private handlers: ISchemaHandlers = { - ast: handlers.handleKaz, - computedInstruction: handlers.handleComputedInstruction, - importInstruction: handlers.handleImportInstruction, - defaultImport: handlers.handleDefaultImport, - namedImport: handlers.handleNamedImport, - namespaceImport: handlers.handleNamespaceImport, - propInstruction: handlers.handlePropInstruction, - stateInstruction: handlers.handleStateInstruction, - watchInstruction: handlers.handleWatchInstruction, - templateTagAttribute: handlers.handleTemplateTagAttribute, - templateTagEventAttribute: handlers.handleTemplateTagEventAttribute, - templateTag: handlers.handleTemplateTag, - templateText: handlers.handleTemplateText, - templateExpression: handlers.handleTemplateExpression, - templateFor: handlers.handleTemplateFor, - templateIf: handlers.handleTemplateIf, - templateElseIf: handlers.handleTemplateElseIf, - templateElse: handlers.handleTemplateElse, - } - - private generatedComponents: { [key: string]: string } = {} - private imports: { [key: string]: ImportInfos[] } = {} - private generatedTypescript: Record = {} - - transform() { - for (const componentName in this.input) { - const component = this.input[componentName] - - const result = this.handle(component, { name: componentName }) - this.generatedComponents[componentName] = prettier.format( - ` - ${importsToString(mergeImports(this.imports[componentName] ?? []))} - - ${result} - `, - { - parser: 'babel-ts', - printWidth: Number.POSITIVE_INFINITY, - }, - ) - } - - return Object.entries(this.generatedComponents).reduce((output, [id, content]) => { - output[id] = Object.assign( - new Blob([content], { type: 'text/plain' }), - { name: `${path.basename(id, path.extname(id))}.tsx` }, - ) - return output - }, {}) - } - - private handle(input: unknown | undefined, componentMeta: IComponentMeta): THandlerReturnType { - if (input === undefined) - return '' - - for (const handlerName in this.handlers) { - const handler = this.handlers[handlerName as keyof ISchemaHandlers] - - const result = schemas[`kaz${upperFirst(handlerName as keyof ISchemaHandlers)}Schema`].safeParse(input) - if (result.success) { - return handler(result.data as never, { - handle: input => this.handle(input, componentMeta), - addImport: (...importInfos) => this.addImport(componentMeta.name, ...importInfos), - transformExpression: (expression) => { - const kazAst = this.input[componentMeta.name] - - if (kazAst === undefined) - throw new Error(`No kazAst found for component ${componentMeta.name}`) - - const transformedToTypescript = this.transformToTypescript(componentMeta.name) - - return transformExpression(expression, { - kazAst, - typescriptFileContent: transformedToTypescript?.content, - typescriptMapping: transformedToTypescript?.mapping, - typescriptAst: transformedToTypescript?.ast, - }) - }, - checkIsComponent: componentName => this.checkIsComponent(componentName), - importComponent: componentName => this.importComponent(componentName, componentMeta), - componentMeta, - }) - } - } - - let inputString: string - - try { - inputString = JSON.stringify(input) - } - catch { - inputString = input?.toString() ?? '' - } - - throw new Error(`No handler found for input ${inputString}`) - } - - private checkIsComponent(componentName: string): boolean { - return Object.keys(this.input) - .map(componentName => path.basename(componentName, path.extname(componentName))) - .includes(componentName) - } - - private async importComponent(componentName: string, componentMeta: IComponentMeta) { - const relativePath = path.relative( - path.dirname(componentMeta.name), - path.resolve( - path.dirname(componentMeta.name), - `${componentName}.tsx`, - ), - ) - - this.addImport(componentMeta.name, { - namedImports: [ - { - name: componentName, - }, - ], - path: `./${relativePath}`, - }) - } - - private addImport(componentName: string, ...importInfos: ImportInfos[]) { - this.imports[componentName] = [ - ...(this.imports[componentName] ?? []), - ...importInfos, - ] - } - - private transformToTypescript(componentName: string) { - const foundGeneratedTypescript = this.generatedTypescript[componentName] - if (foundGeneratedTypescript !== undefined) - return foundGeneratedTypescript - - const input = this.input[componentName] - - if (input === undefined) - throw new Error(`No input found for component ${componentName}`) - - const transformerTypescript = new TransformerTypescript({ - [componentName]: input, - }, {}) - - const result = transformerTypescript.transformAndGenerateMappings()[componentName] - - if (result === undefined) - throw new Error(`No result found for component ${componentName}`) - - const ast = babelParser.parse(result.content, { - sourceType: 'module', - plugins: ['typescript'], - }) - - const resultWithAst = { - ...result, - ast, - } - - this.generatedTypescript[componentName] = resultWithAst - - return resultWithAst - } -} diff --git a/packages/transformer-react/src/transformer-react/transform/create-services.ts b/packages/transformer-react/src/transformer-react/transform/create-services.ts new file mode 100644 index 0000000..c4f948b --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/create-services.ts @@ -0,0 +1,21 @@ +import { Layer, Ref } from 'effect' + +import { ImportStateServiceLive } from './transform-service/states/import-state' +import { MetadataStateServiceLive } from './transform-service/states/metadata-state' +import { TransformServiceLive } from './transform-service/transform-service' + +export const createServices = () => Layer.mergeAll( + TransformServiceLive, + ImportStateServiceLive(Ref.unsafeMake( + { + imports: new Map(), + }, + )), + MetadataStateServiceLive(Ref.unsafeMake( + { + componentName: '', + filePath: '', + input: {}, + }, + )), +) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/add-import.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/add-import.ts new file mode 100644 index 0000000..3bdbf59 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/add-import.ts @@ -0,0 +1,68 @@ +import { Effect, Ref } from 'effect' + +import { ImportStateService } from '../states/import-state' +import { TransformService } from '../transform-service' + +interface DefaultImport { + type: 'defaultImport' + name: string + typeOnly?: boolean | undefined +} + +interface NamedImport { + type: 'namedImport' + name: string + alias?: string | undefined + typeOnly?: boolean | undefined +} + +interface NamespaceImport { + type: 'namespaceImport' + alias: string + typeOnly?: boolean | undefined +} + +interface SideEffectImport { + type: 'sideEffectImport' +} + +export type Import = ( + | DefaultImport + | NamedImport + | NamespaceImport + | SideEffectImport +) & { + path: string +} + +export const addImport = < + T extends Import['type'], + I extends Extract, +>( + type: T, + import_: Omit, + ) => + Effect.gen(function* (_) { + const importState = yield * _(ImportStateService) + const transformService = yield * _(TransformService) + + const metadata = yield * _(transformService.getMetadata()) + + yield * _(Ref.update( + importState, + importState => ({ + ...importState, + imports: importState.imports.set( + metadata.filePath, + [ + ...(importState.imports.get(metadata.filePath) ?? []), + { + type, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ...import_ as any, + }, + ], + ), + }), + )) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/auto-import.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/auto-import.ts new file mode 100644 index 0000000..91195e2 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/auto-import.ts @@ -0,0 +1,36 @@ +import path from 'node:path' + +import { Effect, pipe } from 'effect' + +import { TransformService } from '../transform-service' + +export const autoImport = (tagName: string) => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + const metadata = yield * _(transformService.getMetadata()) + + const componentPath = yield * _( + pipe( + Object.keys(metadata.input), + Effect.forEach(filePath => + Effect.all([transformService.getComponentName(filePath), Effect.succeed(filePath)])), + Effect.map(componentInfos => componentInfos.find(([componentName]) => componentName === tagName)), + Effect.map(componentInfo => componentInfo?.[1]), + ), + ) + + if (componentPath === undefined) + return + + yield * _(transformService.addImport('namedImport', { + name: tagName, + path: `./${path.relative( + path.dirname(metadata.filePath), + path.resolve( + path.dirname(metadata.filePath), + `${componentPath}.tsx`, + ), + )}`, + })) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/get-component-name.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/get-component-name.ts new file mode 100644 index 0000000..29fe91a --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/get-component-name.ts @@ -0,0 +1,12 @@ +import * as path from 'node:path' + +import { Effect, pipe } from 'effect' +import { camelCase, upperFirst } from 'lodash' + +export const getComponentName = (filePath: string) => + pipe( + path.basename(filePath, path.extname(filePath)), + camelCase, + upperFirst, + Effect.succeed, + ) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/get-import-string.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/get-import-string.ts new file mode 100644 index 0000000..afc42d6 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/get-import-string.ts @@ -0,0 +1,38 @@ +import { Effect, Ref } from 'effect' + +import { ImportStateService } from '../states/import-state' +import { TransformService } from '../transform-service' + +export const getImportString = () => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + const importStateService = yield * _(ImportStateService) + const importState = yield * _(Ref.get(importStateService)) + + const metadata = yield * _(transformService.getMetadata()) + + const imports = importState.imports.get(metadata.filePath) + + if (imports === undefined) + return '' + + return imports.map((import_) => { + if (import_.type === 'sideEffectImport') + return `import '${import_.path}'` + + return String.prototype.concat( + 'import ', + import_.typeOnly === true ? 'type ' : '', + import_.type === 'defaultImport' + ? import_.name + : import_.type === 'namedImport' + ? `{ ${import_.name}${import_.alias !== undefined ? ` as ${import_.alias}` : ''} }` + : import_.type === 'namespaceImport' + ? `* as ${import_.alias}` + : '', + ' from ', + `'${import_.path}'`, + ) + }).join('\n') + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/get-set-metadata.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/get-set-metadata.ts new file mode 100644 index 0000000..a5fd38f --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/get-set-metadata.ts @@ -0,0 +1,21 @@ +import { Effect, Ref, pipe } from 'effect' + +import { type MetadataState, MetadataStateService } from '../states/metadata-state' + +type Metadata = Parameters[0]>[0] + +export const getMetadata = () => + pipe( + MetadataStateService, + Effect.flatMap(metadataState => + Ref.get(metadataState), + ), + ) + +export const setMetadata = (metadata: Metadata) => + pipe( + MetadataStateService, + Effect.tap(metadataState => + Ref.set(metadataState, metadata), + ), + ) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handle.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handle.ts new file mode 100644 index 0000000..c6ead69 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handle.ts @@ -0,0 +1,74 @@ +import * as schemas from '@whitebird/kaz-ast' +import type { Effect } from 'effect' +import { upperFirst } from 'lodash' +import type { z } from 'zod' + +import * as importedHandlers from './handlers' +import type { ImportState } from '../states/import-state' +import type { MetadataState } from '../states/metadata-state' +import type { TransformService } from '../transform-service' + +type GetSchemaName = T extends `kaz${infer U}Schema` ? Uncapitalize : never + +type AllSchemaNames = GetSchemaName + +type GetZodSchema = typeof schemas[`kaz${Capitalize}Schema`] + +type GetSchema = z.infer> + +export type Handle = ( + data: GetSchema, +) => Effect.Effect + +type Handlers = { + [ + SchemaName in AllSchemaNames as GetSchema extends { $type: string } + ? GetZodSchema extends z.ZodUnion + ? never + : SchemaName + : never + ]: Handle +} + +const handlers = { + ast: importedHandlers.handleKaz, + computedInstruction: importedHandlers.handleComputedInstruction, + importInstruction: importedHandlers.handleImportInstruction, + defaultImport: importedHandlers.handleDefaultImport, + namedImport: importedHandlers.handleNamedImport, + namespaceImport: importedHandlers.handleNamespaceImport, + propInstruction: importedHandlers.handlePropInstruction, + stateInstruction: importedHandlers.handleStateInstruction, + watchInstruction: importedHandlers.handleWatchInstruction, + templateTagAttribute: importedHandlers.handleTemplateTagAttribute, + templateTagEventAttribute: importedHandlers.handleTemplateTagEventAttribute, + templateTag: importedHandlers.handleTemplateTag, + templateText: importedHandlers.handleTemplateText, + templateExpression: importedHandlers.handleTemplateExpression, + templateFor: importedHandlers.handleTemplateFor, + templateIf: importedHandlers.handleTemplateIf, + templateElseIf: importedHandlers.handleTemplateElseIf, + templateElse: importedHandlers.handleTemplateElse, +} satisfies Handlers + +type _FindHandler[number]> = { + [SchemaName in AllSchemaNames as GetSchema extends Data ? SchemaName : never]: typeof handlers[SchemaName & keyof typeof handlers] +} +type FindHandler[number]> = _FindHandler[keyof _FindHandler] + +export const handle = [number]>( + data: Data, +): ReturnType> => { + for (const _handlerName in handlers) { + const handlerName = _handlerName as keyof typeof handlers + + const handler = handlers[handlerName] as Handle + + const result = schemas[`kaz${upperFirst(handlerName) as Capitalize}Schema`].safeParse(data) + + if (result.success) + return handler(result.data) as never + } + + throw new Error(`No handler found for ${JSON.stringify(data.$type)}`) +} diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/computedInstruction.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/computedInstruction.ts new file mode 100644 index 0000000..fd39859 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/computedInstruction.ts @@ -0,0 +1,17 @@ +import { Effect } from 'effect' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleComputedInstruction: Handle<'computedInstruction', string> = computedInstruction => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + return String.prototype.concat( + 'const ', + computedInstruction.name.$value, + computedInstruction.type !== undefined ? `: ${computedInstruction.type.$value}` : '', + ' = ', + yield * _(transformService.transformExpression(computedInstruction.computeValue.expression)), + ) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/defaultImport.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/defaultImport.ts new file mode 100644 index 0000000..35ce41a --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/defaultImport.ts @@ -0,0 +1,12 @@ +import { Effect } from 'effect' + +import type { Handle } from '../handle' + +export const handleDefaultImport = ( + defaultImport => + Effect.gen(function* () { + return { + name: defaultImport.name.$value, + } + }) +) satisfies Handle<'defaultImport'> diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/importInstruction.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/importInstruction.ts new file mode 100644 index 0000000..222fe19 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/importInstruction.ts @@ -0,0 +1,61 @@ +import { Effect } from 'effect' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleImportInstruction: Handle<'importInstruction', void> = importInstructions => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + if (importInstructions.imports === undefined) { + yield * _(transformService.addImport( + 'sideEffectImport', + { path: importInstructions.from.$value }, + )) + return + } + + for (const importInstruction of importInstructions.imports) { + switch (importInstruction.$type) { + case 'NamedImport': { + const importType: Uncapitalize = 'namedImport' + + yield * _(transformService.addImport( + importType, + { + ...yield * _(transformService.handle(importInstruction)), + path: importInstructions.from.$value, + }, + )) + + break + } + case 'DefaultImport': { + const importType: Uncapitalize = 'defaultImport' + + yield * _(transformService.addImport( + importType, + { + ...yield * _(transformService.handle(importInstruction)), + path: importInstructions.from.$value, + }, + )) + + break + } + case 'NamespaceImport': { + const importType: Uncapitalize = 'namespaceImport' + + yield * _(transformService.addImport( + importType, + { + ...yield * _(transformService.handle(importInstruction)), + path: importInstructions.from.$value, + }, + )) + + break + } + } + } + }) diff --git a/packages/transformer-react/src/handlers/index.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/index.ts similarity index 100% rename from packages/transformer-react/src/handlers/index.ts rename to packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/index.ts diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/kaz.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/kaz.ts new file mode 100644 index 0000000..ef29d01 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/kaz.ts @@ -0,0 +1,74 @@ +import * as path from 'node:path' + +import { Effect, pipe } from 'effect' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleKaz: Handle<'ast', string> + = kaz => Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + yield * _(transformService.addImport( + 'namespaceImport', + { path: 'react', alias: 'React' }, + )) + + const findInstructionOfType = (type: T) => + kaz.instructions.filter(instruction => instruction.$type === type) as Extract[] + + yield * _(Effect.forEach( + findInstructionOfType('ImportInstruction'), + transformService.handle, + )) + + const props = yield * _(Effect.forEach( + findInstructionOfType('PropInstruction'), + transformService.handle, + )) + const propsDeclaration = props.map(prop => prop.declaration).join(', ') + const propsType = props.map(prop => prop.type).join(', ') + + const otherInstructions = ( + kaz.instructions.filter(instruction => instruction.$type !== 'ImportInstruction' && instruction.$type !== 'PropInstruction') as + Exclude[] + ) + + const metadata = yield * _(transformService.getMetadata()) + const componentName = path.basename(metadata.componentName, path.extname(metadata.componentName)) + + return yield * _(pipe( + String.prototype.concat( + 'export const ', + componentName, + ' = (', + props.length > 0 + ? `{ ${propsDeclaration} }: { ${propsType} }` + : '', + ') => {', + yield * _( + pipe( + otherInstructions, + Effect.forEach( + transformService.handle, + ), + Effect.map(instructions => instructions.join(';\n')), + ), + ), + '\nreturn (<>', + yield * _( + pipe( + kaz.template, + Effect.forEach( + transformService.handle, + ), + Effect.map(template => template.join('\n')), + ), + ), + ')', + '}', + ), + code => Effect.all([transformService.getImportString(), Effect.succeed(code)]), + Effect.map(([imports, code]) => `${imports}\n\n${code}`), + )) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/namedImport.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/namedImport.ts new file mode 100644 index 0000000..8b130a0 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/namedImport.ts @@ -0,0 +1,12 @@ +import { Effect } from 'effect' + +import type { Handle } from '../handle' + +export const handleNamedImport = ( + namedImport => Effect.gen(function* () { + return { + name: namedImport.name.$value, + alias: namedImport.alias?.$value, + } + }) +) satisfies Handle<'namedImport'> diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/namespaceImport.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/namespaceImport.ts new file mode 100644 index 0000000..5b52a8c --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/namespaceImport.ts @@ -0,0 +1,11 @@ +import { Effect } from 'effect' + +import type { Handle } from '../handle' + +export const handleNamespaceImport = ( + namespaceImport => Effect.gen(function* () { + return { + alias: namespaceImport.name.$value, + } + }) +) satisfies Handle<'namespaceImport'> diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/propInstruction.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/propInstruction.ts new file mode 100644 index 0000000..88ef5e1 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/propInstruction.ts @@ -0,0 +1,26 @@ +import { Effect } from 'effect' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handlePropInstruction: Handle<'propInstruction', { + declaration: string + type: string +}> = propInstruction => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + return { + declaration: String.prototype.concat( + propInstruction.name.$value, + propInstruction.defaultValue !== undefined + ? ` = ${transformService.transformExpression(propInstruction.defaultValue.expression)}` + : '', + ), + type: String.prototype.concat( + propInstruction.name.$value, + ': ', + propInstruction.type?.$value ?? 'any', + ), + } + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/stateInstruction.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/stateInstruction.ts new file mode 100644 index 0000000..577826b --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/stateInstruction.ts @@ -0,0 +1,31 @@ +import { Effect } from 'effect' +import { upperFirst } from 'lodash' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleStateInstruction: Handle<'stateInstruction', string> = stateInstruction => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + yield * _(transformService.addImport( + 'namedImport', + { name: 'useState', path: 'react' }, + )) + + return String.prototype.concat( + 'const [', + stateInstruction.name.$value, + ', set', + upperFirst(stateInstruction.name.$value), + '] = useState', + stateInstruction.type?.$value + ? `<${stateInstruction.type.$value}>` + : '', + '(', + stateInstruction.defaultValue !== undefined + ? yield * _(transformService.transformExpression(stateInstruction.defaultValue.expression)) + : '', + ')', + ) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateElse.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateElse.ts new file mode 100644 index 0000000..68d47a3 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateElse.ts @@ -0,0 +1,19 @@ +import { Effect, pipe } from 'effect' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleTemplateElse: Handle<'templateElse', string> = templateElse => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + return yield * _( + pipe( + templateElse.children, + Effect.forEach( + transformService.handle, + ), + Effect.map(instructions => instructions.join('\n')), + ), + ) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateElseIf.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateElseIf.ts new file mode 100644 index 0000000..9cfb21d --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateElseIf.ts @@ -0,0 +1,19 @@ +import { Effect, pipe } from 'effect' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleTemplateElseIf: Handle<'templateElseIf', string> = templateElseIf => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + transformService.handle({ ...templateElseIf.if, $type: 'IfLogical' }) + + return yield * _( + pipe( + { ...templateElseIf.if, $type: 'IfLogical' as const }, + transformService.handle, + Effect.map(instruction => instruction.slice(1, -1)), + ), + ) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateExpression.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateExpression.ts new file mode 100644 index 0000000..f358c8d --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateExpression.ts @@ -0,0 +1,15 @@ +import { Effect } from 'effect' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleTemplateExpression: Handle<'templateExpression', string> = templateExpression => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + return String.prototype.concat( + '{', + yield * _(transformService.transformExpression(templateExpression.expression)), + '}', + ) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateFor.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateFor.ts new file mode 100644 index 0000000..1cec847 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateFor.ts @@ -0,0 +1,35 @@ +import { Effect, pipe } from 'effect' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleTemplateFor: Handle<'templateFor', string> = templateFor => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + yield * _(transformService.addImport( + 'namedImport', + { name: 'Fragment', path: 'react' }, + )) + + return String.prototype.concat( + '{Array.from((function* () {', + 'let key = 0;', + 'for (', + templateFor.parameters.$value, + ') {', + 'yield ', + yield * _( + pipe( + templateFor.children, + Effect.forEach( + transformService.handle, + ), + Effect.map(template => template.join('\n')), + ), + ), + '', + '}', + '})())}', + ) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateIf.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateIf.ts new file mode 100644 index 0000000..534fe0c --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateIf.ts @@ -0,0 +1,31 @@ +import { Effect, pipe } from 'effect' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleTemplateIf: Handle<'templateIf', string> = templateIf => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + return String.prototype.concat( + '{', + templateIf.condition.$value, + ' ? <>', + yield * _( + pipe( + templateIf.children, + Effect.forEach( + transformService.handle, + ), + Effect.map(template => template.join('\n')), + ), + ), + '', + templateIf.else !== undefined + ? 'if' in templateIf.else + ? ` : ${yield * _(transformService.handle(templateIf.else))}` + : ` : <>${yield * _(transformService.handle(templateIf.else))}` + : '', + '}', + ) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateTag.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateTag.ts new file mode 100644 index 0000000..3e1df87 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateTag.ts @@ -0,0 +1,43 @@ +import { Effect, pipe } from 'effect' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleTemplateTag: Handle<'templateTag', string> = templateTag => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + yield * _(transformService.autoImport(templateTag.tagName.$value)) + + return String.prototype.concat( + '<', + templateTag.tagName.$value, + ' ', + yield * _( + pipe( + templateTag.attributes, + Effect.forEach( + transformService.handle, + ), + Effect.map(attributes => attributes.join(' ')), + ), + ), + templateTag.children === undefined + ? '/>' + : String.prototype.concat( + '>', + yield * _( + pipe( + templateTag.children, + Effect.forEach( + transformService.handle, + ), + Effect.map(instructions => instructions.join('\n')), + ), + ), + '', + ), + ) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateTagAttribute.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateTagAttribute.ts new file mode 100644 index 0000000..05048c7 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateTagAttribute.ts @@ -0,0 +1,58 @@ +import { Effect, pipe } from 'effect' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleTemplateTagAttribute: Handle<'templateTagAttribute', string> = templateTagAttribute => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + switch (templateTagAttribute.name.$value) { + case 'class': { + templateTagAttribute.name.$value = 'className' + break + } + } + + const wrapValue = (value: string) => Effect.gen(function* () { + const isStringValue + = 'value' in templateTagAttribute && typeof templateTagAttribute.value !== 'boolean' + + if (templateTagAttribute.name.$value === 'style') { + if (isStringValue) + return `{{ cssText: "${value}" }}` + + return `{{ cssText: ${value} }}` + } + + if (isStringValue) + return `"${value}"` + + return `{${value}}` + }) + + const getValue = () => Effect.gen(function* (_) { + if ('value' in templateTagAttribute) { + if (typeof templateTagAttribute.value === 'boolean') + return String(templateTagAttribute.value) + + return templateTagAttribute.value.$value + } + + if ('expression' in templateTagAttribute) + return yield * _(transformService.transformExpression(templateTagAttribute.expression)) + + return 'true' + }) + + return String.prototype.concat( + templateTagAttribute.name.$value, + '=', + yield * _( + pipe( + getValue(), + Effect.flatMap(wrapValue), + ), + ), + ) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateTagEventAttribute.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateTagEventAttribute.ts new file mode 100644 index 0000000..c0dbca1 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateTagEventAttribute.ts @@ -0,0 +1,19 @@ +import { Effect } from 'effect' +import { upperFirst } from 'lodash' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleTemplateTagEventAttribute: Handle<'templateTagEventAttribute', string> = templateTagEventAttribute => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + return String.prototype.concat( + 'on', + upperFirst(templateTagEventAttribute.name.$value), + '=', + '{', + yield * _(transformService.transformExpression(templateTagEventAttribute.expression)), + '}', + ) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateText.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateText.ts new file mode 100644 index 0000000..3aa00ec --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/templateText.ts @@ -0,0 +1,7 @@ +import { Effect } from 'effect' + +import type { Handle } from '../handle' + +export const handleTemplateText = ( + templateText => Effect.succeed(templateText.text.$value) +) satisfies Handle<'templateText'> diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/watchInstruction.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/watchInstruction.ts new file mode 100644 index 0000000..dd2ab58 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/handlers/watchInstruction.ts @@ -0,0 +1,22 @@ +import { Effect } from 'effect' + +import { TransformService } from '../../transform-service' +import type { Handle } from '../handle' + +export const handleWatchInstruction: Handle<'watchInstruction', string> = watchInstruction => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + yield * _(transformService.addImport( + 'namedImport', + { name: 'useEffect', path: 'react' }, + )) + + return String.prototype.concat( + 'useEffect(() => {', + yield * _(transformService.transformExpression(watchInstruction.callbackExpression)), + '}, [', + watchInstruction.watchedVariables.map(variable => variable.name.$value).join(', '), + '])', + ) + }) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/functions/transform-expression.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/transform-expression.ts new file mode 100644 index 0000000..5250c7f --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/functions/transform-expression.ts @@ -0,0 +1,226 @@ +/* eslint-disable @typescript-eslint/no-use-before-define */ + +import * as babelParser from '@babel/parser' +import traverse, { type NodePath } from '@babel/traverse' +import type { AssignmentExpression, UpdateExpression } from '@babel/types' +import type { KazAst, kazStateInstructionSchema, kazTemplateExpressionSchema } from '@whitebird/kaz-ast' +import { TransformerTypescript } from '@whitebird/kazam-transformer-typescript' +import { Effect, pipe } from 'effect' +import { upperFirst } from 'lodash' +import type { z } from 'zod' + +import { TransformService } from '../transform-service' + +type KazExpression = z.infer['expression'] + +type StateInstruction = z.infer + +export const transformExpression = ( + kazExpression: KazExpression, +) => + pipe( + Effect.all([Effect.succeed(kazExpression), Effect.succeed(kazExpression.$value)]), + Effect.flatMap(transformSetStateInExpression), + // Add other transformations here + ).pipe( + Effect.map(([, fixedExpression]) => fixedExpression), + ) + +const transformToTypescript = () => + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + const metadata = yield * _(transformService.getMetadata()) + + const kazAst = metadata.input[metadata.filePath] + + if (kazAst === undefined) + throw new Error(`No AST found for file ${metadata.filePath}`) + + const transformerTypescript = new TransformerTypescript({ + [metadata.componentName]: kazAst, + }, {}) + + const result = transformerTypescript.transformAndGenerateMappings()[metadata.componentName] + + if (result === undefined) + throw new Error(`No result found for component ${metadata.componentName}`) + + const ast = babelParser.parse(result.content, { + sourceType: 'module', + plugins: ['typescript'], + }) + + const resultWithAst = { + ...result, + ast, + } + + return resultWithAst + }) + +const transformSetStateInExpression = ( + [kazExpression, fixedExpression]: [KazExpression, string], +) => Effect.gen(function* (_) { + const assignments = yield * _( + pipe( + // Find the corresponding Typescript expression range + findCorrespondingTypescriptExpressionRange(kazExpression), + // Find the node paths in the Typescript AST corresponding to the Kaz expression + Effect.flatMap(findCorrespondingTypescriptExpressionNodePaths), + // Find the assigments to a state variable + Effect.flatMap(findAssignmentsToStateVariable), + ), + ) + + let shift = 0 + + for (const assignmentIdentifier of assignments) { + // Find the range of the replacement expression + const [start, end] = yield * _(findReplacementExpressionRange(assignmentIdentifier)) + + const identifier = (() => { + if (assignmentIdentifier.isAssignmentExpression()) + return assignmentIdentifier.get('left') + + if (assignmentIdentifier.isUpdateExpression()) + return assignmentIdentifier.get('argument') + + throw new Error('Expected assignment or update expression') + })() + + if (!identifier.isIdentifier()) + throw new Error('Expected identifier') + + const replacement = `set${upperFirst(identifier.node.name)}((${identifier.node.name}) => { + ${fixedExpression.slice(start + shift, end + shift)}; + return ${identifier.node.name}; + })` + + fixedExpression = fixedExpression.slice(0, start + shift) + replacement + fixedExpression.slice(end + shift) + shift += replacement.length - (end - start) + } + + return [kazExpression, fixedExpression] as const +}) + +const findCorrespondingTypescriptExpressionRange = ( + kazExpression: KazExpression, +) => + Effect.gen(function* (_) { + const { mapping: typescriptMapping } = yield * _(transformToTypescript()) + + const typescriptExpression = typescriptMapping.find(mapping => + mapping.sourceRange[0] === kazExpression.$range[0] && mapping.sourceRange[1] === kazExpression.$range[1]) + + if (typescriptExpression === undefined) + throw new Error('Could not find corresponding Typescript expression') + + return typescriptExpression.generatedRange + }) + +const findCorrespondingTypescriptExpressionNodePaths = ( + searchRange: [number, number], +) => Effect.gen(function* (_) { + const nodePaths: NodePath[] = [] + + yield * _( + pipe( + transformToTypescript(), + Effect.map(({ ast: typescriptAst }) => typescriptAst), + Effect.map(ast => + traverse(ast, { + enter(path) { + const node = path.node + + if (node.start === undefined || node.start === null || node.end === undefined || node.end === null) + return + + if (node.start >= searchRange[0] && node.end <= searchRange[1]) + nodePaths.push(path) + }, + }), + ), + ), + ) + + return nodePaths +}) + +const findStates = (kazAst: KazAst) => + Effect.gen(function* () { + return kazAst.instructions.filter( + (instruction): instruction is StateInstruction => instruction.$type === 'StateInstruction', + ) + }) + +const findAssignmentsToStateVariable = ( + nodePaths: NodePath[], +) => Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + const metadata = yield * _(transformService.getMetadata()) + + const kazAst = metadata.input[metadata.filePath] + + if (kazAst === undefined) + throw new Error(`No AST found for file ${metadata.filePath}`) + + const stateInstructions = yield * _(findStates(kazAst)) + + const assignmentIdentifiers = new Set>() + + for (const nodePath of nodePaths) { + const parentNodePath = nodePath.parentPath + + if (parentNodePath === null) + continue + + if (!parentNodePath.isAssignmentExpression() && !parentNodePath.isUpdateExpression()) + continue + + const updatedNodePath = parentNodePath.isAssignmentExpression() + ? parentNodePath.get('left') + : parentNodePath.isUpdateExpression() + ? parentNodePath.get('argument') + : null + + if (updatedNodePath === null) + continue + + if (!updatedNodePath.isIdentifier()) + continue + + if (stateInstructions.some(stateInstruction => stateInstruction.name.$value === updatedNodePath.node.name)) + assignmentIdentifiers.add(parentNodePath) + } + + return assignmentIdentifiers +}) + +const findReplacementExpressionRange = ( + assignmentIdentifier: NodePath, +) => Effect.gen(function* (_) { + const { mapping: typescriptMapping } = yield * _(transformToTypescript()) + + const [assigmentStart, assignmentEnd] = [assignmentIdentifier.node.start, assignmentIdentifier.node.end] + + if (assigmentStart === null || assigmentStart === undefined || assignmentEnd === null || assignmentEnd === undefined) + throw new Error('Unexpected null or undefined value') + + const assignmentLength = assignmentEnd - assigmentStart + + const correspondingMapping = typescriptMapping.find(mapping => + mapping.generatedRange[0] <= assigmentStart && mapping.generatedRange[1] >= assignmentEnd, + ) + + if (correspondingMapping === undefined) + throw new Error('Could not find corresponding mapping') + + const [typescriptStart] = correspondingMapping.generatedRange + + const start = assigmentStart - typescriptStart + const end = start + assignmentLength + + return [start, end] as const +}) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/states/import-state.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/states/import-state.ts new file mode 100644 index 0000000..859a872 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/states/import-state.ts @@ -0,0 +1,13 @@ +import type { Ref } from 'effect' +import { Context, Layer } from 'effect' + +import type { Import } from '../functions/add-import' + +// eslint-disable-next-line import/namespace +export interface ImportState extends Ref.Ref<{ + imports: Map +}> { } + +export const ImportStateService = Context.Tag() + +export const ImportStateServiceLive = Layer.succeed(ImportStateService) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/states/metadata-state.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/states/metadata-state.ts new file mode 100644 index 0000000..2ff36cc --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/states/metadata-state.ts @@ -0,0 +1,15 @@ +import type { Ref } from 'effect' +import { Context, Layer } from 'effect' + +import type { TransformerReact } from '../../../transformer-react' + +// eslint-disable-next-line import/namespace +export interface MetadataState extends Ref.Ref<{ + componentName: string + filePath: string + input: TransformerReact['input'] +}> { } + +export const MetadataStateService = Context.Tag() + +export const MetadataStateServiceLive = Layer.succeed(MetadataStateService) diff --git a/packages/transformer-react/src/transformer-react/transform/transform-service/transform-service.ts b/packages/transformer-react/src/transformer-react/transform/transform-service/transform-service.ts new file mode 100644 index 0000000..c26f683 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform-service/transform-service.ts @@ -0,0 +1,37 @@ +import { Context, Layer } from 'effect' + +import { addImport } from './functions/add-import' +import { autoImport } from './functions/auto-import' +import { getComponentName } from './functions/get-component-name' +import { getImportString } from './functions/get-import-string' +import { getMetadata, setMetadata } from './functions/get-set-metadata' +import { handle } from './functions/handle' +import { transformExpression } from './functions/transform-expression' + +export interface TransformService { + handle: typeof handle + getMetadata: typeof getMetadata + setMetadata: typeof setMetadata + getComponentName: typeof getComponentName + addImport: typeof addImport + getImportString: typeof getImportString + autoImport: typeof autoImport + transformExpression: typeof transformExpression +} + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const TransformService = Context.Tag() + +export const TransformServiceLive = Layer.succeed( + TransformService, + TransformService.of({ + handle, + getMetadata, + setMetadata, + getComponentName, + addImport, + getImportString, + autoImport, + transformExpression, + }), +) diff --git a/packages/transformer-react/src/transformer-react/transform/transform.ts b/packages/transformer-react/src/transformer-react/transform/transform.ts new file mode 100644 index 0000000..b0ded11 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transform/transform.ts @@ -0,0 +1,47 @@ +import { Effect, pipe } from 'effect' +import * as prettier from 'prettier' + +import { createServices } from './create-services' +import { TransformService } from './transform-service/transform-service' +import type { TransformerReact } from '../transformer-react' + +export const transform = ({ input }: Pick) => Effect.provide( + Effect.gen(function* (_) { + const transformService = yield * _(TransformService) + + const output = new Map() + + for (const filePath in input) { + const file = input[filePath] + + if (file === undefined) + continue + + yield * _(transformService.setMetadata({ + componentName: yield * _(transformService.getComponentName(filePath)), + filePath, + input, + })) + + const transformed = yield * _( + pipe( + transformService.handle(file), + Effect.map(transformed => + prettier.format(transformed, { + parser: 'babel-ts', + printWidth: Number.POSITIVE_INFINITY, + }), + ), + ), + ) + + output.set(filePath, { + filePath: `${filePath}.tsx`, + content: transformed, + }) + } + + return output + }), + createServices(), +) diff --git a/packages/transformer-react/src/transformer-react/transformer-react.ts b/packages/transformer-react/src/transformer-react/transformer-react.ts new file mode 100644 index 0000000..6218699 --- /dev/null +++ b/packages/transformer-react/src/transformer-react/transformer-react.ts @@ -0,0 +1,15 @@ +import { TransformerBase } from '@whitebird/kazam-transformer-base' +import { Effect } from 'effect' + +import { transform } from './transform/transform' + +export class TransformerReact extends TransformerBase<{ + outputFileNameFormat: `${string}.tsx` +}> { + public transform() { + return Effect.runSync(transform({ + input: this.input, + options: this.options, + })) + } +} diff --git a/packages/transformer-react/src/utils/imports-to-string.ts b/packages/transformer-react/src/utils/imports-to-string.ts deleted file mode 100644 index 66545a7..0000000 --- a/packages/transformer-react/src/utils/imports-to-string.ts +++ /dev/null @@ -1,78 +0,0 @@ -export interface ImportInfo { - name: string - alias?: string - typeOnly?: boolean -} - -export type ImportInfos = ( - { - defaultImport?: Omit - namedImports?: ImportInfo[] - } - | { wildcardImport?: Required> } -) & { path: string } - -function generateImportName(importInfo: ImportInfo) { - return `${importInfo.typeOnly ? 'type ' : ''}${importInfo.name}${importInfo.alias ? ` as ${importInfo.alias}` : ''}` -} - -export function importsToString(importInfos: ImportInfos[]) { - return importInfos.reduce((acc, importInfo) => { - let importString: string - - if ('wildcardImport' in importInfo) { - importString = `* as ${importInfo.wildcardImport.alias}` - } - else { - importString = [ - ...(['defaultImport' in importInfo ? generateImportName(importInfo.defaultImport) : undefined]), - ...([('namedImports' in importInfo && importInfo.namedImports.length > 0) - ? `{ ${importInfo.namedImports.map(namedImport => generateImportName(namedImport)).join(', ')} }` - : undefined]), - ].filter(Boolean).join(', ') - } - - if (importString.trim().length === 0) - return `${acc}\nimport '${importInfo.path}'` - - return `${acc}\nimport ${importString} from '${importInfo.path}'` - }, '') -} - -export function mergeImports(importInfos: ImportInfos[]) { - return importInfos.reduce((acc, importInfo) => { - if ('wildcardImport' in importInfo) { - if (acc.some(accImportInfo => 'wildcardImport' in accImportInfo && accImportInfo.wildcardImport.alias === importInfo.wildcardImport?.alias)) - return acc - - return [...acc, importInfo] - } - - const defaultImport = 'defaultImport' in importInfo && importInfo.defaultImport - const namedImports = 'namedImports' in importInfo && importInfo.namedImports - - const existingImportInfo = acc.find(accImportInfo => accImportInfo.path === importInfo.path) - - if (existingImportInfo && !('wildcardImport' in existingImportInfo)) { - if (defaultImport && ('defaultImport' in existingImportInfo)) - throw new Error(`Cannot add default import ${defaultImport.name} to existing import ${existingImportInfo.defaultImport.name}`) - - if (namedImports) { - const existingNamedImports = 'namedImports' in existingImportInfo ? existingImportInfo.namedImports : [] - const newNamedImports = namedImports.filter(namedImport => !existingNamedImports.some(existingNamedImport => existingNamedImport.name === namedImport.name)) - - if (newNamedImports.length === 0) - return acc - - return [ - ...acc.filter(accImportInfo => accImportInfo.path !== importInfo.path), - { ...existingImportInfo, namedImports: [...existingNamedImports, ...newNamedImports] }, - ] - } - - return acc - } - - return [...acc, importInfo] - }, []) -} diff --git a/packages/transformer-react/src/utils/transform-expression.ts b/packages/transformer-react/src/utils/transform-expression.ts deleted file mode 100644 index d354daf..0000000 --- a/packages/transformer-react/src/utils/transform-expression.ts +++ /dev/null @@ -1,181 +0,0 @@ -import type * as babelParser from '@babel/parser' -import traverse, { type NodePath } from '@babel/traverse' -import type { AssignmentExpression, UpdateExpression } from '@babel/types' -import type { KazAst, kazStateInstructionSchema, kazTemplateExpressionSchema } from '@whitebird/kaz-ast' -import type { TransformerTypescript } from '@whitebird/kazam-transformer-typescript' -import type { z } from 'zod' - -import { upperFirst } from './upperFirst' - -type TransformerTypescriptGenerated = Awaited>[string] -type TypescriptAst = ReturnType -type Mapping = TransformerTypescriptGenerated['mapping'][number] -type KazExpression = z.infer['expression'] -type StateInstruction = z.infer - -export function transformExpression( - kazExpression: KazExpression, - { kazAst, typescriptFileContent, typescriptMapping, typescriptAst }: { - kazAst: KazAst - typescriptFileContent: string - typescriptMapping: Mapping[] - typescriptAst: TypescriptAst - }, -) { - let fixedExpression = kazExpression.$value; - - [ - transformSetStateInExpression, - ].forEach((transform) => { - fixedExpression = transform(kazExpression, { kazAst, typescriptFileContent, typescriptMapping, typescriptAst }) - }) - - return fixedExpression -} - -function transformSetStateInExpression( - ...[kazExpression, { kazAst, typescriptMapping, typescriptAst }]: Parameters -) { - let fixedExpression = kazExpression.$value - let shift = 0 - - // Find the corresponding Typescript expression range - const typescriptExpressionRange = findCorrespondingTypescriptExpressionRange(kazExpression, typescriptMapping) - - // Find the node paths in the Typescript AST corresponding to the Kaz expression - const nodePaths = findCorrespondingTypescriptExpressionNodePaths(typescriptExpressionRange, typescriptAst) - - // Find the states in the Kaz AST - const states = findStates(kazAst) - - // Find the assigments to a state variable - const assignments = findAssignmentsToStateVariable(states, nodePaths) - - for (const assignmentIdentifier of assignments) { - // Find the range of the replacement expression - const [start, end] = findReplacementExpressionRange(assignmentIdentifier, typescriptMapping) - - const identifier = (() => { - if (assignmentIdentifier.isAssignmentExpression()) - return assignmentIdentifier.get('left') - - if (assignmentIdentifier.isUpdateExpression()) - return assignmentIdentifier.get('argument') - - throw new Error('Expected assignment or update expression') - })() - - if (!identifier.isIdentifier()) - throw new Error('Expected identifier') - - const replacement = `set${upperFirst(identifier.node.name)}((${identifier.node.name}) => { - ${fixedExpression.slice(start + shift, end + shift)}; - return ${identifier.node.name}; - })` - - fixedExpression = fixedExpression.slice(0, start + shift) + replacement + fixedExpression.slice(end + shift) - shift += replacement.length - (end - start) - } - - return fixedExpression -} - -function findCorrespondingTypescriptExpressionRange( - kazExpression: KazExpression, - typescriptMapping: Mapping[], -) { - const typescriptExpression = typescriptMapping.find(mapping => mapping.sourceRange[0] === kazExpression.$range[0] && mapping.sourceRange[1] === kazExpression.$range[1]) - - if (typescriptExpression === undefined) - throw new Error('Could not find corresponding Typescript expression') - - return typescriptExpression.generatedRange -} - -function findCorrespondingTypescriptExpressionNodePaths( - searchRange: [number, number], - typescriptAst: TypescriptAst, -) { - const nodePaths: NodePath[] = [] - - traverse(typescriptAst, { - enter(path) { - const node = path.node - - if (node.start === undefined || node.start === null || node.end === undefined || node.end === null) - return - - if (node.start >= searchRange[0] && node.end <= searchRange[1]) - nodePaths.push(path) - }, - }) - - return nodePaths -} - -function findStates(kazAst: KazAst) { - return kazAst.instructions.filter((instruction): instruction is StateInstruction => instruction.$type === 'StateInstruction') -} - -function findAssignmentsToStateVariable( - stateInstructions: StateInstruction[], - nodePaths: NodePath[], -) { - const assignmentIdentifiers: NodePath[] = [] - - for (const nodePath of nodePaths) { - const parentNodePath = nodePath.parentPath - - if (parentNodePath === null) - continue - - if (!parentNodePath.isAssignmentExpression() && !parentNodePath.isUpdateExpression()) - continue - - if (assignmentIdentifiers.includes(parentNodePath)) - continue - - const updatedNodePath = parentNodePath.isAssignmentExpression() - ? parentNodePath.get('left') - : parentNodePath.isUpdateExpression() - ? parentNodePath.get('argument') - : null - - if (updatedNodePath === null) - continue - - if (!updatedNodePath.isIdentifier()) - continue - - if (stateInstructions.some(stateInstruction => stateInstruction.name.$value === updatedNodePath.node.name)) - assignmentIdentifiers.push(parentNodePath) - } - - return assignmentIdentifiers -} - -function findReplacementExpressionRange( - assignmentIdentifier: NodePath, - typescriptMapping: Mapping[], -) { - const [assigmentStart, assignmentEnd] = [assignmentIdentifier.node.start, assignmentIdentifier.node.end] - - if (assigmentStart === null || assigmentStart === undefined || assignmentEnd === null || assignmentEnd === undefined) - throw new Error('Unexpected null or undefined value') - - const assignmentLength = assignmentEnd - assigmentStart - - const correspondingMapping = typescriptMapping.find(mapping => - mapping.generatedRange[0] <= assigmentStart && mapping.generatedRange[1] >= assignmentEnd, - ) - - if (correspondingMapping === undefined) - throw new Error('Could not find corresponding mapping') - - const [typescriptStart] = correspondingMapping.generatedRange - - const start = assigmentStart - typescriptStart - const end = start + assignmentLength - - return [start, end] as const -} diff --git a/packages/transformer-react/src/utils/upperFirst.ts b/packages/transformer-react/src/utils/upperFirst.ts deleted file mode 100644 index dddfb2d..0000000 --- a/packages/transformer-react/src/utils/upperFirst.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const upperFirst = (str: T): TUppercaseFirst => ((str[0] ?? '').toUpperCase() + str.slice(1)) as TUppercaseFirst -export type TUppercaseFirst = T extends `${infer U}${infer V}` ? `${Uppercase}${V}` : T diff --git a/packages/transformer-react/tests/helpers/render-transformer-react-output-to-html.ts b/packages/transformer-react/tests/helpers/render-transformer-react-output-to-html.ts index db95719..f4856cb 100644 --- a/packages/transformer-react/tests/helpers/render-transformer-react-output-to-html.ts +++ b/packages/transformer-react/tests/helpers/render-transformer-react-output-to-html.ts @@ -2,17 +2,13 @@ import type { testWebTransformer } from '@whitebird/kazam-test-web-transformer/s import * as esbuild from 'esbuild' type RenderHtml = Parameters[1] -type ITransformerOutput = Parameters[0] -type FlattenedOutput = Record export const renderTransformerReactOutputToHtml: RenderHtml = async (output) => { - const flattenedOutput = await flattenOutput(output) - - const indexTsx = findOutput(flattenedOutput, 'Index.tsx') + const indexTsx = await findOutput(output, 'Index') const { outputFiles } = await buildTsx( formatTsxForClient(indexTsx), - flattenedOutput, + output, ) const indexJs = outputFiles.find(({ path }) => path.endsWith('out.js'))?.text @@ -24,41 +20,16 @@ export const renderTransformerReactOutputToHtml: RenderHtml = async (output) => return html } -async function flattenOutput( - output: ITransformerOutput, - parentPath = '', -): Promise { - const flattenedOutput: FlattenedOutput = {} - - if (output === undefined) - return flattenedOutput - - for (const [key, value] of Object.entries(output)) { - if (value instanceof Blob) { - const blob = value as Blob - const blobText = await blob.text() - flattenedOutput[parentPath + value.name] = blobText - } - else { - const nestedOutput = value as ITransformerOutput - const nestedFlattenedOutput = await flattenOutput(nestedOutput, `${parentPath + key}/`) - Object.assign(flattenedOutput, nestedFlattenedOutput) - } - } - - return flattenedOutput -} - -function findOutput( - output: FlattenedOutput, +async function findOutput( + output: Parameters[0], id: string, -): string { - const foundOutput = output[id] +): Promise { + const foundOutput = output.get(id) if (foundOutput === undefined) throw new Error(`Output not found: ${id}`) - return foundOutput + return foundOutput.content } function formatTsxForClient( @@ -78,7 +49,7 @@ function formatTsxForClient( function buildTsx( sourceTsx: string, - output: FlattenedOutput, + output: Parameters[0], ) { return esbuild.build({ bundle: true, @@ -95,28 +66,30 @@ function buildTsx( } function resolveOutputPlugin( - output: FlattenedOutput, + output: Parameters[0], ): esbuild.Plugin { return { name: 'resolveOutput', - setup(build) { - Object.entries(output).forEach(([id]) => { + async setup(build) { + Array.from(output.entries()).forEach(([id]) => { const resolveResult: esbuild.OnResolveResult = { - path: id, + path: `${id}`, namespace: 'resolveOutput', } build.onResolve( - { filter: new RegExp(`^\.\/${id}$`) }, + { filter: new RegExp(`^\.\/${id}\.tsx$`) }, () => resolveResult, ) }) - build.onLoad({ filter: /.*/, namespace: 'resolveOutput' }, async args => ({ - contents: output[args.path], - loader: 'tsx', - resolveDir: __dirname, - })) + build.onLoad({ filter: /.*/, namespace: 'resolveOutput' }, async (args) => { + return { + contents: output.get(args.path)?.content ?? '', + loader: 'tsx', + resolveDir: __dirname, + } + }) }, } } diff --git a/packages/transformer-typescript/src/transformer-typescript.ts b/packages/transformer-typescript/src/transformer-typescript.ts index 4b7340c..9629aea 100644 --- a/packages/transformer-typescript/src/transformer-typescript.ts +++ b/packages/transformer-typescript/src/transformer-typescript.ts @@ -1,5 +1,5 @@ import * as schemas from '@whitebird/kaz-ast' -import { type ITransformerOutput, TransformerBase } from '@whitebird/kazam-transformer-base' +import { TransformerBase } from '@whitebird/kazam-transformer-base' import type { z } from 'zod' import * as handlers from './handlers' @@ -37,7 +37,7 @@ type ISchemaHandlers = { export type IHandler = ISchemaHandlers[T] -export class TransformerTypescript extends TransformerBase { +export class TransformerTypescript extends TransformerBase<{ outputFileNameFormat: `${string}.ts` }> { private handlers: ISchemaHandlers = { ast: handlers.handleKaz, computedInstruction: handlers.handleComputedInstruction, @@ -65,7 +65,7 @@ export class TransformerTypescript extends TransformerBase { /** * @deprecated Use `transformAndGenerateMappings` instead. */ - override transform(): void | ITransformerOutput { + override transform(): never { throw new Error('Method not implemented. Use `transformAndGenerateMappings` instead.') } diff --git a/packages/transformer-vue/src/transformer-vue.ts b/packages/transformer-vue/src/transformer-vue.ts index e031c27..bd8db56 100644 --- a/packages/transformer-vue/src/transformer-vue.ts +++ b/packages/transformer-vue/src/transformer-vue.ts @@ -1,7 +1,7 @@ import * as path from 'node:path' import * as schemas from '@whitebird/kaz-ast' -import { type ITransformerOutput, TransformerBase } from '@whitebird/kazam-transformer-base' +import { TransformerBase } from '@whitebird/kazam-transformer-base' import prettier from 'prettier' import type { z } from 'zod' @@ -35,7 +35,9 @@ type ISchemaHandlers = { export type IHandler = ISchemaHandlers[T] -export class TransformerVue extends TransformerBase { +export class TransformerVue extends TransformerBase<{ + outputFileNameFormat: `${string}.vue` +}> { private handlers: ISchemaHandlers = { ast: handlers.handleKaz, computedInstruction: handlers.handleComputedInstruction, @@ -82,13 +84,17 @@ export class TransformerVue extends TransformerBase { `.trim() } - return Object.entries(this.generatedComponents).reduce((output, [id, content]) => { - output[id] = Object.assign( - new Blob([content], { type: 'text/plain' }), - { name: `${id}.vue` }, - ) - return output - }, {}) + return Object.entries(this.generatedComponents).reduce( + (output, [id, content]) => + output.set(id, { + content, + filePath: `${id}.vue`, + }), + new Map(), + ) } private handle(input: unknown | undefined, componentMeta: IComponentMeta): THandlerReturnType { diff --git a/packages/transformer-vue/tests/helpers/render-transformer-vue-output-to-html.ts b/packages/transformer-vue/tests/helpers/render-transformer-vue-output-to-html.ts index 90c4587..1c48174 100644 --- a/packages/transformer-vue/tests/helpers/render-transformer-vue-output-to-html.ts +++ b/packages/transformer-vue/tests/helpers/render-transformer-vue-output-to-html.ts @@ -5,24 +5,21 @@ import process from 'node:process' import vue from '@vitejs/plugin-vue' import type { testWebTransformer } from '@whitebird/kazam-test-web-transformer' +import type { TransformerOutput } from '@whitebird/kazam-transformer-base' import tmp from 'tmp' import * as vite from 'vite' import { viteSingleFile } from 'vite-plugin-singlefile' type RenderHtml = Parameters[1] -type ITransformerOutput = Parameters[0] -type FlattenedOutput = Record export const renderTransformerVueOutputToHtml: RenderHtml = async (output) => { - const flattenedOutput = await flattenOutput(output) - const tmpProjectDir = tmp.dirSync({ tmpdir: process.cwd(), unsafeCleanup: true, }) try { - writeProjectFiles(tmpProjectDir.name, flattenedOutput) + writeProjectFiles(tmpProjectDir.name, output) let indexHtml = await getBundledIndexHtml(tmpProjectDir.name) @@ -40,39 +37,18 @@ export const renderTransformerVueOutputToHtml: RenderHtml = async (output) => { } } -async function flattenOutput( - output: ITransformerOutput, - parentPath = '', -): Promise { - const flattenedOutput: FlattenedOutput = {} - - if (output === undefined) - return flattenedOutput - - for (const [key, value] of Object.entries(output)) { - if (value instanceof Blob) { - const blob = value as Blob - const blobText = await blob.text() - flattenedOutput[parentPath + value.name] = blobText - } - else { - const nestedOutput = value as ITransformerOutput - const nestedFlattenedOutput = await flattenOutput(nestedOutput, `${parentPath + key}/`) - Object.assign(flattenedOutput, nestedFlattenedOutput) - } - } - - return flattenedOutput -} - function writeProjectFiles( projectDir: string, - output: FlattenedOutput, + output: TransformerOutput, ) { - for (const [id, content] of Object.entries(output)) { - const filePath = path.join(projectDir, id) - fs.mkdirSync(path.dirname(filePath), { recursive: true }) - fs.writeFileSync(filePath, content) + for (const [, { filePath, content }] of output.entries()) { + if (filePath === null) + continue + + const realFilePath = path.join(projectDir, filePath) + + fs.mkdirSync(path.dirname(realFilePath), { recursive: true }) + fs.writeFileSync(realFilePath, content) } fs.writeFileSync(path.join(projectDir, 'index.html'), ` diff --git a/patches/ink@4.4.1.patch b/patches/ink@4.4.1.patch new file mode 100644 index 0000000..edba276 --- /dev/null +++ b/patches/ink@4.4.1.patch @@ -0,0 +1,12 @@ +diff --git a/package.json b/package.json +index 39f8da78cdd80034ff530b0bed822e872b9305bb..018166148fd7575e642180df0255f45a0100f98a 100644 +--- a/package.json ++++ b/package.json +@@ -14,6 +14,7 @@ + "types": "./build/index.d.ts", + "default": "./build/index.js" + }, ++ "types": "./build/index.d.ts", + "engines": { + "node": ">=14.16" + }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 292112d..07e3006 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,11 @@ settings: overrides: '@antfu/eslint-config': 0.43.1 +patchedDependencies: + ink@4.4.1: + hash: tfc34kbmccvqcswnrusn6necjq + path: patches/ink@4.4.1.patch + importers: .: @@ -38,7 +43,7 @@ importers: version: 4.1.5 turbo: specifier: latest - version: 1.10.14 + version: 1.10.15 typescript: specifier: ^5.1.6 version: 5.2.2 @@ -68,7 +73,7 @@ importers: version: link:../../packages/transformer-typescript volar-service-typescript: specifier: 0.0.13 - version: 0.0.13(@volar/language-service@1.10.1)(@volar/typescript@1.10.1) + version: 0.0.13(@volar/language-service@1.10.1)(@volar/typescript@1.10.3) zod: specifier: ^3.19.1 version: 3.22.2 @@ -196,6 +201,9 @@ importers: '@whitebird/kazam-transformer-base': specifier: workspace:* version: link:../../packages/transformer-base + c12: + specifier: ^1.4.2 + version: 1.4.2 chalk: specifier: ^4 version: 4.1.2 @@ -205,6 +213,18 @@ importers: glob: specifier: 10.1.0 version: 10.1.0 + ink: + specifier: ^4.4.1 + version: 4.4.1(patch_hash=tfc34kbmccvqcswnrusn6necjq)(react@18.2.0) + ink-spinner: + specifier: ^5.0.0 + version: 5.0.0(ink@4.4.1)(react@18.2.0) + just-kebab-case: + specifier: ^4.2.0 + version: 4.2.0 + react: + specifier: ^18.2.0 + version: 18.2.0 typescript: specifier: ^5.0.0 version: 5.2.2 @@ -212,6 +232,9 @@ importers: specifier: ^3.21.4 version: 3.22.2 devDependencies: + '@types/ink-spinner': + specifier: ^3.0.2 + version: 3.0.2 '@types/node': specifier: ^18.11.9 version: 18.18.0 @@ -302,6 +325,9 @@ importers: '@vitest/coverage-v8': specifier: ^0.34.1 version: 0.34.5(vitest@0.34.5) + '@whitebird/kazam-transformer-base': + specifier: workspace:* + version: link:../transformer-base vitest: specifier: ^0.34.1 version: 0.34.5 @@ -376,9 +402,9 @@ importers: '@whitebird/kazam-transformer-typescript': specifier: workspace:* version: link:../transformer-typescript - deepmerge: - specifier: ^4.3.1 - version: 4.3.1 + effect: + specifier: 2.0.0-next.48 + version: 2.0.0-next.48 lodash: specifier: ^4.17.21 version: 4.17.21 @@ -404,6 +430,9 @@ importers: '@whitebird/kazam-test-web-transformer': specifier: workspace:* version: link:../test-web-transformer + deepmerge: + specifier: ^4.3.1 + version: 4.3.1 esbuild: specifier: ^0.18.2 version: 0.18.20 @@ -495,7 +524,7 @@ importers: version: 4.4.9(@types/node@18.18.0) vite-plugin-singlefile: specifier: ^0.13.5 - version: 0.13.5(rollup@3.29.3)(vite@4.4.9) + version: 0.13.5(rollup@4.0.2)(vite@4.4.9) vitest: specifier: ^0.34.1 version: 0.34.5 @@ -509,6 +538,14 @@ packages: resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} engines: {node: '>=0.10.0'} + /@alcalzone/ansi-tokenize@0.1.3: + resolution: {integrity: sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==} + engines: {node: '>=14.13.1'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: false + /@alloc/quick-lru@5.2.0: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -521,7 +558,7 @@ packages: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.19 - /@antfu/eslint-config-basic@0.43.1(@typescript-eslint/eslint-plugin@6.7.3)(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0)(typescript@5.2.2): + /@antfu/eslint-config-basic@0.43.1(@typescript-eslint/eslint-plugin@6.7.5)(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0)(typescript@5.2.2): resolution: {integrity: sha512-SW6hmGmqI985fsCJ+oivo4MbiMmRMgCJ0Ne8j/hwCB6O6Mc0m5bDqYeKn5HqFhvZhG84GEg5jPDKNiHrBYnQjw==} peerDependencies: eslint: '>=7.4.0' @@ -531,16 +568,16 @@ packages: eslint-plugin-antfu: 0.43.1(eslint@8.46.0)(typescript@5.2.2) eslint-plugin-eslint-comments: 3.2.0(eslint@8.46.0) eslint-plugin-html: 7.1.0 - eslint-plugin-import: /eslint-plugin-i@2.28.1(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0) + eslint-plugin-import: /eslint-plugin-i@2.28.1(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0) eslint-plugin-jsdoc: 46.8.2(eslint@8.46.0) - eslint-plugin-jsonc: 2.9.0(eslint@8.46.0) + eslint-plugin-jsonc: 2.10.0(eslint@8.46.0) eslint-plugin-markdown: 3.0.1(eslint@8.46.0) eslint-plugin-n: 16.1.0(eslint@8.46.0) eslint-plugin-no-only-tests: 3.1.0 eslint-plugin-promise: 6.1.1(eslint@8.46.0) eslint-plugin-unicorn: 48.0.1(eslint@8.46.0) - eslint-plugin-unused-imports: 3.0.0(@typescript-eslint/eslint-plugin@6.7.3)(eslint@8.46.0) - eslint-plugin-yml: 1.9.0(eslint@8.46.0) + eslint-plugin-unused-imports: 3.0.0(@typescript-eslint/eslint-plugin@6.7.5)(eslint@8.46.0) + eslint-plugin-yml: 1.10.0(eslint@8.46.0) jsonc-eslint-parser: 2.3.0 yaml-eslint-parser: 1.2.2 transitivePeerDependencies: @@ -558,12 +595,12 @@ packages: eslint: '>=7.4.0' typescript: '>=3.9' dependencies: - '@antfu/eslint-config-basic': 0.43.1(@typescript-eslint/eslint-plugin@6.7.3)(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0)(typescript@5.2.2) + '@antfu/eslint-config-basic': 0.43.1(@typescript-eslint/eslint-plugin@6.7.5)(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0)(typescript@5.2.2) '@stylistic/eslint-plugin-ts': 0.0.4(eslint@8.46.0)(typescript@5.2.2) - '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.46.0)(typescript@5.2.2) - '@typescript-eslint/parser': 6.7.3(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/eslint-plugin': 6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.7.5(eslint@8.46.0)(typescript@5.2.2) eslint: 8.46.0 - eslint-plugin-jest: 27.4.2(@typescript-eslint/eslint-plugin@6.7.3)(eslint@8.46.0)(typescript@5.2.2) + eslint-plugin-jest: 27.4.2(@typescript-eslint/eslint-plugin@6.7.5)(eslint@8.46.0)(typescript@5.2.2) typescript: 5.2.2 transitivePeerDependencies: - eslint-import-resolver-typescript @@ -572,12 +609,12 @@ packages: - supports-color dev: true - /@antfu/eslint-config-vue@0.43.1(@typescript-eslint/eslint-plugin@6.7.3)(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0)(typescript@5.2.2): + /@antfu/eslint-config-vue@0.43.1(@typescript-eslint/eslint-plugin@6.7.5)(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0)(typescript@5.2.2): resolution: {integrity: sha512-HxOfe8Vl+DPrzssbs5LHRDCnBtCy1LSA1DIeV71IC+iTpzoASFahSsVX5qckYu1InFgUm93XOhHCWm34LzPsvg==} peerDependencies: eslint: '>=7.4.0' dependencies: - '@antfu/eslint-config-basic': 0.43.1(@typescript-eslint/eslint-plugin@6.7.3)(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0)(typescript@5.2.2) + '@antfu/eslint-config-basic': 0.43.1(@typescript-eslint/eslint-plugin@6.7.5)(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0)(typescript@5.2.2) '@antfu/eslint-config-ts': 0.43.1(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0)(typescript@5.2.2) eslint: 8.46.0 eslint-plugin-vue: 9.17.0(eslint@8.46.0) @@ -597,19 +634,19 @@ packages: peerDependencies: eslint: '>=7.4.0' dependencies: - '@antfu/eslint-config-vue': 0.43.1(@typescript-eslint/eslint-plugin@6.7.3)(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0)(typescript@5.2.2) - '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.46.0)(typescript@5.2.2) - '@typescript-eslint/parser': 6.7.3(eslint@8.46.0)(typescript@5.2.2) + '@antfu/eslint-config-vue': 0.43.1(@typescript-eslint/eslint-plugin@6.7.5)(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/eslint-plugin': 6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.7.5(eslint@8.46.0)(typescript@5.2.2) eslint: 8.46.0 eslint-plugin-eslint-comments: 3.2.0(eslint@8.46.0) eslint-plugin-html: 7.1.0 - eslint-plugin-import: /eslint-plugin-i@2.28.1(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0) - eslint-plugin-jsonc: 2.9.0(eslint@8.46.0) + eslint-plugin-import: /eslint-plugin-i@2.28.1(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0) + eslint-plugin-jsonc: 2.10.0(eslint@8.46.0) eslint-plugin-n: 16.1.0(eslint@8.46.0) eslint-plugin-promise: 6.1.1(eslint@8.46.0) eslint-plugin-unicorn: 48.0.1(eslint@8.46.0) eslint-plugin-vue: 9.17.0(eslint@8.46.0) - eslint-plugin-yml: 1.9.0(eslint@8.46.0) + eslint-plugin-yml: 1.10.0(eslint@8.46.0) jsonc-eslint-parser: 2.3.0 yaml-eslint-parser: 1.2.2 transitivePeerDependencies: @@ -1763,6 +1800,11 @@ packages: resolution: {integrity: sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + /@eslint-community/regexpp@4.9.1: + resolution: {integrity: sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + /@eslint/eslintrc@2.1.2: resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2061,6 +2103,102 @@ packages: rollup: 3.29.3 dev: true + /@rollup/rollup-android-arm-eabi@4.0.2: + resolution: {integrity: sha512-xDvk1pT4vaPU2BOLy0MqHMdYZyntqpaBf8RhBiezlqG9OjY8F50TyctHo8znigYKd+QCFhCmlmXHOL/LoaOl3w==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.0.2: + resolution: {integrity: sha512-lqCglytY3E6raze27DD9VQJWohbwCxzqs9aSHcj5X/8hJpzZfNdbsr4Ja9Hqp6iPyF53+5PtPx0pKRlkSvlHZg==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.0.2: + resolution: {integrity: sha512-nkBKItS6E6CCzvRwgiKad+j+1ibmL7SIInj7oqMWmdkCjiSX6VeVZw2mLlRKIUL+JjsBgpATTfo7BiAXc1v0jA==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.0.2: + resolution: {integrity: sha512-vX2C8xvWPIbpEgQht95+dY6BReKAvtDgPDGi0XN0kWJKkm4WdNmq5dnwscv/zxvi+n6jUTBhs6GtpkkWT4q8Gg==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.0.2: + resolution: {integrity: sha512-DVFIfcHOjgmeHOAqji4xNz2wczt1Bmzy9MwBZKBa83SjBVO/i38VHDR+9ixo8QpBOiEagmNw12DucG+v55tCrg==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.0.2: + resolution: {integrity: sha512-GCK/a9ItUxPI0V5hQEJjH4JtOJO90GF2Hja7TO+EZ8rmkGvEi8/ZDMhXmcuDpQT7/PWrTT9RvnG8snMd5SrhBQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.0.2: + resolution: {integrity: sha512-cLuBp7rOjIB1R2j/VazjCmHC7liWUur2e9mFflLJBAWCkrZ+X0+QwHLvOQakIwDymungzAKv6W9kHZnTp/Mqrg==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.0.2: + resolution: {integrity: sha512-Zqw4iVnJr2naoyQus0yLy7sLtisCQcpdMKUCeXPBjkJtpiflRime/TMojbnl8O3oxUAj92mxr+t7im/RbgA20w==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.0.2: + resolution: {integrity: sha512-jJRU9TyUD/iMqjf8aLAp7XiN3pIj5v6Qcu+cdzBfVTKDD0Fvua4oUoK8eVJ9ZuKBEQKt3WdlcwJXFkpmMLk6kg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.0.2: + resolution: {integrity: sha512-ZkS2NixCxHKC4zbOnw64ztEGGDVIYP6nKkGBfOAxEPW71Sji9v8z3yaHNuae/JHPwXA+14oDefnOuVfxl59SmQ==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.0.2: + resolution: {integrity: sha512-3SKjj+tvnZ0oZq2BKB+fI+DqYI83VrRzk7eed8tJkxeZ4zxJZcLSE8YDQLYGq1tZAnAX+H076RHHB4gTZXsQzw==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.0.2: + resolution: {integrity: sha512-MBdJIOxRauKkry7t2q+rTHa3aWjVez2eioWg+etRVS3dE4tChhmt5oqZYr48R6bPmcwEhxQr96gVRfeQrLbqng==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true @@ -2083,9 +2221,9 @@ packages: typescript: '*' dependencies: '@stylistic/eslint-plugin-js': 0.0.4 - '@typescript-eslint/scope-manager': 6.7.3 - '@typescript-eslint/type-utils': 6.7.3(eslint@8.46.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.7.3(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': 6.7.5 + '@typescript-eslint/type-utils': 6.7.5(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.7.5(eslint@8.46.0)(typescript@5.2.2) eslint: 8.46.0 graphemer: 1.4.0 typescript: 5.2.2 @@ -2152,6 +2290,10 @@ packages: resolution: {integrity: sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==} dev: true + /@types/cli-spinners@1.3.1: + resolution: {integrity: sha512-p3gskTADMPvG8eIfT+infCZ3SGwVhoBjMo/ljEU1PY5KpImsOEtcXKb7Bzszfhy6rEHSD7FnTQ2O8OU0QVTqtw==} + dev: true + /@types/debug@4.1.9: resolution: {integrity: sha512-8Hz50m2eoS56ldRlepxSBa6PWEVCtzUo/92HgLc2qTMnotJNIm7xP+UZhyWoYsyOdd5dxZ+NZLb24rsKyFs2ow==} dependencies: @@ -2181,6 +2323,13 @@ packages: '@types/unist': 2.0.8 dev: false + /@types/ink-spinner@3.0.2: + resolution: {integrity: sha512-bOnaJ1O5wp/lYB9kELgBzGVWVEeRXNYT1pL0/5kw/3hNOZ/G/HHd2MM9XvVz2dmvL2/weam+3R+Qgp9SxB11PQ==} + dependencies: + '@types/cli-spinners': 1.3.1 + '@types/react': 18.2.22 + dev: true + /@types/is-ci@3.0.0: resolution: {integrity: sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==} dependencies: @@ -2211,6 +2360,13 @@ packages: resolution: {integrity: sha512-DT+iNIRNX884cx0/Q1ja7NyUPpZuv0KPyL5rGNxm1WC1OtHstl7n4Jb7nk+xacNShQMbczJjt8uFzznpp6kYBg==} dependencies: '@types/unist': 2.0.8 + dev: false + + /@types/mdast@3.0.13: + resolution: {integrity: sha512-HjiGiWedR0DVFkeNljpa6Lv4/IZU1+30VY5d747K7lBudFc3R0Ibr6yJ9lN3BE28VnZyDfLF/VB1Ql1ZIbKrmg==} + dependencies: + '@types/unist': 2.0.8 + dev: true /@types/minimist@1.2.2: resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} @@ -2286,8 +2442,8 @@ packages: resolution: {integrity: sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ==} dev: false - /@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.46.0)(typescript@5.2.2): - resolution: {integrity: sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==} + /@typescript-eslint/eslint-plugin@6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.46.0)(typescript@5.2.2): + resolution: {integrity: sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -2297,12 +2453,12 @@ packages: typescript: optional: true dependencies: - '@eslint-community/regexpp': 4.8.1 - '@typescript-eslint/parser': 6.7.3(eslint@8.46.0)(typescript@5.2.2) - '@typescript-eslint/scope-manager': 6.7.3 - '@typescript-eslint/type-utils': 6.7.3(eslint@8.46.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.7.3(eslint@8.46.0)(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.7.3 + '@eslint-community/regexpp': 4.9.1 + '@typescript-eslint/parser': 6.7.5(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': 6.7.5 + '@typescript-eslint/type-utils': 6.7.5(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.7.5(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.7.5 debug: 4.3.4 eslint: 8.46.0 graphemer: 1.4.0 @@ -2334,8 +2490,8 @@ packages: transitivePeerDependencies: - supports-color - /@typescript-eslint/parser@6.7.3(eslint@8.46.0)(typescript@5.2.2): - resolution: {integrity: sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==} + /@typescript-eslint/parser@6.7.5(eslint@8.46.0)(typescript@5.2.2): + resolution: {integrity: sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -2344,10 +2500,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.7.3 - '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.7.3 + '@typescript-eslint/scope-manager': 6.7.5 + '@typescript-eslint/types': 6.7.5 + '@typescript-eslint/typescript-estree': 6.7.5(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.7.5 debug: 4.3.4 eslint: 8.46.0 typescript: 5.2.2 @@ -2362,16 +2518,16 @@ packages: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - /@typescript-eslint/scope-manager@6.7.3: - resolution: {integrity: sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==} + /@typescript-eslint/scope-manager@6.7.5: + resolution: {integrity: sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/visitor-keys': 6.7.3 + '@typescript-eslint/types': 6.7.5 + '@typescript-eslint/visitor-keys': 6.7.5 dev: true - /@typescript-eslint/type-utils@6.7.3(eslint@8.46.0)(typescript@5.2.2): - resolution: {integrity: sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw==} + /@typescript-eslint/type-utils@6.7.5(eslint@8.46.0)(typescript@5.2.2): + resolution: {integrity: sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -2380,8 +2536,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.2.2) - '@typescript-eslint/utils': 6.7.3(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.7.5(typescript@5.2.2) + '@typescript-eslint/utils': 6.7.5(eslint@8.46.0)(typescript@5.2.2) debug: 4.3.4 eslint: 8.46.0 ts-api-utils: 1.0.3(typescript@5.2.2) @@ -2394,8 +2550,8 @@ packages: resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - /@typescript-eslint/types@6.7.3: - resolution: {integrity: sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==} + /@typescript-eslint/types@6.7.5: + resolution: {integrity: sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==} engines: {node: ^16.0.0 || >=18.0.0} dev: true @@ -2419,8 +2575,8 @@ packages: transitivePeerDependencies: - supports-color - /@typescript-eslint/typescript-estree@6.7.3(typescript@5.2.2): - resolution: {integrity: sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==} + /@typescript-eslint/typescript-estree@6.7.5(typescript@5.2.2): + resolution: {integrity: sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -2428,8 +2584,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/visitor-keys': 6.7.3 + '@typescript-eslint/types': 6.7.5 + '@typescript-eslint/visitor-keys': 6.7.5 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -2460,8 +2616,8 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.7.3(eslint@8.46.0)(typescript@5.2.2): - resolution: {integrity: sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg==} + /@typescript-eslint/utils@6.7.5(eslint@8.46.0)(typescript@5.2.2): + resolution: {integrity: sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -2469,9 +2625,9 @@ packages: '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) '@types/json-schema': 7.0.13 '@types/semver': 7.5.3 - '@typescript-eslint/scope-manager': 6.7.3 - '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.2.2) + '@typescript-eslint/scope-manager': 6.7.5 + '@typescript-eslint/types': 6.7.5 + '@typescript-eslint/typescript-estree': 6.7.5(typescript@5.2.2) eslint: 8.46.0 semver: 7.5.4 transitivePeerDependencies: @@ -2486,11 +2642,11 @@ packages: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 - /@typescript-eslint/visitor-keys@6.7.3: - resolution: {integrity: sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==} + /@typescript-eslint/visitor-keys@6.7.5: + resolution: {integrity: sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/types': 6.7.5 eslint-visitor-keys: 3.4.3 dev: true @@ -2598,6 +2754,12 @@ packages: dependencies: '@volar/source-map': 1.10.1 + /@volar/language-core@1.10.3: + resolution: {integrity: sha512-7Qgwu9bWUHN+cLrOkCbIVBkL+RVPREhvY07wY89dGxi4mY9mQCsUVRRp64F61lX7Nc27meMnvy0sWlzY0x6oQQ==} + dependencies: + '@volar/source-map': 1.10.3 + dev: false + /@volar/language-server@1.10.1: resolution: {integrity: sha512-UXgRMAPKoy4EZBcBT1SFp8YIb5AJqe7Is1/TnqRUq0LBBV2M7HpEeHHI8E4fy05Eg4TlSVRcrlZtiTrY9fRjJg==} dependencies: @@ -2626,11 +2788,23 @@ packages: dependencies: muggle-string: 0.3.1 + /@volar/source-map@1.10.3: + resolution: {integrity: sha512-QE9nwK3xsdBQGongHnC9SCR0itx7xUKQFsUDn5HbZY3pHpyXxdY1hSBG0eh9mE+aTKoM4KlqMvrb+19Tv9vS1Q==} + dependencies: + muggle-string: 0.3.1 + dev: false + /@volar/typescript@1.10.1: resolution: {integrity: sha512-+iiO9yUSRHIYjlteT+QcdRq8b44qH19/eiUZtjNtuh6D9ailYM7DVR0zO2sEgJlvCaunw/CF9Ov2KooQBpR4VQ==} dependencies: '@volar/language-core': 1.10.1 + /@volar/typescript@1.10.3: + resolution: {integrity: sha512-n0ar6xGYpRoSvgGMetm/JXP0QAXx+NOUvxCaWCfCjiFivQRSLJeydYDijhoGBUl5KSKosqq9In5L3e/m2TqTcQ==} + dependencies: + '@volar/language-core': 1.10.3 + dev: false + /@volar/vscode@1.10.1: resolution: {integrity: sha512-zrwc3pFcPzApod2zg0NPNwYToUbzXx7dKdFDm/DUvjxD6H90T7StEdVO2a+u+7abQGTwXtJ7L/aSjyfCIbRuUw==} dependencies: @@ -2775,7 +2949,7 @@ packages: '@typescript-eslint/parser': 5.62.0(eslint@8.46.0)(typescript@5.2.2) eslint: 8.46.0 eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.28.1)(eslint@8.46.0) - eslint-plugin-import: 2.28.1(@typescript-eslint/parser@6.7.3)(eslint@8.46.0) + eslint-plugin-import: 2.28.1(@typescript-eslint/parser@6.7.5)(eslint@8.46.0) transitivePeerDependencies: - eslint-import-resolver-node - eslint-import-resolver-webpack @@ -2833,6 +3007,15 @@ packages: transitivePeerDependencies: - supports-color + /agent-base@7.1.0: + resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} + engines: {node: '>= 14'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: @@ -2861,6 +3044,13 @@ packages: engines: {node: '>=6'} dev: false + /ansi-escapes@6.2.0: + resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==} + engines: {node: '>=14.16'} + dependencies: + type-fest: 3.13.1 + dev: false + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -3101,6 +3291,11 @@ packages: resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} dev: false + /auto-bind@5.0.1: + resolution: {integrity: sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + /autoprefixer@10.4.16(postcss@8.4.30): resolution: {integrity: sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==} engines: {node: ^10 || ^12 || >=14} @@ -3284,6 +3479,24 @@ packages: streamsearch: 1.1.0 dev: false + /c12@1.4.2: + resolution: {integrity: sha512-3IP/MuamSVRVw8W8+CHWAz9gKN4gd+voF2zm/Ln6D25C2RhytEZ1ABbC8MjKr4BR9rhoV1JQ7jJA158LDiTkLg==} + dependencies: + chokidar: 3.5.3 + defu: 6.1.2 + dotenv: 16.3.1 + giget: 1.1.3 + jiti: 1.20.0 + mlly: 1.4.2 + ohash: 1.1.3 + pathe: 1.1.1 + perfect-debounce: 1.0.0 + pkg-types: 1.0.3 + rc9: 2.1.1 + transitivePeerDependencies: + - supports-color + dev: false + /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -3446,6 +3659,11 @@ packages: /ci-info@3.8.0: resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} + dev: false + + /ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} /citty@0.1.4: resolution: {integrity: sha512-Q3bK1huLxzQrvj7hImJ7Z1vKYJRPQCDnd0EjXfHMidcjecGOMuLrmuQmtWmFkuKLcMThlGh1yCKG8IEc6VeNXQ==} @@ -3477,6 +3695,14 @@ packages: engines: {node: '>=6'} dev: false + /cli-truncate@3.1.0: + resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + dev: false + /cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} dependencies: @@ -3498,6 +3724,13 @@ packages: engines: {node: '>=0.8'} dev: false + /code-excerpt@4.0.0: + resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + convert-to-spaces: 2.0.1 + dev: false + /color-convert@0.5.3: resolution: {integrity: sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling==} dev: false @@ -3543,6 +3776,10 @@ packages: color-string: 1.9.1 dev: false + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: false + /comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} dev: false @@ -3630,6 +3867,11 @@ packages: /convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + /convert-to-spaces@2.0.1: + resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + /cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} @@ -3876,7 +4118,6 @@ packages: /defu@6.1.2: resolution: {integrity: sha512-+uO4+qr7msjNNWKYPHqN/3+Dx3NFkmIzayk2L1MyZQlvgZb/J1A0fo410dpKrN2SnqFjt8n4JL8fDJE0wIgjFQ==} - dev: true /delegates@1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} @@ -3887,6 +4128,10 @@ packages: engines: {node: '>=6'} dev: false + /destr@2.0.1: + resolution: {integrity: sha512-M1Ob1zPSIvlARiJUkKqvAZ3VAqQY6Jcuth/pBKQ2b1dX/Qx0OnJ8Vux6J2H5PTMQeRzWrrbTu70VxBfv/OPDJA==} + dev: false + /detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -3980,6 +4225,11 @@ packages: is-obj: 2.0.0 dev: true + /dotenv@16.3.1: + resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} + engines: {node: '>=12'} + dev: false + /dset@3.1.2: resolution: {integrity: sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==} engines: {node: '>=4'} @@ -3988,6 +4238,10 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + /effect@2.0.0-next.48: + resolution: {integrity: sha512-vwMIl39m8fMBeXoGIdSwMi2lrg7NltyrGMK0N/liGDl7G9LXvERKOCipNcobSIGO0V7hjaXEWgL6W/KEWEww+g==} + dev: false + /electron-to-chromium@1.4.528: resolution: {integrity: sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA==} @@ -4054,7 +4308,7 @@ packages: get-symbol-description: 1.0.0 globalthis: 1.0.3 gopd: 1.0.1 - has: 1.0.3 + has: 1.0.4 has-property-descriptors: 1.0.0 has-proto: 1.0.1 has-symbols: 1.0.3 @@ -4092,13 +4346,13 @@ packages: engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.2.1 - has: 1.0.3 + has: 1.0.4 has-tostringtag: 1.0.0 /es-shim-unscopables@1.0.0: resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} dependencies: - has: 1.0.3 + has: 1.0.4 /es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} @@ -4394,6 +4648,11 @@ packages: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + /escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + dev: false + /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -4403,12 +4662,21 @@ packages: engines: {node: '>=12'} dev: false + /eslint-compat-utils@0.1.2(eslint@8.46.0): + resolution: {integrity: sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + eslint: 8.46.0 + dev: true + /eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: debug: 3.2.7 is-core-module: 2.13.0 - resolve: 1.22.6 + resolve: 1.22.8 transitivePeerDependencies: - supports-color dev: true @@ -4424,7 +4692,7 @@ packages: enhanced-resolve: 5.15.0 eslint: 8.46.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0) - eslint-plugin-import: 2.28.1(@typescript-eslint/parser@6.7.3)(eslint@8.46.0) + eslint-plugin-import: 2.28.1(@typescript-eslint/parser@6.7.5)(eslint@8.46.0) fast-glob: 3.3.1 get-tsconfig: 4.7.2 is-core-module: 2.13.0 @@ -4466,7 +4734,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -4487,7 +4755,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.7.3(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.7.5(eslint@8.46.0)(typescript@5.2.2) debug: 3.2.7 eslint: 8.46.0 eslint-import-resolver-node: 0.3.9 @@ -4499,7 +4767,7 @@ packages: /eslint-plugin-antfu@0.43.1(eslint@8.46.0)(typescript@5.2.2): resolution: {integrity: sha512-Nak+Qpy5qEK10dCXtVaabPTUmLBPLhsVKAFXAtxYGYRlY/SuuZUBhW2YIsLsixNROiICGuov8sN+eNOCC7Wb5g==} dependencies: - '@typescript-eslint/utils': 6.7.3(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.7.5(eslint@8.46.0)(typescript@5.2.2) transitivePeerDependencies: - eslint - supports-color @@ -4513,7 +4781,7 @@ packages: eslint: '>=8' dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) - '@eslint-community/regexpp': 4.8.1 + '@eslint-community/regexpp': 4.9.1 eslint: 8.46.0 dev: true @@ -4534,7 +4802,7 @@ packages: htmlparser2: 8.0.2 dev: true - /eslint-plugin-i@2.28.1(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0): + /eslint-plugin-i@2.28.1(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0): resolution: {integrity: sha512-a4oVt0j3ixNhGhvV4XF6NS7OWRFK2rrJ0Q5C4S2dSRb8FxZi31J0uUd5WJLL58wnVJ/OiQ1BxiXnFA4dWQO1Cg==} engines: {node: '>=12'} peerDependencies: @@ -4544,11 +4812,11 @@ packages: doctrine: 2.1.0 eslint: 8.46.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0) get-tsconfig: 4.7.2 is-glob: 4.0.3 minimatch: 3.1.2 - resolve: 1.22.6 + resolve: 1.22.8 semver: 7.5.4 transitivePeerDependencies: - '@typescript-eslint/parser' @@ -4557,7 +4825,7 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.3)(eslint@8.46.0): + /eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.5)(eslint@8.46.0): resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} engines: {node: '>=4'} peerDependencies: @@ -4567,7 +4835,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.7.3(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.7.5(eslint@8.46.0)(typescript@5.2.2) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 @@ -4576,8 +4844,8 @@ packages: doctrine: 2.1.0 eslint: 8.46.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0) - has: 1.0.3 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.46.0) + has: 1.0.4 is-core-module: 2.13.0 is-glob: 4.0.3 minimatch: 3.1.2 @@ -4592,7 +4860,7 @@ packages: - supports-color dev: true - /eslint-plugin-jest@27.4.2(@typescript-eslint/eslint-plugin@6.7.3)(eslint@8.46.0)(typescript@5.2.2): + /eslint-plugin-jest@27.4.2(@typescript-eslint/eslint-plugin@6.7.5)(eslint@8.46.0)(typescript@5.2.2): resolution: {integrity: sha512-3Nfvv3wbq2+PZlRTf2oaAWXWwbdBejFRBR2O8tAO67o+P8zno+QGbcDYaAXODlreXVg+9gvWhKKmG2rgfb8GEg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -4605,7 +4873,7 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/eslint-plugin': 6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.46.0)(typescript@5.2.2) '@typescript-eslint/utils': 5.62.0(eslint@8.46.0)(typescript@5.2.2) eslint: 8.46.0 transitivePeerDependencies: @@ -4633,14 +4901,15 @@ packages: - supports-color dev: true - /eslint-plugin-jsonc@2.9.0(eslint@8.46.0): - resolution: {integrity: sha512-RK+LeONVukbLwT2+t7/OY54NJRccTXh/QbnXzPuTLpFMVZhPuq1C9E07+qWenGx7rrQl0kAalAWl7EmB+RjpGA==} + /eslint-plugin-jsonc@2.10.0(eslint@8.46.0): + resolution: {integrity: sha512-9d//o6Jyh4s1RxC9fNSt1+MMaFN2ruFdXPG9XZcb/mR2KkfjADYiNL/hbU6W0Cyxfg3tS/XSFuhl5LgtMD8hmw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) eslint: 8.46.0 + eslint-compat-utils: 0.1.2(eslint@8.46.0) jsonc-eslint-parser: 2.3.0 natural-compare: 1.4.0 dev: true @@ -4671,7 +4940,7 @@ packages: ignore: 5.2.4 is-core-module: 2.13.0 minimatch: 3.1.2 - resolve: 1.22.6 + resolve: 1.22.8 semver: 7.5.4 dev: true @@ -4697,7 +4966,7 @@ packages: dependencies: '@babel/helper-validator-identifier': 7.22.20 '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) - ci-info: 3.8.0 + ci-info: 3.9.0 clean-regexp: 1.0.0 eslint: 8.46.0 esquery: 1.5.0 @@ -4713,7 +4982,7 @@ packages: strip-indent: 3.0.0 dev: true - /eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.7.3)(eslint@8.46.0): + /eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.7.5)(eslint@8.46.0): resolution: {integrity: sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -4723,7 +4992,7 @@ packages: '@typescript-eslint/eslint-plugin': optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.46.0)(typescript@5.2.2) + '@typescript-eslint/eslint-plugin': 6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.46.0)(typescript@5.2.2) eslint: 8.46.0 eslint-rule-composer: 0.3.0 dev: true @@ -4740,20 +5009,21 @@ packages: nth-check: 2.1.1 postcss-selector-parser: 6.0.13 semver: 7.5.4 - vue-eslint-parser: 9.3.1(eslint@8.46.0) + vue-eslint-parser: 9.3.2(eslint@8.46.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-yml@1.9.0(eslint@8.46.0): - resolution: {integrity: sha512-ayuC57WyVQ5+QZ02y62GiB//5+zsiyzUGxUX/mrhLni+jfsKA4KoITjkbR65iUdjjhWpyTJHPcAIFLKQIOwgsw==} + /eslint-plugin-yml@1.10.0(eslint@8.46.0): + resolution: {integrity: sha512-53SUwuNDna97lVk38hL/5++WXDuugPM9SUQ1T645R0EHMRCdBIIxGye/oOX2qO3FQ7aImxaUZJU/ju+NMUBrLQ==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4 eslint: 8.46.0 + eslint-compat-utils: 0.1.2(eslint@8.46.0) lodash: 4.17.21 natural-compare: 1.4.0 yaml-eslint-parser: 1.2.2 @@ -5035,6 +5305,11 @@ packages: keyv: 4.5.3 rimraf: 3.0.2 + /flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + dev: false + /flatted@3.2.9: resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} @@ -5165,7 +5440,7 @@ packages: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} dependencies: function-bind: 1.1.1 - has: 1.0.3 + has: 1.0.4 has-proto: 1.0.1 has-symbols: 1.0.3 @@ -5186,6 +5461,21 @@ packages: resolve-pkg-maps: 1.0.0 dev: true + /giget@1.1.3: + resolution: {integrity: sha512-zHuCeqtfgqgDwvXlR84UNgnJDuUHQcNI5OqWqFxxuk2BshuKbYhJWdxBsEo4PvKqoGh23lUAIvBNpChMLv7/9Q==} + hasBin: true + dependencies: + colorette: 2.0.20 + defu: 6.1.2 + https-proxy-agent: 7.0.2 + mri: 1.2.0 + node-fetch-native: 1.4.0 + pathe: 1.1.1 + tar: 6.2.0 + transitivePeerDependencies: + - supports-color + dev: false + /git-raw-commits@2.0.11: resolution: {integrity: sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==} engines: {node: '>=10'} @@ -5426,11 +5716,9 @@ packages: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} dev: false - /has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + /has@1.0.4: + resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} engines: {node: '>= 0.4.0'} - dependencies: - function-bind: 1.1.1 /hast-util-from-parse5@7.1.2: resolution: {integrity: sha512-Nz7FfPBuljzsN3tCQ4kCBKqdNhQE2l0Tn+X1ubgKBPRoiDIu1mL08Cfw4k7q71+Duyaw7DXDN+VTAp4Vh3oCOw==} @@ -5596,6 +5884,16 @@ packages: transitivePeerDependencies: - supports-color + /https-proxy-agent@7.0.2: + resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + /human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} dev: false @@ -5660,6 +5958,11 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + /indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + dev: false + /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: @@ -5672,12 +5975,69 @@ packages: /ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + /ink-spinner@5.0.0(ink@4.4.1)(react@18.2.0): + resolution: {integrity: sha512-EYEasbEjkqLGyPOUc8hBJZNuC5GvXGMLu0w5gdTNskPc7Izc5vO3tdQEYnzvshucyGCBXc86ig0ujXPMWaQCdA==} + engines: {node: '>=14.16'} + peerDependencies: + ink: '>=4.0.0' + react: '>=18.0.0' + dependencies: + cli-spinners: 2.9.1 + ink: 4.4.1(patch_hash=tfc34kbmccvqcswnrusn6necjq)(react@18.2.0) + react: 18.2.0 + dev: false + + /ink@4.4.1(patch_hash=tfc34kbmccvqcswnrusn6necjq)(react@18.2.0): + resolution: {integrity: sha512-rXckvqPBB0Krifk5rn/5LvQGmyXwCUpBfmTwbkQNBY9JY8RSl3b8OftBNEYxg4+SWUhEKcPifgope28uL9inlA==} + engines: {node: '>=14.16'} + peerDependencies: + '@types/react': '>=18.0.0' + react: '>=18.0.0' + react-devtools-core: ^4.19.1 + peerDependenciesMeta: + '@types/react': + optional: true + react-devtools-core: + optional: true + dependencies: + '@alcalzone/ansi-tokenize': 0.1.3 + ansi-escapes: 6.2.0 + auto-bind: 5.0.1 + chalk: 5.3.0 + cli-boxes: 3.0.0 + cli-cursor: 4.0.0 + cli-truncate: 3.1.0 + code-excerpt: 4.0.0 + indent-string: 5.0.0 + is-ci: 3.0.1 + is-lower-case: 2.0.2 + is-upper-case: 2.0.2 + lodash: 4.17.21 + patch-console: 2.0.0 + react: 18.2.0 + react-reconciler: 0.29.0(react@18.2.0) + scheduler: 0.23.0 + signal-exit: 3.0.7 + slice-ansi: 6.0.0 + stack-utils: 2.0.6 + string-width: 5.1.2 + type-fest: 0.12.0 + widest-line: 4.0.1 + wrap-ansi: 8.1.0 + ws: 8.14.2 + yoga-wasm-web: 0.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + patched: true + /internal-slot@1.0.5: resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.2.1 - has: 1.0.3 + has: 1.0.4 side-channel: 1.0.4 /is-alphabetical@1.0.4: @@ -5751,13 +6111,13 @@ packages: resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true dependencies: - ci-info: 3.8.0 + ci-info: 3.9.0 dev: false /is-core-module@2.13.0: resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} dependencies: - has: 1.0.3 + has: 1.0.4 /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} @@ -5794,6 +6154,11 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + /is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: false + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -5817,6 +6182,12 @@ packages: engines: {node: '>=12'} dev: false + /is-lower-case@2.0.2: + resolution: {integrity: sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==} + dependencies: + tslib: 2.6.2 + dev: false + /is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} dev: true @@ -5923,6 +6294,12 @@ packages: engines: {node: '>=12'} dev: false + /is-upper-case@2.0.2: + resolution: {integrity: sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==} + dependencies: + tslib: 2.6.2 + dev: false + /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: @@ -6102,6 +6479,10 @@ packages: engines: {'0': node >= 0.2.0} dev: true + /just-kebab-case@4.2.0: + resolution: {integrity: sha512-p2BdO7o4BI+pMun3J+dhaOfYan5JsZrw9wjshRjkWY9+p+u+kKSMhNWYnot2yHDR9CSahZ9iT3dcqJ+V72qHMw==} + dev: false + /keytar@7.9.0: resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==} requiresBuild: true @@ -6366,7 +6747,7 @@ packages: /mdast-util-from-markdown@0.8.5: resolution: {integrity: sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==} dependencies: - '@types/mdast': 3.0.12 + '@types/mdast': 3.0.13 mdast-util-to-string: 2.0.0 micromark: 2.11.4 parse-entities: 2.0.0 @@ -6951,7 +7332,6 @@ packages: pathe: 1.1.1 pkg-types: 1.0.3 ufo: 1.3.0 - dev: true /mocha@5.2.0: resolution: {integrity: sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==} @@ -7063,6 +7443,10 @@ packages: resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} dev: false + /node-fetch-native@1.4.0: + resolution: {integrity: sha512-F5kfEj95kX8tkDhUCYdV8dg3/8Olx/94zB8+ZNthFs6Bz31UpUi8Xh40TN3thLwXgrwXry1pEg9lJ++tLWTcqA==} + dev: false + /node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -7216,6 +7600,10 @@ packages: es-abstract: 1.22.2 dev: true + /ohash@1.1.3: + resolution: {integrity: sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==} + dev: false + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -7412,6 +7800,11 @@ packages: entities: 4.5.0 dev: true + /patch-console@2.0.0: + resolution: {integrity: sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -7461,7 +7854,6 @@ packages: /pathe@1.1.1: resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} - dev: true /pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} @@ -7471,6 +7863,10 @@ packages: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} dev: true + /perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + dev: false + /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -7517,7 +7913,6 @@ packages: jsonc-parser: 3.2.0 mlly: 1.4.2 pathe: 1.1.1 - dev: true /playwright-core@1.38.1: resolution: {integrity: sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg==} @@ -7716,6 +8111,14 @@ packages: resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} engines: {node: '>=8'} + /rc9@2.1.1: + resolution: {integrity: sha512-lNeOl38Ws0eNxpO3+wD1I9rkHGQyj1NU1jlzv4go2CtEnEQEUfqnIvZG7W+bC/aXdJ27n5x/yUjb6RoT9tko+Q==} + dependencies: + defu: 6.1.2 + destr: 2.0.1 + flat: 5.0.2 + dev: false + /rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -7738,6 +8141,17 @@ packages: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} dev: true + /react-reconciler@0.29.0(react@18.2.0): + resolution: {integrity: sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + loose-envify: 1.4.0 + react: 18.2.0 + scheduler: 0.23.0 + dev: false + /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} @@ -7955,6 +8369,15 @@ packages: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + /restore-cursor@4.0.0: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -8037,6 +8460,26 @@ packages: optionalDependencies: fsevents: 2.3.3 + /rollup@4.0.2: + resolution: {integrity: sha512-MCScu4usMPCeVFaiLcgMDaBQeYi1z6vpWxz0r0hq0Hv77Y2YuOTZldkuNJ54BdYBH3e+nkrk6j0Rre/NLDBYzg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.0.2 + '@rollup/rollup-android-arm64': 4.0.2 + '@rollup/rollup-darwin-arm64': 4.0.2 + '@rollup/rollup-darwin-x64': 4.0.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.0.2 + '@rollup/rollup-linux-arm64-gnu': 4.0.2 + '@rollup/rollup-linux-arm64-musl': 4.0.2 + '@rollup/rollup-linux-x64-gnu': 4.0.2 + '@rollup/rollup-linux-x64-musl': 4.0.2 + '@rollup/rollup-win32-arm64-msvc': 4.0.2 + '@rollup/rollup-win32-ia32-msvc': 4.0.2 + '@rollup/rollup-win32-x64-msvc': 4.0.2 + fsevents: 2.3.3 + dev: true + /run-applescript@5.0.0: resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} engines: {node: '>=12'} @@ -8240,6 +8683,22 @@ packages: engines: {node: '>=12'} dev: true + /slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: false + + /slice-ansi@6.0.0: + resolution: {integrity: sha512-6bn4hRfkTvDfUoEQYkERg0BVF1D0vrX9HEkMl08uDiNWvVvjylLHvZFZWkDo6wjT8tUctbYl1nCOuE66ZTaUtA==} + engines: {node: '>=14.16'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: false + /smartwrap@2.0.2: resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==} engines: {node: '>=6'} @@ -8308,6 +8767,13 @@ packages: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: false + /stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + dev: false + /stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} dev: true @@ -8787,64 +9253,64 @@ packages: engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} dev: true - /turbo-darwin-64@1.10.14: - resolution: {integrity: sha512-I8RtFk1b9UILAExPdG/XRgGQz95nmXPE7OiGb6ytjtNIR5/UZBS/xVX/7HYpCdmfriKdVwBKhalCoV4oDvAGEg==} + /turbo-darwin-64@1.10.15: + resolution: {integrity: sha512-Sik5uogjkRTe1XVP9TC2GryEMOJCaKE2pM/O9uLn4koQDnWKGcLQv+mDU+H+9DXvKLnJnKCD18OVRkwK5tdpoA==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-darwin-arm64@1.10.14: - resolution: {integrity: sha512-KAdUWryJi/XX7OD0alOuOa0aJ5TLyd4DNIYkHPHYcM6/d7YAovYvxRNwmx9iv6Vx6IkzTnLeTiUB8zy69QkG9Q==} + /turbo-darwin-arm64@1.10.15: + resolution: {integrity: sha512-xwqyFDYUcl2xwXyGPmHkmgnNm4Cy0oNzMpMOBGRr5x64SErS7QQLR4VHb0ubiR+VAb8M+ECPklU6vD1Gm+wekg==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-linux-64@1.10.14: - resolution: {integrity: sha512-BOBzoREC2u4Vgpap/WDxM6wETVqVMRcM8OZw4hWzqCj2bqbQ6L0wxs1LCLWVrghQf93JBQtIGAdFFLyCSBXjWQ==} + /turbo-linux-64@1.10.15: + resolution: {integrity: sha512-dM07SiO3RMAJ09Z+uB2LNUSkPp3I1IMF8goH5eLj+d8Kkwoxd/+qbUZOj9RvInyxU/IhlnO9w3PGd3Hp14m/nA==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-linux-arm64@1.10.14: - resolution: {integrity: sha512-D8T6XxoTdN5D4V5qE2VZG+/lbZX/89BkAEHzXcsSUTRjrwfMepT3d2z8aT6hxv4yu8EDdooZq/2Bn/vjMI32xw==} + /turbo-linux-arm64@1.10.15: + resolution: {integrity: sha512-MkzKLkKYKyrz4lwfjNXH8aTny5+Hmiu4SFBZbx+5C0vOlyp6fV5jZANDBvLXWiDDL4DSEAuCEK/2cmN6FVH1ow==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-windows-64@1.10.14: - resolution: {integrity: sha512-zKNS3c1w4i6432N0cexZ20r/aIhV62g69opUn82FLVs/zk3Ie0GVkSB6h0rqIvMalCp7enIR87LkPSDGz9K4UA==} + /turbo-windows-64@1.10.15: + resolution: {integrity: sha512-3TdVU+WEH9ThvQGwV3ieX/XHebtYNHv9HARHauPwmVj3kakoALkpGxLclkHFBLdLKkqDvmHmXtcsfs6cXXRHJg==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /turbo-windows-arm64@1.10.14: - resolution: {integrity: sha512-rkBwrTPTxNSOUF7of8eVvvM+BkfkhA2OvpHM94if8tVsU+khrjglilp8MTVPHlyS9byfemPAmFN90oRIPB05BA==} + /turbo-windows-arm64@1.10.15: + resolution: {integrity: sha512-l+7UOBCbfadvPMYsX08hyLD+UIoAkg6ojfH+E8aud3gcA1padpjCJTh9gMpm3QdMbKwZteT5uUM+wyi6Rbbyww==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /turbo@1.10.14: - resolution: {integrity: sha512-hr9wDNYcsee+vLkCDIm8qTtwhJ6+UAMJc3nIY6+PNgUTtXcQgHxCq8BGoL7gbABvNWv76CNbK5qL4Lp9G3ZYRA==} + /turbo@1.10.15: + resolution: {integrity: sha512-mKKkqsuDAQy1wCCIjCdG+jOCwUflhckDMSRoeBPcIL/CnCl7c5yRDFe7SyaXloUUkt4tUR0rvNIhVCcT7YeQpg==} hasBin: true optionalDependencies: - turbo-darwin-64: 1.10.14 - turbo-darwin-arm64: 1.10.14 - turbo-linux-64: 1.10.14 - turbo-linux-arm64: 1.10.14 - turbo-windows-64: 1.10.14 - turbo-windows-arm64: 1.10.14 + turbo-darwin-64: 1.10.15 + turbo-darwin-arm64: 1.10.15 + turbo-linux-64: 1.10.15 + turbo-linux-arm64: 1.10.15 + turbo-windows-64: 1.10.15 + turbo-windows-arm64: 1.10.15 dev: true /type-check@0.4.0: @@ -8858,6 +9324,11 @@ packages: engines: {node: '>=4'} dev: true + /type-fest@0.12.0: + resolution: {integrity: sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==} + engines: {node: '>=10'} + dev: false + /type-fest@0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} @@ -8885,6 +9356,11 @@ packages: engines: {node: '>=12.20'} dev: false + /type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + dev: false + /typed-array-buffer@1.0.0: resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} engines: {node: '>= 0.4'} @@ -8947,7 +9423,6 @@ packages: /ufo@1.3.0: resolution: {integrity: sha512-bRn3CsoojyNStCZe0BG0Mt4Nr/4KF+rhFlnNXybgqt5pXHNFRlqinSoQaTrGyzE4X8aHplSb+TorH+COin9Yxw==} - dev: true /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} @@ -9208,7 +9683,7 @@ packages: - terser dev: true - /vite-plugin-singlefile@0.13.5(rollup@3.29.3)(vite@4.4.9): + /vite-plugin-singlefile@0.13.5(rollup@4.0.2)(vite@4.4.9): resolution: {integrity: sha512-y/aRGh8qHmw2f1IhaI/C6PJAaov47ESYDvUv1am1YHMhpY+19B5k5Odp8P+tgs+zhfvak6QB1ykrALQErEAo7g==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -9216,7 +9691,7 @@ packages: vite: '>=3.2.0' dependencies: micromatch: 4.0.5 - rollup: 3.29.3 + rollup: 4.0.2 vite: 4.4.9(@types/node@18.18.0) dev: true @@ -9368,7 +9843,7 @@ packages: - terser dev: true - /volar-service-typescript@0.0.13(@volar/language-service@1.10.1)(@volar/typescript@1.10.1): + /volar-service-typescript@0.0.13(@volar/language-service@1.10.1)(@volar/typescript@1.10.3): resolution: {integrity: sha512-fwpoA1L/bCXz5hl9W4EYJYNyorocfdfbLQ9lTM3rPVOzjRZVknEE8XP31RMPZhEg3sOxKh18+sLEL7j3bip8ew==} peerDependencies: '@volar/language-service': ~1.10.0 @@ -9378,7 +9853,7 @@ packages: optional: true dependencies: '@volar/language-service': 1.10.1 - '@volar/typescript': 1.10.1 + '@volar/typescript': 1.10.3 semver: 7.5.4 typescript-auto-import-cache: 0.3.0 vscode-languageserver-textdocument: 1.0.8 @@ -9494,8 +9969,8 @@ packages: - supports-color dev: true - /vue-eslint-parser@9.3.1(eslint@8.46.0): - resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==} + /vue-eslint-parser@9.3.2(eslint@8.46.0): + resolution: {integrity: sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' @@ -9671,6 +10146,19 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + /ws@8.14.2: + resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + /xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} @@ -9791,6 +10279,10 @@ packages: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} + /yoga-wasm-web@0.3.3: + resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==} + dev: false + /zod-to-json-schema@3.21.4(zod@3.22.2): resolution: {integrity: sha512-fjUZh4nQ1s6HMccgIeE0VP4QG/YRGPmyjO9sAh890aQKPEk3nqbfUXhMFaC+Dr5KvYBm8BCyvfpZf2jY9aGSsw==} peerDependencies: